CopyOnWriteList<T>
public class CopyOnWriteList<T> : IReadOnlyList<T>, IEnumerable<T>, IEnumerable, IReadOnlyCollection<T>, IList<T>, ICollection<T>, ICloneable
A thread-safe variant of List<T> in which all mutative operations are implemented by making a snapshot copy of the underlying array.
using DotNext.Runtime.InteropServices;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DotNext.Collections.Concurrent
{
[Serializable]
public class CopyOnWriteList<T> : IReadOnlyList<T>, IEnumerable<T>, IEnumerable, IReadOnlyCollection<T>, IList<T>, ICollection<T>, ICloneable
{
[StructLayout(LayoutKind.Auto)]
public struct Enumerator : IEnumerator<T>, IEnumerator, IDisposable
{
private const long InitialPosition = -1;
private readonly T[] snapshot;
private long position;
[System.Runtime.CompilerServices.IsReadOnly]
public ref T Current {
[return: System.Runtime.CompilerServices.IsReadOnly]
get {
return ref Memory.GetReadonlyRef<T>(snapshot, position);
}
}
T IEnumerator<T>.Current {
get {
return Current;
}
}
object IEnumerator.Current {
get {
return Current;
}
}
internal Enumerator(T[] backingStore)
{
snapshot = backingStore;
position = -1;
}
void IDisposable.Dispose()
{
this = default(Enumerator);
}
public bool MoveNext()
{
return ++position < snapshot.LongLength;
}
void IEnumerator.Reset()
{
position = -1;
}
}
private volatile T[] backingStore;
bool ICollection<T>.IsReadOnly {
get {
return false;
}
}
int ICollection<T>.Count {
get {
return backingStore.Length;
}
}
int IReadOnlyCollection<T>.Count {
get {
return backingStore.Length;
}
}
public long Count => backingStore.LongLength;
public ReadOnlyMemory<T> Snapshot => new ReadOnlyMemory<T>(backingStore);
public T this[long index] {
get {
return backingStore[index];
}
set {
T[] array = Snapshot.ToArray();
array[index] = value;
ReplaceStore(array);
}
}
T IList<T>.this[int index] {
get {
return this[index];
}
set {
this[index] = value;
}
}
T IReadOnlyList<T>.this[int index] {
get {
return this[index];
}
}
public CopyOnWriteList(IReadOnlyCollection<T> collection)
{
backingStore = new T[collection.Count];
long num = 0;
foreach (T item in collection) {
T[] array = backingStore;
long num2 = num;
num = num2 + 1;
array[num2] = item;
}
}
private CopyOnWriteList(T[] backingStore)
{
this.backingStore = backingStore;
}
public CopyOnWriteList<T> Clone()
{
return new CopyOnWriteList<T>(Snapshot.ToArray());
}
object ICloneable.Clone()
{
return Clone();
}
public CopyOnWriteList()
{
backingStore = Array.Empty<T>();
}
private static T[] Add(T[] backingStore, T item)
{
long num = backingStore.LongLength;
T[] array = new T[num + 1];
backingStore.CopyTo(array, 0);
array[num] = item;
return array;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void Add(T item)
{
backingStore = Add(backingStore, item);
}
public int IndexOf(T item)
{
return Array.IndexOf<T>(backingStore, item);
}
public int LastIndexOf(T item)
{
return Array.LastIndexOf<T>(backingStore, item);
}
public T Find(Predicate<T> match)
{
return Array.Find<T>(backingStore, match);
}
public T FindLast(Predicate<T> match)
{
return Array.FindLast<T>(backingStore, match);
}
public int FindIndex(Predicate<T> match)
{
return Array.FindIndex<T>(backingStore, match);
}
public int FindLastIndex(Predicate<T> match)
{
return Array.FindLastIndex<T>(backingStore, match);
}
public bool Contains(T item)
{
return IndexOf(item) >= 0;
}
public bool Exists(Predicate<T> match)
{
return Array.Exists<T>(backingStore, match);
}
public void CopyTo(T[] array, int arrayIndex)
{
backingStore.CopyTo(array, arrayIndex);
}
[MethodImpl(MethodImplOptions.Synchronized)]
private T[] ReplaceStore(T[] newStore)
{
T[] result = backingStore;
backingStore = newStore;
return result;
}
public void Set(ReadOnlySpan<T> array)
{
ReplaceStore(array.ToArray());
}
public void Set<G>(ICollection<G> items, [In] [System.Runtime.CompilerServices.IsReadOnly] ref ValueFunc<G, T> converter)
{
if (items.Count == 0)
this.ReplaceStore(Array.Empty<T>());
else {
T[] array = new T[items.Count];
long num = 0;
foreach (G item in (IEnumerable<G>)items) {
T[] array2 = array;
long num2 = num;
num = num2 + 1;
array2[num2] = converter.Invoke(item);
}
this.ReplaceStore(array);
}
}
public void Set<G>(ICollection<G> items, Converter<G, T> converter)
{
ValueFunc<G, T> converter2 = Converter.AsValueFunc<G, T>(converter, true);
Set(items, ref converter2);
}
public void Clear()
{
T[] array = ReplaceStore(Array.Empty<T>());
Array.Clear(array, 0, array.Length);
}
public void Clear([In] [System.Runtime.CompilerServices.IsReadOnly] ref ValueAction<T> cleaner)
{
T[] array = ReplaceStore(Array.Empty<T>());
for (long num = 0; num < array.LongLength; num++) {
ref T reference = ref array[num];
cleaner.Invoke(reference);
reference = default(T);
}
}
public void Clear(Action<T> cleaner)
{
ValueAction<T> cleaner2 = new ValueAction<T>(cleaner, true);
Clear(ref cleaner2);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void RemoveAt(long index)
{
backingStore = OneDimensionalArray.RemoveAt<T>(backingStore, index);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public bool Remove(T item)
{
int num = IndexOf(item);
if ((long)num >= 0) {
RemoveAt(num);
return true;
}
return false;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void Insert(long index, T item)
{
backingStore = OneDimensionalArray.Insert<T>(backingStore, item, index);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public long RemoveAll(ValueFunc<T, bool> match)
{
backingStore = OneDimensionalArray.RemoveAll<T>(backingStore, ref match, out long count);
return count;
}
public long RemoveAll(Predicate<T> match)
{
return RemoveAll(Predicate.AsValueFunc<T>(match, true));
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void RemoveAll([In] [System.Runtime.CompilerServices.IsReadOnly] ref ValueFunc<T, bool> match, [In] [System.Runtime.CompilerServices.IsReadOnly] ref ValueAction<T> callback)
{
backingStore = OneDimensionalArray.RemoveAll<T>(backingStore, ref match, ref callback);
}
public void RemoveAll(Predicate<T> match, Action<T> callback)
{
ValueFunc<T, bool> match2 = Predicate.AsValueFunc<T>(match, true);
ValueAction<T> callback2 = new ValueAction<T>(callback, false);
RemoveAll(ref match2, ref callback2);
}
void IList<T>.Insert(int index, T item)
{
Insert(index, item);
}
void IList<T>.RemoveAt(int index)
{
RemoveAt(index);
}
public Enumerator GetEnumerator()
{
return new Enumerator(backingStore);
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return backingStore.GetEnumerator();
}
public static explicit operator ReadOnlySpan<T>(CopyOnWriteList<T> list)
{
if (list != null)
return new ReadOnlySpan<T>(list.backingStore);
return default(ReadOnlySpan<T>);
}
}
}