| File: System\Collections\Immutable\ImmutableExtensions.cs | Web Access |
| Project: src\runtime\src\libraries\System.Collections.Immutable\src\System.Collections.Immutable.csproj (System.Collections.Immutable) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; namespace System.Collections.Immutable { /// <summary> /// Extension methods for immutable types. /// </summary> internal static partial class ImmutableExtensions { internal static bool IsValueType<T>() { #if NET return typeof(T).IsValueType; #else if (default(T) != null) { return true; } Type t = typeof(T); if (t.IsConstructedGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) { return true; } return false; #endif } /// <summary> /// Provides a known wrapper around a sequence of elements that provides the number of elements /// and an indexer into its contents. /// </summary> /// <typeparam name="T">The type of elements in the collection.</typeparam> /// <param name="sequence">The collection.</param> /// <returns>An ordered collection. May not be thread-safe. Never null.</returns> internal static IReadOnlyList<T> AsReadOnlyList<T>(this IEnumerable<T> sequence) { Requires.NotNull(sequence, nameof(sequence)); if (sequence is IReadOnlyList<T> orderedCollection) { return orderedCollection; } if (sequence is IList<T> listOfT) { return new ListOfTWrapper<T>(listOfT); } // It would be great if SortedSet<T> and SortedDictionary<T> provided indexers into their collections, // but since they don't we have to clone them to an array. return new FallbackWrapper<T>(sequence); } /// <summary> /// Clears the specified stack. For empty stacks, it avoids the call to <see cref="Stack{T}.Clear"/>, which /// avoids a call into the runtime's implementation of <see cref="Array.Clear(Array, int, int)"/>, helping performance, /// in particular around inlining. <see cref="Stack{T}.Count"/> typically gets inlined by today's JIT, while /// <see cref="Stack{T}.Clear"/> and <see cref="Array.Clear(Array, int, int)"/> typically don't. /// </summary> /// <typeparam name="T">Specifies the type of data in the stack to be cleared.</typeparam> /// <param name="stack">The stack to clear.</param> internal static void ClearFastWhenEmpty<T>(this Stack<T> stack) { if (stack.Count > 0) { stack.Clear(); } } /// <summary> /// Gets a disposable enumerable that can be used as the source for a C# foreach loop /// that will not box the enumerator if it is of a particular type. /// </summary> /// <typeparam name="T">The type of value to be enumerated.</typeparam> /// <typeparam name="TEnumerator">The type of the Enumerator struct.</typeparam> /// <param name="enumerable">The collection to be enumerated.</param> /// <returns>A struct that enumerates the collection.</returns> internal static DisposableEnumeratorAdapter<T, TEnumerator> GetEnumerableDisposable<T, TEnumerator>(this IEnumerable<T> enumerable) where TEnumerator : struct, IStrongEnumerator<T>, IEnumerator<T> { Requires.NotNull(enumerable, nameof(enumerable)); if (enumerable is IStrongEnumerable<T, TEnumerator> strongEnumerable) { return new DisposableEnumeratorAdapter<T, TEnumerator>(strongEnumerable.GetEnumerator()); } else { // Consider for future: we could add more special cases for common // mutable collection types like List<T>+Enumerator and such. return new DisposableEnumeratorAdapter<T, TEnumerator>(enumerable.GetEnumerator()); } } /// <summary> /// Wraps a <see cref="IList{T}"/> as an ordered collection. /// </summary> /// <typeparam name="T">The type of element in the collection.</typeparam> private sealed class ListOfTWrapper<T> : IReadOnlyList<T> { /// <summary> /// The list being exposed. /// </summary> private readonly IList<T> _collection; /// <summary> /// Initializes a new instance of the <see cref="ListOfTWrapper{T}"/> class. /// </summary> /// <param name="collection">The collection.</param> internal ListOfTWrapper(IList<T> collection) { Requires.NotNull(collection, nameof(collection)); _collection = collection; } /// <summary> /// Gets the count. /// </summary> public int Count { get { return _collection.Count; } } /// <summary> /// Gets the <typeparamref name="T"/> at the specified index. /// </summary> public T this[int index] { get { return _collection[index]; } } /// <summary> /// Returns an enumerator that iterates through the collection. /// </summary> /// <returns> /// A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection. /// </returns> public IEnumerator<T> GetEnumerator() { return _collection.GetEnumerator(); } /// <summary> /// Returns an enumerator that iterates through a collection. /// </summary> /// <returns> /// An <see cref="IEnumerator"/> object that can be used to iterate through the collection. /// </returns> IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } /// <summary> /// Wraps any <see cref="IEnumerable{T}"/> as an ordered, indexable list. /// </summary> /// <typeparam name="T">The type of element in the collection.</typeparam> private sealed class FallbackWrapper<T> : IReadOnlyList<T> { /// <summary> /// The original sequence. /// </summary> private readonly IEnumerable<T> _sequence; /// <summary> /// The list-ified sequence. /// </summary> #pragma warning disable CA1859 private IList<T>? _collection; #pragma warning restore /// <summary> /// Initializes a new instance of the <see cref="FallbackWrapper{T}"/> class. /// </summary> /// <param name="sequence">The sequence.</param> internal FallbackWrapper(IEnumerable<T> sequence) { Requires.NotNull(sequence, nameof(sequence)); _sequence = sequence; } /// <summary> /// Gets the count. /// </summary> public int Count { get { if (_collection == null) { int count; if (_sequence.TryGetCount(out count)) { return count; } _collection = _sequence.ToArray(); } return _collection.Count; } } /// <summary> /// Gets the <typeparamref name="T"/> at the specified index. /// </summary> public T this[int index] { get { _collection ??= _sequence.ToArray(); return _collection[index]; } } /// <summary> /// Returns an enumerator that iterates through the collection. /// </summary> /// <returns> /// A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection. /// </returns> public IEnumerator<T> GetEnumerator() { return _sequence.GetEnumerator(); } /// <summary> /// Returns an enumerator that iterates through a collection. /// </summary> /// <returns> /// An <see cref="IEnumerator"/> object that can be used to iterate through the collection. /// </returns> IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } } }