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