aboutsummaryrefslogtreecommitdiff
path: root/lib/Utils
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-01-14 16:24:28 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2023-01-14 16:24:28 -0500
commit52b8e30437e235817ed534dec860e781bb0468c0 (patch)
treeb279418c23daec838fab6bf8a0b29c3091d2e300 /lib/Utils
parent0dcecff0f51bdb51b070c05255fbcd9338ab11f2 (diff)
MemoryUtil native integer size update + tests
Diffstat (limited to 'lib/Utils')
-rw-r--r--lib/Utils/src/Extensions/IoExtensions.cs2
-rw-r--r--lib/Utils/src/Extensions/MemoryExtensions.cs150
-rw-r--r--lib/Utils/src/Extensions/VnStringExtensions.cs87
-rw-r--r--lib/Utils/src/IO/InMemoryTemplate.cs2
-rw-r--r--lib/Utils/src/IO/VnMemoryStream.cs124
-rw-r--r--lib/Utils/src/Memory/IMemoryHandle.cs8
-rw-r--r--lib/Utils/src/Memory/IUnmangedHeap.cs4
-rw-r--r--lib/Utils/src/Memory/MemoryHandle.cs43
-rw-r--r--lib/Utils/src/Memory/MemoryUtil.cs (renamed from lib/Utils/src/Memory/Memory.cs)353
-rw-r--r--lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs2
-rw-r--r--lib/Utils/src/Memory/PrivateStringManager.cs4
-rw-r--r--lib/Utils/src/Memory/ProcessHeap.cs28
-rw-r--r--lib/Utils/src/Memory/RpMallocPrivateHeap.cs57
-rw-r--r--lib/Utils/src/Memory/SubSequence.cs29
-rw-r--r--lib/Utils/src/Memory/SysBufferMemoryManager.cs6
-rw-r--r--lib/Utils/src/Memory/UnmanagedHeapBase.cs16
-rw-r--r--lib/Utils/src/Memory/UnsafeMemoryHandle.cs17
-rw-r--r--lib/Utils/src/Memory/VnString.cs73
-rw-r--r--lib/Utils/src/Memory/VnTable.cs68
-rw-r--r--lib/Utils/src/Memory/VnTempBuffer.cs18
-rw-r--r--lib/Utils/src/Memory/Win32PrivateHeap.cs (renamed from lib/Utils/src/Memory/PrivateHeap.cs)43
-rw-r--r--lib/Utils/src/VnEncoding.cs10
-rw-r--r--lib/Utils/tests/Memory/MemoryHandleTest.cs25
-rw-r--r--lib/Utils/tests/Memory/MemoryTests.cs244
-rw-r--r--lib/Utils/tests/Memory/MemoryUtilTests.cs333
-rw-r--r--lib/Utils/tests/Memory/VnTableTests.cs51
-rw-r--r--lib/Utils/tests/VnEncodingTests.cs6
27 files changed, 1038 insertions, 765 deletions
diff --git a/lib/Utils/src/Extensions/IoExtensions.cs b/lib/Utils/src/Extensions/IoExtensions.cs
index baba7dc..637cfab 100644
--- a/lib/Utils/src/Extensions/IoExtensions.cs
+++ b/lib/Utils/src/Extensions/IoExtensions.cs
@@ -33,7 +33,7 @@ using System.Runtime.CompilerServices;
using VNLib.Utils.IO;
using VNLib.Utils.Memory;
-using static VNLib.Utils.Memory.Memory;
+using static VNLib.Utils.Memory.MemoryUtil;
namespace VNLib.Utils.Extensions
{
diff --git a/lib/Utils/src/Extensions/MemoryExtensions.cs b/lib/Utils/src/Extensions/MemoryExtensions.cs
index c8ee5ef..17ad79d 100644
--- a/lib/Utils/src/Extensions/MemoryExtensions.cs
+++ b/lib/Utils/src/Extensions/MemoryExtensions.cs
@@ -124,7 +124,7 @@ namespace VNLib.Utils.Extensions
}
/// <summary>
- /// Allows direct allocation of a fixed size <see cref="MemoryManager{T}"/> from a <see cref="PrivateHeap"/> instance
+ /// Allows direct allocation of a fixed size <see cref="MemoryManager{T}"/> from a <see cref="Win32PrivateHeap"/> instance
/// of the specified number of elements
/// </summary>
/// <typeparam name="T">The unmanaged data type</typeparam>
@@ -133,13 +133,39 @@ namespace VNLib.Utils.Extensions
/// <param name="zero">Optionally zeros conents of the block when allocated</param>
/// <returns>The <see cref="MemoryManager{T}"/> wrapper around the block of memory</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static MemoryManager<T> DirectAlloc<T>(this IUnmangedHeap heap, ulong size, bool zero = false) where T : unmanaged
+ public static MemoryManager<T> DirectAlloc<T>(this IUnmangedHeap heap, nuint size, bool zero = false) where T : unmanaged
{
return new SysBufferMemoryManager<T>(heap, size, zero);
}
/// <summary>
- /// Allows direct allocation of a fixed size <see cref="MemoryManager{T}"/> from a <see cref="PrivateHeap"/> instance
+ /// Gets the integer length (number of elements) of the <see cref="IMemoryHandle{T}"/>
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="handle"></param>
+ /// <returns>
+ /// The integer length of the handle, or throws <see cref="OverflowException"/> if
+ /// the platform is 64bit and the handle is larger than <see cref="int.MaxValue"/>
+ /// </returns>
+ /// <exception cref="OverflowException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int GetIntLength<T>(this IMemoryHandle<T> handle) => Convert.ToInt32(handle.Length);
+
+ /// <summary>
+ /// Gets the integer length (number of elements) of the <see cref="UnsafeMemoryHandle{T}"/>
+ /// </summary>
+ /// <typeparam name="T">The unmanaged type</typeparam>
+ /// <param name="handle"></param>
+ /// <returns>
+ /// The integer length of the handle, or throws <see cref="OverflowException"/> if
+ /// the platform is 64bit and the handle is larger than <see cref="int.MaxValue"/>
+ /// </returns>
+ //Method only exists for consistancy since unsafe handles are always 32bit
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int GetIntLength<T>(this in UnsafeMemoryHandle<T> handle) where T: unmanaged => handle.IntLength;
+
+ /// <summary>
+ /// Allows direct allocation of a fixed size <see cref="MemoryManager{T}"/> from a <see cref="Win32PrivateHeap"/> instance
/// of the specified number of elements
/// </summary>
/// <typeparam name="T">The unmanaged data type</typeparam>
@@ -147,11 +173,12 @@ namespace VNLib.Utils.Extensions
/// <param name="size">The number of elements to allocate on the heap</param>
/// <param name="zero">Optionally zeros conents of the block when allocated</param>
/// <returns>The <see cref="MemoryManager{T}"/> wrapper around the block of memory</returns>
+ /// <exception cref="OverflowException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static MemoryManager<T> DirectAlloc<T>(this IUnmangedHeap heap, long size, bool zero = false) where T : unmanaged
+ public static MemoryManager<T> DirectAlloc<T>(this IUnmangedHeap heap, nint size, bool zero = false) where T : unmanaged
{
- return size < 0 ? throw new ArgumentOutOfRangeException(nameof(size)) : DirectAlloc<T>(heap, (ulong)size, zero);
+ return size >= 0 ? DirectAlloc<T>(heap, (nuint)size, zero) : throw new ArgumentOutOfRangeException(nameof(size), "The size paramter must be a positive integer");
}
/// <summary>
/// Gets an offset pointer from the base postion to the number of bytes specified. Performs bounds checks
@@ -161,11 +188,10 @@ namespace VNLib.Utils.Extensions
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
/// <returns><typeparamref name="T"/> pointer to the memory offset specified</returns>
- /// [MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static unsafe T* GetOffset<T>(this MemoryHandle<T> memory, long elements) where T : unmanaged
+ public static unsafe T* GetOffset<T>(this MemoryHandle<T> memory, nint elements) where T : unmanaged
{
- return elements < 0 ? throw new ArgumentOutOfRangeException(nameof(elements)) : memory.GetOffset((ulong)elements);
+ return elements >= 0 ? memory.GetOffset((nuint)elements) : throw new ArgumentOutOfRangeException(nameof(elements), "The elements paramter must be a positive integer");
}
/// <summary>
/// Resizes the current handle on the heap
@@ -177,13 +203,13 @@ namespace VNLib.Utils.Extensions
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void Resize<T>(this MemoryHandle<T> memory, long elements) where T : unmanaged
+ public static void Resize<T>(this MemoryHandle<T> memory, nint elements) where T : unmanaged
{
if (elements < 0)
{
throw new ArgumentOutOfRangeException(nameof(elements));
}
- memory.Resize((ulong)elements);
+ memory.Resize((nuint)elements);
}
/// <summary>
@@ -197,13 +223,13 @@ namespace VNLib.Utils.Extensions
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void ResizeIfSmaller<T>(this MemoryHandle<T> handle, long count) where T : unmanaged
+ public static void ResizeIfSmaller<T>(this MemoryHandle<T> handle, nint count) where T : unmanaged
{
if(count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count));
}
- ResizeIfSmaller(handle, (ulong)count);
+ ResizeIfSmaller(handle, (nuint)count);
}
/// <summary>
@@ -217,7 +243,7 @@ namespace VNLib.Utils.Extensions
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void ResizeIfSmaller<T>(this MemoryHandle<T> handle, ulong count) where T : unmanaged
+ public static void ResizeIfSmaller<T>(this MemoryHandle<T> handle, nuint count) where T : unmanaged
{
//Check handle size
if(handle.Length < count)
@@ -227,7 +253,7 @@ namespace VNLib.Utils.Extensions
}
}
-#if TARGET_64_BIT
+
/// <summary>
/// Gets a 64bit friendly span offset for the current <see cref="MemoryHandle{T}"/>
/// </summary>
@@ -238,9 +264,10 @@ namespace VNLib.Utils.Extensions
/// <returns>The offset span</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static unsafe Span<T> GetOffsetSpan<T>(this MemoryHandle<T> block, ulong offset, int size) where T: unmanaged
+ public static unsafe Span<T> GetOffsetSpan<T>(this MemoryHandle<T> block, nuint offset, int size) where T: unmanaged
{
_ = block ?? throw new ArgumentNullException(nameof(block));
+
if(size < 0)
{
throw new ArgumentOutOfRangeException(nameof(size));
@@ -249,14 +276,13 @@ namespace VNLib.Utils.Extensions
{
return Span<T>.Empty;
}
- //Make sure the offset size is within the size of the block
- if(offset + (ulong)size <= block.Length)
- {
- //Get long offset from the destination handle
- void* ofPtr = block.GetOffset(offset);
- return new Span<T>(ofPtr, size);
- }
- throw new ArgumentOutOfRangeException(nameof(size));
+
+ //Check bounds
+ MemoryUtil.CheckBounds(block, offset, (nuint)size);
+
+ //Get long offset from the destination handle
+ void* ofPtr = block.GetOffset(offset);
+ return new Span<T>(ofPtr, size);
}
/// <summary>
/// Gets a 64bit friendly span offset for the current <see cref="MemoryHandle{T}"/>
@@ -268,12 +294,11 @@ namespace VNLib.Utils.Extensions
/// <returns>The offset span</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static unsafe Span<T> GetOffsetSpan<T>(this MemoryHandle<T> block, long offset, int size) where T : unmanaged
+ public static unsafe Span<T> GetOffsetSpan<T>(this MemoryHandle<T> block, nint offset, int size) where T : unmanaged
{
- return offset < 0 ? throw new ArgumentOutOfRangeException(nameof(offset)) : block.GetOffsetSpan<T>((ulong)offset, size);
+ return offset >= 0 ? block.GetOffsetSpan((nuint)offset, size) : throw new ArgumentOutOfRangeException(nameof(offset));
}
-
/// <summary>
/// Gets a <see cref="SubSequence{T}"/> window within the current block
/// </summary>
@@ -283,12 +308,8 @@ namespace VNLib.Utils.Extensions
/// <param name="size">The size of the window</param>
/// <returns>The new <see cref="SubSequence{T}"/> within the block</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static SubSequence<T> GetSubSequence<T>(this MemoryHandle<T> block, ulong offset, int size) where T : unmanaged
- {
- return new SubSequence<T>(block, offset, size);
- }
-#else
-
+ public static SubSequence<T> GetSubSequence<T>(this MemoryHandle<T> block, nuint offset, int size) where T : unmanaged => new (block, offset, size);
+
/// <summary>
/// Gets a <see cref="SubSequence{T}"/> window within the current block
/// </summary>
@@ -298,30 +319,12 @@ namespace VNLib.Utils.Extensions
/// <param name="size">The size of the window</param>
/// <returns>The new <see cref="SubSequence{T}"/> within the block</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static SubSequence<T> GetSubSequence<T>(this MemoryHandle<T> block, int offset, int size) where T : unmanaged
+ public static SubSequence<T> GetSubSequence<T>(this MemoryHandle<T> block, nint offset, int size) where T : unmanaged
{
- return new SubSequence<T>(block, offset, size);
+ return offset >= 0 ? new (block, (nuint)offset, size) : throw new ArgumentOutOfRangeException(nameof(offset));
}
/// <summary>
- /// Gets a 64bit friendly span offset for the current <see cref="MemoryHandle{T}"/>
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="block"></param>
- /// <param name="offset">The offset (in elements) from the begining of the block</param>
- /// <param name="size">The size of the block (in elements)</param>
- /// <returns>The offset span</returns>
- /// <exception cref="OverflowException"></exception>
- /// <exception cref="ArgumentOutOfRangeException"></exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static unsafe Span<T> GetOffsetSpan<T>(this MemoryHandle<T> block, long offset, int size) where T : unmanaged
- {
- //TODO fix 32bit/64 bit, this is a safe lazy workaround
- return block.Span.Slice(checked((int) offset), size);
- }
-#endif
-
- /// <summary>
/// Wraps the current instance with a <see cref="MemoryPool{T}"/> wrapper
/// to allow System.Memory buffer rentals.
/// </summary>
@@ -346,10 +349,11 @@ namespace VNLib.Utils.Extensions
public static unsafe T* StructAlloc<T>(this IUnmangedHeap heap) where T : unmanaged
{
//Allocate the struct on the heap and zero memory it points to
- IntPtr handle = heap.Alloc(1, (uint)sizeof(T), true);
+ IntPtr handle = heap.Alloc(1, (nuint)sizeof(T), true);
//returns the handle
return (T*)handle;
}
+
/// <summary>
/// Frees a structure at the specified address from the this heap.
/// This must be the same heap the structure was allocated from
@@ -366,6 +370,7 @@ namespace VNLib.Utils.Extensions
//Clear ref
*structPtr = default;
}
+
/// <summary>
/// Allocates a block of unmanaged memory of the number of elements to store of an unmanged type
/// </summary>
@@ -378,17 +383,18 @@ namespace VNLib.Utils.Extensions
/// <exception cref="OutOfMemoryException"></exception>
/// <exception cref="ObjectDisposedException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static unsafe MemoryHandle<T> Alloc<T>(this IUnmangedHeap heap, ulong elements, bool zero = false) where T : unmanaged
+ public static unsafe MemoryHandle<T> Alloc<T>(this IUnmangedHeap heap, nuint elements, bool zero = false) where T : unmanaged
{
//Minimum of one element
elements = Math.Max(elements, 1);
//Get element size
- uint elementSize = (uint)sizeof(T);
+ nuint elementSize = (nuint)sizeof(T);
//If zero flag is set then specify zeroing memory
IntPtr block = heap.Alloc(elements, elementSize, zero);
//Return handle wrapper
return new MemoryHandle<T>(heap, block, elements, zero);
}
+
/// <summary>
/// Allocates a block of unmanaged memory of the number of elements to store of an unmanged type
/// </summary>
@@ -401,10 +407,11 @@ namespace VNLib.Utils.Extensions
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static MemoryHandle<T> Alloc<T>(this IUnmangedHeap heap, long elements, bool zero = false) where T : unmanaged
+ public static MemoryHandle<T> Alloc<T>(this IUnmangedHeap heap, nint elements, bool zero = false) where T : unmanaged
{
- return elements < 0 ? throw new ArgumentOutOfRangeException(nameof(elements)) : Alloc<T>(heap, (ulong)elements, zero);
+ return elements >= 0 ? Alloc<T>(heap, (nuint)elements, zero) : throw new ArgumentOutOfRangeException(nameof(elements));
}
+
/// <summary>
/// Allocates a buffer from the current heap and initialzies it by copying the initial data buffer
/// </summary>
@@ -417,8 +424,12 @@ namespace VNLib.Utils.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MemoryHandle<T> AllocAndCopy<T>(this IUnmangedHeap heap, ReadOnlySpan<T> initialData) where T:unmanaged
{
+ //Aloc block
MemoryHandle<T> handle = heap.Alloc<T>(initialData.Length);
- Memory.Copy(initialData, handle, 0);
+
+ //Copy initial data
+ MemoryUtil.Copy(initialData, handle, 0);
+
return handle;
}
@@ -435,12 +446,13 @@ namespace VNLib.Utils.Extensions
public static void WriteAndResize<T>(this MemoryHandle<T> handle, ReadOnlySpan<T> input) where T: unmanaged
{
handle.Resize(input.Length);
- Memory.Copy(input, handle, 0);
+ MemoryUtil.Copy(input, handle, 0);
}
/// <summary>
/// Allocates a block of unamanged memory of the number of elements of an unmanaged type, and
- /// returns the <see cref="UnsafeMemoryHandle{T}"/> that must be used cautiously
+ /// returns the <see cref="UnsafeMemoryHandle{T}"/> that must be used cautiously.
+ /// If elements is less than 1 an empty handle is returned
/// </summary>
/// <typeparam name="T">The unamanged value type</typeparam>
/// <param name="heap">The heap to allocate block from</param>
@@ -455,14 +467,16 @@ namespace VNLib.Utils.Extensions
{
if (elements < 1)
{
- throw new ArgumentException("Elements must be greater than 0", nameof(elements));
+ //Return an empty handle
+ return new UnsafeMemoryHandle<T>();
}
- //Minimum of one element
- elements = Math.Max(elements, 1);
+
//Get element size
- uint elementSize = (uint)sizeof(T);
- //If zero flag is set then specify zeroing memory
- IntPtr block = heap.Alloc((uint)elements, elementSize, zero);
+ nuint elementSize = (nuint)sizeof(T);
+
+ //If zero flag is set then specify zeroing memory (safe case because of the above check)
+ IntPtr block = heap.Alloc((nuint)elements, elementSize, zero);
+
//handle wrapper
return new (heap, block, elements);
}
@@ -560,8 +574,6 @@ namespace VNLib.Utils.Extensions
buffer.Advance(charsWritten);
}
-
-
/// <summary>
/// Encodes a set of characters in the input characters span and any characters
/// in the internal buffer into a sequence of bytes that are stored in the input
@@ -644,11 +656,13 @@ namespace VNLib.Utils.Extensions
/// Converts the buffer data to a <see cref="PrivateString"/>
/// </summary>
/// <returns>A <see cref="PrivateString"/> instance that owns the underlying string memory</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PrivateString ToPrivate(this ref ForwardOnlyWriter<char> buffer) => new(buffer.ToString(), true);
/// <summary>
/// Gets a <see cref="Span{T}"/> over the modified section of the internal buffer
/// </summary>
/// <returns>A <see cref="Span{T}"/> over the modified data</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> AsSpan<T>(this ref ForwardOnlyWriter<T> buffer) => buffer.Buffer[..buffer.Written];
diff --git a/lib/Utils/src/Extensions/VnStringExtensions.cs b/lib/Utils/src/Extensions/VnStringExtensions.cs
index 285fc4f..329c7a6 100644
--- a/lib/Utils/src/Extensions/VnStringExtensions.cs
+++ b/lib/Utils/src/Extensions/VnStringExtensions.cs
@@ -25,13 +25,17 @@
using System;
using System.Linq;
using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
using VNLib.Utils.Memory;
+using System.Runtime.CompilerServices;
+
+#pragma warning disable CA1062 // Validate arguments of public methods
namespace VNLib.Utils.Extensions
{
- [SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "<Pending>")]
+ /// <summary>
+ /// A collection of extensions for <see cref="VnString"/>
+ /// </summary>
public static class VnStringExtensions
{
/// <summary>
@@ -41,7 +45,9 @@ namespace VNLib.Utils.Extensions
/// <param name="value">The value to find</param>
/// <returns>True if the character exists within the instance</returns>
/// <exception cref="ObjectDisposedException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Contains(this VnString str, char value) => str.AsSpan().Contains(value);
+
/// <summary>
/// Derermines if the sequence exists within the instance
/// </summary>
@@ -50,9 +56,10 @@ namespace VNLib.Utils.Extensions
/// <param name="stringComparison"></param>
/// <returns>True if the character exists within the instance</returns>
/// <exception cref="ObjectDisposedException"></exception>
-
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Contains(this VnString str, ReadOnlySpan<char> value, StringComparison stringComparison) => str.AsSpan().Contains(value, stringComparison);
+
/// <summary>
/// Searches for the first occurrance of the specified character within the current instance
/// </summary>
@@ -60,7 +67,9 @@ namespace VNLib.Utils.Extensions
/// <param name="value">The character to search for within the instance</param>
/// <returns>The 0 based index of the occurance, -1 if the character was not found</returns>
/// <exception cref="ObjectDisposedException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int IndexOf(this VnString str, char value) => str.IsEmpty ? -1 : str.AsSpan().IndexOf(value);
+
/// <summary>
/// Searches for the first occurrance of the specified sequence within the current instance
/// </summary>
@@ -68,12 +77,9 @@ namespace VNLib.Utils.Extensions
/// <param name="search">The sequence to search for</param>
/// <returns>The 0 based index of the occurance, -1 if the sequence was not found</returns>
/// <exception cref="ObjectDisposedException"></exception>
- public static int IndexOf(this VnString str, ReadOnlySpan<char> search)
- {
- //Using spans to avoid memory leaks...
- ReadOnlySpan<char> self = str.AsSpan();
- return self.IndexOf(search);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int IndexOf(this VnString str, ReadOnlySpan<char> search) => str.AsSpan().IndexOf(search);
+
/// <summary>
/// Searches for the first occurrance of the specified sequence within the current instance
/// </summary>
@@ -82,12 +88,9 @@ namespace VNLib.Utils.Extensions
/// <param name="comparison">The <see cref="StringComparison"/> type to use in searchr</param>
/// <returns>The 0 based index of the occurance, -1 if the sequence was not found</returns>
/// <exception cref="ObjectDisposedException"></exception>
- public static int IndexOf(this VnString str, ReadOnlySpan<char> search, StringComparison comparison)
- {
- //Using spans to avoid memory leaks...
- ReadOnlySpan<char> self = str.AsSpan();
- return self.IndexOf(search, comparison);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int IndexOf(this VnString str, ReadOnlySpan<char> search, StringComparison comparison) => str.AsSpan().IndexOf(search, comparison);
+
/// <summary>
/// Searches for the 0 based index of the first occurance of the search parameter after the start index.
/// </summary>
@@ -136,11 +139,13 @@ namespace VNLib.Utils.Extensions
/// <returns>The trimmed <see cref="VnString"/> instance as a child of the original entry</returns>
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="IndexOutOfRangeException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static VnString AbsoluteTrim(this VnString data, int start, int end)
{
AbsoluteTrim(data, ref start, ref end);
return data[start..end];
}
+
/// <summary>
/// Finds whitespace characters within the sequence defined between start and end parameters
/// and adjusts the specified window to "trim" whitespace
@@ -175,6 +180,7 @@ namespace VNLib.Utils.Extensions
end--;
}
}
+
/// <summary>
/// Allows for trimming whitespace characters in a realtive sequence from
/// within a <see cref="VnString"/> buffer and returning the trimmed entry.
@@ -184,13 +190,16 @@ namespace VNLib.Utils.Extensions
/// <returns>The trimmed <see cref="VnString"/> instance as a child of the original entry</returns>
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="IndexOutOfRangeException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static VnString AbsoluteTrim(this VnString data, int start) => AbsoluteTrim(data, start, data.Length);
+
/// <summary>
/// Trims leading or trailing whitespace characters and returns a new child instance
/// without leading or trailing whitespace
/// </summary>
/// <returns>A child <see cref="VnString"/> of the current instance without leading or trailing whitespaced</returns>
/// <exception cref="ObjectDisposedException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static VnString RelativeTirm(this VnString data) => AbsoluteTrim(data, 0);
/// <summary>
@@ -349,19 +358,6 @@ namespace VNLib.Utils.Extensions
}
/// <summary>
- /// Unoptimized character enumerator. You should use <see cref="VnString.AsSpan"/> to enumerate the unerlying data.
- /// </summary>
- /// <returns>The next character in the sequence</returns>
- /// <exception cref="ObjectDisposedException"></exception>
- public static IEnumerator<char> GetEnumerator(this VnString data)
- {
- int index = 0;
- while (index < data.Length)
- {
- yield return data[index++];
- }
- }
- /// <summary>
/// Converts the current handle to a <see cref="VnString"/>, a zero-alloc immutable wrapper
/// for a memory handle
/// </summary>
@@ -370,14 +366,9 @@ namespace VNLib.Utils.Extensions
/// <returns>The new <see cref="VnString"/> wrapper</returns>
/// <exception cref="OverflowException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public static VnString ToVnString(this MemoryHandle<char> handle, int length)
- {
- if(handle.Length > int.MaxValue)
- {
- throw new OverflowException("The handle is larger than 2GB in size");
- }
- return VnString.ConsumeHandle(handle, 0, length);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static VnString ToVnString(this MemoryHandle<char> handle, int length) => VnString.ConsumeHandle(handle, 0, length);
+
/// <summary>
/// Converts the current handle to a <see cref="VnString"/>, a zero-alloc immutable wrapper
/// for a memory handle
@@ -386,10 +377,9 @@ namespace VNLib.Utils.Extensions
/// <returns>The new <see cref="VnString"/> wrapper</returns>
/// <exception cref="OverflowException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public static VnString ToVnString(this MemoryHandle<char> handle)
- {
- return VnString.ConsumeHandle(handle, 0, handle.IntLength);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static VnString ToVnString(this MemoryHandle<char> handle) => VnString.ConsumeHandle(handle, 0, handle.GetIntLength());
+
/// <summary>
/// Converts the current handle to a <see cref="VnString"/>, a zero-alloc immutable wrapper
/// for a memory handle
@@ -398,21 +388,8 @@ namespace VNLib.Utils.Extensions
/// <param name="offset">The offset in characters that represents the begining of the string</param>
/// <param name="length">The number of characters from the handle to reference (length of the string)</param>
/// <returns>The new <see cref="VnString"/> wrapper</returns>
- /// <exception cref="OverflowException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public static VnString ToVnString(this MemoryHandle<char> handle,
-#if TARGET_64_BIT
- ulong offset,
-#else
- int offset,
-#endif
- int length)
- {
- if (handle.Length > int.MaxValue)
- {
- throw new OverflowException("The handle is larger than 2GB in size");
- }
- return VnString.ConsumeHandle(handle, offset, length);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static VnString ToVnString(this MemoryHandle<char> handle, nuint offset, int length) => VnString.ConsumeHandle(handle, offset, length);
}
} \ No newline at end of file
diff --git a/lib/Utils/src/IO/InMemoryTemplate.cs b/lib/Utils/src/IO/InMemoryTemplate.cs
index ae8bf79..5a4a799 100644
--- a/lib/Utils/src/IO/InMemoryTemplate.cs
+++ b/lib/Utils/src/IO/InMemoryTemplate.cs
@@ -165,7 +165,7 @@ namespace VNLib.Utils.IO
try
{
//Copy async
- await fs.CopyToAsync(newBuf, 8192, Memory.Memory.Shared, cancellationToken);
+ await fs.CopyToAsync(newBuf, 8192, Memory.MemoryUtil.Shared, cancellationToken);
}
catch
{
diff --git a/lib/Utils/src/IO/VnMemoryStream.cs b/lib/Utils/src/IO/VnMemoryStream.cs
index 4e8a2b3..e984cc1 100644
--- a/lib/Utils/src/IO/VnMemoryStream.cs
+++ b/lib/Utils/src/IO/VnMemoryStream.cs
@@ -28,24 +28,23 @@ using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
+using VNLib.Utils.Memory;
using VNLib.Utils.Extensions;
namespace VNLib.Utils.IO
{
-
- using Utils.Memory;
-
/// <summary>
/// Provides an unmanaged memory stream. Desigend to help reduce garbage collector load for
/// high frequency memory operations. Similar to <see cref="UnmanagedMemoryStream"/>
/// </summary>
public sealed class VnMemoryStream : Stream, ICloneable
{
- private long _position;
- private long _length;
+ private nint _position;
+ private nint _length;
+ private bool _isReadonly;
+
//Memory
private readonly MemoryHandle<byte> _buffer;
- private bool IsReadonly;
//Default owns handle
private readonly bool OwnsHandle = true;
@@ -57,7 +56,7 @@ namespace VNLib.Utils.IO
/// <param name="readOnly">Should the stream be readonly?</param>
/// <exception cref="ArgumentException"></exception>
/// <returns>A <see cref="VnMemoryStream"/> wrapper to access the handle data</returns>
- public static VnMemoryStream ConsumeHandle(MemoryHandle<byte> handle, Int64 length, bool readOnly)
+ public static VnMemoryStream ConsumeHandle(MemoryHandle<byte> handle, nint length, bool readOnly)
{
handle.ThrowIfClosed();
return new VnMemoryStream(handle, length, readOnly, true);
@@ -71,7 +70,7 @@ namespace VNLib.Utils.IO
public static VnMemoryStream CreateReadonly(VnMemoryStream stream)
{
//Set the readonly flag
- stream.IsReadonly = true;
+ stream._isReadonly = true;
//Return the stream
return stream;
}
@@ -79,11 +78,12 @@ namespace VNLib.Utils.IO
/// <summary>
/// Creates a new memory stream
/// </summary>
- public VnMemoryStream() : this(Memory.Shared) { }
+ public VnMemoryStream() : this(MemoryUtil.Shared) { }
+
/// <summary>
/// Create a new memory stream where buffers will be allocated from the specified heap
/// </summary>
- /// <param name="heap"><see cref="PrivateHeap"/> to allocate memory from</param>
+ /// <param name="heap"><see cref="Win32PrivateHeap"/> to allocate memory from</param>
/// <exception cref="OutOfMemoryException"></exception>
/// <exception cref="ArgumentNullException"></exception>
public VnMemoryStream(IUnmangedHeap heap) : this(heap, 0, false) { }
@@ -92,13 +92,13 @@ namespace VNLib.Utils.IO
/// Creates a new memory stream and pre-allocates the internal
/// buffer of the specified size on the specified heap to avoid resizing.
/// </summary>
- /// <param name="heap"><see cref="PrivateHeap"/> to allocate memory from</param>
+ /// <param name="heap"><see cref="Win32PrivateHeap"/> to allocate memory from</param>
/// <param name="bufferSize">Number of bytes (length) of the stream if known</param>
/// <param name="zero">Zero memory allocations during buffer expansions</param>
/// <exception cref="OutOfMemoryException"></exception>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public VnMemoryStream(IUnmangedHeap heap, long bufferSize, bool zero)
+ public VnMemoryStream(IUnmangedHeap heap, nuint bufferSize, bool zero)
{
_ = heap ?? throw new ArgumentNullException(nameof(heap));
_buffer = heap.Alloc<byte>(bufferSize, zero);
@@ -107,7 +107,7 @@ namespace VNLib.Utils.IO
/// <summary>
/// Creates a new memory stream from the data provided
/// </summary>
- /// <param name="heap"><see cref="PrivateHeap"/> to allocate memory from</param>
+ /// <param name="heap"><see cref="Win32PrivateHeap"/> to allocate memory from</param>
/// <param name="data">Initial data</param>
public VnMemoryStream(IUnmangedHeap heap, ReadOnlySpan<byte> data)
{
@@ -116,8 +116,7 @@ namespace VNLib.Utils.IO
_buffer = heap.AllocAndCopy(data);
//Set length
_length = data.Length;
- //Position will default to 0 cuz its dotnet :P
- return;
+ _position = 0;
}
/// <summary>
@@ -127,18 +126,18 @@ namespace VNLib.Utils.IO
/// <param name="length">The length property of the stream</param>
/// <param name="readOnly">Is the stream readonly (should mostly be true!)</param>
/// <param name="ownsHandle">Does the new stream own the memory -> <paramref name="buffer"/></param>
- private VnMemoryStream(MemoryHandle<byte> buffer, long length, bool readOnly, bool ownsHandle)
+ private VnMemoryStream(MemoryHandle<byte> buffer, nint length, bool readOnly, bool ownsHandle)
{
OwnsHandle = ownsHandle;
_buffer = buffer; //Consume the handle
_length = length; //Store length of the buffer
- IsReadonly = readOnly;
+ _isReadonly = readOnly;
}
/// <summary>
/// UNSAFE Number of bytes between position and length. Never negative
/// </summary>
- private long LenToPosDiff => Math.Max(_length - _position, 0);
+ private nint LenToPosDiff => Math.Max(_length - _position, 0);
/// <summary>
/// If the current stream is a readonly stream, creates an unsafe shallow copy for reading only.
@@ -148,7 +147,7 @@ namespace VNLib.Utils.IO
public VnMemoryStream GetReadonlyShallowCopy()
{
//Create a new readonly copy (stream does not own the handle)
- return !IsReadonly
+ return !_isReadonly
? throw new NotSupportedException("This stream is not readonly. Cannot create shallow copy on a mutable stream")
: new VnMemoryStream(_buffer, _length, true, false);
}
@@ -163,6 +162,10 @@ namespace VNLib.Utils.IO
public override void CopyTo(Stream destination, int bufferSize)
{
_ = destination ?? throw new ArgumentNullException(nameof(destination));
+ if(bufferSize < 1)
+ {
+ throw new ArgumentOutOfRangeException(nameof(bufferSize), "Buffer size must be greater than 0");
+ }
if (!destination.CanWrite)
{
@@ -250,7 +253,7 @@ namespace VNLib.Utils.IO
/// True unless the stream is (or has been converted to) a readonly
/// stream.
/// </summary>
- public override bool CanWrite => !IsReadonly;
+ public override bool CanWrite => !_isReadonly;
///<inheritdoc/>
public override long Length => _length;
///<inheritdoc/>
@@ -279,7 +282,7 @@ namespace VNLib.Utils.IO
///<inheritdoc/>
public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask;
///<inheritdoc/>
- public override int Read(byte[] buffer, int offset, int count) => Read(new Span<byte>(buffer, offset, count));
+ public override int Read(byte[] buffer, int offset, int count) => Read(buffer.AsSpan(offset, count));
///<inheritdoc/>
public override int Read(Span<byte> buffer)
{
@@ -288,12 +291,14 @@ namespace VNLib.Utils.IO
return 0;
}
//Number of bytes to read from memory buffer
- int bytesToRead = checked((int)Math.Min(LenToPosDiff, buffer.Length));
+ int bytesToRead = (int)Math.Min(LenToPosDiff, buffer.Length);
+
//Copy bytes to buffer
- Memory.Copy(_buffer, _position, buffer, 0, bytesToRead);
+ MemoryUtil.Copy(_buffer, _position, buffer, 0, bytesToRead);
+
//Increment buffer position
_position += bytesToRead;
- //Bytestoread should never be larger than int.max because span length is an integer
+
return bytesToRead;
}
@@ -322,22 +327,27 @@ namespace VNLib.Utils.IO
{
throw new ArgumentOutOfRangeException(nameof(offset), "Offset cannot be less than 0");
}
+ if(offset > nint.MaxValue)
+ {
+ throw new ArgumentOutOfRangeException(nameof(offset), "Offset cannot be less than nint.MaxValue");
+ }
+
+ //safe cast to nint
+ nint _offset = (nint)offset;
+
switch (origin)
{
case SeekOrigin.Begin:
- //Length will never be greater than int.Max so output will never exceed int.max
- _position = Math.Min(_length, offset);
- return _position;
+ //Length will never be greater than nint.Max so output will never exceed nint.max
+ return _position = Math.Min(_length, _offset);
case SeekOrigin.Current:
- long newPos = _position + offset;
- //Length will never be greater than int.Max so output will never exceed length
- _position = Math.Min(_length, newPos);
- return newPos;
+ //Calc new seek position from current position
+ nint newPos = _position + _offset;
+ return _position = Math.Min(_length, newPos);
case SeekOrigin.End:
- long real_index = _length - offset;
- //If offset moves the position negative, just set the position to 0 and continue
- _position = Math.Min(real_index, 0);
- return real_index;
+ //Calc new seek position from end of stream, should be len -1 so 0 can be specified from the end
+ nint realIndex = _length - (_offset - 1);
+ return _position = Math.Min(realIndex, 0);
default:
throw new ArgumentException("Stream operation is not supported on current stream");
}
@@ -356,7 +366,7 @@ namespace VNLib.Utils.IO
/// <exception cref="ArgumentOutOfRangeException"></exception>
public override void SetLength(long value)
{
- if (IsReadonly)
+ if (_isReadonly)
{
throw new NotSupportedException("This stream is readonly");
}
@@ -364,25 +374,33 @@ namespace VNLib.Utils.IO
{
throw new ArgumentOutOfRangeException(nameof(value), "Value cannot be less than 0");
}
+ if(value > nint.MaxValue)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value), "Value cannot be greater than nint.MaxValue");
+ }
+
+ nint _value = (nint)value;
+
//Resize the buffer to the specified length
- _buffer.Resize(value);
+ _buffer.Resize(_value);
+
//Set length
- _length = value;
- //Make sure the position is not pointing outside of the buffer
+ _length = _value;
+
+ //Make sure the position is not pointing outside of the buffer after resize
_position = Math.Min(_position, _length);
- return;
}
///<inheritdoc/>
- public override void Write(byte[] buffer, int offset, int count) => Write(new ReadOnlySpan<byte>(buffer, offset, count));
+ public override void Write(byte[] buffer, int offset, int count) => Write(buffer.AsSpan(offset, count));
///<inheritdoc/>
public override void Write(ReadOnlySpan<byte> buffer)
{
- if (IsReadonly)
+ if (_isReadonly)
{
throw new NotSupportedException("Write operation is not allowed on readonly stream!");
}
//Calculate the new final position
- long newPos = (_position + buffer.Length);
+ nint newPos = (_position + buffer.Length);
//Determine if the buffer needs to be expanded
if (buffer.Length > LenToPosDiff)
{
@@ -392,10 +410,9 @@ namespace VNLib.Utils.IO
_length = newPos;
}
//Copy the input buffer to the internal buffer
- Memory.Copy(buffer, _buffer, _position);
+ MemoryUtil.Copy(buffer, _buffer, (nuint)_position);
//Update the position
_position = newPos;
- return;
}
///<inheritdoc/>
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
@@ -423,16 +440,17 @@ namespace VNLib.Utils.IO
/// </summary>
/// <returns>Copy of internal buffer</returns>
/// <exception cref="OutOfMemoryException"></exception>
- /// <exception cref="OutOfMemoryException"></exception>
public byte[] ToArray()
{
- //Alloc a new array of the size of the internal buffer
+ //Alloc a new array of the size of the internal buffer, may be 64 bit large block
byte[] data = new byte[_length];
- //Copy data from the internal buffer to the output buffer
- _buffer.Span.CopyTo(data);
+
+ //Copy the internal buffer to the new array
+ MemoryUtil.Copy(_buffer, 0, data, 0, (nuint)_length);
+
return data;
-
}
+
/// <summary>
/// Returns a <see cref="ReadOnlySpan{T}"/> window over the data within the entire stream
/// </summary>
@@ -440,8 +458,10 @@ namespace VNLib.Utils.IO
/// <exception cref="OverflowException"></exception>
public ReadOnlySpan<byte> AsSpan()
{
- ReadOnlySpan<byte> output = _buffer.Span;
- return output[..(int)_length];
+ //Get 32bit length or throw
+ int len = Convert.ToInt32(_length);
+ //Get span with no offset
+ return _buffer.AsSpan(0, len);
}
/// <summary>
diff --git a/lib/Utils/src/Memory/IMemoryHandle.cs b/lib/Utils/src/Memory/IMemoryHandle.cs
index 75d1cce..cf19ce9 100644
--- a/lib/Utils/src/Memory/IMemoryHandle.cs
+++ b/lib/Utils/src/Memory/IMemoryHandle.cs
@@ -34,15 +34,9 @@ namespace VNLib.Utils.Memory
public interface IMemoryHandle<T> : IDisposable, IPinnable
{
/// <summary>
- /// The size of the block as an integer
- /// </summary>
- /// <exception cref="OverflowException"></exception>
- int IntLength { get; }
-
- /// <summary>
/// The number of elements in the block
/// </summary>
- ulong Length { get; }
+ nuint Length { get; }
/// <summary>
/// Gets the internal block as a span
diff --git a/lib/Utils/src/Memory/IUnmangedHeap.cs b/lib/Utils/src/Memory/IUnmangedHeap.cs
index 5d8f4bf..94f34c8 100644
--- a/lib/Utils/src/Memory/IUnmangedHeap.cs
+++ b/lib/Utils/src/Memory/IUnmangedHeap.cs
@@ -38,7 +38,7 @@ namespace VNLib.Utils.Memory
/// <param name="elements">The number of elements to allocate</param>
/// <param name="zero">An optional parameter to zero the block of memory</param>
/// <returns></returns>
- IntPtr Alloc(UInt64 elements, UInt64 size, bool zero);
+ IntPtr Alloc(nuint elements, nuint size, bool zero);
/// <summary>
/// Resizes the allocated block of memory to the new size
@@ -47,7 +47,7 @@ namespace VNLib.Utils.Memory
/// <param name="elements">The new number of elements</param>
/// <param name="size">The size (in bytes) of the type</param>
/// <param name="zero">An optional parameter to zero the block of memory</param>
- void Resize(ref IntPtr block, UInt64 elements, UInt64 size, bool zero);
+ void Resize(ref IntPtr block, nuint elements, nuint size, bool zero);
/// <summary>
/// Free's a previously allocated block of memory
diff --git a/lib/Utils/src/Memory/MemoryHandle.cs b/lib/Utils/src/Memory/MemoryHandle.cs
index a09edea..df2792b 100644
--- a/lib/Utils/src/Memory/MemoryHandle.cs
+++ b/lib/Utils/src/Memory/MemoryHandle.cs
@@ -34,7 +34,7 @@ using VNLib.Utils.Extensions;
namespace VNLib.Utils.Memory
{
/// <summary>
- /// Provides a wrapper for using umanged memory handles from an assigned <see cref="PrivateHeap"/> for <see cref="UnmanagedType"/> types
+ /// Provides a wrapper for using umanged memory handles from an assigned <see cref="Win32PrivateHeap"/> for <see cref="UnmanagedType"/> types
/// </summary>
/// <remarks>
/// Handles are configured to address blocks larger than 2GB,
@@ -72,31 +72,21 @@ namespace VNLib.Utils.Memory
get
{
this.ThrowIfClosed();
- return _length == 0 ? Span<T>.Empty : new Span<T>(Base, IntLength);
+ int len = Convert.ToInt32(_length);
+ return _length == 0 ? Span<T>.Empty : new Span<T>(Base, len);
}
}
private readonly bool ZeroMemory;
private readonly IUnmangedHeap Heap;
- private ulong _length;
+ private nuint _length;
- /// <summary>
- /// Number of elements allocated to the current instance
- /// </summary>
- public ulong Length
+ ///<inheritdoc/>
+ public nuint Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _length;
}
- /// <summary>
- /// Number of elements in the memory block casted to an integer
- /// </summary>
- /// <exception cref="OverflowException"></exception>
- public int IntLength
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => checked((int)_length);
- }
/// <summary>
/// Number of bytes allocated to the current instance
@@ -106,7 +96,7 @@ namespace VNLib.Utils.Memory
{
//Check for overflows when converting to bytes (should run out of memory before this is an issue, but just incase)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => checked(_length * (UInt64)sizeof(T));
+ get => MemoryUtil.ByteCount<T>(_length);
}
/// <summary>
@@ -116,7 +106,7 @@ namespace VNLib.Utils.Memory
/// <param name="elements">Number of elements to allocate</param>
/// <param name="zero">Zero all memory during allocations from heap</param>
/// <param name="initial">The initial block of allocated memory to wrap</param>
- internal MemoryHandle(IUnmangedHeap heap, IntPtr initial, ulong elements, bool zero) : base(true)
+ internal MemoryHandle(IUnmangedHeap heap, IntPtr initial, nuint elements, bool zero) : base(true)
{
//Set element size (always allocate at least 1 object)
_length = elements;
@@ -133,7 +123,7 @@ namespace VNLib.Utils.Memory
/// <exception cref="OverflowException"></exception>
/// <exception cref="OutOfMemoryException"></exception>
/// <exception cref="ObjectDisposedException"></exception>
- public unsafe void Resize(ulong elements)
+ public unsafe void Resize(nuint elements)
{
this.ThrowIfClosed();
//Update size (should never be less than inital size)
@@ -141,7 +131,7 @@ namespace VNLib.Utils.Memory
//Re-alloc (Zero if required)
try
{
- Heap.Resize(ref handle, Length, (ulong)sizeof(T), ZeroMemory);
+ Heap.Resize(ref handle, Length, (nuint)sizeof(T), ZeroMemory);
}
//Catch the disposed exception so we can invalidate the current ptr
catch (ObjectDisposedException)
@@ -161,7 +151,7 @@ namespace VNLib.Utils.Memory
/// <exception cref="ArgumentOutOfRangeException"></exception>
/// <returns><typeparamref name="T"/> pointer to the memory offset specified</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe T* GetOffset(ulong elements)
+ public unsafe T* GetOffset(nuint elements)
{
if (elements >= _length)
{
@@ -176,10 +166,14 @@ namespace VNLib.Utils.Memory
///<inheritdoc/>
///<exception cref="ObjectDisposedException"></exception>
///<exception cref="ArgumentOutOfRangeException"></exception>
+ ///<remarks>
+ ///Calling this method increments the handle's referrence count.
+ ///Disposing the returned handle decrements the handle count.
+ ///</remarks>
public unsafe MemoryHandle Pin(int elementIndex)
{
//Get ptr and guard checks before adding the referrence
- T* ptr = GetOffset((ulong)elementIndex);
+ T* ptr = GetOffset((nuint)elementIndex);
bool addRef = false;
//use the pinned field as success val
@@ -198,15 +192,12 @@ namespace VNLib.Utils.Memory
DangerousRelease();
}
-
///<inheritdoc/>
protected override bool ReleaseHandle()
{
//Return result of free
return Heap.Free(ref handle);
- }
-
-
+ }
/// <summary>
/// Determines if the memory blocks are equal by comparing their base addresses.
diff --git a/lib/Utils/src/Memory/Memory.cs b/lib/Utils/src/Memory/MemoryUtil.cs
index e04c386..410db6b 100644
--- a/lib/Utils/src/Memory/Memory.cs
+++ b/lib/Utils/src/Memory/MemoryUtil.cs
@@ -23,7 +23,6 @@
*/
using System;
-using System.IO;
using System.Buffers;
using System.Security;
using System.Threading;
@@ -39,7 +38,7 @@ namespace VNLib.Utils.Memory
/// </summary>
[SecurityCritical]
[ComVisible(false)]
- public unsafe static class Memory
+ public unsafe static class MemoryUtil
{
public const string SHARED_HEAP_TYPE_ENV= "VNLIB_SHARED_HEAP_TYPE";
public const string SHARED_HEAP_INTIAL_SIZE_ENV = "VNLIB_SHARED_HEAP_SIZE";
@@ -47,7 +46,7 @@ namespace VNLib.Utils.Memory
/// <summary>
/// Initial shared heap size (bytes)
/// </summary>
- public const ulong SHARED_HEAP_INIT_SIZE = 20971520;
+ public const nuint SHARED_HEAP_INIT_SIZE = 20971520;
public const int MAX_BUF_SIZE = 2097152;
public const int MIN_BUF_SIZE = 16000;
@@ -68,14 +67,18 @@ namespace VNLib.Utils.Memory
/// </remarks>
public static IUnmangedHeap Shared => _sharedHeap.Value;
- private static readonly Lazy<IUnmangedHeap> _sharedHeap;
+
+ private static readonly Lazy<IUnmangedHeap> _sharedHeap = InitHeapInternal();
- static Memory()
+ //Avoiding statit initializer
+ private static Lazy<IUnmangedHeap> InitHeapInternal()
{
- _sharedHeap = new Lazy<IUnmangedHeap>(() => InitHeapInternal(true), LazyThreadSafetyMode.PublicationOnly);
+ Lazy<IUnmangedHeap> heap = new (() => InitHeapInternal(true), LazyThreadSafetyMode.PublicationOnly);
//Cleanup the heap on process exit
AppDomain.CurrentDomain.DomainUnload += DomainUnloaded;
+ return heap;
}
+
private static void DomainUnloaded(object? sender, EventArgs e)
{
@@ -99,11 +102,11 @@ namespace VNLib.Utils.Memory
{
bool IsWindows = OperatingSystem.IsWindows();
//Get environment varable
- string heapType = Environment.GetEnvironmentVariable(SHARED_HEAP_TYPE_ENV);
+ string? heapType = Environment.GetEnvironmentVariable(SHARED_HEAP_TYPE_ENV);
//Get inital size
- string sharedSize = Environment.GetEnvironmentVariable(SHARED_HEAP_INTIAL_SIZE_ENV);
+ string? sharedSize = Environment.GetEnvironmentVariable(SHARED_HEAP_INTIAL_SIZE_ENV);
//Try to parse the shared size from the env
- if (!ulong.TryParse(sharedSize, out ulong defaultSize))
+ if (!nuint.TryParse(sharedSize, out nuint defaultSize))
{
defaultSize = SHARED_HEAP_INIT_SIZE;
}
@@ -115,12 +118,12 @@ namespace VNLib.Utils.Memory
{
throw new PlatformNotSupportedException("Win32 private heaps are not supported on non-windows platforms");
}
- return PrivateHeap.Create(defaultSize);
+ return Win32PrivateHeap.Create(defaultSize);
case "rpmalloc":
//If the shared heap is being allocated, then return a lock free global heap
return isShared ? RpMallocPrivateHeap.GlobalHeap : new RpMallocPrivateHeap(false);
default:
- return IsWindows ? PrivateHeap.Create(defaultSize) : new ProcessHeap();
+ return IsWindows ? Win32PrivateHeap.Create(defaultSize) : new ProcessHeap();
}
}
@@ -130,6 +133,7 @@ namespace VNLib.Utils.Memory
public static bool IsRpMallocLoaded { get; } = Environment.GetEnvironmentVariable(SHARED_HEAP_TYPE_ENV) == "rpmalloc";
#region Zero
+
/// <summary>
/// Zeros a block of memory of umanged type. If Windows is detected at runtime, calls RtlSecureZeroMemory Win32 function
/// </summary>
@@ -150,6 +154,7 @@ namespace VNLib.Utils.Memory
}
}
}
+
/// <summary>
/// Zeros a block of memory of umanged type. If Windows is detected at runtime, calls RtlSecureZeroMemory Win32 function
/// </summary>
@@ -175,12 +180,15 @@ namespace VNLib.Utils.Memory
/// </summary>
/// <typeparam name="T">The unmanaged</typeparam>
/// <param name="block">The block of memory to initialize</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InitializeBlock<T>(Span<T> block) where T : unmanaged => UnsafeZeroMemory<T>(block);
+
/// <summary>
/// Initializes a block of memory with zeros
/// </summary>
/// <typeparam name="T">The unmanaged</typeparam>
/// <param name="block">The block of memory to initialize</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InitializeBlock<T>(Memory<T> block) where T : unmanaged => UnsafeZeroMemory<T>(block);
/// <summary>
@@ -195,6 +203,7 @@ namespace VNLib.Utils.Memory
//Zero block
Unsafe.InitBlock(block.ToPointer(), 0, (uint)size);
}
+
/// <summary>
/// Zeroes a block of memory pointing to the structure
/// </summary>
@@ -207,6 +216,7 @@ namespace VNLib.Utils.Memory
//Zero block
Unsafe.InitBlock(structPtr, 0, (uint)size);
}
+
/// <summary>
/// Zeroes a block of memory pointing to the structure
/// </summary>
@@ -223,6 +233,7 @@ namespace VNLib.Utils.Memory
#endregion
#region Copy
+
/// <summary>
/// Copies data from source memory to destination memory of an umanged data type
/// </summary>
@@ -231,24 +242,25 @@ namespace VNLib.Utils.Memory
/// <param name="dest">Destination <see cref="MemoryHandle{T}"/></param>
/// <param name="destOffset">Dest offset</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public static void Copy<T>(ReadOnlySpan<T> source, MemoryHandle<T> dest, Int64 destOffset) where T : unmanaged
+ public static void Copy<T>(ReadOnlySpan<T> source, MemoryHandle<T> dest, nuint destOffset) where T : unmanaged
{
- if (source.IsEmpty)
- {
- return;
- }
- if (dest.Length < (ulong)(destOffset + source.Length))
+ if (dest is null)
{
- throw new ArgumentException("Source data is larger than the dest data block", nameof(source));
+ throw new ArgumentNullException(nameof(dest));
}
- //Get long offset from the destination handle
- T* offset = dest.GetOffset(destOffset);
- fixed(void* src = &MemoryMarshal.GetReference(source))
+
+ if (source.IsEmpty)
{
- int byteCount = checked(source.Length * sizeof(T));
- Unsafe.CopyBlock(offset, src, (uint)byteCount);
+ return;
}
+
+ //Get long offset from the destination handle (also checks bounds)
+ Span<T> dst = dest.GetOffsetSpan(destOffset, source.Length);
+
+ //Copy data
+ source.CopyTo(dst);
}
+
/// <summary>
/// Copies data from source memory to destination memory of an umanged data type
/// </summary>
@@ -257,24 +269,25 @@ namespace VNLib.Utils.Memory
/// <param name="dest">Destination <see cref="MemoryHandle{T}"/></param>
/// <param name="destOffset">Dest offset</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public static void Copy<T>(ReadOnlyMemory<T> source, MemoryHandle<T> dest, Int64 destOffset) where T : unmanaged
+ public static void Copy<T>(ReadOnlyMemory<T> source, MemoryHandle<T> dest, nuint destOffset) where T : unmanaged
{
- if (source.IsEmpty)
+ if (dest is null)
{
- return;
+ throw new ArgumentNullException(nameof(dest));
}
- if (dest.Length < (ulong)(destOffset + source.Length))
+
+ if (source.IsEmpty)
{
- throw new ArgumentException("Dest constraints are larger than the dest data block", nameof(source));
+ return;
}
- //Get long offset from the destination handle
- T* offset = dest.GetOffset(destOffset);
- //Pin the source memory
- using MemoryHandle srcHandle = source.Pin();
- int byteCount = checked(source.Length * sizeof(T));
- //Copy block using unsafe class
- Unsafe.CopyBlock(offset, srcHandle.Pointer, (uint)byteCount);
+
+ //Get long offset from the destination handle (also checks bounds)
+ Span<T> dst = dest.GetOffsetSpan(destOffset, source.Length);
+
+ //Copy data
+ source.Span.CopyTo(dst);
}
+
/// <summary>
/// Copies data from source memory to destination memory of an umanged data type
/// </summary>
@@ -285,31 +298,27 @@ namespace VNLib.Utils.Memory
/// <param name="destOffset">Dest offset</param>
/// <param name="count">Number of elements to copy</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public static void Copy<T>(MemoryHandle<T> source, Int64 sourceOffset, Span<T> dest, int destOffset, int count) where T : unmanaged
+ public static void Copy<T>(MemoryHandle<T> source, nint sourceOffset, Span<T> dest, int destOffset, int count) where T : unmanaged
{
- if (count <= 0)
+ //Validate source/dest/count
+ ValidateArgs(sourceOffset, destOffset, count);
+
+ //Check count last for debug reasons
+ if (count == 0)
{
return;
}
- if (source.Length < (ulong)(sourceOffset + count))
- {
- throw new ArgumentException("Source constraints are larger than the source data block", nameof(count));
- }
- if (dest.Length < destOffset + count)
- {
- throw new ArgumentOutOfRangeException(nameof(destOffset), "Destination offset range cannot exceed the size of the destination buffer");
- }
- //Get offset to allow large blocks of memory
- T* src = source.GetOffset(sourceOffset);
- fixed(T* dst = &MemoryMarshal.GetReference(dest))
- {
- //Cacl offset
- T* dstoffset = dst + destOffset;
- int byteCount = checked(count * sizeof(T));
- //Aligned copy
- Unsafe.CopyBlock(dstoffset, src, (uint)byteCount);
- }
+
+ //Get offset span, also checks bounts
+ Span<T> src = source.GetOffsetSpan(sourceOffset, count);
+
+ //slice the dest span
+ Span<T> dst = dest.Slice(destOffset, count);
+
+ //Copy data
+ src.CopyTo(dst);
}
+
/// <summary>
/// Copies data from source memory to destination memory of an umanged data type
/// </summary>
@@ -319,77 +328,214 @@ namespace VNLib.Utils.Memory
/// <param name="dest">Destination <see cref="Memory{T}"/></param>
/// <param name="destOffset">Dest offset</param>
/// <param name="count">Number of elements to copy</param>
+ /// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public static void Copy<T>(MemoryHandle<T> source, Int64 sourceOffset, Memory<T> dest, int destOffset, int count) where T : unmanaged
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Copy<T>(MemoryHandle<T> source, nint sourceOffset, Memory<T> dest, int destOffset, int count) where T : unmanaged
{
- if (count == 0)
+ //Call copy method with dest as span
+ Copy(source, sourceOffset, dest.Span, destOffset, count);
+ }
+
+ private static void ValidateArgs(nint sourceOffset, nint destOffset, nint count)
+ {
+ if(sourceOffset < 0)
{
- return;
+ throw new ArgumentOutOfRangeException(nameof(sourceOffset), "Source offset must be a postive integer");
}
- if (source.Length < (ulong)(sourceOffset + count))
+
+ if(destOffset < 0)
{
- throw new ArgumentException("Source constraints are larger than the source data block", nameof(count));
+ throw new ArgumentOutOfRangeException(nameof(destOffset), "Destination offset must be a positive integer");
}
- if(dest.Length < destOffset + count)
+
+ if(count < 0)
{
- throw new ArgumentOutOfRangeException(nameof(destOffset), "Destination offset range cannot exceed the size of the destination buffer");
+ throw new ArgumentOutOfRangeException(nameof(count), "Count parameter must be a postitive integer");
}
- //Get offset to allow large blocks of memory
- T* src = source.GetOffset(sourceOffset);
- //Pin the memory handle
- using MemoryHandle handle = dest.Pin();
- //Byte count
- int byteCount = checked(count * sizeof(T));
- //Dest offset
- T* dst = ((T*)handle.Pointer) + destOffset;
- //Aligned copy
- Unsafe.CopyBlock(dst, src, (uint)byteCount);
}
- #endregion
- #region Streams
/// <summary>
- /// Copies data from one stream to another in specified blocks
+ /// 32/64 bit large block copy
/// </summary>
- /// <param name="source">Source memory</param>
- /// <param name="srcOffset">Source offset</param>
- /// <param name="dest">Destination memory</param>
- /// <param name="destOffst">Destination offset</param>
- /// <param name="count">Number of elements to copy</param>
- public static void Copy(Stream source, Int64 srcOffset, Stream dest, Int64 destOffst, Int64 count)
+ /// <typeparam name="T"></typeparam>
+ /// <param name="source">The source memory handle to copy data from</param>
+ /// <param name="offset">The element offset to begin reading from</param>
+ /// <param name="dest">The destination array to write data to</param>
+ /// <param name="destOffset"></param>
+ /// <param name="count">The number of elements to copy</param>
+ /// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
+ public static void Copy<T>(IMemoryHandle<T> source, nuint offset, T[] dest, nuint destOffset, nuint count) where T : unmanaged
{
+ if (source is null)
+ {
+ throw new ArgumentNullException(nameof(source));
+ }
+
+ if (dest is null)
+ {
+ throw new ArgumentNullException(nameof(dest));
+ }
+
if (count == 0)
{
return;
}
- if (count < 0)
+
+ //Check source bounds
+ CheckBounds(source, offset, count);
+
+ //Check dest bounts
+ CheckBounds(dest, destOffset, count);
+
+
+#if TARGET_64BIT
+ //Get the number of bytes to copy
+ nuint byteCount = ByteCount<T>(count);
+
+ //Get memory handle from source
+ using MemoryHandle srcHandle = source.Pin(0);
+
+ //get source offset
+ T* src = (T*)srcHandle.Pointer + offset;
+
+ //pin array
+ fixed (T* dst = dest)
+ {
+ //Offset dest ptr
+ T* dstOffset = dst + destOffset;
+
+ //Copy src to set
+ Buffer.MemoryCopy(src, dstOffset, byteCount, byteCount);
+ }
+#else
+ //If 32bit its safe to use spans
+
+ Span<T> src = source.Span.Slice((int)offset, (int)count);
+ Span<T> dst = dest.AsSpan((int)destOffset, (int)count);
+ //Copy
+ src.CopyTo(dst);
+#endif
+ }
+
+ #endregion
+
+ #region Validation
+
+ /// <summary>
+ /// Gets the size in bytes of the handle
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="handle">The handle to get the byte size of</param>
+ /// <returns>The number of bytes pointed to by the handle</returns>
+ /// <exception cref="ArgumentNullException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static nuint ByteSize<T>(IMemoryHandle<T> handle)
+ {
+ _ = handle ?? throw new ArgumentNullException(nameof(handle));
+ return checked(handle.Length * (nuint)Unsafe.SizeOf<T>());
+ }
+
+ /// <summary>
+ /// Gets the size in bytes of the handle
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="handle">The handle to get the byte size of</param>
+ /// <returns>The number of bytes pointed to by the handle</returns>
+ /// <exception cref="ArgumentNullException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static nuint ByteSize<T>(in UnsafeMemoryHandle<T> handle) where T : unmanaged => checked(handle.Length * (nuint)sizeof(T));
+
+ /// <summary>
+ /// Gets the byte multiple of the length parameter
+ /// </summary>
+ /// <typeparam name="T">The type to get the byte offset of</typeparam>
+ /// <param name="elementCount">The number of elements to get the byte count of</param>
+ /// <returns>The byte multiple of the number of elments</returns>
+ /// <exception cref="OverflowException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static nuint ByteCount<T>(nuint elementCount) => checked(elementCount * (nuint)Unsafe.SizeOf<T>());
+ /// <summary>
+ /// Gets the byte multiple of the length parameter
+ /// </summary>
+ /// <typeparam name="T">The type to get the byte offset of</typeparam>
+ /// <param name="elementCount">The number of elements to get the byte count of</param>
+ /// <returns>The byte multiple of the number of elments</returns>
+ /// <exception cref="OverflowException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint ByteCount<T>(uint elementCount) => checked(elementCount * (uint)Unsafe.SizeOf<T>());
+
+ /// <summary>
+ /// Checks if the offset/count paramters for the given memory handle
+ /// point outside the block wrapped in the handle
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="handle">The handle to check bounds of</param>
+ /// <param name="offset">The base offset to add</param>
+ /// <param name="count">The number of bytes expected to be assigned or dereferrenced</param>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void CheckBounds<T>(IMemoryHandle<T> handle, nuint offset, nuint count)
+ {
+ if (offset + count > handle.Length)
{
- throw new ArgumentException("Count must be a positive integer", nameof(count));
+ throw new ArgumentException("The offset or count is outside of the range of the block of memory");
}
- //Seek streams
- _ = source.Seek(srcOffset, SeekOrigin.Begin);
- _ = dest.Seek(destOffst, SeekOrigin.Begin);
- //Create new buffer
- using IMemoryHandle<byte> buffer = Shared.Alloc<byte>(count);
- Span<byte> buf = buffer.Span;
- int total = 0;
- do
+ }
+
+ /// <summary>
+ /// Checks if the offset/count paramters for the given block
+ /// point outside the block wrapped in the handle
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="block">The handle to check bounds of</param>
+ /// <param name="offset">The base offset to add</param>
+ /// <param name="count">The number of bytes expected to be assigned or dereferrenced</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void CheckBounds<T>(ReadOnlySpan<T> block, int offset, int count)
+ {
+ //Call slice and discard to raise exception
+ _ = block.Slice(offset, count);
+ }
+
+ /// <summary>
+ /// Checks if the offset/count paramters for the given block
+ /// point outside the block wrapped in the handle
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="block">The handle to check bounds of</param>
+ /// <param name="offset">The base offset to add</param>
+ /// <param name="count">The number of bytes expected to be assigned or dereferrenced</param>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void CheckBounds<T>(Span<T> block, int offset, int count)
+ {
+ //Call slice and discard to raise exception
+ _ = block.Slice(offset, count);
+ }
+
+ /// <summary>
+ /// Checks if the offset/count paramters for the given block
+ /// point outside the block bounds
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="block">The handle to check bounds of</param>
+ /// <param name="offset">The base offset to add</param>
+ /// <param name="count">The number of bytes expected to be assigned or dereferrenced</param>
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void CheckBounds<T>(T[] block, nuint offset, nuint count)
+ {
+ if (((nuint)block.LongLength - offset) <= count)
{
- //read from source
- int read = source.Read(buf);
- //guard
- if (read == 0)
- {
- break;
- }
- //write read slice to dest
- dest.Write(buf[..read]);
- //update total read
- total += read;
- } while (total < count);
+ throw new ArgumentException("The offset or count is outside of the range of the block of memory");
+ }
}
+
#endregion
+
#region alloc
/// <summary>
@@ -408,6 +554,7 @@ namespace VNLib.Utils.Memory
{
throw new ArgumentException("Number of elements must be a positive integer", nameof(elements));
}
+
if(elements > MAX_UNSAFE_POOL_SIZE || IsRpMallocLoaded)
{
// Alloc from heap
diff --git a/lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs b/lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs
index 1e85207..e73a26f 100644
--- a/lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs
+++ b/lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs
@@ -28,7 +28,7 @@ using System.Buffers;
namespace VNLib.Utils.Memory
{
/// <summary>
- /// Provides a <see cref="MemoryPool{T}"/> wrapper for using unmanged <see cref="PrivateHeap"/>s
+ /// Provides a <see cref="MemoryPool{T}"/> wrapper for using unmanged <see cref="Win32PrivateHeap"/>s
/// </summary>
/// <typeparam name="T">Unamanged memory type to provide data memory instances from</typeparam>
public sealed class PrivateBuffersMemoryPool<T> : MemoryPool<T> where T : unmanaged
diff --git a/lib/Utils/src/Memory/PrivateStringManager.cs b/lib/Utils/src/Memory/PrivateStringManager.cs
index 9ed8f5f..8f01e98 100644
--- a/lib/Utils/src/Memory/PrivateStringManager.cs
+++ b/lib/Utils/src/Memory/PrivateStringManager.cs
@@ -63,7 +63,7 @@ namespace VNLib.Utils.Memory
//Clear the old value before setting the new one
if (!string.IsNullOrEmpty(ProtectedElements[index]))
{
- Memory.UnsafeZeroMemory<char>(ProtectedElements[index]);
+ MemoryUtil.UnsafeZeroMemory<char>(ProtectedElements[index]);
}
//set new value
ProtectedElements[index] = value;
@@ -87,7 +87,7 @@ namespace VNLib.Utils.Memory
if (!string.IsNullOrEmpty(ProtectedElements[i]))
{
//Zero the string memory
- Memory.UnsafeZeroMemory<char>(ProtectedElements[i]);
+ MemoryUtil.UnsafeZeroMemory<char>(ProtectedElements[i]);
//Set to null
ProtectedElements[i] = null;
}
diff --git a/lib/Utils/src/Memory/ProcessHeap.cs b/lib/Utils/src/Memory/ProcessHeap.cs
index 4f06d52..7afe4b1 100644
--- a/lib/Utils/src/Memory/ProcessHeap.cs
+++ b/lib/Utils/src/Memory/ProcessHeap.cs
@@ -48,20 +48,23 @@ namespace VNLib.Utils.Memory
///<inheritdoc/>
///<exception cref="OverflowException"></exception>
///<exception cref="OutOfMemoryException"></exception>
- public IntPtr Alloc(ulong elements, ulong size, bool zero)
+ public IntPtr Alloc(nuint elements, nuint size, bool zero)
{
return zero
- ? (IntPtr)NativeMemory.AllocZeroed((nuint)elements, (nuint)size)
- : (IntPtr)NativeMemory.Alloc((nuint)elements, (nuint)size);
+ ? (IntPtr)NativeMemory.AllocZeroed(elements, size)
+ : (IntPtr)NativeMemory.Alloc(elements, size);
}
///<inheritdoc/>
public bool Free(ref IntPtr block)
{
//Free native mem from ptr
NativeMemory.Free(block.ToPointer());
+
block = IntPtr.Zero;
+
return true;
}
+
///<inheritdoc/>
protected override void Free()
{
@@ -69,14 +72,25 @@ namespace VNLib.Utils.Memory
Trace.WriteLine($"Default heap instnace disposed {GetHashCode():x}");
#endif
}
+
///<inheritdoc/>
///<exception cref="OverflowException"></exception>
///<exception cref="OutOfMemoryException"></exception>
- public void Resize(ref IntPtr block, ulong elements, ulong size, bool zero)
+ public void Resize(ref IntPtr block, nuint elements, nuint size, bool zero)
{
- nuint bytes = checked((nuint)(elements * size));
- IntPtr old = block;
- block = (IntPtr)NativeMemory.Realloc(old.ToPointer(), bytes);
+ nuint bytes = checked(elements * size);
+
+ //Alloc
+ void* newBlock = NativeMemory.Realloc(block.ToPointer(), bytes);
+
+ //Check
+ if (newBlock == null)
+ {
+ throw new NativeMemoryOutOfMemoryException("Failed to resize the allocated block");
+ }
+
+ //Assign block ptr
+ block = (IntPtr)newBlock;
}
}
}
diff --git a/lib/Utils/src/Memory/RpMallocPrivateHeap.cs b/lib/Utils/src/Memory/RpMallocPrivateHeap.cs
index 8ed79b6..f9b7db6 100644
--- a/lib/Utils/src/Memory/RpMallocPrivateHeap.cs
+++ b/lib/Utils/src/Memory/RpMallocPrivateHeap.cs
@@ -28,7 +28,6 @@ using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
-using size_t = System.UInt64;
using LPVOID = System.IntPtr;
using LPHEAPHANDLE = System.IntPtr;
@@ -59,22 +58,22 @@ namespace VNLib.Utils.Memory
static extern void rpmalloc_heap_release(LPHEAPHANDLE heap);
[DllImport(DLL_NAME, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
- static extern LPVOID rpmalloc_heap_alloc(LPHEAPHANDLE heap, size_t size);
+ static extern LPVOID rpmalloc_heap_alloc(LPHEAPHANDLE heap, nuint size);
[DllImport(DLL_NAME, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
- static extern LPVOID rpmalloc_heap_aligned_alloc(LPHEAPHANDLE heap, size_t alignment, size_t size);
+ static extern LPVOID rpmalloc_heap_aligned_alloc(LPHEAPHANDLE heap, nuint alignment, nuint size);
[DllImport(DLL_NAME, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
- static extern LPVOID rpmalloc_heap_calloc(LPHEAPHANDLE heap, size_t num, size_t size);
+ static extern LPVOID rpmalloc_heap_calloc(LPHEAPHANDLE heap, nuint num, nuint size);
[DllImport(DLL_NAME, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
- static extern LPVOID rpmalloc_heap_aligned_calloc(LPHEAPHANDLE heap, size_t alignment, size_t num, size_t size);
+ static extern LPVOID rpmalloc_heap_aligned_calloc(LPHEAPHANDLE heap, nuint alignment, nuint num, nuint size);
[DllImport(DLL_NAME, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
- static extern LPVOID rpmalloc_heap_realloc(LPHEAPHANDLE heap, LPVOID ptr, size_t size, nuint flags);
+ static extern LPVOID rpmalloc_heap_realloc(LPHEAPHANDLE heap, LPVOID ptr, nuint size, nuint flags);
[DllImport(DLL_NAME, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
- static extern LPVOID rpmalloc_heap_aligned_realloc(LPHEAPHANDLE heap, LPVOID ptr, size_t alignment, size_t size, nuint flags);
+ static extern LPVOID rpmalloc_heap_aligned_realloc(LPHEAPHANDLE heap, LPVOID ptr, nuint alignment, nuint size, nuint flags);
[DllImport(DLL_NAME, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
static extern void rpmalloc_heap_free(LPHEAPHANDLE heap, LPVOID ptr);
@@ -96,13 +95,13 @@ namespace VNLib.Utils.Memory
static extern void rpmalloc_thread_finalize(int release_caches);
[DllImport(DLL_NAME, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
- static extern LPVOID rpmalloc(size_t size);
+ static extern LPVOID rpmalloc(nuint size);
[DllImport(DLL_NAME, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
- static extern LPVOID rpcalloc(size_t num, size_t size);
+ static extern LPVOID rpcalloc(nuint num, nuint size);
[DllImport(DLL_NAME, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
- static extern LPVOID rprealloc(LPVOID ptr, size_t size);
+ static extern LPVOID rprealloc(LPVOID ptr, nuint size);
[DllImport(DLL_NAME, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
static extern void rpfree(LPVOID ptr);
@@ -111,9 +110,9 @@ namespace VNLib.Utils.Memory
private sealed class RpMallocGlobalHeap : IUnmangedHeap
{
- IntPtr IUnmangedHeap.Alloc(ulong elements, ulong size, bool zero)
+ IntPtr IUnmangedHeap.Alloc(nuint elements, nuint size, bool zero)
{
- return RpMalloc(elements, (nuint)size, zero);
+ return RpMalloc(elements, size, zero);
}
//Global heap does not need to be disposed
@@ -127,17 +126,13 @@ namespace VNLib.Utils.Memory
return true;
}
- void IUnmangedHeap.Resize(ref IntPtr block, ulong elements, ulong size, bool zero)
+ void IUnmangedHeap.Resize(ref IntPtr block, nuint elements, nuint size, bool zero)
{
//Try to resize the block
- IntPtr resize = RpRealloc(block, elements, (nuint)size);
-
- if (resize == IntPtr.Zero)
- {
- throw new NativeMemoryOutOfMemoryException("Failed to resize the block");
- }
+ IntPtr resize = RpRealloc(block, elements, size);
+
//assign ptr
- block = resize;
+ block = resize != IntPtr.Zero ? resize : throw new NativeMemoryOutOfMemoryException("Failed to resize the block");
}
}
@@ -164,7 +159,7 @@ namespace VNLib.Utils.Memory
/// <param name="size">The number of bytes per element type (aligment)</param>
/// <param name="zero">Zero the block of memory before returning</param>
/// <returns>A pointer to the block, (zero if failed)</returns>
- public static LPVOID RpMalloc(size_t elements, nuint size, bool zero)
+ public static LPVOID RpMalloc(nuint elements, nuint size, bool zero)
{
//See if the current thread has been initialized
if (rpmalloc_is_thread_initialized() == 0)
@@ -172,8 +167,10 @@ namespace VNLib.Utils.Memory
//Initialize the current thread
rpmalloc_thread_initialize();
}
+
//Alloc block
LPVOID block;
+
if (zero)
{
block = rpcalloc(elements, size);
@@ -181,7 +178,8 @@ namespace VNLib.Utils.Memory
else
{
//Calculate the block size
- ulong blockSize = checked(elements * size);
+ nuint blockSize = checked(elements * size);
+
block = rpmalloc(blockSize);
}
return block;
@@ -209,14 +207,16 @@ namespace VNLib.Utils.Memory
/// <returns>A pointer to the new block if the reallocation succeeded, null if the resize failed</returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="OverflowException"></exception>
- public static LPVOID RpRealloc(LPVOID block, size_t elements, nuint size)
+ public static LPVOID RpRealloc(LPVOID block, nuint elements, nuint size)
{
if(block == IntPtr.Zero)
{
throw new ArgumentException("The supplied block is not valid", nameof(block));
}
+
//Calc new block size
- size_t blockSize = checked(elements * size);
+ nuint blockSize = checked(elements * size);
+
return rprealloc(block, blockSize);
}
@@ -239,6 +239,7 @@ namespace VNLib.Utils.Memory
Trace.WriteLine($"RPMalloc heap {handle:x} created");
#endif
}
+
///<inheritdoc/>
protected override bool ReleaseHandle()
{
@@ -252,13 +253,15 @@ namespace VNLib.Utils.Memory
//Release base
return base.ReleaseHandle();
}
+
///<inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected sealed override LPVOID AllocBlock(ulong elements, ulong size, bool zero)
+ protected sealed override LPVOID AllocBlock(nuint elements, nuint size, bool zero)
{
//Alloc or calloc and initalize
return zero ? rpmalloc_heap_calloc(handle, elements, size) : rpmalloc_heap_alloc(handle, checked(size * elements));
}
+
///<inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected sealed override bool FreeBlock(LPVOID block)
@@ -267,13 +270,15 @@ namespace VNLib.Utils.Memory
rpmalloc_heap_free(handle, block);
return true;
}
+
///<inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected sealed override LPVOID ReAllocBlock(LPVOID block, ulong elements, ulong size, bool zero)
+ protected sealed override LPVOID ReAllocBlock(LPVOID block, nuint elements, nuint size, bool zero)
{
//Realloc
return rpmalloc_heap_realloc(handle, block, checked(elements * size), 0);
}
+
#endregion
}
}
diff --git a/lib/Utils/src/Memory/SubSequence.cs b/lib/Utils/src/Memory/SubSequence.cs
index 3800fb5..87e369b 100644
--- a/lib/Utils/src/Memory/SubSequence.cs
+++ b/lib/Utils/src/Memory/SubSequence.cs
@@ -35,10 +35,7 @@ namespace VNLib.Utils.Memory
public readonly struct SubSequence<T> : IEquatable<SubSequence<T>> where T: unmanaged
{
private readonly MemoryHandle<T> _handle;
- /// <summary>
- /// The number of elements in the current window
- /// </summary>
- public readonly int Size { get; }
+ private readonly nuint _offset;
/// <summary>
/// Creates a new <see cref="SubSequence{T}"/> to the handle to get a window of the block
@@ -46,33 +43,23 @@ namespace VNLib.Utils.Memory
/// <param name="block"></param>
/// <param name="offset"></param>
/// <param name="size"></param>
-#if TARGET_64_BIT
- public SubSequence(MemoryHandle<T> block, ulong offset, int size)
-#else
- public SubSequence(MemoryHandle<T> block, int offset, int size)
-#endif
+ public SubSequence(MemoryHandle<T> block, nuint offset, int size)
{
_offset = offset;
Size = size >= 0 ? size : throw new ArgumentOutOfRangeException(nameof(size));
_handle = block ?? throw new ArgumentNullException(nameof(block));
}
+ /// <summary>
+ /// The number of elements in the current window
+ /// </summary>
+ public readonly int Size { get; }
-#if TARGET_64_BIT
- private readonly ulong _offset;
-#else
- private readonly int _offset;
-#endif
/// <summary>
/// Gets a <see cref="Span{T}"/> that is offset from the base of the handle
/// </summary>
/// <exception cref="ArgumentOutOfRangeException"></exception>
-
-#if TARGET_64_BIT
- public readonly Span<T> Span => Size > 0 ? _handle.GetOffsetSpan(_offset, Size) : Span<T>.Empty;
-#else
- public readonly Span<T> Span => Size > 0 ? _handle.Span.Slice(_offset, Size) : Span<T>.Empty;
-#endif
+ public readonly Span<T> Span => Size > 0 ? _handle.GetOffsetSpan(_offset, Size) : Span<T>.Empty;
/// <summary>
/// Slices the current sequence into a smaller <see cref="SubSequence{T}"/>
@@ -80,7 +67,7 @@ namespace VNLib.Utils.Memory
/// <param name="offset">The relative offset from the current window offset</param>
/// <param name="size">The size of the block</param>
/// <returns>A <see cref="SubSequence{T}"/> of the current sequence</returns>
- public readonly SubSequence<T> Slice(uint offset, int size) => new (_handle, _offset + checked((int)offset), size);
+ public readonly SubSequence<T> Slice(nuint offset, int size) => new (_handle, checked(_offset + offset), size);
/// <summary>
/// Returns the signed 32-bit hashcode
diff --git a/lib/Utils/src/Memory/SysBufferMemoryManager.cs b/lib/Utils/src/Memory/SysBufferMemoryManager.cs
index 040467f..aca2543 100644
--- a/lib/Utils/src/Memory/SysBufferMemoryManager.cs
+++ b/lib/Utils/src/Memory/SysBufferMemoryManager.cs
@@ -40,7 +40,7 @@ namespace VNLib.Utils.Memory
private readonly bool _ownsHandle;
/// <summary>
- /// Consumes an exisitng <see cref="MemoryHandle{T}"/> to provide <see cref="Memory"/> wrappers.
+ /// Consumes an exisitng <see cref="MemoryHandle{T}"/> to provide <see cref="MemoryUtil"/> wrappers.
/// The handle should no longer be referrenced directly
/// </summary>
/// <param name="existingHandle">The existing handle to consume</param>
@@ -52,12 +52,12 @@ namespace VNLib.Utils.Memory
}
/// <summary>
- /// Allocates a fized size buffer from the specified unmanaged <see cref="PrivateHeap"/>
+ /// Allocates a fized size buffer from the specified unmanaged <see cref="Win32PrivateHeap"/>
/// </summary>
/// <param name="heap">The heap to perform allocations from</param>
/// <param name="elements">The number of elements to allocate</param>
/// <param name="zero">Zero allocations</param>
- public SysBufferMemoryManager(IUnmangedHeap heap, ulong elements, bool zero)
+ public SysBufferMemoryManager(IUnmangedHeap heap, nuint elements, bool zero)
{
BackingMemory = heap.Alloc<T>(elements, zero);
_ownsHandle = true;
diff --git a/lib/Utils/src/Memory/UnmanagedHeapBase.cs b/lib/Utils/src/Memory/UnmanagedHeapBase.cs
index 5c92aff..1f7dc7f 100644
--- a/lib/Utils/src/Memory/UnmanagedHeapBase.cs
+++ b/lib/Utils/src/Memory/UnmanagedHeapBase.cs
@@ -28,7 +28,6 @@ using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
-using size_t = System.UInt64;
using LPVOID = System.IntPtr;
namespace VNLib.Utils.Memory
@@ -43,6 +42,7 @@ namespace VNLib.Utils.Memory
/// The heap synchronization handle
/// </summary>
protected readonly SemaphoreSlim HeapLock;
+
/// <summary>
/// The global heap zero flag
/// </summary>
@@ -63,7 +63,7 @@ namespace VNLib.Utils.Memory
///<remarks>Increments the handle count</remarks>
///<exception cref="OutOfMemoryException"></exception>
///<exception cref="ObjectDisposedException"></exception>
- public LPVOID Alloc(size_t elements, size_t size, bool zero)
+ public LPVOID Alloc(nuint elements, nuint size, bool zero)
{
//Force zero if global flag is set
zero |= GlobalZero;
@@ -93,6 +93,7 @@ namespace VNLib.Utils.Memory
throw;
}
}
+
///<inheritdoc/>
///<remarks>Decrements the handle count</remarks>
public bool Free(ref LPVOID block)
@@ -116,10 +117,11 @@ namespace VNLib.Utils.Memory
block = IntPtr.Zero;
return result;
}
+
///<inheritdoc/>
///<exception cref="OutOfMemoryException"></exception>
///<exception cref="ObjectDisposedException"></exception>
- public void Resize(ref LPVOID block, size_t elements, size_t size, bool zero)
+ public void Resize(ref LPVOID block, nuint elements, nuint size, bool zero)
{
//wait for lock
HeapLock.Wait();
@@ -155,12 +157,14 @@ namespace VNLib.Utils.Memory
/// <param name="size">The size of the element type (in bytes)</param>
/// <param name="zero">A flag to zero the allocated block</param>
/// <returns>A pointer to the allocated block</returns>
- protected abstract LPVOID AllocBlock(size_t elements, size_t size, bool zero);
+ protected abstract LPVOID AllocBlock(nuint elements, nuint size, bool zero);
+
/// <summary>
/// Frees a previously allocated block of memory
/// </summary>
/// <param name="block">The block to free</param>
protected abstract bool FreeBlock(LPVOID block);
+
/// <summary>
/// Resizes the previously allocated block of memory on the current heap
/// </summary>
@@ -173,9 +177,11 @@ namespace VNLib.Utils.Memory
/// Heap base relies on the block pointer to remain unchanged if the resize fails so the
/// block is still valid, and the return value is used to determine if the resize was successful
/// </remarks>
- protected abstract LPVOID ReAllocBlock(LPVOID block, size_t elements, size_t size, bool zero);
+ protected abstract LPVOID ReAllocBlock(LPVOID block, nuint elements, nuint size, bool zero);
+
///<inheritdoc/>
public override int GetHashCode() => handle.GetHashCode();
+
///<inheritdoc/>
public override bool Equals(object? obj)
{
diff --git a/lib/Utils/src/Memory/UnsafeMemoryHandle.cs b/lib/Utils/src/Memory/UnsafeMemoryHandle.cs
index b05ad40..72edb26 100644
--- a/lib/Utils/src/Memory/UnsafeMemoryHandle.cs
+++ b/lib/Utils/src/Memory/UnsafeMemoryHandle.cs
@@ -40,7 +40,7 @@ namespace VNLib.Utils.Memory
[StructLayout(LayoutKind.Sequential)]
public readonly struct UnsafeMemoryHandle<T> : IMemoryHandle<T>, IEquatable<UnsafeMemoryHandle<T>> where T : unmanaged
{
- private enum HandleType
+ private enum HandleType : byte
{
None,
Pool,
@@ -60,10 +60,12 @@ namespace VNLib.Utils.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _handleType == HandleType.Pool ? _poolArr.AsSpan(0, IntLength) : new (_memoryPtr.ToPointer(), IntLength);
}
- ///<inheritdoc/>
+ /// <summary>
+ /// Gets the integer number of elements of the block of memory pointed to by this handle
+ /// </summary>
public readonly int IntLength => _length;
///<inheritdoc/>
- public readonly ulong Length => (ulong)_length;
+ public readonly nuint Length => (nuint)_length;
/// <summary>
/// Creates an empty <see cref="UnsafeMemoryHandle{T}"/>
@@ -153,11 +155,18 @@ namespace VNLib.Utils.Memory
///<inheritdoc/>
public readonly unsafe MemoryHandle Pin(int elementIndex)
{
- //Guard
+ //guard empty handle
+ if (_handleType == HandleType.None)
+ {
+ throw new InvalidOperationException("The handle is empty, and cannot be pinned");
+ }
+
+ //Guard size
if (elementIndex < 0 || elementIndex >= IntLength)
{
throw new ArgumentOutOfRangeException(nameof(elementIndex));
}
+
if (_handleType == HandleType.Pool)
{
diff --git a/lib/Utils/src/Memory/VnString.cs b/lib/Utils/src/Memory/VnString.cs
index 7fa0c5a..8bb0bb6 100644
--- a/lib/Utils/src/Memory/VnString.cs
+++ b/lib/Utils/src/Memory/VnString.cs
@@ -52,6 +52,7 @@ namespace VNLib.Utils.Memory
/// The number of unicode characters the current instance can reference
/// </summary>
public int Length => _stringSequence.Size;
+
/// <summary>
/// Gets a value indicating if the current instance is empty
/// </summary>
@@ -62,14 +63,7 @@ namespace VNLib.Utils.Memory
_stringSequence = sequence;
}
- private VnString(
- MemoryHandle<char> handle,
-#if TARGET_64_BIT
- ulong start,
-#else
- int start,
-#endif
- int length)
+ private VnString(MemoryHandle<char> handle, nuint start, int length)
{
Handle = handle ?? throw new ArgumentNullException(nameof(handle));
//get sequence
@@ -83,6 +77,7 @@ namespace VNLib.Utils.Memory
{
//Default string sequence is empty and does not hold any memory
}
+
/// <summary>
/// Creates a new <see cref="VnString"/> around a <see cref="ReadOnlySpan{T}"/> or a <see cref="string"/> of data
/// </summary>
@@ -90,13 +85,13 @@ namespace VNLib.Utils.Memory
/// <exception cref="OutOfMemoryException"></exception>
public VnString(ReadOnlySpan<char> data)
{
- //Create new handle with enough size (heap)
- Handle = Memory.Shared.Alloc<char>(data.Length);
- //Copy
- Memory.Copy(data, Handle, 0);
+ //Create new handle and copy incoming data to it
+ Handle = MemoryUtil.Shared.AllocAndCopy(data);
+
//Get subsequence over the whole copy of data
_stringSequence = Handle.GetSubSequence(0, data.Length);
}
+
/// <summary>
/// Allocates a temporary buffer to read data from the stream until the end of the stream is reached.
/// Decodes data from the user-specified encoding
@@ -122,7 +117,7 @@ namespace VNLib.Utils.Memory
//Get the number of characters
int numChars = encoding.GetCharCount(vnms.AsSpan());
//New handle
- MemoryHandle<char> charBuffer = Memory.Shared.Alloc<char>(numChars);
+ MemoryHandle<char> charBuffer = MemoryUtil.Shared.Alloc<char>(numChars);
try
{
//Write characters to character buffer
@@ -141,9 +136,9 @@ namespace VNLib.Utils.Memory
else
{
//Create a new char bufer that will expand dyanmically
- MemoryHandle<char> charBuffer = Memory.Shared.Alloc<char>(bufferSize);
+ MemoryHandle<char> charBuffer = MemoryUtil.Shared.Alloc<char>(bufferSize);
//Allocate a binary buffer
- MemoryHandle<byte> binBuffer = Memory.Shared.Alloc<byte>(bufferSize);
+ MemoryHandle<byte> binBuffer = MemoryUtil.Shared.Alloc<byte>(bufferSize);
try
{
int length = 0;
@@ -194,6 +189,7 @@ namespace VNLib.Utils.Memory
}
}
}
+
/// <summary>
/// Creates a new Vnstring from the <see cref="MemoryHandle{T}"/> buffer provided. This function "consumes"
/// a handle, meaning it now takes ownsership of the the memory it points to.
@@ -203,27 +199,24 @@ namespace VNLib.Utils.Memory
/// <param name="length">The number of characters this string points to</param>
/// <returns>The new <see cref="VnString"/></returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public static VnString ConsumeHandle(
- MemoryHandle<char> handle,
-
-#if TARGET_64_BIT
- ulong start,
-#else
- int start,
-#endif
-
- int length)
+ public static VnString ConsumeHandle(MemoryHandle<char> handle, nuint start, int length)
{
- if(length < 0)
+ if (handle is null)
{
- throw new ArgumentOutOfRangeException(nameof(length));
+ throw new ArgumentNullException(nameof(handle));
}
- if((uint)length > handle.Length)
+
+ if (length < 0)
{
throw new ArgumentOutOfRangeException(nameof(length));
}
+
+ //Check handle bounts
+ MemoryUtil.CheckBounds(handle, start, (nuint)length);
+
return new VnString(handle, start, length);
}
+
/// <summary>
/// Asynchronously reads data from the specified stream and uses the specified encoding
/// to decode the binary data to a new <see cref="VnString"/> heap character buffer.
@@ -354,10 +347,11 @@ namespace VNLib.Utils.Memory
throw new ArgumentOutOfRangeException(nameof(count));
}
//get sub-sequence slice for the current string
- SubSequence<char> sub = _stringSequence.Slice((uint)start, count);
+ SubSequence<char> sub = _stringSequence.Slice((nuint)start, count);
//Create new string with offsets pointing to same internal referrence
return new VnString(sub);
}
+
/// <summary>
/// Creates a <see cref="VnString"/> that is a window within the current string,
/// the referrence points to the same memory as the first instnace.
@@ -403,13 +397,12 @@ namespace VNLib.Utils.Memory
/// </summary>
/// <returns><see cref="string"/> representation of internal data</returns>
/// <exception cref="ObjectDisposedException"></exception>
- public override unsafe string ToString()
+ public override string ToString()
{
- //Check
- Check();
//Create a new
return AsSpan().ToString();
}
+
/// <summary>
/// Gets the value of the character at the specified index
/// </summary>
@@ -474,7 +467,21 @@ namespace VNLib.Utils.Memory
/// a character span etc
/// </remarks>
/// <exception cref="ObjectDisposedException"></exception>
- public override int GetHashCode() => string.GetHashCode(AsSpan());
+ public override int GetHashCode() => GetHashCode(StringComparison.Ordinal);
+
+ /// <summary>
+ /// Gets a hashcode for the underyling string by using the .NET <see cref="string.GetHashCode()"/>
+ /// method on the character representation of the data
+ /// </summary>
+ /// <param name="stringComparison">The string comperison mode</param>
+ /// <returns></returns>
+ /// <remarks>
+ /// It is safe to compare hashcodes of <see cref="VnString"/> to the <see cref="string"/> class or
+ /// a character span etc
+ /// </remarks>
+ /// <exception cref="ObjectDisposedException"></exception>
+ public int GetHashCode(StringComparison stringComparison) => string.GetHashCode(AsSpan(), stringComparison);
+
///<inheritdoc/>
protected override void Free()
{
diff --git a/lib/Utils/src/Memory/VnTable.cs b/lib/Utils/src/Memory/VnTable.cs
index 1d5c0a6..2c6ce74 100644
--- a/lib/Utils/src/Memory/VnTable.cs
+++ b/lib/Utils/src/Memory/VnTable.cs
@@ -35,33 +35,38 @@ namespace VNLib.Utils.Memory
public sealed class VnTable<T> : VnDisposeable, IIndexable<uint, T> where T : unmanaged
{
private readonly MemoryHandle<T>? BufferHandle;
+
/// <summary>
/// A value that indicates if the table does not contain any values
/// </summary>
public bool Empty { get; }
+
/// <summary>
/// The number of rows in the table
/// </summary>
- public int Rows { get; }
+ public uint Rows { get; }
+
/// <summary>
/// The nuber of columns in the table
/// </summary>
- public int Cols { get; }
+ public uint Cols { get; }
+
/// <summary>
- /// Creates a new 2 dimensional table in unmanaged heap memory, using the <see cref="Memory.Shared"/> heap.
+ /// Creates a new 2 dimensional table in unmanaged heap memory, using the <see cref="MemoryUtil.Shared"/> heap.
/// User should dispose of the table when no longer in use
/// </summary>
/// <param name="rows">Number of rows in the table</param>
/// <param name="cols">Number of columns in the table</param>
- public VnTable(int rows, int cols) : this(Memory.Shared, rows, cols) { }
+ public VnTable(uint rows, uint cols) : this(MemoryUtil.Shared, rows, cols) { }
+
/// <summary>
/// Creates a new 2 dimensional table in unmanaged heap memory, using the specified heap.
/// User should dispose of the table when no longer in use
/// </summary>
- /// <param name="heap"><see cref="PrivateHeap"/> to allocate table memory from</param>
+ /// <param name="heap"><see cref="Win32PrivateHeap"/> to allocate table memory from</param>
/// <param name="rows">Number of rows in the table</param>
/// <param name="cols">Number of columns in the table</param>
- public VnTable(IUnmangedHeap heap, int rows, int cols)
+ public VnTable(IUnmangedHeap heap, uint rows, uint cols)
{
if (rows < 0 || cols < 0)
{
@@ -71,19 +76,28 @@ namespace VNLib.Utils.Memory
if (rows == 0 && cols == 0)
{
Empty = true;
- return;
}
+ else
+ {
+ _ = heap ?? throw new ArgumentNullException(nameof(heap));
- _ = heap ?? throw new ArgumentNullException(nameof(heap));
+ this.Rows = rows;
+ this.Cols = cols;
- this.Rows = rows;
- this.Cols = cols;
+ ulong tableSize = checked((ulong) rows * (ulong) cols);
- long tableSize = Math.BigMul(rows, cols);
+ if (tableSize > nuint.MaxValue)
+ {
+#pragma warning disable CA2201 // Do not raise reserved exception types
+ throw new OutOfMemoryException("Table size is too large");
+#pragma warning restore CA2201 // Do not raise reserved exception types
+ }
- //Alloc a buffer with zero memory enabled, with Rows * Cols number of elements
- BufferHandle = heap.Alloc<T>(tableSize, true);
+ //Alloc a buffer with zero memory enabled, with Rows * Cols number of elements
+ BufferHandle = heap.Alloc<T>((nuint)tableSize, true);
+ }
}
+
/// <summary>
/// Gets the value of an item in the table at the given indexes
/// </summary>
@@ -93,7 +107,7 @@ namespace VNLib.Utils.Memory
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="InvalidOperationException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public T Get(int row, int col)
+ public T Get(uint row, uint col)
{
Check();
if (this.Empty)
@@ -114,15 +128,18 @@ namespace VNLib.Utils.Memory
}
//Calculate the address in memory for the item
//Calc row offset
- long address = Cols * row;
+ ulong address = checked(row * this.Cols);
+
//Calc column offset
address += col;
+
unsafe
{
//Get the value item
- return *(BufferHandle!.GetOffset(address));
+ return *(BufferHandle!.GetOffset((nuint)address));
}
}
+
/// <summary>
/// Sets the value of an item in the table at the given address
/// </summary>
@@ -133,7 +150,7 @@ namespace VNLib.Utils.Memory
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="InvalidOperationException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public void Set(int row, int col, T item)
+ public void Set(uint row, uint col, T item)
{
Check();
if (this.Empty)
@@ -152,28 +169,34 @@ namespace VNLib.Utils.Memory
{
throw new ArgumentOutOfRangeException(nameof(col), "Column address out of range of current table");
}
+
//Calculate the address in memory for the item
+
//Calc row offset
- long address = Cols * row;
+ ulong address = checked(Cols * row);
+
//Calc column offset
address += col;
+
//Set the value item
unsafe
{
- *BufferHandle!.GetOffset(address) = item;
+ *BufferHandle!.GetOffset((nuint)address) = item;
}
}
+
/// <summary>
- /// Equivalent to <see cref="VnTable{T}.Get(int, int)"/> and <see cref="VnTable{T}.Set(int, int, T)"/>
+ /// Equivalent to <see cref="VnTable{T}.Get(uint, uint)"/> and <see cref="VnTable{T}.Set(uint, uint, T)"/>
/// </summary>
/// <param name="row">Row address of item</param>
/// <param name="col">Column address of item</param>
/// <returns>The value of the item</returns>
- public T this[int row, int col]
+ public T this[uint row, uint col]
{
get => Get(row, col);
set => Set(row, col, value);
}
+
/// <summary>
/// Allows for direct addressing in the table.
/// </summary>
@@ -200,10 +223,11 @@ namespace VNLib.Utils.Memory
*(BufferHandle!.GetOffset(index)) = value;
}
}
+
///<inheritdoc/>
protected override void Free()
{
- if (!this.Empty)
+ if (!Empty)
{
//Dispose the buffer
BufferHandle!.Dispose();
diff --git a/lib/Utils/src/Memory/VnTempBuffer.cs b/lib/Utils/src/Memory/VnTempBuffer.cs
index 7726fe1..1d8e42f 100644
--- a/lib/Utils/src/Memory/VnTempBuffer.cs
+++ b/lib/Utils/src/Memory/VnTempBuffer.cs
@@ -28,7 +28,6 @@ using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using VNLib.Utils.Extensions;
-using System.Security.Cryptography;
namespace VNLib.Utils.Memory
{
@@ -52,12 +51,7 @@ namespace VNLib.Utils.Memory
/// <summary>
/// Actual length of internal buffer
/// </summary>
- public ulong Length => (ulong)Buffer.LongLength;
-
- /// <summary>
- /// Actual length of internal buffer
- /// </summary>
- public int IntLength => Buffer.Length;
+ public nuint Length => (nuint)Buffer.LongLength;
///<inheritdoc/>
///<exception cref="ObjectDisposedException"></exception>
@@ -77,6 +71,7 @@ namespace VNLib.Utils.Memory
/// <param name="zero">Set the zero memory flag on close</param>
public VnTempBuffer(int minSize, bool zero = false) :this(ArrayPool<T>.Shared, minSize, zero)
{}
+
/// <summary>
/// Allocates a new <see cref="VnTempBuffer{BufType}"/> with a new buffer from specified array-pool
/// </summary>
@@ -89,6 +84,7 @@ namespace VNLib.Utils.Memory
Buffer = pool.Rent(minSize, zero);
InitSize = minSize;
}
+
/// <summary>
/// Gets an offset wrapper around the current buffer
/// </summary>
@@ -101,6 +97,7 @@ namespace VNLib.Utils.Memory
//Let arraysegment throw exceptions for checks
return new ArraySegment<T>(Buffer, offset, count);
}
+
///<inheritdoc/>
public T this[int index]
{
@@ -127,6 +124,7 @@ namespace VNLib.Utils.Memory
Check();
return new Memory<T>(Buffer, 0, InitSize);
}
+
/// <summary>
/// Gets a memory structure around the internal buffer
/// </summary>
@@ -140,6 +138,7 @@ namespace VNLib.Utils.Memory
Check();
return new Memory<T>(Buffer, start, count);
}
+
/// <summary>
/// Gets a memory structure around the internal buffer
/// </summary>
@@ -181,17 +180,20 @@ namespace VNLib.Utils.Memory
unsafe MemoryHandle IPinnable.Pin(int elementIndex)
{
//Guard
- if (elementIndex < 0 || elementIndex >= IntLength)
+ if (elementIndex < 0 || elementIndex >= Buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(elementIndex));
}
//Pin the array
GCHandle arrHandle = GCHandle.Alloc(Buffer, GCHandleType.Pinned);
+
//Get array base address
void* basePtr = (void*)arrHandle.AddrOfPinnedObject();
+
//Get element offset
void* indexOffet = Unsafe.Add<T>(basePtr, elementIndex);
+
return new(indexOffet, arrHandle, this);
}
diff --git a/lib/Utils/src/Memory/PrivateHeap.cs b/lib/Utils/src/Memory/Win32PrivateHeap.cs
index 5d97506..fe214f4 100644
--- a/lib/Utils/src/Memory/PrivateHeap.cs
+++ b/lib/Utils/src/Memory/Win32PrivateHeap.cs
@@ -28,7 +28,6 @@ using System.Runtime.Versioning;
using System.Runtime.InteropServices;
using DWORD = System.Int64;
-using SIZE_T = System.UInt64;
using LPVOID = System.IntPtr;
namespace VNLib.Utils.Memory
@@ -39,13 +38,13 @@ namespace VNLib.Utils.Memory
///</para>
///</summary>
///<remarks>
- /// <see cref="PrivateHeap"/> implements <see cref="SafeHandle"/> and tracks allocated blocks by its
+ /// <see cref="Win32PrivateHeap"/> implements <see cref="SafeHandle"/> and tracks allocated blocks by its
/// referrence counter. Allocations increment the count, and free's decrement the count, so the heap may
/// be disposed safely
/// </remarks>
[ComVisible(false)]
[SupportedOSPlatform("Windows")]
- public sealed class PrivateHeap : UnmanagedHeapBase
+ public sealed class Win32PrivateHeap : UnmanagedHeapBase
{
private const string KERNEL_DLL = "Kernel32";
@@ -59,10 +58,12 @@ namespace VNLib.Utils.Memory
[DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- private static extern LPVOID HeapAlloc(IntPtr hHeap, DWORD flags, SIZE_T dwBytes);
+ private static extern LPVOID HeapAlloc(IntPtr hHeap, DWORD flags, nuint dwBytes);
+
[DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- private static extern LPVOID HeapReAlloc(IntPtr hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes);
+ private static extern LPVOID HeapReAlloc(IntPtr hHeap, DWORD dwFlags, LPVOID lpMem, nuint dwBytes);
+
[DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[return: MarshalAs(UnmanagedType.Bool)]
@@ -70,32 +71,35 @@ namespace VNLib.Utils.Memory
[DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- private static extern LPVOID HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize);
+ private static extern LPVOID HeapCreate(DWORD flOptions, nuint dwInitialSize, nuint dwMaximumSize);
+
[DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool HeapDestroy(IntPtr hHeap);
+
[DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ [return: MarshalAs(UnmanagedType.Bool)]
private static extern bool HeapValidate(IntPtr hHeap, DWORD dwFlags, LPVOID lpMem);
+
[DllImport(KERNEL_DLL, SetLastError = true, ExactSpelling = true)]
- [return: MarshalAs(UnmanagedType.U8)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- private static extern SIZE_T HeapSize(IntPtr hHeap, DWORD flags, LPVOID lpMem);
+ private static extern nuint HeapSize(IntPtr hHeap, DWORD flags, LPVOID lpMem);
#endregion
/// <summary>
- /// Create a new <see cref="PrivateHeap"/> with the specified sizes and flags
+ /// Create a new <see cref="Win32PrivateHeap"/> with the specified sizes and flags
/// </summary>
/// <param name="initialSize">Intial size of the heap</param>
/// <param name="maxHeapSize">Maximum size allowed for the heap (disabled = 0, default)</param>
/// <param name="flags">Defalt heap flags to set globally for all blocks allocated by the heap (default = 0)</param>
- public static PrivateHeap Create(SIZE_T initialSize, SIZE_T maxHeapSize = 0, DWORD flags = HEAP_NO_FLAGS)
+ public static Win32PrivateHeap Create(nuint initialSize, nuint maxHeapSize = 0, DWORD flags = HEAP_NO_FLAGS)
{
//Call create, throw exception if the heap falled to allocate
IntPtr heapHandle = HeapCreate(flags, initialSize, maxHeapSize);
+
if (heapHandle == IntPtr.Zero)
{
throw new NativeMemoryException("Heap could not be created");
@@ -112,16 +116,16 @@ namespace VNLib.Utils.Memory
/// </summary>
/// <param name="win32HeapHandle">An open and valid handle to a win32 private heap</param>
/// <returns>A wrapper around the specified heap</returns>
- public static PrivateHeap ConsumeExisting(IntPtr win32HeapHandle) => new (win32HeapHandle);
+ public static Win32PrivateHeap ConsumeExisting(IntPtr win32HeapHandle) => new (win32HeapHandle);
- private PrivateHeap(IntPtr heapPtr) : base(false, true) => handle = heapPtr;
+ private Win32PrivateHeap(IntPtr heapPtr) : base(false, true) => handle = heapPtr;
/// <summary>
/// Retrieves the size of a memory block allocated from the current heap.
/// </summary>
/// <param name="block">The pointer to a block of memory to get the size of</param>
/// <returns>The size of the block of memory, (SIZE_T)-1 if the operation fails</returns>
- public SIZE_T HeapSize(ref LPVOID block) => HeapSize(handle, HEAP_NO_FLAGS, block);
+ public nuint HeapSize(ref LPVOID block) => HeapSize(handle, HEAP_NO_FLAGS, block);
/// <summary>
/// Validates the specified block of memory within the current heap instance. This function will block hte
@@ -167,17 +171,20 @@ namespace VNLib.Utils.Memory
return HeapDestroy(handle) && base.ReleaseHandle();
}
///<inheritdoc/>
- protected override sealed LPVOID AllocBlock(ulong elements, ulong size, bool zero)
+ protected override sealed LPVOID AllocBlock(nuint elements, nuint size, bool zero)
{
- ulong bytes = checked(elements * size);
+ nuint bytes = checked(elements * size);
+
return HeapAlloc(handle, zero ? HEAP_ZERO_MEMORY : HEAP_NO_FLAGS, bytes);
}
///<inheritdoc/>
protected override sealed bool FreeBlock(LPVOID block) => HeapFree(handle, HEAP_NO_FLAGS, block);
+
///<inheritdoc/>
- protected override sealed LPVOID ReAllocBlock(LPVOID block, ulong elements, ulong size, bool zero)
+ protected override sealed LPVOID ReAllocBlock(LPVOID block, nuint elements, nuint size, bool zero)
{
- ulong bytes = checked(elements * size);
+ nuint bytes = checked(elements * size);
+
return HeapReAlloc(handle, zero ? HEAP_ZERO_MEMORY : HEAP_NO_FLAGS, block, bytes);
}
}
diff --git a/lib/Utils/src/VnEncoding.cs b/lib/Utils/src/VnEncoding.cs
index 94d8a1a..8359f8f 100644
--- a/lib/Utils/src/VnEncoding.cs
+++ b/lib/Utils/src/VnEncoding.cs
@@ -61,7 +61,7 @@ namespace VNLib.Utils
//get number of bytes
int byteCount = encoding.GetByteCount(data);
//resize the handle to fit the data
- handle = Memory.Memory.Shared.Alloc<byte>(byteCount);
+ handle = Memory.MemoryUtil.Shared.Alloc<byte>(byteCount);
//encode
int size = encoding.GetBytes(data, handle);
//Consume the handle into a new vnmemstream and return it
@@ -479,7 +479,7 @@ namespace VNLib.Utils
//Calculate the base32 entropy to alloc an appropriate buffer (minium buffer of 2 chars)
int entropy = Base32CalcMaxBufferSize(binBuffer.Length);
//Alloc buffer for enough size (2*long bytes) is not an issue
- using (UnsafeMemoryHandle<char> charBuffer = Memory.Memory.UnsafeAlloc<char>(entropy))
+ using (UnsafeMemoryHandle<char> charBuffer = Memory.MemoryUtil.UnsafeAlloc<char>(entropy))
{
//Encode
ERRNO encoded = TryToBase32Chars(binBuffer, charBuffer.Span);
@@ -512,7 +512,7 @@ namespace VNLib.Utils
//calc size of bin buffer
int size = base32.Length;
//Rent a bin buffer
- using UnsafeMemoryHandle<byte> binBuffer = Memory.Memory.UnsafeAlloc<byte>(size);
+ using UnsafeMemoryHandle<byte> binBuffer = Memory.MemoryUtil.UnsafeAlloc<byte>(size);
//Try to decode the data
ERRNO decoded = TryFromBase32Chars(base32, binBuffer.Span);
//Marshal back to a struct
@@ -532,7 +532,7 @@ namespace VNLib.Utils
return null;
}
//Buffer size of the base32 string will always be enough buffer space
- using UnsafeMemoryHandle<byte> tempBuffer = Memory.Memory.UnsafeAlloc<byte>(base32.Length);
+ using UnsafeMemoryHandle<byte> tempBuffer = Memory.MemoryUtil.UnsafeAlloc<byte>(base32.Length);
//Try to decode the data
ERRNO decoded = TryFromBase32Chars(base32, tempBuffer.Span);
@@ -903,7 +903,7 @@ namespace VNLib.Utils
int decodedSize = encoding.GetByteCount(chars);
//alloc buffer
- using UnsafeMemoryHandle<byte> decodeHandle = Memory.Memory.UnsafeAlloc<byte>(decodedSize);
+ using UnsafeMemoryHandle<byte> decodeHandle = Memory.MemoryUtil.UnsafeAlloc<byte>(decodedSize);
//Get the utf8 binary data
int count = encoding.GetBytes(chars, decodeHandle);
return Base64UrlDecode(decodeHandle.Span[..count], output);
diff --git a/lib/Utils/tests/Memory/MemoryHandleTest.cs b/lib/Utils/tests/Memory/MemoryHandleTest.cs
index 02ef1f1..34dbb60 100644
--- a/lib/Utils/tests/Memory/MemoryHandleTest.cs
+++ b/lib/Utils/tests/Memory/MemoryHandleTest.cs
@@ -25,10 +25,9 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using VNLib.Utils;
using VNLib.Utils.Extensions;
-using static VNLib.Utils.Memory.Memory;
+using static VNLib.Utils.Memory.MemoryUtil;
namespace VNLib.Utils.Memory.Tests
{
@@ -43,7 +42,7 @@ namespace VNLib.Utils.Memory.Tests
Assert.ThrowsException<ArgumentOutOfRangeException>(() => Shared.Alloc<byte>(-1));
//Make sure over-alloc throws
- Assert.ThrowsException<NativeMemoryOutOfMemoryException>(() => Shared.Alloc<byte>(ulong.MaxValue, false));
+ Assert.ThrowsException<NativeMemoryOutOfMemoryException>(() => Shared.Alloc<byte>(nuint.MaxValue, false));
}
#if TARGET_64_BIT
[TestMethod]
@@ -54,9 +53,9 @@ namespace VNLib.Utils.Memory.Tests
using MemoryHandle<byte> handle = Shared.Alloc<byte>(bigHandleSize);
//verify size
- Assert.AreEqual(handle.ByteLength, (ulong)bigHandleSize);
+ Assert.IsTrue(handle.ByteLength, (ulong)bigHandleSize);
//Since handle is byte, should also match
- Assert.AreEqual(handle.Length, (ulong)bigHandleSize);
+ Assert.IsTrue(handle.Length, (ulong)bigHandleSize);
//Should throw overflow
Assert.ThrowsException<OverflowException>(() => _ = handle.Span);
@@ -68,8 +67,6 @@ namespace VNLib.Utils.Memory.Tests
Assert.ThrowsException<ArgumentOutOfRangeException>(() => _ = handle.GetOffsetSpan((long)int.MaxValue + 1, 1024));
}
-#else
-
#endif
[TestMethod]
@@ -77,15 +74,15 @@ namespace VNLib.Utils.Memory.Tests
{
using MemoryHandle<byte> handle = Shared.Alloc<byte>(128, true);
- Assert.AreEqual(handle.IntLength, 128);
+ Assert.IsTrue(handle.Length == 128);
- Assert.AreEqual(handle.Length, (ulong)128);
+ Assert.IsTrue(handle.Length == 128);
//Check span against base pointer deref
handle.Span[120] = 10;
- Assert.AreEqual(*handle.GetOffset(120), 10);
+ Assert.IsTrue(*handle.GetOffset(120) == 10);
}
@@ -153,14 +150,14 @@ namespace VNLib.Utils.Memory.Tests
{
using MemoryHandle<byte> handle = Shared.Alloc<byte>(1024);
- Assert.AreEqual(handle.IntLength, 1024);
+ Assert.IsTrue(handle.Length == 1024);
Assert.ThrowsException<ArgumentOutOfRangeException>(() => handle.Resize(-1));
//Resize the handle
handle.Resize(2048);
- Assert.AreEqual(handle.IntLength, 2048);
+ Assert.IsTrue(handle.Length == 2048);
Assert.IsTrue(handle.AsSpan(2048).IsEmpty);
@@ -173,11 +170,11 @@ namespace VNLib.Utils.Memory.Tests
//test resize
handle.ResizeIfSmaller(100);
//Handle should be unmodified
- Assert.AreEqual(handle.IntLength, 2048);
+ Assert.IsTrue(handle.Length == 2048);
//test working
handle.ResizeIfSmaller(4096);
- Assert.AreEqual(handle.IntLength, 4096);
+ Assert.IsTrue(handle.Length == 4096);
}
}
}
diff --git a/lib/Utils/tests/Memory/MemoryTests.cs b/lib/Utils/tests/Memory/MemoryTests.cs
deleted file mode 100644
index 5b68cf5..0000000
--- a/lib/Utils/tests/Memory/MemoryTests.cs
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.UtilsTests
-* File: MemoryTests.cs
-*
-* MemoryTests.cs is part of VNLib.UtilsTests which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.UtilsTests is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published
-* by the Free Software Foundation, either version 2 of the License,
-* or (at your option) any later version.
-*
-* VNLib.UtilsTests is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with VNLib.UtilsTests. If not, see http://www.gnu.org/licenses/.
-*/
-
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System.Runtime.InteropServices;
-
-using VNLib.Utils.Extensions;
-
-namespace VNLib.Utils.Memory.Tests
-{
- [TestClass()]
- public class MemoryTests
- {
- [TestMethod]
- public void MemorySharedHeapLoadedTest()
- {
- Assert.IsNotNull(Memory.Shared);
- }
-
- [TestMethod()]
- public void UnsafeAllocTest()
- {
- //test against negative number
- Assert.ThrowsException<ArgumentException>(() => Memory.UnsafeAlloc<byte>(-1));
-
- //Alloc large block test (100mb)
- const int largTestSize = 100000 * 1024;
- //Alloc super small block
- const int smallTestSize = 5;
-
- using (UnsafeMemoryHandle<byte> buffer = Memory.UnsafeAlloc<byte>(largTestSize, false))
- {
- Assert.AreEqual(largTestSize, buffer.IntLength);
- Assert.AreEqual(largTestSize, buffer.Span.Length);
-
- buffer.Span[0] = 254;
- Assert.AreEqual(buffer.Span[0], 254);
- }
-
- using (UnsafeMemoryHandle<byte> buffer = Memory.UnsafeAlloc<byte>(smallTestSize, false))
- {
- Assert.AreEqual(smallTestSize, buffer.IntLength);
- Assert.AreEqual(smallTestSize, buffer.Span.Length);
-
- buffer.Span[0] = 254;
- Assert.AreEqual(buffer.Span[0], 254);
- }
-
- //Different data type
-
- using(UnsafeMemoryHandle<long> buffer = Memory.UnsafeAlloc<long>(largTestSize, false))
- {
- Assert.AreEqual(largTestSize, buffer.IntLength);
- Assert.AreEqual(largTestSize, buffer.Span.Length);
-
- buffer.Span[0] = long.MaxValue;
- Assert.AreEqual(buffer.Span[0], long.MaxValue);
- }
-
- using (UnsafeMemoryHandle<long> buffer = Memory.UnsafeAlloc<long>(smallTestSize, false))
- {
- Assert.AreEqual(smallTestSize, buffer.IntLength);
- Assert.AreEqual(smallTestSize, buffer.Span.Length);
-
- buffer.Span[0] = long.MaxValue;
- Assert.AreEqual(buffer.Span[0], long.MaxValue);
- }
- }
-
- [TestMethod()]
- public void UnsafeZeroMemoryAsSpanTest()
- {
- //Alloc test buffer
- Span<byte> test = new byte[1024];
- test.Fill(0);
- //test other empty span
- Span<byte> verify = new byte[1024];
- verify.Fill(0);
-
- //Fill test buffer with random values
- Random.Shared.NextBytes(test);
-
- //make sure buffers are not equal
- Assert.IsFalse(test.SequenceEqual(verify));
-
- //Zero buffer
- Memory.UnsafeZeroMemory<byte>(test);
-
- //Make sure buffers are equal
- Assert.IsTrue(test.SequenceEqual(verify));
- }
-
- [TestMethod()]
- public void UnsafeZeroMemoryAsMemoryTest()
- {
- //Alloc test buffer
- Memory<byte> test = new byte[1024];
- test.Span.Fill(0);
- //test other empty span
- Memory<byte> verify = new byte[1024];
- verify.Span.Fill(0);
-
- //Fill test buffer with random values
- Random.Shared.NextBytes(test.Span);
-
- //make sure buffers are not equal
- Assert.IsFalse(test.Span.SequenceEqual(verify.Span));
-
- //Zero buffer
- Memory.UnsafeZeroMemory<byte>(test);
-
- //Make sure buffers are equal
- Assert.IsTrue(test.Span.SequenceEqual(verify.Span));
- }
-
- [TestMethod()]
- public void InitializeBlockAsSpanTest()
- {
- //Alloc test buffer
- Span<byte> test = new byte[1024];
- test.Fill(0);
- //test other empty span
- Span<byte> verify = new byte[1024];
- verify.Fill(0);
-
- //Fill test buffer with random values
- Random.Shared.NextBytes(test);
-
- //make sure buffers are not equal
- Assert.IsFalse(test.SequenceEqual(verify));
-
- //Zero buffer
- Memory.InitializeBlock(test);
-
- //Make sure buffers are equal
- Assert.IsTrue(test.SequenceEqual(verify));
- }
-
- [TestMethod()]
- public void InitializeBlockMemoryTest()
- {
- //Alloc test buffer
- Memory<byte> test = new byte[1024];
- test.Span.Fill(0);
- //test other empty span
- Memory<byte> verify = new byte[1024];
- verify.Span.Fill(0);
-
- //Fill test buffer with random values
- Random.Shared.NextBytes(test.Span);
-
- //make sure buffers are not equal
- Assert.IsFalse(test.Span.SequenceEqual(verify.Span));
-
- //Zero buffer
- Memory.InitializeBlock(test);
-
- //Make sure buffers are equal
- Assert.IsTrue(test.Span.SequenceEqual(verify.Span));
- }
-
- #region structmemory tests
-
- [StructLayout(LayoutKind.Sequential)]
- struct TestStruct
- {
- public int X;
- public int Y;
- }
-
- [TestMethod()]
- public unsafe void ZeroStructAsPointerTest()
- {
- TestStruct* s = Memory.Shared.StructAlloc<TestStruct>();
- s->X = 10;
- s->Y = 20;
- Assert.AreEqual(10, s->X);
- Assert.AreEqual(20, s->Y);
- //zero struct
- Memory.ZeroStruct(s);
- //Verify data was zeroed
- Assert.AreEqual(0, s->X);
- Assert.AreEqual(0, s->Y);
- //Free struct
- Memory.Shared.StructFree(s);
- }
-
- [TestMethod()]
- public unsafe void ZeroStructAsVoidPointerTest()
- {
- TestStruct* s = Memory.Shared.StructAlloc<TestStruct>();
- s->X = 10;
- s->Y = 20;
- Assert.AreEqual(10, s->X);
- Assert.AreEqual(20, s->Y);
- //zero struct
- Memory.ZeroStruct<TestStruct>((void*)s);
- //Verify data was zeroed
- Assert.AreEqual(0, s->X);
- Assert.AreEqual(0, s->Y);
- //Free struct
- Memory.Shared.StructFree(s);
- }
-
- [TestMethod()]
- public unsafe void ZeroStructAsIntPtrTest()
- {
- TestStruct* s = Memory.Shared.StructAlloc<TestStruct>();
- s->X = 10;
- s->Y = 20;
- Assert.AreEqual(10, s->X);
- Assert.AreEqual(20, s->Y);
- //zero struct
- Memory.ZeroStruct<TestStruct>((IntPtr)s);
- //Verify data was zeroed
- Assert.AreEqual(0, s->X);
- Assert.AreEqual(0, s->Y);
- //Free struct
- Memory.Shared.StructFree(s);
- }
- #endregion
- }
-} \ No newline at end of file
diff --git a/lib/Utils/tests/Memory/MemoryUtilTests.cs b/lib/Utils/tests/Memory/MemoryUtilTests.cs
new file mode 100644
index 0000000..fb3700e
--- /dev/null
+++ b/lib/Utils/tests/Memory/MemoryUtilTests.cs
@@ -0,0 +1,333 @@
+using System.Buffers;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using VNLib.Utils.Extensions;
+
+namespace VNLib.Utils.Memory.Tests
+{
+ [TestClass()]
+ public class MemoryUtilTests
+ {
+ const int ZERO_TEST_LOOP_ITERATIONS = 1000000;
+ const int ZERO_TEST_MAX_BUFFER_SIZE = 10 * 1024;
+
+ [TestMethod()]
+ public void InitializeNewHeapForProcessTest()
+ {
+ //Check if rpmalloc is loaded
+ if (MemoryUtil.IsRpMallocLoaded)
+ {
+ //Initialize the heap
+ using IUnmangedHeap heap = MemoryUtil.InitializeNewHeapForProcess();
+
+ //Confirm that the heap is actually a rpmalloc heap
+ Assert.IsInstanceOfType(heap, typeof(RpMallocPrivateHeap));
+ }
+ else
+ {
+ //Confirm that Rpmalloc will throw DLLNotFound if the lib is not loaded
+ Assert.ThrowsException<DllNotFoundException>(() => _ = RpMallocPrivateHeap.GlobalHeap.Alloc(1, 1, false));
+ }
+ }
+
+ [TestMethod()]
+ public void UnsafeZeroMemoryTest()
+ {
+ //Get random data buffer as a readonly span
+ ReadOnlyMemory<byte> buffer = RandomNumberGenerator.GetBytes(1024);
+
+ //confirm buffer is not all zero
+ Assert.IsFalse(AllZero(buffer.Span));
+
+ //Zero readonly memory
+ MemoryUtil.UnsafeZeroMemory(buffer);
+
+ //Confirm all zero
+ Assert.IsTrue(AllZero(buffer.Span));
+ }
+
+ private static bool AllZero(ReadOnlySpan<byte> span)
+ {
+ for (int i = 0; i < span.Length; i++)
+ {
+ if (span[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ [TestMethod()]
+ public void UnsafeZeroMemoryTest1()
+ {
+ //Get random data buffer as a readonly span
+ ReadOnlySpan<byte> buffer = RandomNumberGenerator.GetBytes(1024);
+
+ //confirm buffer is not all zero
+ Assert.IsFalse(AllZero(buffer));
+
+ //Zero readonly span
+ MemoryUtil.UnsafeZeroMemory(buffer);
+
+ //Confirm all zero
+ Assert.IsTrue(AllZero(buffer));
+ }
+
+
+ [TestMethod()]
+ public void InitializeBlockAsSpanTest()
+ {
+ //Get random data buffer as a readonly span
+ Span<byte> buffer = RandomNumberGenerator.GetBytes(1024);
+
+ //confirm buffer is not all zero
+ Assert.IsFalse(AllZero(buffer));
+
+ //Zero readonly span
+ MemoryUtil.InitializeBlock(buffer);
+
+ //Confirm all zero
+ Assert.IsTrue(AllZero(buffer));
+ }
+
+ [TestMethod()]
+ public void InitializeBlockMemoryTest()
+ {
+ //Get random data buffer as a readonly span
+ Memory<byte> buffer = RandomNumberGenerator.GetBytes(1024);
+
+ //confirm buffer is not all zero
+ Assert.IsFalse(AllZero(buffer.Span));
+
+ //Zero readonly span
+ MemoryUtil.InitializeBlock(buffer);
+
+ //Confirm all zero
+ Assert.IsTrue(AllZero(buffer.Span));
+ }
+
+
+ [TestMethod()]
+ public unsafe void UnsafeAllocTest()
+ {
+ //No fail
+ using (UnsafeMemoryHandle<byte> handle = MemoryUtil.UnsafeAlloc<byte>(1024))
+ {
+ _ = handle.Span;
+ _ = handle.Length;
+ _ = handle.IntLength;
+
+ //Test span pointer against pinned handle
+ using (MemoryHandle pinned = handle.Pin(0))
+ {
+ fixed (void* ptr = &MemoryMarshal.GetReference(handle.Span))
+ {
+ Assert.IsTrue(ptr == pinned.Pointer);
+ }
+ }
+
+ //Test negative pin
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() => _ = handle.Pin(-1));
+
+ //Test pinned outsie handle size
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() => _ = handle.Pin(1024));
+ }
+
+ //test against negative number
+ Assert.ThrowsException<ArgumentException>(() => MemoryUtil.UnsafeAlloc<byte>(-1));
+
+ //Alloc large block test (100mb)
+ const int largTestSize = 100000 * 1024;
+ //Alloc super small block
+ const int smallTestSize = 5;
+
+ using (UnsafeMemoryHandle<byte> buffer = MemoryUtil.UnsafeAlloc<byte>(largTestSize, false))
+ {
+ Assert.IsTrue(largTestSize == buffer.IntLength);
+ Assert.IsTrue(largTestSize == buffer.Span.Length);
+
+ buffer.Span[0] = 254;
+ Assert.IsTrue(buffer.Span[0] == 254);
+ }
+
+ using (UnsafeMemoryHandle<byte> buffer = MemoryUtil.UnsafeAlloc<byte>(smallTestSize, false))
+ {
+ Assert.IsTrue(smallTestSize == buffer.IntLength);
+ Assert.IsTrue(smallTestSize == buffer.Span.Length);
+
+ buffer.Span[0] = 254;
+ Assert.IsTrue(buffer.Span[0] == 254);
+ }
+
+ //Different data type
+ using (UnsafeMemoryHandle<long> buffer = MemoryUtil.UnsafeAlloc<long>(largTestSize, false))
+ {
+ Assert.IsTrue(largTestSize == buffer.IntLength);
+ Assert.IsTrue(largTestSize == buffer.Span.Length);
+
+ buffer.Span[0] = long.MaxValue;
+ Assert.IsTrue(buffer.Span[0] == long.MaxValue);
+ }
+
+ using (UnsafeMemoryHandle<long> buffer = MemoryUtil.UnsafeAlloc<long>(smallTestSize, false))
+ {
+ Assert.IsTrue(smallTestSize == buffer.IntLength);
+ Assert.IsTrue(smallTestSize == buffer.Span.Length);
+
+ buffer.Span[0] = long.MaxValue;
+ Assert.IsTrue(buffer.Span[0] == long.MaxValue);
+ }
+
+ //Test empty handle
+ using (UnsafeMemoryHandle<byte> empty = new())
+ {
+ Assert.IsTrue(0 == empty.Length);
+ Assert.IsTrue(0 == empty.IntLength);
+
+ //Test pinning while empty
+ Assert.ThrowsException<InvalidOperationException>(() => _ = empty.Pin(0));
+ }
+
+ //Negative value
+ Assert.ThrowsException<ArgumentException>(() => _ = MemoryUtil.UnsafeAlloc<byte>(-1));
+
+
+ /*
+ * Alloc random sized blocks in a loop, confirm they are empty
+ * then fill the block with random data before freeing it back to
+ * the pool. This confirms that if blocks are allocated from a shared
+ * pool are properly zeroed when requestd
+ */
+
+ for (int i = 0; i < ZERO_TEST_LOOP_ITERATIONS; i++)
+ {
+ int randBufferSize = Random.Shared.Next(1024, ZERO_TEST_MAX_BUFFER_SIZE);
+
+ //Alloc block, check if all zero, then free
+ using UnsafeMemoryHandle<byte> handle = MemoryUtil.UnsafeAlloc<byte>(randBufferSize, true);
+
+ //Confirm all zero
+ Assert.IsTrue(AllZero(handle.Span));
+
+ //Fill with random data
+ Random.Shared.NextBytes(handle.Span);
+ }
+ }
+
+ [TestMethod()]
+ public unsafe void SafeAllocTest()
+ {
+ //No fail
+ using (IMemoryHandle<byte> handle = MemoryUtil.SafeAlloc<byte>(1024))
+ {
+ _ = handle.Span;
+ _ = handle.Length;
+ _ = handle.GetIntLength();
+
+ //Test span pointer against pinned handle
+ using (MemoryHandle pinned = handle.Pin(0))
+ {
+ fixed (void* ptr = &MemoryMarshal.GetReference(handle.Span))
+ {
+ Assert.IsTrue(ptr == pinned.Pointer);
+ }
+ }
+
+ //Test negative pin
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() => _ = handle.Pin(-1));
+
+ //Test pinned outsie handle size
+ Assert.ThrowsException<ArgumentOutOfRangeException>(() => _ = handle.Pin(1024));
+ }
+
+
+ //Negative value
+ Assert.ThrowsException<ArgumentException>(() => _ = MemoryUtil.SafeAlloc<byte>(-1));
+
+
+ /*
+ * Alloc random sized blocks in a loop, confirm they are empty
+ * then fill the block with random data before freeing it back to
+ * the pool. This confirms that if blocks are allocated from a shared
+ * pool are properly zeroed when requestd
+ */
+
+ for (int i = 0; i < ZERO_TEST_LOOP_ITERATIONS; i++)
+ {
+ int randBufferSize = Random.Shared.Next(1024, ZERO_TEST_MAX_BUFFER_SIZE);
+
+ //Alloc block, check if all zero, then free
+ using IMemoryHandle<byte> handle = MemoryUtil.SafeAlloc<byte>(randBufferSize, true);
+
+ //Confirm all zero
+ Assert.IsTrue(AllZero(handle.Span));
+
+ //Fill with random data
+ Random.Shared.NextBytes(handle.Span);
+ }
+ }
+
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct TestStruct
+ {
+ public int X;
+ public int Y;
+ }
+
+ [TestMethod()]
+ public unsafe void ZeroStructAsPointerTest()
+ {
+ TestStruct* s = MemoryUtil.Shared.StructAlloc<TestStruct>();
+ s->X = 10;
+ s->Y = 20;
+ Assert.IsTrue(10 == s->X);
+ Assert.IsTrue(20 == s->Y);
+ //zero struct
+ MemoryUtil.ZeroStruct(s);
+ //Verify data was zeroed
+ Assert.IsTrue(0 == s->X);
+ Assert.IsTrue(0 == s->Y);
+ //Free struct
+ MemoryUtil.Shared.StructFree(s);
+ }
+
+ [TestMethod()]
+ public unsafe void ZeroStructAsVoidPointerTest()
+ {
+ TestStruct* s = MemoryUtil.Shared.StructAlloc<TestStruct>();
+ s->X = 10;
+ s->Y = 20;
+ Assert.IsTrue(10 == s->X);
+ Assert.IsTrue(20 == s->Y);
+ //zero struct
+ MemoryUtil.ZeroStruct<TestStruct>((void*)s);
+ //Verify data was zeroed
+ Assert.IsTrue(0 == s->X);
+ Assert.IsTrue(0 == s->Y);
+ //Free struct
+ MemoryUtil.Shared.StructFree(s);
+ }
+
+ [TestMethod()]
+ public unsafe void ZeroStructAsIntPtrTest()
+ {
+ TestStruct* s = MemoryUtil.Shared.StructAlloc<TestStruct>();
+ s->X = 10;
+ s->Y = 20;
+ Assert.IsTrue(10 == s->X);
+ Assert.IsTrue(20 == s->Y);
+ //zero struct
+ MemoryUtil.ZeroStruct<TestStruct>((IntPtr)s);
+ //Verify data was zeroed
+ Assert.IsTrue(0 == s->X);
+ Assert.IsTrue(0 == s->Y);
+ //Free struct
+ MemoryUtil.Shared.StructFree(s);
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/Utils/tests/Memory/VnTableTests.cs b/lib/Utils/tests/Memory/VnTableTests.cs
index 11350d4..c9f99ea 100644
--- a/lib/Utils/tests/Memory/VnTableTests.cs
+++ b/lib/Utils/tests/Memory/VnTableTests.cs
@@ -33,26 +33,13 @@ namespace VNLib.Utils.Memory.Tests
[TestMethod()]
public void VnTableTest()
{
- Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
- {
- using VnTable<int> table = new(-1, 0);
- });
- Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
- {
- using VnTable<int> table = new(0, -1);
- });
- Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
- {
- using VnTable<int> table = new(-1, -1);
- });
-
//Empty table
using (VnTable<int> empty = new(0, 0))
{
Assert.IsTrue(empty.Empty);
//Test 0 rows/cols
- Assert.AreEqual(0, empty.Rows);
- Assert.AreEqual(0, empty.Cols);
+ Assert.IsTrue(0 == empty.Rows);
+ Assert.IsTrue(0 == empty.Cols);
}
using (VnTable<int> table = new(40000, 10000))
@@ -60,8 +47,8 @@ namespace VNLib.Utils.Memory.Tests
Assert.IsFalse(table.Empty);
//Test table size
- Assert.AreEqual(40000, table.Rows);
- Assert.AreEqual(10000, table.Cols);
+ Assert.IsTrue(40000 == table.Rows);
+ Assert.IsTrue(10000 == table.Cols);
}
@@ -89,41 +76,41 @@ namespace VNLib.Utils.Memory.Tests
[TestMethod()]
public void GetSetTest()
{
- static void TestIndexAt(VnTable<int> table, int row, int col, int value)
+ static void TestIndexAt(VnTable<int> table, uint row, uint col, int value)
{
table[row, col] = value;
- Assert.AreEqual(value, table[row, col]);
- Assert.AreEqual(value, table.Get(row, col));
+ Assert.IsTrue(value == table[row, col]);
+ Assert.IsTrue(value == table.Get(row, col));
}
- static void TestSetAt(VnTable<int> table, int row, int col, int value)
+ static void TestSetAt(VnTable<int> table, uint row, uint col, int value)
{
table.Set(row, col, value);
- Assert.AreEqual(value, table[row, col]);
- Assert.AreEqual(value, table.Get(row, col));
+ Assert.IsTrue(value == table[row, col]);
+ Assert.IsTrue(value == table.Get(row, col));
}
- static void TestSetDirectAccess(VnTable<int> table, int row, int col, int value)
+ static void TestSetDirectAccess(VnTable<int> table, uint row, uint col, int value)
{
- int address = row * table.Cols + col;
- table[(uint)address] = value;
+ uint address = row * table.Cols + col;
+ table[address] = value;
//Get value using indexer
- Assert.AreEqual(value, table[row, col]);
+ Assert.IsTrue(value == table[row, col]);
}
- static void TestGetDirectAccess(VnTable<int> table, int row, int col, int value)
+ static void TestGetDirectAccess(VnTable<int> table, uint row, uint col, int value)
{
table[row, col] = value;
- int address = row * table.Cols + col;
+ uint address = row * table.Cols + col;
//Test direct access
- Assert.AreEqual(value, table[(uint)address]);
+ Assert.IsTrue(value == table[address]);
//Get value using indexer
- Assert.AreEqual(value, table[row, col]);
- Assert.AreEqual(value, table.Get(row, col));
+ Assert.IsTrue(value == table[row, col]);
+ Assert.IsTrue(value == table.Get(row, col));
}
diff --git a/lib/Utils/tests/VnEncodingTests.cs b/lib/Utils/tests/VnEncodingTests.cs
index a4e52f0..373b834 100644
--- a/lib/Utils/tests/VnEncodingTests.cs
+++ b/lib/Utils/tests/VnEncodingTests.cs
@@ -23,16 +23,12 @@
*/
using System;
+using System.Text;
using System.Buffers;
using System.Buffers.Text;
-using System.Collections.Generic;
-using System.Linq;
using System.Security.Cryptography;
-using System.Text;
-using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using VNLib.Utils;
namespace VNLib.Utils.Tests
{