forked from bit/DotRecastNetSim
CyclicBuffer optimizations
This commit is contained in:
parent
804cb275a7
commit
097a365528
|
@ -1,12 +1,47 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Security;
|
using System.Net.Security;
|
||||||
|
|
||||||
namespace DotRecast.Core.Buffers
|
namespace DotRecast.Core.Buffers
|
||||||
{
|
{
|
||||||
// https://github.com/joaoportela/CircularBuffer-CSharp/blob/master/CircularBuffer/CircularBuffer.cs
|
// 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 readonly T[] _buffer;
|
||||||
|
|
||||||
private int _start;
|
private int _start;
|
||||||
|
@ -155,29 +190,15 @@ namespace DotRecast.Core.Buffers
|
||||||
|
|
||||||
public T[] ToArray()
|
public T[] ToArray()
|
||||||
{
|
{
|
||||||
int idx = 0;
|
|
||||||
T[] newArray = new T[Size];
|
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;
|
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.")
|
private void ThrowIfEmpty(string message = "Cannot access an empty buffer.")
|
||||||
{
|
{
|
||||||
if (IsEmpty)
|
if (IsEmpty)
|
||||||
|
@ -240,5 +261,11 @@ namespace DotRecast.Core.Buffers
|
||||||
|
|
||||||
return new Span<T>(_buffer, 0, _end);
|
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;
|
long sum = 0;
|
||||||
checked
|
checked
|
||||||
{
|
{
|
||||||
source.ForEach(x => sum += x);
|
// NOTE: SIMD would be nice here
|
||||||
|
foreach (var x in source)
|
||||||
|
{
|
||||||
|
sum += x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sum;
|
return sum;
|
||||||
|
@ -27,11 +31,11 @@
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
long minValue = long.MaxValue;
|
long minValue = long.MaxValue;
|
||||||
source.ForEach(x =>
|
foreach (var x in source)
|
||||||
{
|
{
|
||||||
if (x < minValue)
|
if (x < minValue)
|
||||||
minValue = x;
|
minValue = x;
|
||||||
});
|
}
|
||||||
|
|
||||||
return minValue;
|
return minValue;
|
||||||
}
|
}
|
||||||
|
@ -42,11 +46,11 @@
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
long maxValue = long.MinValue;
|
long maxValue = long.MinValue;
|
||||||
source.ForEach(x =>
|
foreach (var x in source)
|
||||||
{
|
{
|
||||||
if (x > maxValue)
|
if (x > maxValue)
|
||||||
maxValue = x;
|
maxValue = x;
|
||||||
});
|
}
|
||||||
|
|
||||||
return maxValue;
|
return maxValue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using DotRecast.Core.Buffers;
|
using DotRecast.Core.Buffers;
|
||||||
|
using DotRecast.Core.Collections;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Core.Test;
|
namespace DotRecast.Core.Test;
|
||||||
|
@ -39,11 +40,11 @@ public class RcCyclicBufferTests
|
||||||
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3 });
|
var buffer = new RcCyclicBuffer<int>(5, new[] { 0, 1, 2, 3 });
|
||||||
|
|
||||||
int x = 0;
|
int x = 0;
|
||||||
buffer.ForEach(item =>
|
foreach (var item in buffer)
|
||||||
{
|
{
|
||||||
Assert.That(item, Is.EqualTo(x));
|
Assert.That(item, Is.EqualTo(x));
|
||||||
x++;
|
x++;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -290,4 +291,40 @@ public class RcCyclicBufferTests
|
||||||
Assert.That(buffer[i], Is.EqualTo(i));
|
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