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.Collections.ObjectModel;
19 using System.Diagnostics;
21 namespace Microsoft.Scripting.Utils {
22 internal static class CollectionExtensions {
24 /// Wraps the provided enumerable into a ReadOnlyCollection{T}
26 /// Copies all of the data into a new array, so the data can't be
27 /// changed after creation. The exception is if the enumerable is
28 /// already a ReadOnlyCollection{T}, in which case we just return it.
30 internal static ReadOnlyCollection<T> ToReadOnly<T>(this IEnumerable<T> enumerable) {
31 if (enumerable == null) {
32 return EmptyReadOnlyCollection<T>.Instance;
35 var roCollection = enumerable as ReadOnlyCollection<T>;
36 if (roCollection != null) {
40 var collection = enumerable as ICollection<T>;
41 if (collection != null) {
42 int count = collection.Count;
44 return EmptyReadOnlyCollection<T>.Instance;
47 T[] array = new T[count];
48 collection.CopyTo(array, 0);
49 return new ReadOnlyCollection<T>(array);
52 // ToArray trims the excess space and speeds up access
53 return new ReadOnlyCollection<T>(new List<T>(enumerable).ToArray());
56 // We could probably improve the hashing here
57 internal static int ListHashCode<T>(this IEnumerable<T> list) {
58 var cmp = EqualityComparer<T>.Default;
60 foreach (T t in list) {
61 h ^= (h << 5) ^ cmp.GetHashCode(t);
66 internal static bool ListEquals<T>(this ICollection<T> first, ICollection<T> second) {
67 if (first.Count != second.Count) {
70 var cmp = EqualityComparer<T>.Default;
71 var f = first.GetEnumerator();
72 var s = second.GetEnumerator();
73 while (f.MoveNext()) {
76 if (!cmp.Equals(f.Current, s.Current)) {
83 // Name needs to be different so it doesn't conflict with Enumerable.Select
84 internal static U[] Map<T, U>(this ICollection<T> collection, Func<T, U> select) {
85 int count = collection.Count;
86 U[] result = new U[count];
88 foreach (T t in collection) {
89 result[count++] = select(t);
94 internal static T[] RemoveFirst<T>(this T[] array) {
95 T[] result = new T[array.Length - 1];
96 Array.Copy(array, 1, result, 0, result.Length);
100 internal static T[] RemoveLast<T>(this T[] array) {
101 T[] result = new T[array.Length - 1];
102 Array.Copy(array, 0, result, 0, result.Length);
106 internal static T[] AddFirst<T>(this IList<T> list, T item) {
107 T[] res = new T[list.Count + 1];
113 internal static T[] AddLast<T>(this IList<T> list, T item) {
114 T[] res = new T[list.Count + 1];
116 res[list.Count] = item;
120 internal static T[] RemoveAt<T>(this T[] array, int indexToRemove) {
121 Debug.Assert(array != null);
122 Debug.Assert(indexToRemove >= 0 && indexToRemove < array.Length);
124 T[] result = new T[array.Length - 1];
125 if (indexToRemove > 0) {
126 Array.Copy(array, 0, result, 0, indexToRemove);
128 int remaining = array.Length - indexToRemove - 1;
130 Array.Copy(array, array.Length - remaining, result, result.Length - remaining, remaining);
135 internal static T[] RotateRight<T>(this T[] array, int count) {
136 Debug.Assert(count >= 0 && count <= array.Length);
138 T[] result = new T[array.Length];
139 // The head of the array is shifted, and the tail will be rotated to the head of the resulting array
140 int sizeOfShiftedArray = array.Length - count;
141 Array.Copy(array, 0, result, count, sizeOfShiftedArray);
142 Array.Copy(array, sizeOfShiftedArray, result, 0, count);
148 internal static class EmptyReadOnlyCollection<T> {
149 internal static ReadOnlyCollection<T> Instance = new ReadOnlyCollection<T>(new T[0]);
151 // TODO: Should we use this everywhere for empty arrays?
152 // my thought is, probably more hassle than its worth
153 internal static class EmptyArray<T> {
154 internal static T[] Instance = new T[0];