Support split special case

This commit is contained in:
wreng 2024-02-21 16:39:13 +03:00 committed by Ikpil
parent c47cc79552
commit 609508c94f
3 changed files with 102 additions and 24 deletions

View File

@ -191,14 +191,17 @@ namespace DotRecast.Core.Buffers
public T[] ToArray() public T[] ToArray()
{ {
T[] newArray = new T[Size]; T[] newArray = new T[Size];
CopyTo(newArray);
var span1 = ArrayOne();
span1.CopyTo(newArray.AsSpan());
ArrayTwo().CopyTo(newArray.AsSpan(span1.Length..));
return newArray; return newArray;
} }
public void CopyTo(Span<T> destination)
{
var span1 = ArrayOne();
span1.CopyTo(destination);
ArrayTwo().CopyTo(destination[span1.Length..]);
}
private void ThrowIfEmpty(string message = "Cannot access an empty buffer.") private void ThrowIfEmpty(string message = "Cannot access an empty buffer.")
{ {
if (IsEmpty) if (IsEmpty)
@ -232,7 +235,7 @@ namespace DotRecast.Core.Buffers
: index - Capacity); : index - Capacity);
} }
private Span<T> ArrayOne() internal Span<T> ArrayOne()
{ {
if (IsEmpty) if (IsEmpty)
{ {
@ -247,7 +250,7 @@ namespace DotRecast.Core.Buffers
return new Span<T>(_buffer, _start, _buffer.Length - _start); return new Span<T>(_buffer, _start, _buffer.Length - _start);
} }
private Span<T> ArrayTwo() internal Span<T> ArrayTwo()
{ {
if (IsEmpty) if (IsEmpty)
{ {
@ -262,11 +265,6 @@ namespace DotRecast.Core.Buffers
return new Span<T>(_buffer, 0, _end); return new Span<T>(_buffer, 0, _end);
} }
internal ReadOnlySpan<T> GetBufferSpan()
{
return _buffer;
}
public Enumerator GetEnumerator() => new Enumerator(this); public Enumerator GetEnumerator() => new Enumerator(this);
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator(); IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();

View File

@ -6,9 +6,9 @@ namespace DotRecast.Core.Buffers
{ {
public static class RcCyclicBuffers public static class RcCyclicBuffers
{ {
public static long Sum(this RcCyclicBuffer<long> source) public static long Sum(this ReadOnlySpan<long> source)
{ {
var buffer = source.GetBufferSpan(); var buffer = source;
var result = 0L; var result = 0L;
if (Vector.IsHardwareAccelerated) if (Vector.IsHardwareAccelerated)
{ {
@ -18,7 +18,7 @@ namespace DotRecast.Core.Buffers
vecSum += vec; vecSum += vec;
result = Vector.Dot(vecSum, Vector<long>.One); result = Vector.Dot(vecSum, Vector<long>.One);
var remainder = source.Size % Vector<long>.Count; var remainder = source.Length % Vector<long>.Count;
buffer = buffer[^remainder..]; buffer = buffer[^remainder..];
} }
@ -28,17 +28,17 @@ namespace DotRecast.Core.Buffers
return result; return result;
} }
public static double Average(this RcCyclicBuffer<long> source) public static double Average(this ReadOnlySpan<long> source)
{ {
if (0 >= source.Size) if (0 >= source.Length)
return 0; return 0;
return source.Sum() / (double)source.Size; return source.Sum() / (double)source.Length;
} }
public static long Min(this RcCyclicBuffer<long> source) private static long Min(this ReadOnlySpan<long> source)
{ {
var buffer = source.GetBufferSpan(); var buffer = source;
var result = long.MaxValue; var result = long.MaxValue;
if (Vector.IsHardwareAccelerated) if (Vector.IsHardwareAccelerated)
@ -52,7 +52,7 @@ namespace DotRecast.Core.Buffers
for (int i = 0; i < Vector<long>.Count; i++) for (int i = 0; i < Vector<long>.Count; i++)
result = Math.Min(result, vecMin[i]); result = Math.Min(result, vecMin[i]);
var remainder = source.Size % Vector<long>.Count; var remainder = source.Length % Vector<long>.Count;
buffer = buffer[^remainder..]; buffer = buffer[^remainder..];
} }
@ -62,9 +62,9 @@ namespace DotRecast.Core.Buffers
return result; return result;
} }
public static long Max(this RcCyclicBuffer<long> source) private static long Max(this ReadOnlySpan<long> source)
{ {
var buffer = source.GetBufferSpan(); var buffer = source;
var result = long.MinValue; var result = long.MinValue;
if (Vector.IsHardwareAccelerated) if (Vector.IsHardwareAccelerated)
@ -78,7 +78,7 @@ namespace DotRecast.Core.Buffers
for (int i = 0; i < Vector<long>.Count; i++) for (int i = 0; i < Vector<long>.Count; i++)
result = Math.Max(result, vecMax[i]); result = Math.Max(result, vecMax[i]);
var remainder = source.Size % Vector<long>.Count; var remainder = source.Length % Vector<long>.Count;
buffer = buffer[^remainder..]; buffer = buffer[^remainder..];
} }
@ -87,5 +87,33 @@ namespace DotRecast.Core.Buffers
return result; return result;
} }
public static long Sum(this RcCyclicBuffer<long> source)
{
return Sum(source.ArrayOne()) + Sum(source.ArrayTwo());
}
public static double Average(this RcCyclicBuffer<long> source)
{
return Sum(source) / (double)source.Size;
}
public static long Min(this RcCyclicBuffer<long> source)
{
var firstHalf = source.ArrayOne();
var secondHalf = source.ArrayTwo();
var a = firstHalf.Length > 0 ? Min(firstHalf) : long.MaxValue;
var b = secondHalf.Length > 0 ? Min(secondHalf) : long.MaxValue;
return Math.Min(a, b);
}
public static long Max(this RcCyclicBuffer<long> source)
{
var firstHalf = source.ArrayOne();
var secondHalf = source.ArrayTwo();
var a = firstHalf.Length > 0 ? Max(firstHalf) : long.MinValue;
var b = secondHalf.Length > 0 ? Max(secondHalf) : long.MinValue;
return Math.Max(a, b);
}
} }
} }

View File

@ -394,4 +394,56 @@ public class RcCyclicBufferTests
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues); var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
Assert.That(RcCyclicBuffers.Max(buffer), Is.EqualTo(refValues.Max())); Assert.That(RcCyclicBuffers.Max(buffer), Is.EqualTo(refValues.Max()));
} }
[Test]
public void RcCyclicBuffers_SumDeleted()
{
var initialValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
var refValues = initialValues.Skip(1).SkipLast(1).ToArray();
var buffer = new RcCyclicBuffer<long>(initialValues.Length, initialValues);
buffer.PopBack();
buffer.PopFront();
Assert.That(RcCyclicBuffers.Sum(buffer), Is.EqualTo(refValues.Sum()));
}
[Test]
public void RcCyclicBuffers_SumSplit()
{
var refValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
buffer.PopFront();
buffer.PushBack(refValues[0]);
Assert.That(RcCyclicBuffers.Sum(buffer), Is.EqualTo(refValues.Sum()));
}
[Test]
public void RcCyclicBuffers_AverageSplit()
{
var refValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
buffer.PopFront();
buffer.PushBack(refValues[0]);
Assert.That(RcCyclicBuffers.Average(buffer), Is.EqualTo(refValues.Average()));
}
[Test]
public void RcCyclicBuffers_MinSplit()
{
var refValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
buffer.PopFront();
buffer.PushBack(refValues[0]);
Assert.That(RcCyclicBuffers.Min(buffer), Is.EqualTo(refValues.Min()));
}
[Test]
public void RcCyclicBuffers_MaxSplit()
{
var refValues = Enumerable.Range(-100, 211).Select(x => (long)x).ToArray();
var buffer = new RcCyclicBuffer<long>(refValues.Length, refValues);
buffer.PopFront();
buffer.PushBack(refValues[0]);
Assert.That(RcCyclicBuffers.Max(buffer), Is.EqualTo(refValues.Max()));
}
} }