1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
6 * copy of the license can be found in the License.html file at the root of this distribution. If
7 * you cannot locate the Apache License, Version 2.0, please send an email to
8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
9 * by the terms of the Apache License, Version 2.0.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
17 using System
.Collections
.Generic
;
18 using System
.Diagnostics
;
21 namespace Microsoft
.Scripting
.Utils
{
22 public static class ArrayUtils
{
23 internal sealed class FunctorComparer
<T
> : IComparer
<T
> {
24 private readonly Comparison
<T
> _comparison
;
26 public FunctorComparer(Comparison
<T
> comparison
) {
27 Assert
.NotNull(comparison
);
28 _comparison
= comparison
;
31 public int Compare(T x
, T y
) {
32 return _comparison(x
, y
);
37 [System
.Diagnostics
.CodeAnalysis
.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
38 public static readonly string[] EmptyStrings
= new string[0];
40 [System
.Diagnostics
.CodeAnalysis
.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
41 public static readonly object[] EmptyObjects
= new object[0];
43 public static IComparer
<T
> ToComparer
<T
>(Comparison
<T
> comparison
) {
44 return new FunctorComparer
<T
>(comparison
);
47 public static TOutput
[] ConvertAll
<TInput
, TOutput
>(TInput
[] input
, Func
<TInput
, TOutput
> conv
) {
48 ContractUtils
.RequiresNotNull(input
, "input");
49 ContractUtils
.RequiresNotNull(conv
, "conv");
51 TOutput
[] res
= new TOutput
[input
.Length
];
52 for (int i
= 0; i
< input
.Length
; i
++) {
53 res
[i
] = conv(input
[i
]);
59 [System
.Diagnostics
.CodeAnalysis
.SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId
= "1#")] // TODO: fix
60 public static void PrintTable(StringBuilder output
, string[,] table
) {
61 ContractUtils
.RequiresNotNull(output
, "output");
62 ContractUtils
.RequiresNotNull(table
, "table");
65 for (int i
= 0; i
< table
.GetLength(0); i
++) {
66 if (table
[i
, 0].Length
> max_width
) {
67 max_width
= table
[i
, 0].Length
;
71 for (int i
= 0; i
< table
.GetLength(0); i
++) {
73 output
.Append(table
[i
, 0]);
75 for (int j
= table
[i
, 0].Length
; j
< max_width
+ 1; j
++) {
79 output
.AppendLine(table
[i
, 1]);
83 public static T
[] Copy
<T
>(T
[] array
) {
84 return (array
.Length
> 0) ? (T
[])array
.Clone() : array
;
88 /// Converts a generic ICollection of T into an array of T.
90 /// If the collection is already an array of T the original collection is returned.
92 public static T
[] ToArray
<T
>(ICollection
<T
> list
) {
93 return (list
as T
[]) ?? MakeArray(list
);
97 /// Converts a generic ICollection of T into an array of R using a given conversion.
99 /// If the collection is already an array of R the original collection is returned.
101 public static TResult
[] ToArray
<TElement
, TResult
>(ICollection
<TElement
> list
, Func
<TElement
, TResult
> convertor
) {
102 TResult
[] res
= list
as TResult
[];
104 res
= new TResult
[list
.Count
];
106 foreach (TElement obj
in list
) {
107 res
[i
++] = convertor(obj
);
113 public static T
[] MakeArray
<T
>(ICollection
<T
> list
) {
114 if (list
.Count
== 0) {
118 T
[] res
= new T
[list
.Count
];
123 public static T
[] MakeArray
<T
>(ICollection
<T
> elements
, int reservedSlotsBefore
, int reservedSlotsAfter
) {
124 if (reservedSlotsAfter
< 0) throw new ArgumentOutOfRangeException("reservedSlotsAfter");
125 if (reservedSlotsBefore
< 0) throw new ArgumentOutOfRangeException("reservedSlotsBefore");
127 if (elements
== null) {
128 return new T
[reservedSlotsBefore
+ reservedSlotsAfter
];
131 T
[] result
= new T
[reservedSlotsBefore
+ elements
.Count
+ reservedSlotsAfter
];
132 elements
.CopyTo(result
, reservedSlotsBefore
);
136 public static T
[] RotateRight
<T
>(T
[] array
, int count
) {
137 ContractUtils
.RequiresNotNull(array
, "array");
138 if ((count
< 0) || (count
> array
.Length
)) throw new ArgumentOutOfRangeException("count");
140 T
[] result
= new T
[array
.Length
];
141 // The head of the array is shifted, and the tail will be rotated to the head of the resulting array
142 int sizeOfShiftedArray
= array
.Length
- count
;
143 Array
.Copy(array
, 0, result
, count
, sizeOfShiftedArray
);
144 Array
.Copy(array
, sizeOfShiftedArray
, result
, 0, count
);
148 public static T
[] ShiftRight
<T
>(T
[] array
, int count
) {
149 ContractUtils
.RequiresNotNull(array
, "array");
150 if (count
< 0) throw new ArgumentOutOfRangeException("count");
152 T
[] result
= new T
[array
.Length
+ count
];
153 System
.Array
.Copy(array
, 0, result
, count
, array
.Length
);
157 public static T
[] ShiftLeft
<T
>(T
[] array
, int count
) {
158 ContractUtils
.RequiresNotNull(array
, "array");
159 if (count
< 0) throw new ArgumentOutOfRangeException("count");
161 T
[] result
= new T
[array
.Length
- count
];
162 System
.Array
.Copy(array
, count
, result
, 0, result
.Length
);
166 public static T
[] Insert
<T
>(T item
, IList
<T
> list
) {
167 T
[] res
= new T
[list
.Count
+ 1];
173 public static T
[] Insert
<T
>(T item1
, T item2
, IList
<T
> list
) {
174 T
[] res
= new T
[list
.Count
+ 2];
181 public static T
[] Insert
<T
>(T item
, T
[] array
) {
182 T
[] result
= ShiftRight(array
, 1);
187 public static T
[] Insert
<T
>(T item1
, T item2
, T
[] array
) {
188 T
[] result
= ShiftRight(array
, 2);
194 public static T
[] Append
<T
>(T
[] array
, T item
) {
195 System
.Array
.Resize
<T
>(ref array
, (array
== null) ? 1 : array
.Length
+ 1);
196 array
[array
.Length
- 1] = item
;
200 public static T
[] AppendRange
<T
>(T
[] array
, IList
<T
> items
) {
201 return AppendRange
<T
>(array
, items
, 0);
204 public static T
[] AppendRange
<T
>(T
[] array
, IList
<T
> items
, int additionalItemCount
) {
205 if (additionalItemCount
< 0) {
206 throw new ArgumentOutOfRangeException("additionalItemCount");
209 int j
= (array
== null) ? 0 : array
.Length
;
210 System
.Array
.Resize
<T
>(ref array
, j
+ items
.Count
+ additionalItemCount
);
212 for (int i
= 0; i
< items
.Count
; i
++, j
++) {
219 [System
.Diagnostics
.CodeAnalysis
.SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional")] // TODO: fix
220 public static T
[,] Concatenate
<T
>(T
[,] array1
, T
[,] array2
) {
221 int columnsCount
= array1
.GetLength(1);
222 Debug
.Assert(array2
.GetLength(1) == columnsCount
);
224 int row1Count
= array1
.GetLength(0);
225 int row2Count
= array2
.GetLength(0);
226 int totalRowsCount
= row1Count
+ row2Count
;
227 T
[,] result
= new T
[totalRowsCount
, columnsCount
];
229 for (int i
= 0; i
< row1Count
; i
++) {
230 for (int j
= 0; j
< columnsCount
; j
++) {
231 result
[i
, j
] = array1
[i
, j
];
235 for (int i
= 0; i
< row2Count
; i
++) {
236 for (int j
= 0; j
< columnsCount
; j
++) {
237 result
[(i
+ row1Count
), j
] = array2
[i
, j
];
244 public static void SwapLastTwo
<T
>(T
[] array
) {
245 Debug
.Assert(array
!= null && array
.Length
>= 2);
247 T temp
= array
[array
.Length
- 1];
248 array
[array
.Length
- 1] = array
[array
.Length
- 2];
249 array
[array
.Length
- 2] = temp
;
252 public static T
[] RemoveFirst
<T
>(IList
<T
> list
) {
253 return ShiftLeft(MakeArray(list
), 1);
256 public static T
[] RemoveFirst
<T
>(T
[] array
) {
257 return ShiftLeft(array
, 1);
260 public static T
[] RemoveLast
<T
>(T
[] array
) {
261 ContractUtils
.RequiresNotNull(array
, "array");
263 System
.Array
.Resize(ref array
, array
.Length
- 1);
267 public static T
[] RemoveAt
<T
>(IList
<T
> list
, int indexToRemove
) {
268 return RemoveAt(MakeArray(list
), indexToRemove
);
271 public static T
[] RemoveAt
<T
>(T
[] array
, int indexToRemove
) {
272 ContractUtils
.RequiresNotNull(array
, "array");
273 ContractUtils
.Requires(indexToRemove
>= 0 && indexToRemove
< array
.Length
, "index");
275 T
[] result
= new T
[array
.Length
- 1];
276 if (indexToRemove
> 0) {
277 Array
.Copy(array
, 0, result
, 0, indexToRemove
);
279 int remaining
= array
.Length
- indexToRemove
- 1;
281 Array
.Copy(array
, array
.Length
- remaining
, result
, result
.Length
- remaining
, remaining
);
286 public static T
[] InsertAt
<T
>(IList
<T
> list
, int index
, params T
[] items
) {
287 return InsertAt(MakeArray(list
), index
, items
);
290 public static T
[] InsertAt
<T
>(T
[] array
, int index
, params T
[] items
) {
291 ContractUtils
.RequiresNotNull(array
, "array");
292 ContractUtils
.RequiresNotNull(items
, "items");
293 ContractUtils
.Requires(index
>= 0 && index
<= array
.Length
, "index");
295 if (items
.Length
== 0) {
299 T
[] result
= new T
[array
.Length
+ items
.Length
];
301 Array
.Copy(array
, 0, result
, 0, index
);
303 Array
.Copy(items
, 0, result
, index
, items
.Length
);
305 int remaining
= array
.Length
- index
;
307 Array
.Copy(array
, array
.Length
- remaining
, result
, result
.Length
- remaining
, remaining
);
312 public static bool ValueEquals
<T
>(this T
[] array
, T
[] other
) {
313 if (other
.Length
!= array
.Length
) {
317 for (int i
= 0; i
< array
.Length
; i
++) {
318 if (!Object
.Equals(array
[i
], other
[i
])) {
326 public static int GetValueHashCode
<T
>(this T
[] array
) {
327 return GetValueHashCode
<T
>(array
, 0, array
.Length
);
330 public static int GetValueHashCode
<T
>(this T
[] array
, int start
, int count
) {
331 ContractUtils
.RequiresNotNull(array
, "array");
332 ContractUtils
.RequiresArrayRange(array
.Length
, start
, count
, "start", "count");
338 int result
= array
[start
].GetHashCode();
339 for (int i
= 1; i
< count
; i
++) {
340 result
= ((result
<< 5) | (result
>> 27)) ^ array
[start
+ i
].GetHashCode();
346 public static T
[] Reverse
<T
>(this T
[] array
) {
347 T
[] res
= new T
[array
.Length
];
348 for (int i
= 0; i
< array
.Length
; i
++) {
349 res
[array
.Length
- i
- 1] = array
[i
];