forked from mirror/DotRecast
CyclicBuffer optimizations
This commit is contained in:
parent
804cb275a7
commit
097a365528
|
@ -1,12 +1,47 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Security;
|
||||
|
||||
namespace DotRecast.Core.Buffers
|
||||
{
|
||||
// https://github.com/joaoportela/CircularBuffer-CSharp/blob/master/CircularBuffer/CircularBuffer.cs
|
||||
public class RcCyclicBuffer<T>
|
||||
public class RcCyclicBuffer<T> : IEnumerable<T>
|
||||
{
|
||||
public struct Enumerator : IEnumerator<T>
|
||||
{
|
||||
private readonly RcCyclicBuffer<T> _buffer;
|
||||
private int _index;
|
||||
private readonly int _size;
|
||||
|
||||
internal Enumerator(RcCyclicBuffer<T> buffer)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_size = _buffer._size;
|
||||
_index = default;
|
||||
Reset();
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
return ++_index < _size;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
}
|
||||
|
||||
public T Current => _buffer[_index];
|
||||
|
||||
object IEnumerator.Current => Current;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// This could be used to unlock write access to collection
|
||||
}
|
||||
}
|
||||
|
||||
private readonly T[] _buffer;
|
||||
|
||||
private int _start;
|
||||
|
@ -155,29 +190,15 @@ namespace DotRecast.Core.Buffers
|
|||
|
||||
public T[] ToArray()
|
||||
{
|
||||
int idx = 0;
|
||||
T[] newArray = new T[Size];
|
||||
|
||||
ForEach(x => newArray[idx++] = x);
|
||||
var span1 = ArrayOne();
|
||||
span1.CopyTo(newArray.AsSpan());
|
||||
ArrayTwo().CopyTo(newArray.AsSpan(span1.Length..));
|
||||
|
||||
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)
|
||||
|
@ -240,5 +261,11 @@ namespace DotRecast.Core.Buffers
|
|||
|
||||
return new Span<T>(_buffer, 0, _end);
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator() => new Enumerator(this);
|
||||
|
||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
}
|
|
@ -7,7 +7,11 @@
|
|||
long sum = 0;
|
||||
checked
|
||||
{
|
||||
source.ForEach(x => sum += x);
|
||||
// NOTE: SIMD would be nice here
|
||||
foreach (var x in source)
|
||||
{
|
||||
sum += x;
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
|
@ -27,11 +31,11 @@
|
|||
return 0;
|
||||
|
||||
long minValue = long.MaxValue;
|
||||
source.ForEach(x =>
|
||||
foreach (var x in source)
|
||||
{
|
||||
if (x < minValue)
|
||||
minValue = x;
|
||||
});
|
||||
}
|
||||
|
||||
return minValue;
|
||||
}
|
||||
|
@ -42,11 +46,11 @@
|
|||
return 0;
|
||||
|
||||
long maxValue = long.MinValue;
|
||||
source.ForEach(x =>
|
||||
foreach (var x in source)
|
||||
{
|
||||
if (x > maxValue)
|
||||
maxValue = x;
|
||||
});
|
||||
}
|
||||
|
||||
return maxValue;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using DotRecast.Core.Buffers;
|
||||
using DotRecast.Core.Collections;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Core.Test;
|
||||
|
@ -39,11 +40,11 @@ public class RcCyclicBufferTests
|
|||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3 });
|
||||
|
||||
int x = 0;
|
||||
buffer.ForEach(item =>
|
||||
foreach (var item in buffer)
|
||||
{
|
||||
Assert.That(item, Is.EqualTo(x));
|
||||
x++;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -290,4 +291,40 @@ public class RcCyclicBufferTests
|
|||
Assert.That(buffer[i], Is.EqualTo(i));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RcCyclicBuffer_RegularForEachWorks()
|
||||
{
|
||||
var refValues = new[] { 4, 3, 2, 1, 0 };
|
||||
var buffer = new RcCyclicBuffer<int>(5, refValues);
|
||||
|
||||
var index = 0;
|
||||
foreach (var element in buffer)
|
||||
{
|
||||
Assert.That(element, Is.EqualTo(refValues[index++]));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RcCyclicBuffer_EnumeratorWorks()
|
||||
{
|
||||
var refValues = new[] { 4, 3, 2, 1, 0 };
|
||||
var buffer = new RcCyclicBuffer<int>(5, refValues);
|
||||
|
||||
var index = 0;
|
||||
var enumerator = buffer.GetEnumerator();
|
||||
enumerator.Reset();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
Assert.That(enumerator.Current, Is.EqualTo(refValues[index++]));
|
||||
}
|
||||
|
||||
// Ensure Reset works properly
|
||||
index = 0;
|
||||
enumerator.Reset();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
Assert.That(enumerator.Current, Is.EqualTo(refValues[index++]));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue