Collection
Provides utility methods to work with collections.
using DotNext.Buffers;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace DotNext.Collections.Generic
{
[NullableContext(1)]
[Nullable(0)]
public static class Collection
{
[StructLayout(LayoutKind.Auto)]
[NullableContext(0)]
public readonly struct ConsumingEnumerable<[Nullable(2)] T> : IEnumerable<T>, IEnumerable
{
[StructLayout(LayoutKind.Auto)]
public struct Enumerator : IEnumerator<T>, IEnumerator, IDisposable
{
private readonly IProducerConsumerCollection<T> collection;
private T current;
[Nullable(1)]
public T Current {
[IsReadOnly]
[NullableContext(1)]
get {
return current;
}
}
[Nullable(2)]
object IEnumerator.Current {
[IsReadOnly]
get {
return Current;
}
}
internal Enumerator(IProducerConsumerCollection<T> collection)
{
this.collection = collection;
current = default(T);
}
public bool MoveNext()
{
return collection?.TryTake(out current) ?? false;
}
[IsReadOnly]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
void IDisposable.Dispose()
{
this = default(Enumerator);
}
}
private readonly IProducerConsumerCollection<T> collection;
internal ConsumingEnumerable(IProducerConsumerCollection<T> collection)
{
this.collection = collection;
}
public Enumerator GetEnumerator()
{
return new Enumerator(collection);
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
private sealed class NotNullEnumerable<T> : IEnumerable<T>, IEnumerable where T : class
{
private sealed class Enumerator : Disposable, IEnumerator<T>, IEnumerator, IDisposable
{
private readonly IEnumerator<T> enumerator;
private T current;
public T Current {
get {
T val = current;
if (val == null)
throw new InvalidOperationException();
return val;
}
}
object IEnumerator.Current {
get {
return Current;
}
}
internal Enumerator(IEnumerable<T> enumerable)
{
enumerator = enumerable.GetEnumerator();
}
public bool MoveNext()
{
while (enumerator.MoveNext()) {
T val = enumerator.Current;
if (val != null) {
current = val;
return true;
}
}
return false;
}
public void Reset()
{
enumerator.Reset();
}
protected override void Dispose(bool disposing)
{
if (disposing) {
current = null;
enumerator.Dispose();
}
base.Dispose(disposing);
}
}
private readonly IEnumerable<T> enumerable;
internal NotNullEnumerable(IEnumerable<T> enumerable)
{
this.enumerable = enumerable;
}
public IEnumerator<T> GetEnumerator()
{
return new Enumerator(enumerable);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
[return: Nullable(new byte[] {
0,
1
})]
public static MemoryOwner<T> Copy<[Nullable(2)] T>(this IEnumerable<T> enumerable, int sizeHint = 0, [Nullable(new byte[] {
2,
1
})] MemoryAllocator<T> allocator = null)
{
ArgumentNullException.ThrowIfNull((object)enumerable, "enumerable");
ArgumentOutOfRangeException.ThrowIfNegative<int>(sizeHint, "sizeHint");
List<T> list = enumerable as List<T>;
if (list != null)
return CollectionsMarshal.AsSpan(list).Copy(allocator);
T[] array = enumerable as T[];
if (array != null)
return Span.Copy(array, allocator);
string text = enumerable as string;
if (text != null)
return Unsafe.BitCast<MemoryOwner<char>, MemoryOwner<T>>(text.AsSpan().Copy(Unsafe.As<MemoryAllocator<char>>((object)allocator)));
if (!(enumerable is ArraySegment<T>)) {
ICollection<T> collection = enumerable as ICollection<T>;
if (collection != null)
return (collection.Count == 0) ? default(MemoryOwner<T>) : ((allocator == null) ? <Copy>g__CopyCollection|0_0(collection) : <Copy>g__CopySlow|0_1(collection, collection.Count, allocator));
IReadOnlyCollection<T> readOnlyCollection = enumerable as IReadOnlyCollection<T>;
if (readOnlyCollection != null)
return (readOnlyCollection.Count == 0) ? default(MemoryOwner<T>) : <Copy>g__CopySlow|0_1(enumerable, readOnlyCollection.Count, allocator);
return <Copy>g__CopySlow|0_1(enumerable, <Copy>g__GetSize|0_2(enumerable, sizeHint), allocator);
}
ArraySegment<T> segment = (ArraySegment<T>)enumerable;
return segment.AsSpan().Copy(allocator);
}
[return: Nullable(new byte[] {
0,
1
})]
public static ConsumingEnumerable<T> GetConsumer<[Nullable(2)] T>(this IProducerConsumerCollection<T> collection)
{
if (collection == null)
throw new ArgumentNullException("collection");
return new ConsumingEnumerable<T>(collection);
}
[return: Nullable(new byte[] {
0,
1,
1
})]
public static ReadOnlyCollectionView<TInput, TOutput> Convert<[Nullable(2)] TInput, [Nullable(2)] TOutput>(this IReadOnlyCollection<TInput> collection, Converter<TInput, TOutput> converter)
{
return new ReadOnlyCollectionView<TInput, TOutput>(collection, converter);
}
public static T[] ToArray<[Nullable(2)] T>(ICollection<T> collection)
{
int count = collection.Count;
T[] array;
if (count == 0)
array = Array.Empty<T>();
else {
array = GC.AllocateUninitializedArray<T>(count, false);
collection.CopyTo(array, 0);
}
return array;
}
public unsafe static T[] ToArray<[Nullable(2)] T>(IReadOnlyCollection<T> collection)
{
int count = collection.Count;
if (count == 0)
return Array.Empty<T>();
T[] array = GC.AllocateUninitializedArray<T>(count, false);
UIntPtr uIntPtr = (UIntPtr)(void*)null;
foreach (T item in (IEnumerable<T>)collection) {
T[] array2 = array;
UIntPtr intPtr = uIntPtr;
uIntPtr = (UIntPtr)(void*)((long)(ulong)intPtr + 1);
array2[(ulong)intPtr] = item;
}
return array;
}
public static void AddAll<[Nullable(2)] T>(this ICollection<T> collection, IEnumerable<T> items)
{
if (collection == null)
throw new ArgumentNullException("collection");
List<T> list = collection as List<T>;
if (list == null) {
HashSet<T> hashSet = collection as HashSet<T>;
if (hashSet != null)
hashSet.UnionWith(items);
else
items.ForEach(collection.Add);
} else
list.AddRange(items);
}
public static int SequenceHashCode<[Nullable(2)] T>(this IEnumerable<T> sequence, bool salted = true)
{
int num = sequence.Aggregate(-910176598, (int hash, T obj) => hash * -1521134295 + ((obj != null) ? EqualityComparer<T>.Default.GetHashCode(obj) : 0));
if (!salted)
return num;
return num * -1521134295 + RandomExtensions.BitwiseHashSalt;
}
internal static bool SequenceEqual<T>(IEnumerable<T> first, IEnumerable<T> second)
{
if (first != null) {
if (second != null)
return first.SequenceEqual(second);
return false;
}
return second == null;
}
public static void ForEach<[Nullable(2)] T>(this IEnumerable<T> collection, Action<T> action)
{
List<T> list = collection as List<T>;
if (list == null) {
T[] array = collection as T[];
if (array == null) {
if (collection is ArraySegment<T>) {
ArraySegment<T> segment = (ArraySegment<T>)collection;
Span.ForEach(segment.AsSpan(), action);
} else {
LinkedList<T> linkedList = collection as LinkedList<T>;
if (linkedList == null) {
string text = collection as string;
if (text != null)
Span.ForEach(text.AsSpan(), Unsafe.As<Action<char>>((object)action));
else
<ForEach>g__ForEachSlow|9_0(collection, action);
} else
<ForEach>g__ForEachNode|9_1(linkedList, action);
}
} else
Array.ForEach(array, action);
} else
Span.ForEach(CollectionsMarshal.AsSpan(list), action);
}
[AsyncStateMachine(typeof(<ForEachAsync>d__10<>))]
public static ValueTask ForEachAsync<[Nullable(2)] T>(this IEnumerable<T> collection, Func<T, CancellationToken, ValueTask> action, CancellationToken token = default(CancellationToken))
{
<ForEachAsync>d__10<T> stateMachine = default(<ForEachAsync>d__10<T>);
stateMachine.<>t__builder = AsyncValueTaskMethodBuilder.Create();
stateMachine.collection = collection;
stateMachine.action = action;
stateMachine.token = token;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
[return: Nullable(new byte[] {
0,
1
})]
public static Optional<T> FirstOrNone<[Nullable(2)] T>(this IEnumerable<T> collection)
{
if (collection == null)
throw new ArgumentNullException("collection");
List<T> list = collection as List<T>;
if (list != null)
return CollectionsMarshal.AsSpan(list).FirstOrNone<T>(null);
T[] array = collection as T[];
if (array != null)
return array.FirstOrNone<T>(null);
string text = collection as string;
if (text != null)
return Unsafe.BitCast<Optional<char>, Optional<T>>(text.FirstOrNone<char>(null));
LinkedList<T> linkedList = collection as LinkedList<T>;
if (linkedList != null) {
LinkedListNode<T> first = linkedList.First;
return (first != null) ? ((Optional<T>)first.Value) : Optional<T>.None;
}
IList<T> list2 = collection as IList<T>;
if (list2 != null)
return (((ICollection<T>)list2).Count > 0) ? ((Optional<T>)list2[0]) : Optional<T>.None;
IReadOnlyList<T> readOnlyList = collection as IReadOnlyList<T>;
if (readOnlyList != null)
return (((IReadOnlyCollection<T>)readOnlyList).Count > 0) ? ((Optional<T>)readOnlyList[0]) : Optional<T>.None;
return <FirstOrNone>g__FirstOrNoneSlow|11_0(collection);
}
[return: Nullable(new byte[] {
0,
1
})]
public static Optional<T> LastOrNone<[Nullable(2)] T>(this IEnumerable<T> collection)
{
if (collection == null)
throw new ArgumentNullException("collection");
List<T> list = collection as List<T>;
if (list != null)
return Span.LastOrNone<T>(CollectionsMarshal.AsSpan(list));
T[] array = collection as T[];
if (array != null)
return Span.LastOrNone<T>(array);
string text = collection as string;
if (text != null)
return Unsafe.BitCast<Optional<char>, Optional<T>>(Span.LastOrNone<char>(text));
LinkedList<T> linkedList = collection as LinkedList<T>;
if (linkedList != null) {
LinkedListNode<T> last = linkedList.Last;
return (last != null) ? ((Optional<T>)last.Value) : Optional<T>.None;
}
IList<T> list2 = collection as IList<T>;
if (list2 != null) {
Optional<T> result;
if (((ICollection<T>)list2).Count <= 0)
result = Optional<T>.None;
else {
IList<T> list3 = list2;
result = list3[((ICollection<T>)list3).Count - 1];
}
return result;
}
IReadOnlyList<T> readOnlyList = collection as IReadOnlyList<T>;
if (readOnlyList != null) {
Optional<T> result2;
if (((IReadOnlyCollection<T>)readOnlyList).Count <= 0)
result2 = Optional<T>.None;
else {
IReadOnlyList<T> readOnlyList2 = readOnlyList;
result2 = readOnlyList2[((IReadOnlyCollection<T>)readOnlyList2).Count - 1];
}
return result2;
}
return <LastOrNone>g__LastOrNoneSlow|12_0(collection);
}
public static bool ElementAt<[Nullable(2)] T>(this IEnumerable<T> collection, int index, [MaybeNullWhen(false)] out T element)
{
if (collection == null)
throw new ArgumentNullException("collection");
List<T> list = collection as List<T>;
if (list != null)
return Span.ElementAt(CollectionsMarshal.AsSpan(list), index, out element);
T[] array = collection as T[];
if (array != null)
return Span.ElementAt(array, index, out element);
LinkedList<T> linkedList = collection as LinkedList<T>;
if (linkedList != null)
return <ElementAt>g__NodeValueAt|13_0(linkedList, index, out element);
IList<T> list2 = collection as IList<T>;
if (list2 != null)
return <ElementAt>g__ListElementAt|13_2(list2, index, out element);
IReadOnlyList<T> readOnlyList = collection as IReadOnlyList<T>;
if (readOnlyList != null)
return <ElementAt>g__ReadOnlyListElementAt|13_3(readOnlyList, index, out element);
return <ElementAt>g__ElementAtSlow|13_1(collection, index, out element);
}
public static IEnumerable<T> SkipNulls<T>([Nullable(new byte[] {
1,
2
})] this IEnumerable<T> collection) where T : class
{
return new NotNullEnumerable<T>(collection);
}
public static string ToString<[Nullable(2)] T>(this IEnumerable<T> collection, string delimiter, string ifEmpty = "")
{
string text = string.Join(delimiter, collection);
if (text == null || text.Length <= 0)
return ifEmpty;
return text;
}
public static IEnumerable<T> Prepend<[Nullable(2)] T>(this IEnumerable<T> collection, params T[] items)
{
return items.Concat(collection);
}
public static IEnumerable<T> Append<[Nullable(2)] T>(this IEnumerable<T> collection, params T[] items)
{
return collection.Concat(items);
}
public static IAsyncEnumerable<T> ToAsyncEnumerable<[Nullable(2)] T>(this IEnumerable<T> enumerable)
{
if (enumerable == null)
throw new ArgumentNullException("enumerable");
return new AsyncEnumerable.Proxy<T>(enumerable);
}
}
}