Mirror
This commit is contained in:
parent
b618f509ad
commit
b5431b9f9d
@ -1,13 +1,13 @@
|
|||||||
using System;
|
using System.Buffers;
|
||||||
using System.Buffers;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace ObservableCollections.Internal
|
namespace ObservableCollections.Internal
|
||||||
{
|
{
|
||||||
internal struct CopyedCollection<T> : IDisposable
|
/// <summary>
|
||||||
|
/// ReadOnly cloned collection.
|
||||||
|
/// </summary>
|
||||||
|
internal struct CloneCollection<T> : IDisposable
|
||||||
{
|
{
|
||||||
T[]? array;
|
T[]? array;
|
||||||
int length;
|
int length;
|
||||||
@ -16,13 +16,13 @@ namespace ObservableCollections.Internal
|
|||||||
|
|
||||||
public IEnumerable<T> AsEnumerable() => new EnumerableCollection(array, length);
|
public IEnumerable<T> AsEnumerable() => new EnumerableCollection(array, length);
|
||||||
|
|
||||||
public CopyedCollection(T item)
|
public CloneCollection(T item)
|
||||||
{
|
{
|
||||||
this.array = ArrayPool<T>.Shared.Rent(1);
|
this.array = ArrayPool<T>.Shared.Rent(1);
|
||||||
this.length = 1;
|
this.length = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CopyedCollection(IEnumerable<T> source)
|
public CloneCollection(IEnumerable<T> source)
|
||||||
{
|
{
|
||||||
if (Enumerable.TryGetNonEnumeratedCount(source, out var count))
|
if (Enumerable.TryGetNonEnumeratedCount(source, out var count))
|
||||||
{
|
{
|
||||||
@ -58,7 +58,7 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CopyedCollection(ReadOnlySpan<T> source)
|
public CloneCollection(ReadOnlySpan<T> source)
|
||||||
{
|
{
|
||||||
var array = ArrayPool<T>.Shared.Rent(source.Length);
|
var array = ArrayPool<T>.Shared.Rent(source.Length);
|
||||||
source.CopyTo(array);
|
source.CopyTo(array);
|
214
src/ObservableCollections/ObservableFixedSizeRingBuffer.cs
Normal file
214
src/ObservableCollections/ObservableFixedSizeRingBuffer.cs
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
using ObservableCollections.Internal;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace ObservableCollections
|
||||||
|
{
|
||||||
|
public sealed partial class ObservableFixedSizeRingBuffer<T> : IList<T>, IReadOnlyList<T>, IObservableCollection<T>
|
||||||
|
{
|
||||||
|
readonly RingBuffer<T> buffer;
|
||||||
|
readonly int capacity;
|
||||||
|
|
||||||
|
public event NotifyCollectionChangedEventHandler<T>? CollectionChanged;
|
||||||
|
|
||||||
|
public ObservableFixedSizeRingBuffer(int capacity)
|
||||||
|
{
|
||||||
|
this.capacity = capacity;
|
||||||
|
this.buffer = new RingBuffer<T>(capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableFixedSizeRingBuffer(int capacity, IEnumerable<T> collection)
|
||||||
|
{
|
||||||
|
this.capacity = capacity;
|
||||||
|
this.buffer = new RingBuffer<T>(capacity);
|
||||||
|
foreach (var item in collection)
|
||||||
|
{
|
||||||
|
if (capacity == buffer.Count)
|
||||||
|
{
|
||||||
|
buffer.RemoveFirst();
|
||||||
|
}
|
||||||
|
buffer.AddLast(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsReadOnly => false;
|
||||||
|
|
||||||
|
public object SyncRoot { get; } = new object();
|
||||||
|
|
||||||
|
public T this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
return this.buffer[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
var oldValue = buffer[index];
|
||||||
|
buffer[index] = value;
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Replace(value, oldValue, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
return buffer.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddFirst(T item)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
if (capacity == buffer.Count)
|
||||||
|
{
|
||||||
|
buffer.RemoveLast();
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(item, capacity - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.AddFirst(item);
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(item, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddLast(T item)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
if (capacity == buffer.Count)
|
||||||
|
{
|
||||||
|
buffer.RemoveLast();
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(item, capacity - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.AddLast(item);
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(item, buffer.Count - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddFirstRange is not exists.
|
||||||
|
|
||||||
|
public void AddLastRange(IEnumerable<T> items)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
var index = buffer.Count;
|
||||||
|
using (var xs = new CloneCollection<T>(items))
|
||||||
|
{
|
||||||
|
foreach (var item in xs.Span)
|
||||||
|
{
|
||||||
|
buffer.AddLast(item);
|
||||||
|
}
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(xs.Span, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddLastRange(T[] items)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
var index = buffer.Count;
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
buffer.AddLast(item);
|
||||||
|
}
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddLastRange(ReadOnlySpan<T> items)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
var index = buffer.Count;
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
buffer.AddLast(item);
|
||||||
|
}
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IndexOf(T item)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
return buffer.IndexOf(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList<T>.Insert(int index, T item)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ICollection<T>.Remove(T item)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList<T>.RemoveAt(int index)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICollection<T>.Add(T item)
|
||||||
|
{
|
||||||
|
AddLast(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
buffer.Clear();
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Reset());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(T item)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
return buffer.Contains(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(T[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
buffer.CopyTo(array, arrayIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<T> GetEnumerator()
|
||||||
|
{
|
||||||
|
return new SynchronizedEnumerator<T>(SyncRoot, buffer.GetEnumerator());
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// View
|
||||||
|
|
||||||
|
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
// return new View<TView>(this, transform, reverse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -78,7 +78,7 @@ namespace ObservableCollections
|
|||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
var index = list.Count;
|
var index = list.Count;
|
||||||
using (var xs = new CopyedCollection<T>(items))
|
using (var xs = new CloneCollection<T>(items))
|
||||||
{
|
{
|
||||||
// to avoid iterate twice, require copy before insert.
|
// to avoid iterate twice, require copy before insert.
|
||||||
list.AddRange(xs.AsEnumerable());
|
list.AddRange(xs.AsEnumerable());
|
||||||
@ -189,7 +189,7 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
using (var xs = new CopyedCollection<T>(items))
|
using (var xs = new CloneCollection<T>(items))
|
||||||
{
|
{
|
||||||
list.InsertRange(index, xs.AsEnumerable());
|
list.InsertRange(index, xs.AsEnumerable());
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(xs.Span, index));
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(xs.Span, index));
|
||||||
@ -201,7 +201,7 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
using (var xs = new CopyedCollection<T>(items))
|
using (var xs = new CloneCollection<T>(items))
|
||||||
{
|
{
|
||||||
list.InsertRange(index, xs.AsEnumerable());
|
list.InsertRange(index, xs.AsEnumerable());
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(xs.Span, index));
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(xs.Span, index));
|
||||||
@ -245,7 +245,7 @@ namespace ObservableCollections
|
|||||||
var range = CollectionsMarshal.AsSpan(list).Slice(index, count);
|
var range = CollectionsMarshal.AsSpan(list).Slice(index, count);
|
||||||
|
|
||||||
// require copy before remove
|
// require copy before remove
|
||||||
using (var xs = new CopyedCollection<T>(range))
|
using (var xs = new CloneCollection<T>(range))
|
||||||
{
|
{
|
||||||
list.RemoveRange(index, count);
|
list.RemoveRange(index, count);
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(xs.Span, index));
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(xs.Span, index));
|
||||||
|
@ -54,7 +54,7 @@ namespace ObservableCollections
|
|||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
var index = queue.Count;
|
var index = queue.Count;
|
||||||
using (var xs = new CopyedCollection<T>(items))
|
using (var xs = new CloneCollection<T>(items))
|
||||||
{
|
{
|
||||||
foreach (var item in xs.Span)
|
foreach (var item in xs.Span)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections;
|
using ObservableCollections.Internal;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
namespace ObservableCollections
|
namespace ObservableCollections
|
||||||
{
|
{
|
||||||
@ -8,8 +9,6 @@ namespace ObservableCollections
|
|||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T>? CollectionChanged;
|
public event NotifyCollectionChangedEventHandler<T>? CollectionChanged;
|
||||||
|
|
||||||
// TODO:SyncRoot
|
|
||||||
|
|
||||||
public ObservableRingBuffer()
|
public ObservableRingBuffer()
|
||||||
{
|
{
|
||||||
this.buffer = new RingBuffer<T>();
|
this.buffer = new RingBuffer<T>();
|
||||||
@ -26,15 +25,21 @@ namespace ObservableCollections
|
|||||||
|
|
||||||
public T this[int index]
|
public T this[int index]
|
||||||
{
|
{
|
||||||
// TODO:notify!
|
|
||||||
|
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return this.buffer[index];
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
return this.buffer[index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
this.buffer[index] = value;
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
var oldValue = buffer[index];
|
||||||
|
buffer[index] = value;
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Replace(value, oldValue, index));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,120 +72,111 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddFirstRange???
|
// AddFirstRange is not exists.
|
||||||
|
|
||||||
|
public void AddLastRange(IEnumerable<T> items)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
var index = buffer.Count;
|
||||||
|
using (var xs = new CloneCollection<T>(items))
|
||||||
|
{
|
||||||
|
foreach (var item in xs.Span)
|
||||||
|
{
|
||||||
|
buffer.AddLast(item);
|
||||||
|
}
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(xs.Span, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void AddLastRange(T[] items)
|
public void AddLastRange(T[] items)
|
||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
|
var index = buffer.Count;
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
buffer.AddLast(item);
|
buffer.AddLast(item);
|
||||||
}
|
}
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddLastRange(ReadOnlySpan<T> items)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
var index = buffer.Count;
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
buffer.AddLast(item);
|
||||||
|
}
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(items, index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int IndexOf(T item)
|
public int IndexOf(T item)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
return buffer.IndexOf(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Insert(int index, T item)
|
void IList<T>.Insert(int index, T item)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveAt(int index)
|
bool ICollection<T>.Remove(T item)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(T item)
|
void IList<T>.RemoveAt(int index)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICollection<T>.Add(T item)
|
||||||
|
{
|
||||||
|
AddLast(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
buffer.Clear();
|
||||||
|
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Reset());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Contains(T item)
|
public bool Contains(T item)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
return buffer.Contains(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyTo(T[] array, int arrayIndex)
|
public void CopyTo(T[] array, int arrayIndex)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
lock (SyncRoot)
|
||||||
}
|
{
|
||||||
|
buffer.CopyTo(array, arrayIndex);
|
||||||
public bool Remove(T item)
|
}
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
public IEnumerator<T> GetEnumerator()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return new SynchronizedEnumerator<T>(SyncRoot, buffer.GetEnumerator());
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return GetEnumerator();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO:Is this?
|
|
||||||
public sealed class ObservableFixedSizeRingBuffer<T>
|
|
||||||
{
|
|
||||||
RingBuffer<T> buffer = default!; // TODO:???
|
|
||||||
|
|
||||||
int fixedSize;
|
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<T>? CollectionChanged;
|
|
||||||
|
|
||||||
// TODO:SyncRoot
|
|
||||||
public bool IsReadOnly => false;
|
|
||||||
|
|
||||||
public object SyncRoot { get; } = new object();
|
|
||||||
|
|
||||||
public void AddLast(T value)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (buffer.Count == fixedSize)
|
|
||||||
{
|
|
||||||
// Remove One.
|
|
||||||
var removed = buffer.RemoveFirst();
|
|
||||||
buffer.AddLast(value);
|
|
||||||
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Remove(removed, 0));
|
|
||||||
CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs<T>.Add(value, buffer.Count - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddLastRange(T[] values)
|
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
|
||||||
{
|
|
||||||
if (buffer.Count + values.Length -1 == fixedSize)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < values.Length; i++)
|
|
||||||
{
|
|
||||||
buffer.RemoveFirst(); // removes...
|
|
||||||
}
|
|
||||||
for (int i = 0; i < values.Length; i++)
|
|
||||||
{
|
|
||||||
buffer.AddLast(values[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove...
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
lock (SyncRoot)
|
lock (SyncRoot)
|
||||||
{
|
{
|
||||||
using (var xs = new CopyedCollection<T>(items))
|
using (var xs = new CloneCollection<T>(items))
|
||||||
{
|
{
|
||||||
foreach (var item in xs.Span)
|
foreach (var item in xs.Span)
|
||||||
{
|
{
|
||||||
|
@ -171,12 +171,7 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumerator GetEnumerator()
|
public IEnumerator<T> GetEnumerator()
|
||||||
{
|
|
||||||
return new Enumerator(GetSpan());
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
||||||
{
|
{
|
||||||
if (count == 0) yield break;
|
if (count == 0) yield break;
|
||||||
|
|
||||||
@ -251,7 +246,7 @@ namespace ObservableCollections
|
|||||||
public int IndexOf(T item)
|
public int IndexOf(T item)
|
||||||
{
|
{
|
||||||
var i = 0;
|
var i = 0;
|
||||||
foreach (var v in this)
|
foreach (var v in GetSpan())
|
||||||
{
|
{
|
||||||
if (EqualityComparer<T>.Default.Equals(item, v))
|
if (EqualityComparer<T>.Default.Equals(item, v))
|
||||||
{
|
{
|
||||||
@ -266,7 +261,7 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
var result = new T[count];
|
var result = new T[count];
|
||||||
var i = 0;
|
var i = 0;
|
||||||
foreach (var item in this)
|
foreach (var item in GetSpan())
|
||||||
{
|
{
|
||||||
result[i++] = item;
|
result[i++] = item;
|
||||||
}
|
}
|
||||||
@ -298,6 +293,25 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
throw new InvalidOperationException("RingBuffer is empty.");
|
throw new InvalidOperationException("RingBuffer is empty.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref struct RingBufferSpan<T>
|
||||||
|
{
|
||||||
|
public readonly ReadOnlySpan<T> First;
|
||||||
|
public readonly ReadOnlySpan<T> Second;
|
||||||
|
public readonly int Count;
|
||||||
|
|
||||||
|
internal RingBufferSpan(ReadOnlySpan<T> first, ReadOnlySpan<T> second, int count)
|
||||||
|
{
|
||||||
|
First = first;
|
||||||
|
Second = second;
|
||||||
|
Count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new Enumerator(this);
|
||||||
|
}
|
||||||
|
|
||||||
public ref struct Enumerator
|
public ref struct Enumerator
|
||||||
{
|
{
|
||||||
@ -349,18 +363,4 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref struct RingBufferSpan<T>
|
|
||||||
{
|
|
||||||
public readonly ReadOnlySpan<T> First;
|
|
||||||
public readonly ReadOnlySpan<T> Second;
|
|
||||||
public readonly int Count;
|
|
||||||
|
|
||||||
internal RingBufferSpan(ReadOnlySpan<T> first, ReadOnlySpan<T> second, int count)
|
|
||||||
{
|
|
||||||
First = first;
|
|
||||||
Second = second;
|
|
||||||
Count = count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user