forked from bit/DotRecastNetSim
Changed from List<T> to RcCyclicBuffer in DtCrowdTelemetry execution timing sampling @wrenge
- https://github.com/ikpil/DotRecast/issues/51
This commit is contained in:
parent
a359686171
commit
ad504fe217
|
@ -7,11 +7,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
## [Unreleased] - yyyy-mm-dd
|
## [Unreleased] - yyyy-mm-dd
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- Added RcCircularBuffer<T> [@ikpil](https://github.com/ikpil)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Added DtPathCorridor.Init(int maxPath) function to allow setting the maximum path [@ikpil](https://github.com/ikpil)
|
- Changed DtPathCorridor.Init(int maxPath) function to allow setting the maximum path [@ikpil](https://github.com/ikpil)
|
||||||
|
- Changed from List<T> to RcCyclicBuffer in DtCrowdTelemetry execution timing sampling [@wrenge](https://github.com/wrenge)
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
|
|
@ -1,48 +1,244 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Security;
|
||||||
|
|
||||||
namespace DotRecast.Core.Buffers
|
namespace DotRecast.Core.Buffers
|
||||||
{
|
{
|
||||||
|
// https://github.com/joaoportela/CircularBuffer-CSharp/blob/master/CircularBuffer/CircularBuffer.cs
|
||||||
public class RcCyclicBuffer<T>
|
public class RcCyclicBuffer<T>
|
||||||
{
|
{
|
||||||
public int MinIndex { get; private set; }
|
|
||||||
public int MaxIndex { get; private set; }
|
|
||||||
public int Count => MaxIndex - MinIndex + 1;
|
|
||||||
public readonly int Size;
|
|
||||||
|
|
||||||
public T this[int index] => Get(index);
|
|
||||||
|
|
||||||
private readonly T[] _buffer;
|
private readonly T[] _buffer;
|
||||||
|
|
||||||
public RcCyclicBuffer(in int size)
|
private int _start;
|
||||||
|
private int _end;
|
||||||
|
private int _size;
|
||||||
|
|
||||||
|
public RcCyclicBuffer(int capacity)
|
||||||
|
: this(capacity, new T[] { })
|
||||||
{
|
{
|
||||||
_buffer = new T[size];
|
|
||||||
Size = size;
|
|
||||||
MinIndex = 0;
|
|
||||||
MaxIndex = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(in T item)
|
public RcCyclicBuffer(int capacity, T[] items)
|
||||||
{
|
{
|
||||||
MaxIndex++;
|
if (capacity < 1)
|
||||||
var index = MaxIndex % Size;
|
{
|
||||||
|
throw new ArgumentException("RcCyclicBuffer cannot have negative or zero capacity.", nameof(capacity));
|
||||||
|
}
|
||||||
|
|
||||||
if (MaxIndex >= Size)
|
if (items == null)
|
||||||
MinIndex = MaxIndex - Size + 1;
|
{
|
||||||
|
throw new ArgumentNullException(nameof(items));
|
||||||
|
}
|
||||||
|
|
||||||
_buffer[index] = item;
|
if (items.Length > capacity)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Too many items to fit RcCyclicBuffer", nameof(items));
|
||||||
|
}
|
||||||
|
|
||||||
|
_buffer = new T[capacity];
|
||||||
|
|
||||||
|
Array.Copy(items, _buffer, items.Length);
|
||||||
|
_size = items.Length;
|
||||||
|
|
||||||
|
_start = 0;
|
||||||
|
_end = _size == capacity ? 0 : _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Get(in int index)
|
public int Capacity => _buffer.Length;
|
||||||
{
|
public bool IsFull => Size == Capacity;
|
||||||
if (index < MinIndex || index > MaxIndex)
|
public bool IsEmpty => Size == 0;
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
|
|
||||||
return _buffer[index % Size];
|
public int Size => _size;
|
||||||
|
|
||||||
|
public T Front()
|
||||||
|
{
|
||||||
|
ThrowIfEmpty();
|
||||||
|
return _buffer[_start];
|
||||||
}
|
}
|
||||||
|
|
||||||
public Span<T> AsSpan()
|
public T Back()
|
||||||
{
|
{
|
||||||
return _buffer.AsSpan(0, Count);
|
ThrowIfEmpty();
|
||||||
|
return _buffer[(_end != 0 ? _end : Capacity) - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public T this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (IsEmpty)
|
||||||
|
{
|
||||||
|
throw new IndexOutOfRangeException($"Cannot access index {index}. Buffer is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= _size)
|
||||||
|
{
|
||||||
|
throw new IndexOutOfRangeException($"Cannot access index {index}. Buffer size is {_size}");
|
||||||
|
}
|
||||||
|
|
||||||
|
int actualIndex = InternalIndex(index);
|
||||||
|
return _buffer[actualIndex];
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (IsEmpty)
|
||||||
|
{
|
||||||
|
throw new IndexOutOfRangeException($"Cannot access index {index}. Buffer is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= _size)
|
||||||
|
{
|
||||||
|
throw new IndexOutOfRangeException($"Cannot access index {index}. Buffer size is {_size}");
|
||||||
|
}
|
||||||
|
|
||||||
|
int actualIndex = InternalIndex(index);
|
||||||
|
_buffer[actualIndex] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PushBack(T item)
|
||||||
|
{
|
||||||
|
if (IsFull)
|
||||||
|
{
|
||||||
|
_buffer[_end] = item;
|
||||||
|
Increment(ref _end);
|
||||||
|
_start = _end;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_buffer[_end] = item;
|
||||||
|
Increment(ref _end);
|
||||||
|
++_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PushFront(T item)
|
||||||
|
{
|
||||||
|
if (IsFull)
|
||||||
|
{
|
||||||
|
Decrement(ref _start);
|
||||||
|
_end = _start;
|
||||||
|
_buffer[_start] = item;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Decrement(ref _start);
|
||||||
|
_buffer[_start] = item;
|
||||||
|
++_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PopBack()
|
||||||
|
{
|
||||||
|
ThrowIfEmpty("Cannot take elements from an empty buffer.");
|
||||||
|
Decrement(ref _end);
|
||||||
|
_buffer[_end] = default(T);
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PopFront()
|
||||||
|
{
|
||||||
|
ThrowIfEmpty("Cannot take elements from an empty buffer.");
|
||||||
|
_buffer[_start] = default(T);
|
||||||
|
Increment(ref _start);
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
// to clear we just reset everything.
|
||||||
|
_start = 0;
|
||||||
|
_end = 0;
|
||||||
|
_size = 0;
|
||||||
|
Array.Clear(_buffer, 0, _buffer.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T[] ToArray()
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
T[] newArray = new T[Size];
|
||||||
|
|
||||||
|
ForEach(x => newArray[idx++] = x);
|
||||||
|
|
||||||
|
return newArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ForEach(Action<T> action)
|
||||||
|
{
|
||||||
|
var spanOne = ArrayOne();
|
||||||
|
foreach (var item in spanOne)
|
||||||
|
{
|
||||||
|
action.Invoke(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
var spanTwo = ArrayTwo();
|
||||||
|
foreach (var item in spanTwo)
|
||||||
|
{
|
||||||
|
action.Invoke(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThrowIfEmpty(string message = "Cannot access an empty buffer.")
|
||||||
|
{
|
||||||
|
if (IsEmpty)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Increment(ref int index)
|
||||||
|
{
|
||||||
|
if (++index == Capacity)
|
||||||
|
{
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Decrement(ref int index)
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
index = Capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int InternalIndex(int index)
|
||||||
|
{
|
||||||
|
return _start + (index < (Capacity - _start)
|
||||||
|
? index
|
||||||
|
: index - Capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Span<T> ArrayOne()
|
||||||
|
{
|
||||||
|
if (IsEmpty)
|
||||||
|
{
|
||||||
|
return new Span<T>(Array.Empty<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_start < _end)
|
||||||
|
{
|
||||||
|
return new Span<T>(_buffer, _start, _end - _start);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Span<T>(_buffer, _start, _buffer.Length - _start);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Span<T> ArrayTwo()
|
||||||
|
{
|
||||||
|
if (IsEmpty)
|
||||||
|
{
|
||||||
|
return new Span<T>(Array.Empty<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_start < _end)
|
||||||
|
{
|
||||||
|
return new Span<T>(_buffer, _end, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Span<T>(_buffer, 0, _end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,12 +19,9 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection.Emit;
|
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Buffers;
|
using DotRecast.Core.Buffers;
|
||||||
using DotRecast.Core.Numerics;
|
|
||||||
|
|
||||||
namespace DotRecast.Detour.Crowd
|
namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
|
@ -86,25 +83,25 @@ namespace DotRecast.Detour.Crowd
|
||||||
private void Stop(DtCrowdTimerLabel name)
|
private void Stop(DtCrowdTimerLabel name)
|
||||||
{
|
{
|
||||||
long duration = RcFrequency.Ticks - _executionTimings[name];
|
long duration = RcFrequency.Ticks - _executionTimings[name];
|
||||||
if (!_executionTimingSamples.TryGetValue(name, out var s))
|
if (!_executionTimingSamples.TryGetValue(name, out var cb))
|
||||||
{
|
{
|
||||||
s = new RcCyclicBuffer<long>(TIMING_SAMPLES);
|
cb = new RcCyclicBuffer<long>(TIMING_SAMPLES);
|
||||||
_executionTimingSamples.Add(name, s);
|
_executionTimingSamples.Add(name, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Add(duration);
|
cb.PushBack(duration);
|
||||||
_executionTimings[name] = CalculateAverage(s.AsSpan());
|
_executionTimings[name] = CalculateAverage(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long CalculateAverage(Span<long> buffer)
|
private static long CalculateAverage(RcCyclicBuffer<long> buffer)
|
||||||
{
|
{
|
||||||
long sum = 0L;
|
long sum = 0L;
|
||||||
foreach (var item in buffer)
|
buffer.ForEach(item =>
|
||||||
{
|
{
|
||||||
sum += item;
|
sum += item;
|
||||||
}
|
});
|
||||||
|
|
||||||
return sum / buffer.Length;
|
return sum / buffer.Size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,293 @@
|
||||||
|
using System;
|
||||||
|
using DotRecast.Core.Buffers;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace DotRecast.Core.Test;
|
||||||
|
|
||||||
|
// https://github.com/joaoportela/CircularBuffer-CSharp/blob/master/CircularBuffer.Tests/CircularBufferTests.cs
|
||||||
|
public class RcCyclicBufferTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_GetEnumeratorConstructorCapacity_ReturnsEmptyCollection()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<string>(5);
|
||||||
|
Assert.That(buffer.ToArray(), Is.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_ConstructorSizeIndexAccess_CorrectContent()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3 });
|
||||||
|
|
||||||
|
Assert.That(buffer.Capacity, Is.EqualTo(5));
|
||||||
|
Assert.That(buffer.Size, Is.EqualTo(4));
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
Assert.That(buffer[i], Is.EqualTo(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_Constructor_ExceptionWhenSourceIsLargerThanCapacity()
|
||||||
|
{
|
||||||
|
Assert.Throws<ArgumentException>(() => new RcCyclicBuffer<int>(3, new[] { 0, 1, 2, 3 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_GetEnumeratorConstructorDefinedArray_CorrectContent()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3 });
|
||||||
|
|
||||||
|
int x = 0;
|
||||||
|
buffer.ForEach(item =>
|
||||||
|
{
|
||||||
|
Assert.That(item, Is.EqualTo(x));
|
||||||
|
x++;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_PushBack_CorrectContent()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5);
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
buffer.PushBack(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(buffer.Front(), Is.EqualTo(0));
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
Assert.That(buffer[i], Is.EqualTo(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_PushBackOverflowingBuffer_CorrectContent()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
buffer.PushBack(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 5, 6, 7, 8, 9 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_GetEnumeratorOverflowedArray_CorrectContent()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
buffer.PushBack(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// buffer should have [5,6,7,8,9]
|
||||||
|
int x = 5;
|
||||||
|
buffer.ForEach(item =>
|
||||||
|
{
|
||||||
|
Assert.That(item, Is.EqualTo(x));
|
||||||
|
x++;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_ToArrayConstructorDefinedArray_CorrectContent()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3 });
|
||||||
|
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 0, 1, 2, 3 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_ToArrayOverflowedBuffer_CorrectContent()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
buffer.PushBack(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 5, 6, 7, 8, 9 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_PushFront_CorrectContent()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5);
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
buffer.PushFront(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 4, 3, 2, 1, 0 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_PushFrontAndOverflow_CorrectContent()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
buffer.PushFront(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 9, 8, 7, 6, 5 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_Front_CorrectItem()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
||||||
|
|
||||||
|
Assert.That(buffer.Front(), Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_Back_CorrectItem()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
||||||
|
Assert.That(buffer.Back(), Is.EqualTo(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_BackOfBufferOverflowByOne_CorrectItem()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
||||||
|
buffer.PushBack(42);
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 1, 2, 3, 4, 42 }));
|
||||||
|
Assert.That(buffer.Back(), Is.EqualTo(42));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_Front_EmptyBufferThrowsException()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5);
|
||||||
|
|
||||||
|
Assert.Throws<InvalidOperationException>(() => buffer.Front());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_Back_EmptyBufferThrowsException()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5);
|
||||||
|
Assert.Throws<InvalidOperationException>(() => buffer.Back());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_PopBack_RemovesBackElement()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
||||||
|
|
||||||
|
Assert.That(buffer.Size, Is.EqualTo(5));
|
||||||
|
|
||||||
|
buffer.PopBack();
|
||||||
|
|
||||||
|
Assert.That(buffer.Size, Is.EqualTo(4));
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 0, 1, 2, 3 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_PopBackInOverflowBuffer_RemovesBackElement()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
||||||
|
buffer.PushBack(5);
|
||||||
|
|
||||||
|
Assert.That(buffer.Size, Is.EqualTo(5));
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 1, 2, 3, 4, 5 }));
|
||||||
|
|
||||||
|
buffer.PopBack();
|
||||||
|
|
||||||
|
Assert.That(buffer.Size, Is.EqualTo(4));
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 1, 2, 3, 4 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_PopFront_RemovesBackElement()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
||||||
|
|
||||||
|
Assert.That(buffer.Size, Is.EqualTo(5));
|
||||||
|
|
||||||
|
buffer.PopFront();
|
||||||
|
|
||||||
|
Assert.That(buffer.Size, Is.EqualTo(4));
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 1, 2, 3, 4 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_PopFrontInOverflowBuffer_RemovesBackElement()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
||||||
|
buffer.PushFront(5);
|
||||||
|
|
||||||
|
Assert.That(buffer.Size, Is.EqualTo(5));
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 5, 0, 1, 2, 3 }));
|
||||||
|
|
||||||
|
buffer.PopFront();
|
||||||
|
|
||||||
|
Assert.That(buffer.Size, Is.EqualTo(4));
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 0, 1, 2, 3 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_SetIndex_ReplacesElement()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
||||||
|
|
||||||
|
buffer[1] = 10;
|
||||||
|
buffer[3] = 30;
|
||||||
|
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new[] { 0, 10, 2, 30, 4 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_WithDifferentSizeAndCapacity_BackReturnsLastArrayPosition()
|
||||||
|
{
|
||||||
|
// test to confirm this issue does not happen anymore:
|
||||||
|
// https://github.com/joaoportela/RcCyclicBuffer-CSharp/issues/2
|
||||||
|
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3, 4 });
|
||||||
|
|
||||||
|
buffer.PopFront(); // (make size and capacity different)
|
||||||
|
|
||||||
|
Assert.That(buffer.Back(), Is.EqualTo(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_Clear_ClearsContent()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 4, 3, 2, 1, 0 });
|
||||||
|
|
||||||
|
buffer.Clear();
|
||||||
|
|
||||||
|
Assert.That(buffer.Size, Is.EqualTo(0));
|
||||||
|
Assert.That(buffer.Capacity, Is.EqualTo(5));
|
||||||
|
Assert.That(buffer.ToArray(), Is.EqualTo(new int[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RcCyclicBuffer_Clear_WorksNormallyAfterClear()
|
||||||
|
{
|
||||||
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 4, 3, 2, 1, 0 });
|
||||||
|
|
||||||
|
buffer.Clear();
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
buffer.PushBack(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(buffer.Front(), Is.EqualTo(0));
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
Assert.That(buffer[i], Is.EqualTo(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue