From 609508c94fe32e15642b591dae9d022a08437311 Mon Sep 17 00:00:00 2001 From: wreng Date: Wed, 21 Feb 2024 16:39:13 +0300 Subject: [PATCH] Support split special case --- src/DotRecast.Core/Buffers/RcCyclicBuffer.cs | 22 ++++---- src/DotRecast.Core/Buffers/RcCyclicBuffers.cs | 52 ++++++++++++++----- .../DotRecast.Core.Test/RcCyclicBufferTest.cs | 52 +++++++++++++++++++ 3 files changed, 102 insertions(+), 24 deletions(-) diff --git a/src/DotRecast.Core/Buffers/RcCyclicBuffer.cs b/src/DotRecast.Core/Buffers/RcCyclicBuffer.cs index 41c5a92..343e821 100644 --- a/src/DotRecast.Core/Buffers/RcCyclicBuffer.cs +++ b/src/DotRecast.Core/Buffers/RcCyclicBuffer.cs @@ -191,14 +191,17 @@ namespace DotRecast.Core.Buffers public T[] ToArray() { T[] newArray = new T[Size]; - - var span1 = ArrayOne(); - span1.CopyTo(newArray.AsSpan()); - ArrayTwo().CopyTo(newArray.AsSpan(span1.Length..)); - + CopyTo(newArray); return newArray; } + public void CopyTo(Span destination) + { + var span1 = ArrayOne(); + span1.CopyTo(destination); + ArrayTwo().CopyTo(destination[span1.Length..]); + } + private void ThrowIfEmpty(string message = "Cannot access an empty buffer.") { if (IsEmpty) @@ -232,7 +235,7 @@ namespace DotRecast.Core.Buffers : index - Capacity); } - private Span ArrayOne() + internal Span ArrayOne() { if (IsEmpty) { @@ -247,7 +250,7 @@ namespace DotRecast.Core.Buffers return new Span(_buffer, _start, _buffer.Length - _start); } - private Span ArrayTwo() + internal Span ArrayTwo() { if (IsEmpty) { @@ -262,11 +265,6 @@ namespace DotRecast.Core.Buffers return new Span(_buffer, 0, _end); } - internal ReadOnlySpan GetBufferSpan() - { - return _buffer; - } - public Enumerator GetEnumerator() => new Enumerator(this); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); diff --git a/src/DotRecast.Core/Buffers/RcCyclicBuffers.cs b/src/DotRecast.Core/Buffers/RcCyclicBuffers.cs index 71b88f7..fc94285 100644 --- a/src/DotRecast.Core/Buffers/RcCyclicBuffers.cs +++ b/src/DotRecast.Core/Buffers/RcCyclicBuffers.cs @@ -6,9 +6,9 @@ namespace DotRecast.Core.Buffers { public static class RcCyclicBuffers { - public static long Sum(this RcCyclicBuffer source) + public static long Sum(this ReadOnlySpan source) { - var buffer = source.GetBufferSpan(); + var buffer = source; var result = 0L; if (Vector.IsHardwareAccelerated) { @@ -18,7 +18,7 @@ namespace DotRecast.Core.Buffers vecSum += vec; result = Vector.Dot(vecSum, Vector.One); - var remainder = source.Size % Vector.Count; + var remainder = source.Length % Vector.Count; buffer = buffer[^remainder..]; } @@ -28,17 +28,17 @@ namespace DotRecast.Core.Buffers return result; } - public static double Average(this RcCyclicBuffer source) + public static double Average(this ReadOnlySpan source) { - if (0 >= source.Size) + if (0 >= source.Length) return 0; - return source.Sum() / (double)source.Size; + return source.Sum() / (double)source.Length; } - public static long Min(this RcCyclicBuffer source) + private static long Min(this ReadOnlySpan source) { - var buffer = source.GetBufferSpan(); + var buffer = source; var result = long.MaxValue; if (Vector.IsHardwareAccelerated) @@ -52,7 +52,7 @@ namespace DotRecast.Core.Buffers for (int i = 0; i < Vector.Count; i++) result = Math.Min(result, vecMin[i]); - var remainder = source.Size % Vector.Count; + var remainder = source.Length % Vector.Count; buffer = buffer[^remainder..]; } @@ -62,9 +62,9 @@ namespace DotRecast.Core.Buffers return result; } - public static long Max(this RcCyclicBuffer source) + private static long Max(this ReadOnlySpan source) { - var buffer = source.GetBufferSpan(); + var buffer = source; var result = long.MinValue; if (Vector.IsHardwareAccelerated) @@ -78,7 +78,7 @@ namespace DotRecast.Core.Buffers for (int i = 0; i < Vector.Count; i++) result = Math.Max(result, vecMax[i]); - var remainder = source.Size % Vector.Count; + var remainder = source.Length % Vector.Count; buffer = buffer[^remainder..]; } @@ -87,5 +87,33 @@ namespace DotRecast.Core.Buffers return result; } + + public static long Sum(this RcCyclicBuffer source) + { + return Sum(source.ArrayOne()) + Sum(source.ArrayTwo()); + } + + public static double Average(this RcCyclicBuffer source) + { + return Sum(source) / (double)source.Size; + } + + public static long Min(this RcCyclicBuffer 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 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); + } } } \ No newline at end of file diff --git a/test/DotRecast.Core.Test/RcCyclicBufferTest.cs b/test/DotRecast.Core.Test/RcCyclicBufferTest.cs index 98f3f5c..df11f1d 100644 --- a/test/DotRecast.Core.Test/RcCyclicBufferTest.cs +++ b/test/DotRecast.Core.Test/RcCyclicBufferTest.cs @@ -394,4 +394,56 @@ public class RcCyclicBufferTests var buffer = new RcCyclicBuffer(refValues.Length, refValues); 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(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(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(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(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(refValues.Length, refValues); + buffer.PopFront(); + buffer.PushBack(refValues[0]); + Assert.That(RcCyclicBuffers.Max(buffer), Is.EqualTo(refValues.Max())); + } } \ No newline at end of file