/* **************************************************************************** * * 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; using System.Collections.Generic; namespace Microsoft.Scripting.Utils { /// /// Allows wrapping of proxy types (like COM RCWs) to expose their IEnumerable functionality /// which is supported after casting to IEnumerable, even though Reflection will not indicate /// IEnumerable as a supported interface /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1010:CollectionsShouldImplementGenericInterface")] // TODO public class EnumerableWrapper : IEnumerable { private IEnumerable _wrappedObject; public EnumerableWrapper(IEnumerable o) { _wrappedObject = o; } public IEnumerator GetEnumerator() { return _wrappedObject.GetEnumerator(); } } public static class CollectionUtils { #if !FEATURE_VARIANCE public static IEnumerable Cast(this IEnumerable sequence) where S : T { foreach (var item in sequence) { yield return (T)item; } } #else public static IEnumerable Cast(this IEnumerable sequence) where S : T { return (IEnumerable)sequence; } #endif public static IEnumerable ToCovariant(IEnumerable enumerable) where T : TSuper { #if FEATURE_VARIANCE return (IEnumerable)enumerable; #else return new CovariantConvertor(enumerable); #endif } public static void AddRange(ICollection collection, IEnumerable items) { ContractUtils.RequiresNotNull(collection, "collection"); ContractUtils.RequiresNotNull(items, "items"); List list = collection as List; if (list != null) { list.AddRange(items); } else { foreach (T item in items) { collection.Add(item); } } } public static void AddRange(this IList list, IEnumerable items) { foreach (var item in items) { list.Add(item); } } public static IEnumerable ToEnumerable(IEnumerable enumerable) { foreach (T item in enumerable) { yield return item; } } public static IEnumerator ToCovariant(IEnumerator enumerator) where T : TSuper { ContractUtils.RequiresNotNull(enumerator, "enumerator"); while (enumerator.MoveNext()) { yield return enumerator.Current; } } private class CovariantConvertor : IEnumerable where T : TSuper { private IEnumerable _enumerable; public CovariantConvertor(IEnumerable enumerable) { ContractUtils.RequiresNotNull(enumerable, "enumerable"); _enumerable = enumerable; } public IEnumerator GetEnumerator() { return CollectionUtils.ToCovariant(_enumerable.GetEnumerator()); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public static IDictionaryEnumerator ToDictionaryEnumerator(IEnumerator> enumerator) { return new DictionaryEnumerator(enumerator); } private sealed class DictionaryEnumerator : IDictionaryEnumerator { private readonly IEnumerator> _enumerator; public DictionaryEnumerator(IEnumerator> enumerator) { _enumerator = enumerator; } public DictionaryEntry Entry { get { return new DictionaryEntry(_enumerator.Current.Key, _enumerator.Current.Value); } } public object Key { get { return _enumerator.Current.Key; } } public object Value { get { return _enumerator.Current.Value; } } public object Current { get { return Entry; } } public bool MoveNext() { return _enumerator.MoveNext(); } public void Reset() { _enumerator.Reset(); } } public static List MakeList(T item) { List result = new List(); result.Add(item); return result; } public static int CountOf(IList list, T item) where T : IEquatable { if (list == null) return 0; int result = 0; for (int i = 0; i < list.Count; i++) { if (list[i].Equals(item)) { result++; } } return result; } public static int Max(this IEnumerable values) { ContractUtils.RequiresNotNull(values, "values"); int result = Int32.MinValue; foreach (var value in values) { if (value > result) { result = value; } } return result; } public static bool TrueForAll(IEnumerable collection, Predicate predicate) { ContractUtils.RequiresNotNull(collection, "collection"); ContractUtils.RequiresNotNull(predicate, "predicate"); foreach (T item in collection) { if (!predicate(item)) return false; } return true; } public static IList ConvertAll(IList collection, Func predicate) { ContractUtils.RequiresNotNull(collection, "collection"); ContractUtils.RequiresNotNull(predicate, "predicate"); List res = new List(collection.Count); foreach (T item in collection) { res.Add(predicate(item)); } return res; } public static List GetRange(IList list, int index, int count) { ContractUtils.RequiresNotNull(list, "list"); ContractUtils.RequiresArrayRange(list, index, count, "index", "count"); List result = new List(count); int stop = index + count; for (int i = index; i < stop; i++) { result.Add(list[i]); } return result; } public static void InsertRange(IList collection, int index, IEnumerable items) { ContractUtils.RequiresNotNull(collection, "collection"); ContractUtils.RequiresNotNull(items, "items"); ContractUtils.RequiresArrayInsertIndex(collection, index, "index"); List list = collection as List; if (list != null) { list.InsertRange(index, items); } else { int i = index; foreach (T obj in items) { collection.Insert(i++, obj); } } } public static void RemoveRange(IList collection, int index, int count) { ContractUtils.RequiresNotNull(collection, "collection"); ContractUtils.RequiresArrayRange(collection, index, count, "index", "count"); List list = collection as List; if (list != null) { list.RemoveRange(index, count); } else { for (int i = index + count - 1; i >= index; i--) { collection.RemoveAt(i); } } } public static int FindIndex(this IList collection, Predicate predicate) { ContractUtils.RequiresNotNull(collection, "collection"); ContractUtils.RequiresNotNull(predicate, "predicate"); for (int i = 0; i < collection.Count; i++) { if (predicate(collection[i])) { return i; } } return -1; } public static IList ToSortedList(this ICollection collection, Comparison comparison) { ContractUtils.RequiresNotNull(collection, "collection"); ContractUtils.RequiresNotNull(comparison, "comparison"); var array = new T[collection.Count]; collection.CopyTo(array, 0); Array.Sort(array, comparison); return array; } public static T[] ToReverseArray(this IList list) { ContractUtils.RequiresNotNull(list, "list"); T[] result = new T[list.Count]; for (int i = 0; i < result.Length; i++) { result[i] = list[result.Length - 1 - i]; } return result; } #if SILVERLIGHT || WIN8 || WP75 // HashSet.CreateSetComparer not available on Silverlight public static IEqualityComparer> CreateSetComparer() { return new HashSetEqualityComparer(); } class HashSetEqualityComparer : IEqualityComparer> { private IEqualityComparer _comparer; public HashSetEqualityComparer() { _comparer = EqualityComparer.Default; } public bool Equals(HashSet x, HashSet y) { if (x == y) { return true; } else if (x == null || y == null || x.Count != y.Count) { return false; } foreach (T value in x) { if (!y.Contains(value)) { return false; } } return true; } public int GetHashCode(HashSet obj) { int res = 6551; if (obj != null) { foreach (T t in obj) { res = res ^ _comparer.GetHashCode(t); } } return res; } } #else public static IEqualityComparer> CreateSetComparer() { return HashSet.CreateSetComparer(); } #endif } }