/ndp/fx/src/Core/Microsoft/Scripting/Utils/CollectionExtensions.cs
C# | 195 lines | 146 code | 25 blank | 24 comment | 20 complexity | fd33335213c84bac01420745132ef788 MD5 | raw file
1/* ****************************************************************************
2 *
3 * Copyright (c) Microsoft Corporation.
4 *
5 * This source code is subject to terms and conditions of the Microsoft Public License. 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 Microsoft Public License, 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 Microsoft Public License.
10 *
11 * You must not remove this notice, or any other, from this software.
12 *
13 *
14 * ***************************************************************************/
15
16#if CLR2
17using Microsoft.Scripting.Utils;
18#else
19using System.Diagnostics.Contracts;
20#endif
21
22using System.Collections.Generic;
23using System.Collections.ObjectModel;
24using System.Diagnostics;
25using System.Runtime.CompilerServices;
26
27namespace System.Dynamic.Utils {
28 internal static class CollectionExtensions {
29 /// <summary>
30 /// Wraps the provided enumerable into a ReadOnlyCollection{T}
31 ///
32 /// Copies all of the data into a new array, so the data can't be
33 /// changed after creation. The exception is if the enumerable is
34 /// already a ReadOnlyCollection{T}, in which case we just return it.
35 /// </summary>
36#if !CLR2
37 [Pure]
38#endif
39 internal static ReadOnlyCollection<T> ToReadOnly<T>(this IEnumerable<T> enumerable) {
40 if (enumerable == null) {
41 return EmptyReadOnlyCollection<T>.Instance;
42 }
43
44 var troc = enumerable as TrueReadOnlyCollection<T>;
45 if (troc != null) {
46 return troc;
47 }
48
49 var builder = enumerable as ReadOnlyCollectionBuilder<T>;
50 if (builder != null) {
51 return builder.ToReadOnlyCollection();
52 }
53
54 var collection = enumerable as ICollection<T>;
55 if (collection != null) {
56 int count = collection.Count;
57 if (count == 0) {
58 return EmptyReadOnlyCollection<T>.Instance;
59 }
60
61 T[] clone = new T[count];
62 collection.CopyTo(clone, 0);
63 return new TrueReadOnlyCollection<T>(clone);
64 }
65
66 // ToArray trims the excess space and speeds up access
67 return new TrueReadOnlyCollection<T>(new List<T>(enumerable).ToArray());
68 }
69
70 // We could probably improve the hashing here
71 internal static int ListHashCode<T>(this IEnumerable<T> list) {
72 var cmp = EqualityComparer<T>.Default;
73 int h = 6551;
74 foreach (T t in list) {
75 h ^= (h << 5) ^ cmp.GetHashCode(t);
76 }
77 return h;
78 }
79
80#if !CLR2
81 [Pure]
82#endif
83 internal static bool ListEquals<T>(this ICollection<T> first, ICollection<T> second) {
84 if (first.Count != second.Count) {
85 return false;
86 }
87 var cmp = EqualityComparer<T>.Default;
88 var f = first.GetEnumerator();
89 var s = second.GetEnumerator();
90 while (f.MoveNext()) {
91 s.MoveNext();
92
93 if (!cmp.Equals(f.Current, s.Current)) {
94 return false;
95 }
96 }
97 return true;
98 }
99
100 internal static IEnumerable<U> Select<T, U>(this IEnumerable<T> enumerable, Func<T, U> select) {
101 foreach (T t in enumerable) {
102 yield return select(t);
103 }
104 }
105
106 // Name needs to be different so it doesn't conflict with Enumerable.Select
107 internal static U[] Map<T, U>(this ICollection<T> collection, Func<T, U> select) {
108 int count = collection.Count;
109 U[] result = new U[count];
110 count = 0;
111 foreach (T t in collection) {
112 result[count++] = select(t);
113 }
114 return result;
115 }
116
117 internal static IEnumerable<T> Where<T>(this IEnumerable<T> enumerable, Func<T, bool> where) {
118 foreach (T t in enumerable) {
119 if (where(t)) {
120 yield return t;
121 }
122 }
123 }
124
125 internal static bool Any<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
126 foreach (T element in source) {
127 if (predicate(element)) {
128 return true;
129 }
130 }
131 return false;
132 }
133
134 internal static bool All<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
135 foreach (T element in source) {
136 if (!predicate(element)) {
137 return false;
138 }
139 }
140 return true;
141 }
142
143 internal static T[] RemoveFirst<T>(this T[] array) {
144 T[] result = new T[array.Length - 1];
145 Array.Copy(array, 1, result, 0, result.Length);
146 return result;
147 }
148
149 internal static T[] RemoveLast<T>(this T[] array) {
150 T[] result = new T[array.Length - 1];
151 Array.Copy(array, 0, result, 0, result.Length);
152 return result;
153 }
154
155 internal static T[] AddFirst<T>(this IList<T> list, T item) {
156 T[] res = new T[list.Count + 1];
157 res[0] = item;
158 list.CopyTo(res, 1);
159 return res;
160 }
161
162 internal static T[] AddLast<T>(this IList<T> list, T item) {
163 T[] res = new T[list.Count + 1];
164 list.CopyTo(res, 0);
165 res[list.Count] = item;
166 return res;
167 }
168
169 internal static T First<T>(this IEnumerable<T> source) {
170 var list = source as IList<T>;
171 if (list != null) {
172 return list[0];
173 }
174 using (var e = source.GetEnumerator()) {
175 if (e.MoveNext()) return e.Current;
176 }
177 throw new InvalidOperationException();
178 }
179
180 internal static T Last<T>(this IList<T> list) {
181 return list[list.Count - 1];
182 }
183
184 internal static T[] Copy<T>(this T[] array) {
185 T[] copy = new T[array.Length];
186 Array.Copy(array, copy, array.Length);
187 return copy;
188 }
189 }
190
191
192 internal static class EmptyReadOnlyCollection<T> {
193 internal static ReadOnlyCollection<T> Instance = new TrueReadOnlyCollection<T>(new T[0]);
194 }
195}