diff --git a/src/DotRecast.Core/Buffers/RcRentedArray.cs b/src/DotRecast.Core/Buffers/RcRentedArray.cs new file mode 100644 index 0000000..793fdad --- /dev/null +++ b/src/DotRecast.Core/Buffers/RcRentedArray.cs @@ -0,0 +1,60 @@ +using System; +using System.Buffers; +using System.Runtime.CompilerServices; + +namespace DotRecast.Core.Buffers +{ + public static class RcRentedArray + { + public static RcRentedArray RentDisposableArray(int minimumLength) + { + var array = ArrayPool.Shared.Rent(minimumLength); + return new RcRentedArray(ArrayPool.Shared, array, minimumLength); + } + } + + public class RcRentedArray : IDisposable + { + private ArrayPool _owner; + private T[] _array; + private readonly RcAtomicInteger _disposed; + + public int Length { get; } + + internal RcRentedArray(ArrayPool owner, T[] array, int length) + { + _owner = owner; + _array = array; + Length = length; + _disposed = new RcAtomicInteger(0); + } + + public T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); + return _array[index]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); + _array[index] = value; + } + } + + + public void Dispose() + { + if (1 != _disposed.IncrementAndGet()) + return; + + _owner?.Return(_array, true); + _array = null; + _owner = null; + } + } +} \ No newline at end of file diff --git a/src/DotRecast.Core/Collections/RcStackArray128.cs b/src/DotRecast.Core/Collections/RcStackArray128.cs index de45d8a..d3caa30 100644 --- a/src/DotRecast.Core/Collections/RcStackArray128.cs +++ b/src/DotRecast.Core/Collections/RcStackArray128.cs @@ -139,21 +139,12 @@ namespace DotRecast.Core.Collections public T V126; public T V127; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ThrowExceptionIfIndexOutOfRange(int index) - { - if (0 > index || index >= Size) - { - throw new IndexOutOfRangeException($"{index}"); - } - } - public T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - ThrowExceptionIfIndexOutOfRange(index); + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); return index switch { @@ -291,7 +282,7 @@ namespace DotRecast.Core.Collections set { - ThrowExceptionIfIndexOutOfRange(index); + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); switch (index) { diff --git a/src/DotRecast.Core/Collections/RcStackArray16.cs b/src/DotRecast.Core/Collections/RcStackArray16.cs index 48aca6a..461bff1 100644 --- a/src/DotRecast.Core/Collections/RcStackArray16.cs +++ b/src/DotRecast.Core/Collections/RcStackArray16.cs @@ -27,22 +27,12 @@ namespace DotRecast.Core.Collections public T V14; public T V15; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ThrowExceptionIfIndexOutOfRange(int index) - { - if (0 > index || index >= Size) - { - throw new IndexOutOfRangeException($"{index}"); - } - } - public T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - ThrowExceptionIfIndexOutOfRange(index); + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); return index switch { @@ -68,7 +58,7 @@ namespace DotRecast.Core.Collections set { - ThrowExceptionIfIndexOutOfRange(index); + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); switch (index) { diff --git a/src/DotRecast.Core/Collections/RcStackArray256.cs b/src/DotRecast.Core/Collections/RcStackArray256.cs index 71ad603..4bb1ee1 100644 --- a/src/DotRecast.Core/Collections/RcStackArray256.cs +++ b/src/DotRecast.Core/Collections/RcStackArray256.cs @@ -267,21 +267,12 @@ namespace DotRecast.Core.Collections public T V254; public T V255; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ThrowExceptionIfIndexOutOfRange(int index) - { - if (0 > index || index >= Size) - { - throw new IndexOutOfRangeException($"{index}"); - } - } - public T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - ThrowExceptionIfIndexOutOfRange(index); + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); return index switch { @@ -547,7 +538,7 @@ namespace DotRecast.Core.Collections set { - ThrowExceptionIfIndexOutOfRange(index); + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); switch (index) { diff --git a/src/DotRecast.Core/Collections/RcStackArray32.cs b/src/DotRecast.Core/Collections/RcStackArray32.cs index 37fe203..8f1c834 100644 --- a/src/DotRecast.Core/Collections/RcStackArray32.cs +++ b/src/DotRecast.Core/Collections/RcStackArray32.cs @@ -43,21 +43,12 @@ namespace DotRecast.Core.Collections public T V30; public T V31; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ThrowExceptionIfIndexOutOfRange(int index) - { - if (0 > index || index >= Size) - { - throw new IndexOutOfRangeException($"{index}"); - } - } - public T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - ThrowExceptionIfIndexOutOfRange(index); + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); return index switch { @@ -99,7 +90,7 @@ namespace DotRecast.Core.Collections set { - ThrowExceptionIfIndexOutOfRange(index); + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); switch (index) { diff --git a/src/DotRecast.Core/Collections/RcStackArray512.cs b/src/DotRecast.Core/Collections/RcStackArray512.cs index cb4a0d2..91b4aa2 100644 --- a/src/DotRecast.Core/Collections/RcStackArray512.cs +++ b/src/DotRecast.Core/Collections/RcStackArray512.cs @@ -523,21 +523,12 @@ namespace DotRecast.Core.Collections public T V510; public T V511; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ThrowExceptionIfIndexOutOfRange(int index) - { - if (0 > index || index >= Size) - { - throw new IndexOutOfRangeException($"{index}"); - } - } - public T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - ThrowExceptionIfIndexOutOfRange(index); + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); return index switch { @@ -1060,7 +1051,7 @@ namespace DotRecast.Core.Collections set { - ThrowExceptionIfIndexOutOfRange(index); + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); switch (index) { @@ -1576,7 +1567,6 @@ namespace DotRecast.Core.Collections case 509: V509 = value; break; case 510: V510 = value; break; case 511: V511 = value; break; - } } } diff --git a/src/DotRecast.Core/Collections/RcStackArray64.cs b/src/DotRecast.Core/Collections/RcStackArray64.cs index 1f21675..6d15947 100644 --- a/src/DotRecast.Core/Collections/RcStackArray64.cs +++ b/src/DotRecast.Core/Collections/RcStackArray64.cs @@ -75,21 +75,12 @@ namespace DotRecast.Core.Collections public T V62; public T V63; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ThrowExceptionIfIndexOutOfRange(int index) - { - if (0 > index || index >= Size) - { - throw new IndexOutOfRangeException($"{index}"); - } - } - public T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - ThrowExceptionIfIndexOutOfRange(index); + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); return index switch { @@ -163,7 +154,7 @@ namespace DotRecast.Core.Collections set { - ThrowExceptionIfIndexOutOfRange(index); + ThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length); switch (index) { diff --git a/test/DotRecast.Core.Test/RcRentedArrayTest.cs b/test/DotRecast.Core.Test/RcRentedArrayTest.cs new file mode 100644 index 0000000..1cf67c8 --- /dev/null +++ b/test/DotRecast.Core.Test/RcRentedArrayTest.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using DotRecast.Core.Buffers; +using NUnit.Framework; + +namespace DotRecast.Core.Test; + +public class RcRentedArrayTest +{ + public List RandomValues(int length) + { + var rand = new RcRand(); + + // excepted values + var list = new List(); + for (int i = 0; i < length; ++i) + { + list.Add(rand.NextInt32()); + } + + return list; + } + + [Test] + public void Test() + { + var rand = new RcRand(); + for (int loop = 0; loop < 1024; ++loop) + { + int length = (int)(rand.Next() * 2048); + var values = RandomValues(length); + using var array = RcRentedArray.RentDisposableArray(length); + + for (int i = 0; i < array.Length; ++i) + { + array[i] = values[i]; + } + + for (int i = 0; i < array.Length; ++i) + { + Assert.That(array[i], Is.EqualTo(values[i])); + } + + Assert.That(array[^1], Is.EqualTo(values[^1])); + + Assert.Throws(() => array[-1] = 0); + Assert.Throws(() => array[array.Length + 1] = 0); + Assert.Throws(() => _ = array[-1]); + Assert.Throws(() => _ = array[array.Length + 1]); + } + } +} \ No newline at end of file