/* **************************************************************************** * * Copyright (c) Microsoft Corporation. * * This source code is subject to terms and conditions of the Apache License, Version 2.0. A * copy of the license can be found in the License.html file at the root of this distribution. If * you cannot locate the Apache License, Version 2.0, please send an email to * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound * by the terms of the Apache License, Version 2.0. * * You must not remove this notice, or any other, from this software. * * * ***************************************************************************/ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; namespace Microsoft.Scripting.Utils { internal static class CollectionExtensions { /// /// Wraps the provided enumerable into a ReadOnlyCollection{T} /// /// Copies all of the data into a new array, so the data can't be /// changed after creation. The exception is if the enumerable is /// already a ReadOnlyCollection{T}, in which case we just return it. /// internal static ReadOnlyCollection ToReadOnly(this IEnumerable enumerable) { if (enumerable == null) { return EmptyReadOnlyCollection.Instance; } var roCollection = enumerable as ReadOnlyCollection; if (roCollection != null) { return roCollection; } var collection = enumerable as ICollection; if (collection != null) { int count = collection.Count; if (count == 0) { return EmptyReadOnlyCollection.Instance; } T[] array = new T[count]; collection.CopyTo(array, 0); return new ReadOnlyCollection(array); } // ToArray trims the excess space and speeds up access return new ReadOnlyCollection(new List(enumerable).ToArray()); } // We could probably improve the hashing here internal static int ListHashCode(this IEnumerable list) { var cmp = EqualityComparer.Default; int h = 6551; foreach (T t in list) { h ^= (h << 5) ^ cmp.GetHashCode(t); } return h; } internal static bool ListEquals(this ICollection first, ICollection second) { if (first.Count != second.Count) { return false; } var cmp = EqualityComparer.Default; var f = first.GetEnumerator(); var s = second.GetEnumerator(); while (f.MoveNext()) { s.MoveNext(); if (!cmp.Equals(f.Current, s.Current)) { return false; } } return true; } // Name needs to be different so it doesn't conflict with Enumerable.Select internal static U[] Map(this ICollection collection, Func select) { int count = collection.Count; U[] result = new U[count]; count = 0; foreach (T t in collection) { result[count++] = select(t); } return result; } internal static T[] RemoveFirst(this T[] array) { T[] result = new T[array.Length - 1]; Array.Copy(array, 1, result, 0, result.Length); return result; } internal static T[] RemoveLast(this T[] array) { T[] result = new T[array.Length - 1]; Array.Copy(array, 0, result, 0, result.Length); return result; } internal static T[] AddFirst(this IList list, T item) { T[] res = new T[list.Count + 1]; res[0] = item; list.CopyTo(res, 1); return res; } internal static T[] AddLast(this IList list, T item) { T[] res = new T[list.Count + 1]; list.CopyTo(res, 0); res[list.Count] = item; return res; } internal static T[] RemoveAt(this T[] array, int indexToRemove) { Debug.Assert(array != null); Debug.Assert(indexToRemove >= 0 && indexToRemove < array.Length); T[] result = new T[array.Length - 1]; if (indexToRemove > 0) { Array.Copy(array, 0, result, 0, indexToRemove); } int remaining = array.Length - indexToRemove - 1; if (remaining > 0) { Array.Copy(array, array.Length - remaining, result, result.Length - remaining, remaining); } return result; } internal static T[] RotateRight(this T[] array, int count) { Debug.Assert(count >= 0 && count <= array.Length); T[] result = new T[array.Length]; // The head of the array is shifted, and the tail will be rotated to the head of the resulting array int sizeOfShiftedArray = array.Length - count; Array.Copy(array, 0, result, count, sizeOfShiftedArray); Array.Copy(array, sizeOfShiftedArray, result, 0, count); return result; } } internal static class EmptyReadOnlyCollection { internal static ReadOnlyCollection Instance = new ReadOnlyCollection(new T[0]); } // TODO: Should we use this everywhere for empty arrays? // my thought is, probably more hassle than its worth internal static class EmptyArray { internal static T[] Instance = new T[0]; } }