/* ****************************************************************************
*
* 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];
}
}