// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. #if ASPNETCORE50 using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; namespace System.Collections.Generic { /// /// Helper extension methods for fast use of collections. /// internal static class CollectionExtensions { /// /// Return a new array with the value added to the end. Slow and best suited to long lived arrays with few /// writes relative to reads. /// public static T[] AppendAndReallocate(this T[] array, T value) { Debug.Assert(array != null); var originalLength = array.Length; var newArray = new T[originalLength + 1]; array.CopyTo(newArray, 0); newArray[originalLength] = value; return newArray; } /// /// Return the enumerable as an Array, copying if required. Optimized for common case where it is an Array. /// Avoid mutating the return value. /// public static T[] AsArray(this IEnumerable values) { Debug.Assert(values != null); var array = values as T[]; if (array == null) { array = values.ToArray(); } return array; } /// /// Return the enumerable as a Collection of T, copying if required. Optimized for the common case where it is /// a Collection of T and avoiding a copy if it implements IList of T. Avoid mutating the return value. /// public static Collection AsCollection(this IEnumerable enumerable) { Debug.Assert(enumerable != null); var collection = enumerable as Collection; if (collection != null) { return collection; } // Check for IList so that collection can wrap it instead of copying var list = enumerable as IList; if (list == null) { list = new List(enumerable); } return new Collection(list); } /// /// Return the enumerable as a IList of T, copying if required. Avoid mutating the return value. /// public static IList AsIList(this IEnumerable enumerable) { Debug.Assert(enumerable != null); var list = enumerable as IList; if (list != null) { return list; } return new List(enumerable); } /// /// Return the enumerable as a List of T, copying if required. Optimized for common case where it is an List of /// T or a ListWrapperCollection of T. Avoid mutating the return value. /// public static List AsList(this IEnumerable enumerable) { Debug.Assert(enumerable != null); List list = enumerable as List; if (list != null) { return list; } ListWrapperCollection listWrapper = enumerable as ListWrapperCollection; if (listWrapper != null) { return listWrapper.ItemsList; } return new List(enumerable); } /// /// Remove values from the list starting at the index start. /// public static void RemoveFrom(this List list, int start) { Debug.Assert(list != null); Debug.Assert(start >= 0 && start <= list.Count); list.RemoveRange(start, list.Count - start); } /// /// Return the only value from list, the type's default value if empty, or call the errorAction for 2 or more. /// public static T SingleDefaultOrError(this IList list, Action errorAction, TArg1 errorArg1) { Debug.Assert(list != null); Debug.Assert(errorAction != null); switch (list.Count) { case 0: return default(T); case 1: var value = list[0]; return value; default: errorAction(errorArg1); return default(T); } } /// /// Returns a single value in list matching type TMatch if there is only one, null if there are none of type /// TMatch or calls the errorAction with errorArg1 if there is more than one. /// public static TMatch SingleOfTypeDefaultOrError( this IList list, Action errorAction, TArg1 errorArg1) where TMatch : class { Debug.Assert(list != null); Debug.Assert(errorAction != null); TMatch result = null; for (var i = 0; i < list.Count; i++) { var typedValue = list[i] as TMatch; if (typedValue != null) { if (result == null) { result = typedValue; } else { errorAction(errorArg1); return null; } } } return result; } /// /// Convert an ICollection to an array, removing null values. Fast path for case where there are no null /// values. /// public static T[] ToArrayWithoutNulls(this ICollection collection) where T : class { Debug.Assert(collection != null); var result = new T[collection.Count]; var count = 0; foreach (var value in collection) { if (value != null) { result[count] = value; count++; } } if (count == collection.Count) { return result; } else { var trimmedResult = new T[count]; Array.Copy(result, trimmedResult, count); return trimmedResult; } } /// /// Convert the array to a Dictionary using the keySelector to extract keys from values and the specified /// comparer. Optimized for array input. /// public static Dictionary ToDictionaryFast( this TValue[] array, Func keySelector, IEqualityComparer comparer) { Debug.Assert(array != null); Debug.Assert(keySelector != null); var dictionary = new Dictionary(array.Length, comparer); for (var i = 0; i < array.Length; i++) { var value = array[i]; dictionary.Add(keySelector(value), value); } return dictionary; } /// /// Convert the list to a Dictionary using the keySelector to extract keys from values and the specified /// comparer. Optimized for IList of T input with fast path for array. /// public static Dictionary ToDictionaryFast( this IList list, Func keySelector, IEqualityComparer comparer) { Debug.Assert(list != null); Debug.Assert(keySelector != null); var array = list as TValue[]; if (array != null) { return ToDictionaryFast(array, keySelector, comparer); } return ToDictionaryFastNoCheck(list, keySelector, comparer); } /// /// Convert the enumerable to a Dictionary using the keySelector to extract keys from values and the specified /// comparer. Fast paths for array and IList of T. /// public static Dictionary ToDictionaryFast( this IEnumerable enumerable, Func keySelector, IEqualityComparer comparer) { Debug.Assert(enumerable != null); Debug.Assert(keySelector != null); var array = enumerable as TValue[]; if (array != null) { return ToDictionaryFast(array, keySelector, comparer); } var list = enumerable as IList; if (list != null) { return ToDictionaryFastNoCheck(list, keySelector, comparer); } var dictionary = new Dictionary(comparer); foreach (var value in enumerable) { dictionary.Add(keySelector(value), value); } return dictionary; } /// /// Convert the list to a Dictionary using the keySelector to extract keys from values and the specified /// comparer. Optimized for IList of T input. No checking for other types. /// private static Dictionary ToDictionaryFastNoCheck( IList list, Func keySelector, IEqualityComparer comparer) { Debug.Assert(list != null); Debug.Assert(keySelector != null); var listCount = list.Count; var dictionary = new Dictionary(listCount, comparer); for (var i = 0; i < listCount; i++) { var value = list[i]; dictionary.Add(keySelector(value), value); } return dictionary; } } } #endif