From 50885f7cd7e0519c96b0c95fce9ba6bf69502cf7 Mon Sep 17 00:00:00 2001 From: vnugent Date: Mon, 8 Jan 2024 22:04:41 -0500 Subject: Some net 8.0 goodies like sha3 support --- lib/Utils/src/Extensions/MemoryExtensions.cs | 185 +++++++++------------ lib/Utils/src/IO/VnMemoryStream.cs | 78 +++++---- lib/Utils/src/Memory/ArrayPoolBuffer.cs | 26 +-- lib/Utils/src/Memory/MemoryHandle.cs | 30 ++-- lib/Utils/src/Memory/MemoryUtil.cs | 77 +++------ lib/Utils/src/Memory/MemoryUtilAlloc.cs | 12 +- lib/Utils/src/Memory/UnmanagedHeapBase.cs | 30 ++-- .../src/Native/NativeMemoryOutOfMemoryException.cs | 16 +- lib/Utils/src/Native/SafeLibraryHandle.cs | 11 +- lib/Utils/src/VnEncoding.cs | 4 +- 10 files changed, 210 insertions(+), 259 deletions(-) (limited to 'lib/Utils') diff --git a/lib/Utils/src/Extensions/MemoryExtensions.cs b/lib/Utils/src/Extensions/MemoryExtensions.cs index 28969ea..8f90525 100644 --- a/lib/Utils/src/Extensions/MemoryExtensions.cs +++ b/lib/Utils/src/Extensions/MemoryExtensions.cs @@ -71,6 +71,8 @@ namespace VNLib.Utils.Extensions /// A new encapsulating the rented array public static IMemoryHandle SafeAlloc(this ArrayPool pool, int size, bool zero = false) where T : struct { + ArgumentNullException.ThrowIfNull(pool); + T[] array = pool.Rent(size); if (zero) @@ -94,6 +96,8 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T[] Rent(this ArrayPool pool, int size, bool zero) { + ArgumentNullException.ThrowIfNull(pool); + //Rent the array T[] arr = pool.Rent(size); //If zero flag is set, zero only the used section @@ -186,7 +190,8 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static MemoryManager DirectAlloc(this IUnmangedHeap heap, nint size, bool zero = false) where T : unmanaged { - return size >= 0 ? DirectAlloc(heap, (nuint)size, zero) : throw new ArgumentOutOfRangeException(nameof(size), "The size paramter must be a positive integer"); + ArgumentOutOfRangeException.ThrowIfNegative(size); + return DirectAlloc(heap, (nuint)size, zero); } /// @@ -200,7 +205,9 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe T* GetOffset(this MemoryHandle memory, nint elements) where T : unmanaged { - return elements >= 0 ? memory.GetOffset((nuint)elements) : throw new ArgumentOutOfRangeException(nameof(elements), "The elements paramter must be a positive integer"); + ArgumentNullException.ThrowIfNull(memory); + ArgumentOutOfRangeException.ThrowIfNegative(elements); + return memory.GetOffset((nuint)elements); } /// @@ -215,10 +222,8 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Resize(this IResizeableMemoryHandle memory, nint elements) { - if (elements < 0) - { - throw new ArgumentOutOfRangeException(nameof(elements)); - } + ArgumentNullException.ThrowIfNull(memory); + ArgumentOutOfRangeException.ThrowIfNegative(elements); memory.Resize((nuint)elements); } @@ -235,10 +240,7 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ResizeIfSmaller(this IResizeableMemoryHandle handle, nint count) { - if(count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } + ArgumentOutOfRangeException.ThrowIfNegative(count); ResizeIfSmaller(handle, (nuint)count); } @@ -255,6 +257,7 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ResizeIfSmaller(this IResizeableMemoryHandle handle, nuint count) { + ArgumentNullException.ThrowIfNull(handle); //Check handle size if(handle.Length < count) { @@ -274,12 +277,8 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref T GetOffsetRef(this IMemoryHandle block, nuint offset) { - _ = block ?? throw new ArgumentNullException(nameof(block)); - - if (offset >= block.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } + ArgumentNullException.ThrowIfNull(block); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(offset, block.Length); return ref Unsafe.Add(ref block.GetReference(), offset); } @@ -297,12 +296,8 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref byte GetOffsetByteRef(this IMemoryHandle block, nuint offset) { - _ = block ?? throw new ArgumentNullException(nameof(block)); - - if (offset >= block.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } + ArgumentNullException.ThrowIfNull(block); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(offset, block.Length); //Get the base reference, then offset by the desired number of elements and cast to a byte reference ref T baseRef = ref block.GetReference(); @@ -322,13 +317,10 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span GetOffsetSpan(this IMemoryHandle block, nuint offset, int size) { - _ = block ?? throw new ArgumentNullException(nameof(block)); - - if(size < 0) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - if(size == 0) + ArgumentNullException.ThrowIfNull(block); + ArgumentOutOfRangeException.ThrowIfNegative(size); + + if (size == 0) { return Span.Empty; } @@ -353,7 +345,9 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe Span GetOffsetSpan(this IMemoryHandle block, nint offset, int size) { - return offset >= 0 ? block.GetOffsetSpan((nuint)offset, size) : throw new ArgumentOutOfRangeException(nameof(offset)); + ArgumentNullException.ThrowIfNull(block); + ArgumentOutOfRangeException.ThrowIfNegative(size); + return block.GetOffsetSpan((nuint)offset, size); } /// @@ -380,7 +374,9 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static SubSequence GetSubSequence(this IMemoryHandle block, nint offset, int size) { - return offset >= 0 ? new (block, (nuint)offset, size) : throw new ArgumentOutOfRangeException(nameof(offset)); + ArgumentNullException.ThrowIfNull(block); + ArgumentOutOfRangeException.ThrowIfNegative(size); + return new (block, (nuint)offset, size); } /// @@ -390,7 +386,8 @@ namespace VNLib.Utils.Extensions /// The unmanged data type to provide allocations from /// The new heap wrapper. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static MemoryPool ToPool(this IUnmangedHeap heap, int maxBufferSize = int.MaxValue) where T : unmanaged => new PrivateBuffersMemoryPool(heap, maxBufferSize); + public static MemoryPool ToPool(this IUnmangedHeap heap, int maxBufferSize = int.MaxValue) where T : unmanaged + => new PrivateBuffersMemoryPool(heap, maxBufferSize); /// /// Allocates a structure of the specified type on the current unmanged heap and optionally zero's its memory @@ -403,7 +400,8 @@ namespace VNLib.Utils.Extensions /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe T* StructAlloc(this IUnmangedHeap heap, bool zero = true) where T : unmanaged => MemoryUtil.StructAlloc(heap, zero); + public static unsafe T* StructAlloc(this IUnmangedHeap heap, bool zero = true) where T : unmanaged + => MemoryUtil.StructAlloc(heap, zero); /// /// Allocates a structure of the specified type on the current unmanged heap and optionally zero's its memory @@ -416,7 +414,8 @@ namespace VNLib.Utils.Extensions /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref T StructAllocRef(this IUnmangedHeap heap, bool zero = true) where T : unmanaged => ref MemoryUtil.StructAllocRef(heap, zero); + public static ref T StructAllocRef(this IUnmangedHeap heap, bool zero = true) where T : unmanaged + => ref MemoryUtil.StructAllocRef(heap, zero); /// @@ -427,7 +426,8 @@ namespace VNLib.Utils.Extensions /// /// A reference/pointer to the structure [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void StructFree(this IUnmangedHeap heap, T* structPtr) where T : unmanaged => MemoryUtil.StructFree(heap, structPtr); + public static unsafe void StructFree(this IUnmangedHeap heap, T* structPtr) where T : unmanaged + => MemoryUtil.StructFree(heap, structPtr); /// /// Frees a structure at the specified address from the this heap. @@ -437,7 +437,8 @@ namespace VNLib.Utils.Extensions /// /// A reference to the structure [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void StructFreeRef(this IUnmangedHeap heap, ref T structRef) where T : unmanaged => MemoryUtil.StructFreeRef(heap, ref structRef); + public static void StructFreeRef(this IUnmangedHeap heap, ref T structRef) where T : unmanaged + => MemoryUtil.StructFreeRef(heap, ref structRef); /// /// Allocates a block of unmanaged memory of the number of elements to store of an unmanged type @@ -452,7 +453,7 @@ namespace VNLib.Utils.Extensions /// public static unsafe MemoryHandle Alloc(this IUnmangedHeap heap, nuint elements, bool zero = false) where T : unmanaged { - _ = heap ?? throw new ArgumentNullException(nameof(heap)); + ArgumentNullException.ThrowIfNull(heap); //Minimum of one element elements = Math.Max(elements, 1); //If zero flag is set then specify zeroing memory @@ -475,7 +476,8 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static MemoryHandle Alloc(this IUnmangedHeap heap, nint elements, bool zero = false) where T : unmanaged { - return elements >= 0 ? Alloc(heap, (nuint)elements, zero) : throw new ArgumentOutOfRangeException(nameof(elements)); + ArgumentOutOfRangeException.ThrowIfNegative(elements); + return Alloc(heap, (nuint)elements, zero); } /// @@ -532,6 +534,7 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void WriteAndResize(this IResizeableMemoryHandle handle, ReadOnlySpan input) where T: unmanaged { + ArgumentNullException.ThrowIfNull(handle); handle.Resize(input.Length); MemoryUtil.Copy(input, 0, handle, 0, input.Length); } @@ -552,6 +555,8 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static UnsafeMemoryHandle UnsafeAlloc(this IUnmangedHeap heap, int elements, bool zero = false) where T : unmanaged { + ArgumentNullException.ThrowIfNull(heap); + if (elements < 1) { //Return an empty handle @@ -583,7 +588,7 @@ namespace VNLib.Utils.Extensions Span output = buffer.Remaining[..size]; //Format value and write to buffer - MemoryMarshal.Write(output, ref value); + MemoryMarshal.Write(output, in value); //If byte order is reversed, reverse elements if (!BitConverter.IsLittleEndian) @@ -608,7 +613,7 @@ namespace VNLib.Utils.Extensions Span output = buffer.Remaining.Span[..size]; //Format value and write to buffer - MemoryMarshal.Write(output, ref value); + MemoryMarshal.Write(output, in value); //If byte order is reversed, reverse elements if (BitConverter.IsLittleEndian) @@ -676,10 +681,8 @@ namespace VNLib.Utils.Extensions /// The actual number of bytes written at the location indicated by the bytes parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetBytes(this Encoder enc, char[] chars, int offset, int charCount, ref ForwardOnlyWriter writer, bool flush) - { - return GetBytes(enc, chars.AsSpan(offset, charCount), ref writer, flush); - } + public static int GetBytes(this Encoder enc, char[] chars, int offset, int charCount, ref ForwardOnlyWriter writer, bool flush) + => GetBytes(enc, chars.AsSpan(offset, charCount), ref writer, flush); /// /// Encodes a set of characters in the input characters span and any characters @@ -696,6 +699,7 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetBytes(this Encoder enc, ReadOnlySpan chars, ref ForwardOnlyWriter writer, bool flush) { + ArgumentNullException.ThrowIfNull(enc); //Encode the characters int written = enc.GetBytes(chars, writer.Remaining, flush); //Update the writer position @@ -715,6 +719,7 @@ namespace VNLib.Utils.Extensions /// public static int GetBytes(this Encoding encoding, ReadOnlySpan chars, ref ForwardOnlyWriter writer) { + ArgumentNullException.ThrowIfNull(encoding); //Encode the characters int written = encoding.GetBytes(chars, writer.Remaining); //Update the writer position @@ -734,6 +739,7 @@ namespace VNLib.Utils.Extensions /// public static int GetChars(this Encoding encoding, ReadOnlySpan bytes, ref ForwardOnlyWriter writer) { + ArgumentNullException.ThrowIfNull(encoding); int charCount = encoding.GetCharCount(bytes); //Encode the characters _ = encoding.GetChars(bytes, writer.Remaining); @@ -770,10 +776,10 @@ namespace VNLib.Utils.Extensions /// public static T[] Slice(this T[] arr, int start) { - if(start < 0 || start > arr.Length) - { - throw new ArgumentOutOfRangeException(nameof(start)); - } + ArgumentNullException.ThrowIfNull(arr); + ArgumentOutOfRangeException.ThrowIfNegative(start); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(start, arr.Length); + Range sliceRange = new(start, arr.Length - start); return RuntimeHelpers.GetSubArray(arr, sliceRange); } @@ -790,22 +796,16 @@ namespace VNLib.Utils.Extensions /// public static T[] Slice(this T[] arr, int start, int count) { - if(start < 0) - { - throw new ArgumentOutOfRangeException(nameof(start)); - } - if(count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - if(start + count >= arr.Length) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } + ArgumentNullException.ThrowIfNull(arr); + ArgumentOutOfRangeException.ThrowIfNegative(start); + ArgumentOutOfRangeException.ThrowIfNegative(count); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(start + count, arr.Length); + if(count == 0) { - return Array.Empty(); + return []; } + //Calc the slice range Range sliceRange = new(start, start + count); return RuntimeHelpers.GetSubArray(arr, sliceRange); @@ -822,28 +822,23 @@ namespace VNLib.Utils.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span AsSpan(this IMemoryHandle handle, nint start) { - _ = handle ?? throw new ArgumentNullException(nameof(handle)); - if(start < 0 || (uint)start > handle.Length) + ArgumentNullException.ThrowIfNull(handle); + ArgumentOutOfRangeException.ThrowIfNegative(start); + + //Allow empty spans for empty handles or last elements + if((nuint)start == handle.Length) { - throw new ArgumentOutOfRangeException(nameof(start)); + return Span.Empty; } + + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual((nuint)start, handle.Length); + //calculate a remaining count int count = checked((int)(handle.Length - (uint)start)); //call the other overload return AsSpan(handle, start, count); } - /// - /// Creates a new sub-sequence over the target handle. (allows for convient sub span) - /// - /// - /// - /// Intial offset into the handle - /// The sub-sequence of the current handle - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span AsSpan(this IMemoryHandle handle, int start) => AsSpan(handle, (nint)start); - /// /// Creates a new sub-sequence over the target handle. (allows for convient sub span) /// @@ -855,41 +850,24 @@ namespace VNLib.Utils.Extensions /// public static Span AsSpan(this IMemoryHandle handle, nint start, int count) { - _ = handle ?? throw new ArgumentNullException(nameof(handle)); - if(start < 0) - { - throw new ArgumentOutOfRangeException(nameof(start)); - } - if(count < 0) + ArgumentNullException.ThrowIfNull(handle); + ArgumentOutOfRangeException.ThrowIfNegative(start); + ArgumentOutOfRangeException.ThrowIfNegative(count); + + //Allow empty spans for empty handles + if (count == 0) { - throw new ArgumentOutOfRangeException(nameof(count)); + return Span.Empty; } //guard against buffer overrun MemoryUtil.CheckBounds(handle, (nuint)start, (nuint)count); - if(count == 0) - { - return Span.Empty; - } - //Get the offset ref and create a new span from the pointer ref T asRef = ref handle.GetOffsetRef((nuint)start); return MemoryMarshal.CreateSpan(ref asRef, count); } - /// - /// Creates a new sub-sequence over the target handle. (allows for convient sub span) - /// - /// - /// - /// Intial offset into the handle - /// The number of elements within the new sequence - /// The sub-sequence of the current handle - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span AsSpan(this IMemoryHandle handle, int start, int count) => AsSpan(handle, (nint)start, count); - /// /// Creates a new sub-sequence over the target handle. (allows for convient sub span) /// @@ -920,12 +898,7 @@ namespace VNLib.Utils.Extensions /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ThrowIfClosed(this SafeHandle handle) - { - if (handle.IsClosed || handle.IsInvalid) - { - throw new ObjectDisposedException(handle.GetType().Name); - } - } + public static void ThrowIfClosed(this SafeHandle handle) + => ObjectDisposedException.ThrowIf(handle.IsClosed || handle.IsInvalid, handle); } } diff --git a/lib/Utils/src/IO/VnMemoryStream.cs b/lib/Utils/src/IO/VnMemoryStream.cs index 45c4a55..885d9c2 100644 --- a/lib/Utils/src/IO/VnMemoryStream.cs +++ b/lib/Utils/src/IO/VnMemoryStream.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Utils @@ -75,7 +75,7 @@ namespace VNLib.Utils.IO public static VnMemoryStream FromHandle(IResizeableMemoryHandle handle, bool ownsHandle, nint length, bool readOnly) { //Check the handle - _ = handle ?? throw new ArgumentNullException(nameof(handle)); + ArgumentNullException.ThrowIfNull(handle); return handle.CanRealloc || readOnly ? new VnMemoryStream(handle, length, readOnly, ownsHandle) @@ -121,7 +121,7 @@ namespace VNLib.Utils.IO /// public VnMemoryStream(IUnmangedHeap heap, nuint bufferSize, bool zero) { - _ = heap ?? throw new ArgumentNullException(nameof(heap)); + ArgumentNullException.ThrowIfNull(heap); _buffer = heap.Alloc(bufferSize, zero); } @@ -132,7 +132,7 @@ namespace VNLib.Utils.IO /// Initial data public VnMemoryStream(IUnmangedHeap heap, ReadOnlySpan data) { - _ = heap ?? throw new ArgumentNullException(nameof(heap)); + ArgumentNullException.ThrowIfNull(heap); //Alloc the internal buffer to match the data stream _buffer = heap.AllocAndCopy(data); //Set length @@ -147,7 +147,7 @@ namespace VNLib.Utils.IO /// Initial data public VnMemoryStream(IUnmangedHeap heap, ReadOnlyMemory data) { - _ = heap ?? throw new ArgumentNullException(nameof(heap)); + ArgumentNullException.ThrowIfNull(heap); //Alloc the internal buffer to match the data stream _buffer = heap.AllocAndCopy(data); //Set length @@ -200,12 +200,9 @@ 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"); - } - + ArgumentNullException.ThrowIfNull(destination); + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(bufferSize, 0); + if (!destination.CanWrite) { throw new IOException("The destinaion stream is not writeable"); @@ -239,12 +236,8 @@ namespace VNLib.Utils.IO /// public override async Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) { - _ = destination ?? throw new ArgumentNullException(nameof(destination)); - - if (bufferSize < 1) - { - throw new ArgumentOutOfRangeException(nameof(bufferSize), "Buffer size must be greater than 0"); - } + ArgumentNullException.ThrowIfNull(destination); + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(bufferSize, 0); if (!destination.CanWrite) { @@ -400,14 +393,9 @@ namespace VNLib.Utils.IO /// public override long Seek(long offset, SeekOrigin origin) { - if (offset < 0) - { - 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"); - } + //gaurd for overflow, offset cannot be greater than platform pointer size + ArgumentOutOfRangeException.ThrowIfGreaterThan(offset, nint.MaxValue); + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(offset, nint.MinValue); //safe cast to nint nint _offset = (nint)offset; @@ -415,16 +403,38 @@ namespace VNLib.Utils.IO switch (origin) { case SeekOrigin.Begin: + + ArgumentOutOfRangeException.ThrowIfNegative(offset); + ArgumentOutOfRangeException.ThrowIfGreaterThan(offset, _length); + //Length will never be greater than nint.Max so output will never exceed nint.max return _position = Math.Min(_length, _offset); + case SeekOrigin.Current: + + if(_offset < 0) + { + ArgumentOutOfRangeException.ThrowIfLessThan(offset, -_position); + } + else + { + ArgumentOutOfRangeException.ThrowIfGreaterThan(offset, LenToPosDiff); + } + //Calc new seek position from current position nint newPos = _position + _offset; return _position = Math.Min(_length, newPos); + case SeekOrigin.End: + + //Must be negative value + ArgumentOutOfRangeException.ThrowIfGreaterThan(_offset, 0, nameof(offset)); + ArgumentOutOfRangeException.ThrowIfLessThan(_offset, -_length, nameof(offset)); + //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); + nint realIndex = _length + _offset; return _position = Math.Min(realIndex, 0); + default: throw new ArgumentException("Stream operation is not supported on current stream"); } @@ -446,14 +456,9 @@ namespace VNLib.Utils.IO { throw new NotSupportedException("This stream is readonly"); } - if (value < 0) - { - 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"); - } + + ArgumentOutOfRangeException.ThrowIfNegative(value); + ArgumentOutOfRangeException.ThrowIfGreaterThan(value, nint.MaxValue); nint _value = (nint)value; @@ -468,9 +473,11 @@ namespace VNLib.Utils.IO } /// + /// public override void Write(byte[] buffer, int offset, int count) => Write(buffer.AsSpan(offset, count)); /// + /// public override void Write(ReadOnlySpan buffer) { if (_isReadonly) @@ -494,6 +501,7 @@ namespace VNLib.Utils.IO } /// + /// public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { //Write synchronously and return a completed task @@ -502,6 +510,7 @@ namespace VNLib.Utils.IO } /// + /// public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) { //Write synchronously and return a completed task @@ -510,6 +519,7 @@ namespace VNLib.Utils.IO } /// + /// public override void WriteByte(byte value) { Span buf = MemoryMarshal.CreateSpan(ref value, 1); diff --git a/lib/Utils/src/Memory/ArrayPoolBuffer.cs b/lib/Utils/src/Memory/ArrayPoolBuffer.cs index 2f00e66..e728cd7 100644 --- a/lib/Utils/src/Memory/ArrayPoolBuffer.cs +++ b/lib/Utils/src/Memory/ArrayPoolBuffer.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Utils @@ -91,11 +91,8 @@ namespace VNLib.Utils.Memory /// Minimum size of the buffer /// Set the zero memory flag on close public ArrayPoolBuffer(ArrayPool pool, int minSize, bool zero = false) - { - Pool = pool ?? throw new ArgumentNullException(nameof(pool)); - Buffer = pool.Rent(minSize, zero); - InitSize = minSize; - } + :this(pool, pool.Rent(minSize, zero), minSize) + { } /// /// Initialzies a new from the specified rented array @@ -108,12 +105,13 @@ namespace VNLib.Utils.Memory /// public ArrayPoolBuffer(ArrayPool pool, T[] array, int size) { - Pool = pool ?? throw new ArgumentNullException(nameof(pool)); - Buffer = array ?? throw new ArgumentNullException(nameof(array)); - - if (size < 0 || size > array.Length) - throw new ArgumentOutOfRangeException(nameof(size)); + ArgumentNullException.ThrowIfNull(pool); + ArgumentNullException.ThrowIfNull(array); + ArgumentOutOfRangeException.ThrowIfNegative(size); + ArgumentOutOfRangeException.ThrowIfGreaterThan(size, array.Length); + Pool = pool; + Buffer = array; InitSize = size; } @@ -209,7 +207,11 @@ namespace VNLib.Utils.Memory //Pin, will also check bounds /// - public MemoryHandle Pin(int elementIndex) => MemoryUtil.PinArrayAndGetHandle(Buffer, elementIndex); + public MemoryHandle Pin(int elementIndex) + { + Check(); + return MemoryUtil.PinArrayAndGetHandle(Buffer, elementIndex); + } void IPinnable.Unpin() { diff --git a/lib/Utils/src/Memory/MemoryHandle.cs b/lib/Utils/src/Memory/MemoryHandle.cs index f474abd..09d4c32 100644 --- a/lib/Utils/src/Memory/MemoryHandle.cs +++ b/lib/Utils/src/Memory/MemoryHandle.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Utils @@ -106,7 +106,7 @@ namespace VNLib.Utils.Memory public bool CanRealloc { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Heap != null && Heap.CreationFlags.HasFlag(HeapCreation.SupportsRealloc); + get => !IsClosed && Heap != null && Heap.CreationFlags.HasFlag(HeapCreation.SupportsRealloc); } /// @@ -184,11 +184,7 @@ namespace VNLib.Utils.Memory [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe T* GetOffset(nuint elements) { - if (elements >= _length) - { - throw new ArgumentOutOfRangeException(nameof(elements), "Element offset cannot be larger than allocated size"); - } - + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(elements, _length); this.ThrowIfClosed(); //Get ptr and offset it @@ -212,30 +208,26 @@ namespace VNLib.Utils.Memory /// public unsafe MemoryHandle Pin(int elementIndex) { - if (elementIndex < 0) - { - throw new ArgumentOutOfRangeException(nameof(elementIndex)); - } + ArgumentOutOfRangeException.ThrowIfNegative(elementIndex); //Get ptr and guard checks before adding the referrence T* ptr = GetOffset((nuint)elementIndex); bool addRef = false; + //use the pinned field as success val DangerousAddRef(ref addRef); + + //If adding ref failed, the handle is closed + ObjectDisposedException.ThrowIf(!addRef, this); + //Create a new system.buffers memory handle from the offset ptr address - return !addRef - ? throw new ObjectDisposedException("Failed to increase referrence count on the memory handle because it was released") - : new MemoryHandle(ptr, pinnable: this); + return new MemoryHandle(ptr, pinnable: this); } /// /// - public void Unpin() - { - //Dec count on release - DangerousRelease(); - } + public void Unpin() => DangerousRelease(); /// protected override bool ReleaseHandle() => Heap.Free(ref handle); diff --git a/lib/Utils/src/Memory/MemoryUtil.cs b/lib/Utils/src/Memory/MemoryUtil.cs index 1e0d11a..dacb6b4 100644 --- a/lib/Utils/src/Memory/MemoryUtil.cs +++ b/lib/Utils/src/Memory/MemoryUtil.cs @@ -520,10 +520,7 @@ namespace VNLib.Utils.Memory [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void CopyStruct(ref byte source, T* target) where T : unmanaged { - if (target == null) - { - throw new ArgumentNullException(nameof(target)); - } + ArgumentNullException.ThrowIfNull(target); CopyStruct(ref source, ref *target); } @@ -593,11 +590,7 @@ namespace VNLib.Utils.Memory [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void CopyStruct(T* source, ref byte target) where T : unmanaged { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - + ArgumentNullException.ThrowIfNull(source); CopyStruct(ref *source, ref target); } @@ -633,10 +626,7 @@ namespace VNLib.Utils.Memory public static void CopyStruct(ref T source, Span target) where T : unmanaged { //check that the span is large enough to hold the structure - if (target.Length < sizeof(T)) - { - throw new ArgumentException("Target span is smaller than the size of the structure"); - } + ArgumentOutOfRangeException.ThrowIfLessThan(target.Length, sizeof(T), nameof(target)); CopyStruct(ref source, ref MemoryMarshal.GetReference(target)); } @@ -657,10 +647,9 @@ namespace VNLib.Utils.Memory [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void CopyStruct(T* source, Span target) where T : unmanaged { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } + ArgumentNullException.ThrowIfNull(source); + ArgumentOutOfRangeException.ThrowIfLessThan(target.Length, sizeof(T), nameof(target)); + CopyStruct(ref *source, target); } @@ -732,14 +721,8 @@ namespace VNLib.Utils.Memory [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void CloneStruct(T* source, T* target) where T : unmanaged { - if(source == null) - { - throw new ArgumentNullException(nameof(source)); - } - if(target == null) - { - throw new ArgumentNullException(nameof(target)); - } + ArgumentNullException.ThrowIfNull(source); + ArgumentNullException.ThrowIfNull(target); Unsafe.CopyBlockUnaligned(target, source, (uint)sizeof(T)); } @@ -1102,7 +1085,7 @@ namespace VNLib.Utils.Memory [MethodImpl(MethodImplOptions.AggressiveInlining)] public static nuint ByteSize(IMemoryHandle handle) { - _ = handle ?? throw new ArgumentNullException(nameof(handle)); + ArgumentNullException.ThrowIfNull(handle); return checked(handle.Length * (nuint)Unsafe.SizeOf()); } @@ -1167,12 +1150,7 @@ namespace VNLib.Utils.Memory /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void CheckBounds(IMemoryHandle handle, nuint offset, nuint count) - { - if (offset + count > handle.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset), "Offset or count are beyond the range of the supplied memory handle"); - } - } + => ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + count, handle.Length, nameof(count)); /// /// Checks if the offset/count paramters for the given block @@ -1185,11 +1163,9 @@ namespace VNLib.Utils.Memory [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void CheckBounds(ReadOnlySpan block, int offset, int count) { - //Check span bounds - if (offset < 0 || count < 0 || offset + count > block.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset), "Offset or count are beyond the range of the supplied memory handle"); - } + ArgumentOutOfRangeException.ThrowIfNegative(offset); + ArgumentOutOfRangeException.ThrowIfNegative(count); + ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + count, block.Length, nameof(count)); } /// @@ -1204,11 +1180,9 @@ namespace VNLib.Utils.Memory [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void CheckBounds(Span block, int offset, int count) { - //Check span bounds - if (offset < 0 || count < 0 || offset + count > block.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset), "Offset or count are beyond the range of the supplied memory handle"); - } + ArgumentOutOfRangeException.ThrowIfNegative(offset); + ArgumentOutOfRangeException.ThrowIfNegative(count); + ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + count, block.Length, nameof(count)); } /// @@ -1222,12 +1196,7 @@ namespace VNLib.Utils.Memory /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void CheckBounds(T[] block, nuint offset, nuint count) - { - if (offset + count > (ulong)block.LongLength) - { - throw new ArgumentOutOfRangeException(nameof(offset), "The offset or count is outside of the range of the block of memory"); - } - } + => ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + count, (ulong)block.LongLength, nameof(count)); #endregion @@ -1242,11 +1211,7 @@ namespace VNLib.Utils.Memory /// public static MemoryHandle PinArrayAndGetHandle(T[] array, nint elementOffset) { - if(elementOffset < 0) - { - throw new ArgumentOutOfRangeException(nameof(elementOffset)); - } - + ArgumentOutOfRangeException.ThrowIfNegative(elementOffset); return PinArrayAndGetHandle(array, (nuint)elementOffset); } @@ -1475,6 +1440,8 @@ namespace VNLib.Utils.Memory } } + const nuint _avx32ByteAlignment = 0x20u; + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] private static void _avx32ByteCopy( ref byte src, @@ -1486,7 +1453,7 @@ namespace VNLib.Utils.Memory Debug.Assert(Avx2.IsSupported, "AVX2 is not supported on this platform"); //determine the number of loops - nuint loopCount = count / (nuint)Vector256.Count; + nuint loopCount = count / _avx32ByteAlignment; fixed (byte* srcPtr = &src, dstPtr = &dst) { @@ -1514,7 +1481,7 @@ namespace VNLib.Utils.Memory /// The block size to test /// A value that indicates if the block size is 32byte aligned [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool Is32ByteAligned(nuint size) => unchecked(size % 0x20u) == 0; + public static bool Is32ByteAligned(nuint size) => unchecked(size % _avx32ByteAlignment) == 0; } private static class Refs diff --git a/lib/Utils/src/Memory/MemoryUtilAlloc.cs b/lib/Utils/src/Memory/MemoryUtilAlloc.cs index 0f25682..e2e7434 100644 --- a/lib/Utils/src/Memory/MemoryUtilAlloc.cs +++ b/lib/Utils/src/Memory/MemoryUtilAlloc.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Utils @@ -174,7 +174,7 @@ namespace VNLib.Utils.Memory [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T* StructAlloc(IUnmangedHeap heap, bool zero) where T : unmanaged { - _ = heap ?? throw new ArgumentNullException(nameof(heap)); + ArgumentNullException.ThrowIfNull(heap); return (T*)heap.Alloc(1, (nuint)sizeof(T), zero); } @@ -228,11 +228,9 @@ namespace VNLib.Utils.Memory /// public static void StructFree(IUnmangedHeap heap, void* structPtr) { - _ = heap ?? throw new ArgumentNullException(nameof(heap)); - if(structPtr == null) - { - throw new ArgumentNullException(nameof(structPtr)); - } + ArgumentNullException.ThrowIfNull(heap); + ArgumentNullException.ThrowIfNull(structPtr); + //Get intpointer IntPtr ptr = (IntPtr)structPtr; //Free diff --git a/lib/Utils/src/Memory/UnmanagedHeapBase.cs b/lib/Utils/src/Memory/UnmanagedHeapBase.cs index daf360c..a038358 100644 --- a/lib/Utils/src/Memory/UnmanagedHeapBase.cs +++ b/lib/Utils/src/Memory/UnmanagedHeapBase.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Utils @@ -78,10 +78,7 @@ namespace VNLib.Utils.Memory DangerousAddRef(ref handleCountIncremented); //Failed to increment ref count, class has been disposed - if (!handleCountIncremented) - { - throw new ObjectDisposedException("The handle has been released"); - } + ObjectDisposedException.ThrowIf(handleCountIncremented == false, "The handle has been released"); try { @@ -102,8 +99,12 @@ namespace VNLib.Utils.Memory //Alloc block without lock block = AllocBlock(elements, size, zero); } + + //Check block + NativeMemoryOutOfMemoryException.ThrowIfNullPointer(block); + //Check if block was allocated - return block != IntPtr.Zero ? block : throw new NativeMemoryOutOfMemoryException("Failed to allocate the requested block"); + return block; } catch { @@ -146,7 +147,7 @@ namespace VNLib.Utils.Memory //Decrement handle count DangerousRelease(); //set block to invalid - block = IntPtr.Zero; + block = 0; return result; } @@ -186,12 +187,9 @@ namespace VNLib.Utils.Memory { newBlock = ReAllocBlock(block, elements, size, zero); } - + //Check block - if (newBlock == IntPtr.Zero) - { - throw new NativeMemoryOutOfMemoryException("The memory block could not be resized"); - } + NativeMemoryOutOfMemoryException.ThrowIfNullPointer(newBlock, "The memory block could not be resized"); //Set the new block block = newBlock; @@ -228,11 +226,9 @@ namespace VNLib.Utils.Memory /// public override int GetHashCode() => handle.GetHashCode(); - + /// - public override bool Equals(object? obj) - { - return obj is UnmanagedHeapBase heap && !heap.IsInvalid && !heap.IsClosed && handle == heap.handle; - } + public override bool Equals(object? obj) + => obj is UnmanagedHeapBase heap && !heap.IsInvalid && !heap.IsClosed && handle == heap.handle; } } diff --git a/lib/Utils/src/Native/NativeMemoryOutOfMemoryException.cs b/lib/Utils/src/Native/NativeMemoryOutOfMemoryException.cs index 5a836da..d257233 100644 --- a/lib/Utils/src/Native/NativeMemoryOutOfMemoryException.cs +++ b/lib/Utils/src/Native/NativeMemoryOutOfMemoryException.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Utils @@ -40,5 +40,19 @@ namespace VNLib.Utils.Native public NativeMemoryOutOfMemoryException() { } + + /// + /// Throws an if the pointer is null + /// + /// The pointer value to test + /// The message to use if the pointer is null + /// + public static void ThrowIfNullPointer(nint value, string? message = null) + { + if (value == 0) + { + throw new NativeMemoryOutOfMemoryException(message ?? "Failed to allocate or reallocte memory region"); + } + } } } diff --git a/lib/Utils/src/Native/SafeLibraryHandle.cs b/lib/Utils/src/Native/SafeLibraryHandle.cs index 4772bd4..b3594e1 100644 --- a/lib/Utils/src/Native/SafeLibraryHandle.cs +++ b/lib/Utils/src/Native/SafeLibraryHandle.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Utils @@ -169,11 +169,10 @@ namespace VNLib.Utils.Native { //Increment handle count before obtaining a method bool success = false; - DangerousAddRef(ref success); - if (!success) - { - throw new ObjectDisposedException("The libary has been released!"); - } + DangerousAddRef(ref success); + + ObjectDisposedException.ThrowIf(success == false, "The libary has been released!"); + try { //Get the method pointer diff --git a/lib/Utils/src/VnEncoding.cs b/lib/Utils/src/VnEncoding.cs index 3e895bc..ffdebae 100644 --- a/lib/Utils/src/VnEncoding.cs +++ b/lib/Utils/src/VnEncoding.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Utils @@ -539,7 +539,7 @@ namespace VNLib.Utils //Rent a bin buffer Span binBuffer = stackalloc byte[binSize]; //Write memory to buffer - MemoryMarshal.Write(binBuffer, ref value); + MemoryMarshal.Write(binBuffer, in value); //Convert to base32 return ToBase32String(binBuffer, withPadding); } -- cgit