aboutsummaryrefslogtreecommitdiff
path: root/lib/Utils/src
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-09-14 15:54:30 -0400
committerLibravatar vnugent <public@vaughnnugent.com>2024-09-14 15:54:30 -0400
commitbb706bbfa7519c8b5c506e76a787b9b016acfb75 (patch)
tree12abc5835dc6df87c3aaf7d39dfd541fa26b6529 /lib/Utils/src
parenta19807f7f73ffb023e4ffe93071fe91525fd2c8d (diff)
Squashed commit of the following:HEADmaster
commit 322bbe00f77772ba6b0e25759de95dd517b6014c Author: vnugent <public@vaughnnugent.com> Date: Sat Sep 14 15:43:45 2024 -0400 build: Testing updates and easier dev-testing commit abcd0e0d6cb5532c8a19a8cd8c7dd83e7f143442 Author: vnugent <public@vaughnnugent.com> Date: Wed Sep 11 16:43:20 2024 -0400 Managed library & package updates commit 2ae018af277b808786cf398c689910bc016e7ef0 Author: vnugent <public@vaughnnugent.com> Date: Tue Sep 10 18:59:06 2024 -0400 fix: zero/unsafezero with data types > sizeof(byte) commit 17c646a619eaa101d66871faa8f57c76500a8ad2 Merge: 97d0c46 a19807f Author: vnugent <public@vaughnnugent.com> Date: Sat Sep 7 15:31:01 2024 -0400 Merge branch 'master' into develop
Diffstat (limited to 'lib/Utils/src')
-rw-r--r--lib/Utils/src/ERRNO.cs25
-rw-r--r--lib/Utils/src/Extensions/CacheExtensions.cs77
-rw-r--r--lib/Utils/src/IO/TemporayIsolatedFile.cs57
-rw-r--r--lib/Utils/src/Memory/ArrayPoolBuffer.cs30
-rw-r--r--lib/Utils/src/Memory/ForwardOnlyMemoryReader.cs8
-rw-r--r--lib/Utils/src/Memory/ForwardOnlyMemoryWriter.cs69
-rw-r--r--lib/Utils/src/Memory/MemoryUtil.cs143
-rw-r--r--lib/Utils/src/Memory/NativeHeap.cs17
-rw-r--r--lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs14
-rw-r--r--lib/Utils/src/Memory/PrivateStringManager.cs23
-rw-r--r--lib/Utils/src/Memory/SubSequence.cs7
-rw-r--r--lib/Utils/src/Memory/VnString.cs164
-rw-r--r--lib/Utils/src/Native/SafeLibraryHandle.cs3
-rw-r--r--lib/Utils/src/Resources/ManagedLibrary.cs80
14 files changed, 389 insertions, 328 deletions
diff --git a/lib/Utils/src/ERRNO.cs b/lib/Utils/src/ERRNO.cs
index 684a3c7..0a95780 100644
--- a/lib/Utils/src/ERRNO.cs
+++ b/lib/Utils/src/ERRNO.cs
@@ -30,8 +30,12 @@ namespace VNLib.Utils
/// <summary>
/// Implements a C style integer error code type. Size is platform dependent
/// </summary>
+ /// <remarks>
+ /// Creates a new <see cref="ERRNO"/> from the specified error value
+ /// </remarks>
+ /// <param name="errno">The value of the error to represent</param>
[StructLayout(LayoutKind.Sequential)]
- public readonly struct ERRNO : IEquatable<ERRNO>, ISpanFormattable, IFormattable
+ public readonly struct ERRNO(nint errno) : IEquatable<ERRNO>, ISpanFormattable, IFormattable
{
/// <summary>
/// Represents a successfull error code (true)
@@ -43,13 +47,7 @@ namespace VNLib.Utils
/// </summary>
public static readonly ERRNO E_FAIL = false;
- private readonly nint ErrorCode;
-
- /// <summary>
- /// Creates a new <see cref="ERRNO"/> from the specified error value
- /// </summary>
- /// <param name="errno">The value of the error to represent</param>
- public ERRNO(nint errno) => ErrorCode = errno;
+ private readonly nint ErrorCode = errno;
/// <summary>
/// Creates a new <see cref="ERRNO"/> from an <see cref="int"/> error code. null = 0 = false
@@ -130,13 +128,14 @@ namespace VNLib.Utils
}
return false;
}
+#pragma warning disable CA1305 // Specify IFormatProvider
/// <summary>
/// The integer error value of the current instance in radix 10
/// </summary>
/// <returns>The radix 10 formatted error code</returns>
- public readonly override string ToString() => ErrorCode.ToString();
+ public override readonly string ToString() => ErrorCode.ToString();
/// <summary>
/// Formats the internal nint error code as a string in specified format
/// </summary>
@@ -144,11 +143,15 @@ namespace VNLib.Utils
/// <returns>The formatted error code</returns>
public readonly string ToString(string format) => ErrorCode.ToString(format);
+#pragma warning restore CA1305 // Specify IFormatProvider
+
///<inheritdoc/>
- public readonly bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) => ErrorCode.TryFormat(destination, out charsWritten, format, provider);
+ public readonly bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
+ => ErrorCode.TryFormat(destination, out charsWritten, format, provider);
///<inheritdoc/>
- public readonly string ToString(string? format, IFormatProvider? formatProvider) => ErrorCode.ToString(format, formatProvider);
+ public readonly string ToString(string? format, IFormatProvider? formatProvider)
+ => ErrorCode.ToString(format, formatProvider);
public static ERRNO operator +(ERRNO err, int add) => new(err.ErrorCode + add);
public static ERRNO operator +(ERRNO err, nint add) => new(err.ErrorCode + add);
diff --git a/lib/Utils/src/Extensions/CacheExtensions.cs b/lib/Utils/src/Extensions/CacheExtensions.cs
index 665e282..7efc36d 100644
--- a/lib/Utils/src/Extensions/CacheExtensions.cs
+++ b/lib/Utils/src/Extensions/CacheExtensions.cs
@@ -52,10 +52,7 @@ namespace VNLib.Utils.Extensions
/// </remarks>
public static void StoreRecord<TKey, T>(this IDictionary<TKey, T> store, TKey key, T record) where T : ICacheable
{
- if (store is null)
- {
- throw new ArgumentNullException(nameof(store));
- }
+ ArgumentNullException.ThrowIfNull(store);
T ?oldRecord = default;
lock (store)
@@ -128,10 +125,7 @@ namespace VNLib.Utils.Extensions
/// </remarks>
public static ERRNO TryGetOrEvictRecord<TKey, T>(this IDictionary<TKey, T> store, TKey key, out T? value) where T : ICacheable
{
- if (store is null)
- {
- throw new ArgumentNullException(nameof(store));
- }
+ ArgumentNullException.ThrowIfNull(store);
value = default;
//Cache current date time before entering the lock
@@ -194,10 +188,7 @@ namespace VNLib.Utils.Extensions
/// <returns>True if the record was found and evicted</returns>
public static bool EvictRecord<TKey, T>(this IDictionary<TKey, T> store, TKey key) where T : ICacheable
{
- if (store is null)
- {
- throw new ArgumentNullException(nameof(store));
- }
+ ArgumentNullException.ThrowIfNull(store);
T? record = default;
lock (store)
@@ -218,10 +209,8 @@ namespace VNLib.Utils.Extensions
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="T"></typeparam>
- public static void CollectRecords<TKey, T>(this IDictionary<TKey, T> store) where T : ICacheable
- {
- CollectRecords(store, DateTime.UtcNow);
- }
+ public static void CollectRecords<TKey, T>(this IDictionary<TKey, T> store) where T : ICacheable
+ => CollectRecords(store, DateTime.UtcNow);
/// <summary>
/// Evicts all expired records from the store
@@ -232,10 +221,7 @@ namespace VNLib.Utils.Extensions
/// <param name="validAfter">A time that specifies the time which expired records should be evicted</param>
public static void CollectRecords<TKey, T>(this IDictionary<TKey, T> store, DateTime validAfter) where T : ICacheable
{
- if (store is null)
- {
- throw new ArgumentNullException(nameof(store));
- }
+ ArgumentNullException.ThrowIfNull(store);
//Build a query to get the keys that belong to the expired records
IEnumerable<KeyValuePair<TKey, T>> expired = store.Where(s => s.Value.Expires < validAfter);
//temp list for expired records
@@ -273,15 +259,8 @@ namespace VNLib.Utils.Extensions
/// <param name="useCtx">A callback method that will be passed the record to use within an exclusive context</param>
public static void UseRecord<TKey, T, TState>(this IDictionary<TKey, T> store, TKey key, TState state, Action<T, TState> useCtx) where T: ICacheable
{
- if (store is null)
- {
- throw new ArgumentNullException(nameof(store));
- }
-
- if (useCtx is null)
- {
- throw new ArgumentNullException(nameof(useCtx));
- }
+ ArgumentNullException.ThrowIfNull(store);
+ ArgumentNullException.ThrowIfNull(useCtx);
lock (store)
{
@@ -303,15 +282,8 @@ namespace VNLib.Utils.Extensions
/// <param name="useCtx">A callback method that will be passed the record to use within an exclusive context</param>
public static void UseRecord<TKey, T>(this IDictionary<TKey, T> store, TKey key, Action<T> useCtx) where T : ICacheable
{
- if (store is null)
- {
- throw new ArgumentNullException(nameof(store));
- }
-
- if (useCtx is null)
- {
- throw new ArgumentNullException(nameof(useCtx));
- }
+ ArgumentNullException.ThrowIfNull(store);
+ ArgumentNullException.ThrowIfNull(useCtx);
lock (store)
{
@@ -335,17 +307,15 @@ namespace VNLib.Utils.Extensions
/// <param name="state">A user-token type state parameter to pass to the use callback method</param>
/// <param name="useCtx">A callback method that will be passed the record to use within an exclusive context</param>
/// <remarks>If the record is found, but is expired, the record is evicted from the store. The callback is never invoked</remarks>
- public static void UseIfValid<TKey, T, TState>(this IDictionary<TKey, T> store, TKey key, TState state, Action<T, TState> useCtx) where T : ICacheable
+ public static void UseIfValid<TKey, T, TState>(
+ this IDictionary<TKey, T> store,
+ TKey key,
+ TState state,
+ Action<T, TState> useCtx
+ ) where T : ICacheable
{
- if (store is null)
- {
- throw new ArgumentNullException(nameof(store));
- }
-
- if (useCtx is null)
- {
- throw new ArgumentNullException(nameof(useCtx));
- }
+ ArgumentNullException.ThrowIfNull(store);
+ ArgumentNullException.ThrowIfNull(useCtx);
DateTime now = DateTime.UtcNow;
T? record;
@@ -376,15 +346,8 @@ namespace VNLib.Utils.Extensions
/// <remarks>If the record is found, but is expired, the record is evicted from the store. The callback is never invoked</remarks>
public static void UseIfValid<TKey, T>(this IDictionary<TKey, T> store, TKey key, Action<T> useCtx) where T : ICacheable
{
- if (store is null)
- {
- throw new ArgumentNullException(nameof(store));
- }
-
- if (useCtx is null)
- {
- throw new ArgumentNullException(nameof(useCtx));
- }
+ ArgumentNullException.ThrowIfNull(store);
+ ArgumentNullException.ThrowIfNull(useCtx);
DateTime now = DateTime.UtcNow;
T? record;
diff --git a/lib/Utils/src/IO/TemporayIsolatedFile.cs b/lib/Utils/src/IO/TemporayIsolatedFile.cs
deleted file mode 100644
index 3bee92b..0000000
--- a/lib/Utils/src/IO/TemporayIsolatedFile.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Utils
-* File: TemporayIsolatedFile.cs
-*
-* TemporayIsolatedFile.cs is part of VNLib.Utils which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Utils 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.Utils 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.Utils. If not, see http://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.IO.IsolatedStorage;
-
-namespace VNLib.Utils.IO
-{
- /// <summary>
- /// Allows for temporary files to be generated, used, then removed from an <see cref="IsolatedStorageFile"/>
- /// </summary>
- public sealed class TemporayIsolatedFile : BackingStream<IsolatedStorageFileStream>
- {
- private readonly IsolatedStorageDirectory Storage;
- private readonly string Filename;
- /// <summary>
- /// Creates a new temporary filestream within the specified <see cref="IsolatedStorageFile"/>
- /// </summary>
- /// <param name="storage">The file store to genreate temporary files within</param>
- public TemporayIsolatedFile(IsolatedStorageDirectory storage)
- {
- //Store ref
- this.Storage = storage;
- //Creaet a new random filename
- this.Filename = Path.GetRandomFileName();
- //try to created a new file within the isolaged storage
- this.BaseStream = storage.CreateFile(this.Filename);
- }
- protected override void OnClose()
- {
- //Remove the file from the storage
- Storage.DeleteFile(this.Filename);
- }
- }
-} \ No newline at end of file
diff --git a/lib/Utils/src/Memory/ArrayPoolBuffer.cs b/lib/Utils/src/Memory/ArrayPoolBuffer.cs
index e728cd7..67789de 100644
--- a/lib/Utils/src/Memory/ArrayPoolBuffer.cs
+++ b/lib/Utils/src/Memory/ArrayPoolBuffer.cs
@@ -150,20 +150,16 @@ namespace VNLib.Utils.Memory
/// <returns>A memory structure over the buffer</returns>
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public Memory<T> AsMemory()
- {
- Check();
- return new Memory<T>(Buffer, 0, InitSize);
- }
+ public Memory<T> AsMemory() => AsMemory(start: 0, InitSize);
/// <summary>
/// Gets a memory structure around the internal buffer
/// </summary>
- /// <param name="count">The number of elements included in the result</param>
+ /// <param name="start">The number of elements included in the result</param>
/// <returns>A memory structure over the buffer</returns>
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public Memory<T> AsMemory(int count) => AsMemory()[..count];
+ public Memory<T> AsMemory(int start) => AsMemory(start, InitSize - start);
/// <summary>
/// Gets a memory structure around the internal buffer
@@ -173,18 +169,20 @@ namespace VNLib.Utils.Memory
/// <returns>A memory structure over the buffer</returns>
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
- public Memory<T> AsMemory(int start, int count) => AsMemory().Slice(start, count);
+ public Memory<T> AsMemory(int start, int count)
+ {
+ Check();
+ //Memory constructor will check for array bounds
+ return new(Buffer, start, count);
+ }
/// <summary>
/// Gets an array segment around the internal buffer
/// </summary>
/// <returns>The internal array segment</returns>
/// <exception cref="ObjectDisposedException"></exception>
- public ArraySegment<T> AsArraySegment()
- {
- Check();
- return new ArraySegment<T>(Buffer, 0, InitSize);
- }
+ public ArraySegment<T> AsArraySegment() => GetOffsetWrapper(0, InitSize);
+
/// <summary>
/// Gets an array segment around the internal buffer
@@ -194,10 +192,8 @@ namespace VNLib.Utils.Memory
/// <exception cref="ArgumentOutOfRangeException"></exception>
public ArraySegment<T> AsArraySegment(int start, int count)
{
- if(start< 0 || count < 0)
- {
- throw new ArgumentOutOfRangeException(start < 0 ? nameof(start) : nameof(count), "Cannot be less than zero");
- }
+ ArgumentOutOfRangeException.ThrowIfNegative(start);
+ ArgumentOutOfRangeException.ThrowIfNegative(count);
MemoryUtil.CheckBounds(Buffer, (uint)start, (uint)count);
diff --git a/lib/Utils/src/Memory/ForwardOnlyMemoryReader.cs b/lib/Utils/src/Memory/ForwardOnlyMemoryReader.cs
index 53d3d77..df3990c 100644
--- a/lib/Utils/src/Memory/ForwardOnlyMemoryReader.cs
+++ b/lib/Utils/src/Memory/ForwardOnlyMemoryReader.cs
@@ -59,13 +59,17 @@ namespace VNLib.Utils.Memory
/// The number of elements remaining in the window
/// </summary>
public readonly int WindowSize => _size - _position;
-
/// <summary>
/// Advances the window position the specified number of elements
/// </summary>
/// <param name="count">The number of elements to advance the widnow position</param>
- public void Advance(int count) => _position += count;
+ public void Advance(int count)
+ {
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(count, WindowSize);
+
+ _position += count;
+ }
/// <summary>
/// Resets the sliding window to the begining of the buffer
diff --git a/lib/Utils/src/Memory/ForwardOnlyMemoryWriter.cs b/lib/Utils/src/Memory/ForwardOnlyMemoryWriter.cs
index e0fbe41..791d63c 100644
--- a/lib/Utils/src/Memory/ForwardOnlyMemoryWriter.cs
+++ b/lib/Utils/src/Memory/ForwardOnlyMemoryWriter.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -29,43 +29,39 @@ namespace VNLib.Utils.Memory
/// <summary>
/// Provides a mutable sliding buffer writer
/// </summary>
- public record struct ForwardOnlyMemoryWriter<T>
+ /// <param name="Buffer">The buffer to write data to</param>
+ public record struct ForwardOnlyMemoryWriter<T>(Memory<T> Buffer)
{
- /// <summary>
- /// The buffer for writing output data to
- /// </summary>
- public readonly Memory<T> Buffer { get; }
+ private int _written;
/// <summary>
/// The number of characters written to the buffer
/// </summary>
- public int Written { readonly get; set; }
+ public int Written
+ {
+ readonly get => _written;
+ set
+ {
+ ArgumentOutOfRangeException.ThrowIfNegative(value);
+ _written = value;
+ }
+ }
/// <summary>
/// The number of characters remaining in the buffer
/// </summary>
- public readonly int RemainingSize => Buffer.Length - Written;
+ public readonly int RemainingSize => Buffer.Length - _written;
/// <summary>
/// The remaining buffer window
/// </summary>
- public readonly Memory<T> Remaining => Buffer[Written..];
-
- /// <summary>
- /// Creates a new <see cref="ForwardOnlyWriter{T}"/> assigning the specified buffer
- /// </summary>
- /// <param name="buffer">The buffer to write data to</param>
- public ForwardOnlyMemoryWriter(Memory<T> buffer)
- {
- Buffer = buffer;
- Written = 0;
- }
-
+ public readonly Memory<T> Remaining => Buffer[_written..];
+
/// <summary>
/// Returns a compiled string from the characters written to the buffer
/// </summary>
/// <returns>A string of the characters written to the buffer</returns>
- public readonly override string ToString() => Buffer[..Written].ToString();
+ public readonly override string ToString() => Buffer[.._written].ToString();
/// <summary>
/// Appends a sequence to the buffer
@@ -75,15 +71,14 @@ namespace VNLib.Utils.Memory
public void Append(ReadOnlyMemory<T> data)
{
//Make sure the current window is large enough to buffer the new string
- if (data.Length > RemainingSize)
- {
- throw new ArgumentOutOfRangeException(nameof(Remaining), "The internal buffer does not have enough buffer space");
- }
- Memory<T> window = Buffer[Written..];
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(data.Length, RemainingSize, nameof(data));
+
+ Memory<T> window = Buffer[_written..];
+
//write data to window
data.CopyTo(window);
- //update char position
- Written += data.Length;
+
+ Advance(data.Length);
}
/// <summary>
@@ -94,12 +89,10 @@ namespace VNLib.Utils.Memory
public void Append(T c)
{
//Make sure the current window is large enough to buffer the new string
- if (RemainingSize == 0)
- {
- throw new ArgumentOutOfRangeException(nameof(Remaining), "The internal buffer does not have enough buffer space");
- }
+ ArgumentOutOfRangeException.ThrowIfZero(RemainingSize);
+
//Write data to buffer and increment the buffer position
- Buffer.Span[Written++] = c;
+ Buffer.Span[_written++] = c;
}
/// <summary>
@@ -109,17 +102,15 @@ namespace VNLib.Utils.Memory
/// <exception cref="ArgumentOutOfRangeException"></exception>
public void Advance(int count)
{
- if (count > RemainingSize)
- {
- throw new ArgumentOutOfRangeException(nameof(count), count, "Cannot advance past the end of the buffer");
- }
- Written += count;
+ ArgumentOutOfRangeException.ThrowIfGreaterThan(count, RemainingSize);
+
+ _written += count;
}
/// <summary>
/// Resets the writer by setting the <see cref="Written"/>
/// property to 0.
/// </summary>
- public void Reset() => Written = 0;
+ public void Reset() => _written = 0;
}
}
diff --git a/lib/Utils/src/Memory/MemoryUtil.cs b/lib/Utils/src/Memory/MemoryUtil.cs
index 1d3bccb..cbaaa2f 100644
--- a/lib/Utils/src/Memory/MemoryUtil.cs
+++ b/lib/Utils/src/Memory/MemoryUtil.cs
@@ -155,7 +155,8 @@ namespace VNLib.Utils.Memory
/// <returns>An <see cref="IUnmangedHeap"/> for the current process</returns>
/// <exception cref="SystemException"></exception>
/// <exception cref="DllNotFoundException"></exception>
- public static IUnmangedHeap InitializeNewHeapForProcess(bool globalZero = false) => InitHeapInternal(false, false, globalZero);
+ public static IUnmangedHeap InitializeNewHeapForProcess(bool globalZero = false)
+ => InitHeapInternal(false, false, globalZero);
private static IUnmangedHeap InitHeapInternal(bool isShared, bool enableStats, bool globalZero)
{
@@ -228,6 +229,19 @@ namespace VNLib.Utils.Memory
#region Zero
+ [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
+ private static void ZeroByRef<T>(ref T src, uint elements)
+ {
+ Debug.Assert(Unsafe.IsNullRef(ref src) == false, "Null reference passed to ZeroByRef");
+
+ //Call init block on bytes
+ Unsafe.InitBlock(
+ ref Refs.AsByte(ref src, 0),
+ value: 0,
+ byteCount: ByteCount<T>(elements)
+ );
+ }
+
/// <summary>
/// Zeros a block of memory of umanged type. If Windows is detected at runtime, calls RtlSecureZeroMemory Win32 function
/// </summary>
@@ -241,11 +255,10 @@ namespace VNLib.Utils.Memory
return;
}
- //Calls memset
ZeroByRef(
- ref Refs.AsByte(block, 0),
- (uint)block.Length
- );
+ ref MemoryMarshal.GetReference(block), //Get typed reference
+ (uint)block.Length //block must be a positive value
+ );
}
/// <summary>
@@ -260,28 +273,18 @@ namespace VNLib.Utils.Memory
{
return;
}
-
- uint byteSize = ByteCount<T>((uint)block.Length);
//Pin memory and get pointer
using MemoryHandle handle = block.Pin();
- //Calls memset
- Unsafe.InitBlock(handle.Pointer, 0, byteSize);
- }
-
- [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
- private static void ZeroByRef<T>(ref T src, uint elements)
- {
- Debug.Assert(Unsafe.IsNullRef(ref src) == false, "Null reference passed to ZeroByRef");
- //Call init block on bytes
+ //Calls memset
Unsafe.InitBlock(
- ref Refs.AsByte(ref src, 0),
- 0,
- ByteCount<T>(elements)
+ startAddress: handle.Pointer,
+ value: 0,
+ byteCount: ByteCount<T>((uint)block.Length)
);
}
-
+
/*
* Initializing a non-readonly span/memory as of .NET 6.0 is a reference
* reintpretation, essentially a pointer cast, so there is little/no cost
@@ -294,7 +297,8 @@ namespace VNLib.Utils.Memory
/// <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 : struct => UnsafeZeroMemory<T>(block);
+ public static void InitializeBlock<T>(Span<T> block) where T : struct
+ => UnsafeZeroMemory<T>(block);
/// <summary>
/// Initializes a block of memory with zeros
@@ -302,7 +306,8 @@ namespace VNLib.Utils.Memory
/// <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 : struct => UnsafeZeroMemory<T>(block);
+ public static void InitializeBlock<T>(Memory<T> block) where T : struct
+ => UnsafeZeroMemory<T>(block);
/// <summary>
/// Initializes the entire array with zeros
@@ -398,7 +403,8 @@ namespace VNLib.Utils.Memory
/// <param name="block">A pointer to the block of memory to zero</param>
/// <param name="itemCount">The number of elements in the block to zero</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void InitializeBlock<T>(IntPtr block, int itemCount) where T : unmanaged => InitializeBlock((T*)block, itemCount);
+ public static void InitializeBlock<T>(IntPtr block, int itemCount) where T : unmanaged
+ => InitializeBlock((T*)block, itemCount);
/// <summary>
/// Zeroes a block of memory pointing to the structure
@@ -434,7 +440,8 @@ namespace VNLib.Utils.Memory
/// <typeparam name="T">The structure type</typeparam>
/// <param name="structPtr">The pointer to the allocated structure</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void ZeroStruct<T>(void* structPtr) where T: unmanaged => ZeroStruct((T*)structPtr);
+ public static void ZeroStruct<T>(void* structPtr) where T: unmanaged
+ => ZeroStruct((T*)structPtr);
/// <summary>
/// Zeroes a block of memory pointing to the structure
@@ -442,7 +449,8 @@ namespace VNLib.Utils.Memory
/// <typeparam name="T">The structure type</typeparam>
/// <param name="block">The pointer to the allocated structure</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void ZeroStruct<T>(IntPtr block) where T : unmanaged => ZeroStruct<T>(block.ToPointer());
+ public static void ZeroStruct<T>(IntPtr block) where T : unmanaged
+ => ZeroStruct<T>(block.ToPointer());
#endregion
@@ -462,10 +470,11 @@ namespace VNLib.Utils.Memory
ThrowIfNullRef(in source, nameof(target));
ThrowIfNullRef(ref target, nameof(target));
- //Recover byte reference of target struct
- ref byte dst = ref Unsafe.As<T, byte>(ref target);
-
- Unsafe.CopyBlockUnaligned(ref dst, in source, (uint)sizeof(T));
+ Unsafe.CopyBlockUnaligned(
+ destination: ref Unsafe.As<T, byte>(ref target), //Recover byte reference of target struct
+ in source,
+ byteCount: ByteCount<T>(1u)
+ );
}
/// <summary>
@@ -485,11 +494,12 @@ namespace VNLib.Utils.Memory
ThrowIfNullRef(in source, nameof(source));
ThrowIfNullRef(in target, nameof(target));
- //Recover byte reference to struct
- ref byte src = ref Unsafe.As<T, byte>(ref Unsafe.AsRef(in source));
-
//Memmove
- Unsafe.CopyBlockUnaligned(ref target, ref src, (uint)sizeof(T));
+ Unsafe.CopyBlockUnaligned(
+ ref target,
+ in Unsafe.As<T, byte>(ref Unsafe.AsRef(in source)), //Recover byte reference to struct
+ byteCount: ByteCount<T>(1u)
+ );
}
@@ -594,7 +604,8 @@ namespace VNLib.Utils.Memory
/// <param name="target">A reference to the first byte of the memory location to copy the struct data to</param>
/// <exception cref="ArgumentNullException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CopyStruct<T>(void* source, ref byte target) where T : unmanaged => CopyStruct((T*)source, ref target);
+ public static void CopyStruct<T>(void* source, ref byte target) where T : unmanaged
+ => CopyStruct((T*)source, ref target);
/// <summary>
/// Copies the memory of the structure pointed to by the source pointer to the target
@@ -660,7 +671,8 @@ namespace VNLib.Utils.Memory
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CopyStruct<T>(void* source, Span<byte> target) where T : unmanaged => CopyStruct((T*)source, target);
+ public static void CopyStruct<T>(void* source, Span<byte> target) where T : unmanaged
+ => CopyStruct((T*)source, target);
/// <summary>
/// Copies the memory of the structure pointed to by the source pointer to the target
@@ -675,7 +687,8 @@ namespace VNLib.Utils.Memory
/// <param name="target">A reference to the first byte of the memory location to copy the struct data to</param>
/// <exception cref="ArgumentNullException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CopyStruct<T>(IntPtr source, ref byte target) where T : unmanaged => CopyStruct(ref GetRef<T>(source), ref target);
+ public static void CopyStruct<T>(IntPtr source, ref byte target) where T : unmanaged
+ => CopyStruct(ref GetRef<T>(source), ref target);
/// <summary>
@@ -694,7 +707,7 @@ namespace VNLib.Utils.Memory
Unsafe.CopyBlockUnaligned(
ref Refs.AsByte(ref target, 0),
in Refs.AsByteR(in source, 0),
- (uint)sizeof(T)
+ byteCount: ByteCount<T>(1u)
);
}
@@ -711,7 +724,11 @@ namespace VNLib.Utils.Memory
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(target);
- Unsafe.CopyBlockUnaligned(target, source, (uint)sizeof(T));
+ Unsafe.CopyBlockUnaligned(
+ destination: target,
+ source,
+ byteCount: ByteCount<T>(1u)
+ );
}
@@ -735,7 +752,7 @@ namespace VNLib.Utils.Memory
return;
}
- //Check bounds
+ //Check bounds (will verify that count is a positive integer)
CheckBounds(source, sourceOffset, count);
CheckBounds(dest, destOffset, (uint)count);
@@ -1151,7 +1168,7 @@ namespace VNLib.Utils.Memory
public static nuint ByteSize<T>(IMemoryHandle<T> handle)
{
ArgumentNullException.ThrowIfNull(handle);
- return checked(handle.Length * (nuint)Unsafe.SizeOf<T>());
+ return ByteCount<T>(handle.Length);
}
/// <summary>
@@ -1162,7 +1179,8 @@ namespace VNLib.Utils.Memory
/// <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));
+ public static nuint ByteSize<T>(in UnsafeMemoryHandle<T> handle) where T : unmanaged
+ => ByteCount<T>(handle.Length);
/// <summary>
/// Gets the byte multiple of the length parameter
@@ -1172,7 +1190,8 @@ namespace VNLib.Utils.Memory
/// <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>());
+ public static nuint ByteCount<T>(nuint elementCount)
+ => checked(elementCount * (nuint)Unsafe.SizeOf<T>());
/// <summary>
/// Gets the byte multiple of the length parameter
@@ -1182,7 +1201,8 @@ namespace VNLib.Utils.Memory
/// <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>());
+ public static uint ByteCount<T>(uint elementCount)
+ => checked(elementCount * (uint)Unsafe.SizeOf<T>());
/// <summary>
/// Gets the byte multiple of the length parameter. NOTE: Does not verify negative values
@@ -1192,7 +1212,8 @@ namespace VNLib.Utils.Memory
/// <returns>The byte multiple of the number of elments</returns>
/// <exception cref="OverflowException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static nint ByteCount<T>(nint elementCount) => checked(elementCount * Unsafe.SizeOf<T>());
+ public static nint ByteCount<T>(nint elementCount)
+ => checked(elementCount * Unsafe.SizeOf<T>());
/// <summary>
/// Gets the byte multiple of the length parameter. NOTE: Does not verify negative values
@@ -1202,7 +1223,8 @@ namespace VNLib.Utils.Memory
/// <returns>The byte multiple of the number of elments</returns>
/// <exception cref="OverflowException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int ByteCount<T>(int elementCount) => checked(elementCount * Unsafe.SizeOf<T>());
+ public static int ByteCount<T>(int elementCount)
+ => checked(elementCount * Unsafe.SizeOf<T>());
/// <summary>
/// Checks if the offset/count paramters for the given memory handle
@@ -1243,12 +1265,8 @@ namespace VNLib.Utils.Memory
/// <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)
- {
- ArgumentOutOfRangeException.ThrowIfNegative(offset);
- ArgumentOutOfRangeException.ThrowIfNegative(count);
- ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + count, block.Length, nameof(count));
- }
+ public static void CheckBounds<T>(Span<T> block, int offset, int count)
+ => CheckBounds((ReadOnlySpan<T>)block, offset, count);
/// <summary>
/// Checks if the offset/count paramters for the given block
@@ -1277,12 +1295,8 @@ namespace VNLib.Utils.Memory
/// <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>(Memory<T> block, int offset, int count)
- {
- ArgumentOutOfRangeException.ThrowIfNegative(offset);
- ArgumentOutOfRangeException.ThrowIfNegative(count);
- ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + count, block.Length, nameof(count));
- }
+ public static void CheckBounds<T>(Memory<T> block, int offset, int count)
+ => CheckBounds((ReadOnlyMemory<T>)block, offset, count);
/// <summary>
/// Checks if the offset/count paramters for the given block
@@ -1406,7 +1420,8 @@ namespace VNLib.Utils.Memory
/// <param name="size">The size of the sequence</param>
/// <returns>The span pointing to the memory at the supplied addres</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<T> GetSpan<T>(IntPtr address, int size) => new(address.ToPointer(), size);
+ public static Span<T> GetSpan<T>(IntPtr address, int size)
+ => new(address.ToPointer(), size);
/// <summary>
/// Gets a <see cref="Span{T}"/> over the block of memory pointed to by the supplied handle.
@@ -1417,7 +1432,8 @@ namespace VNLib.Utils.Memory
/// <param name="size">The size of the span (the size of the block)</param>
/// <returns>A span over the block of memory pointed to by the handle of the specified size</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<T> GetSpan<T>(ref readonly MemoryHandle handle, int size) => new(handle.Pointer, size);
+ public static Span<T> GetSpan<T>(ref readonly MemoryHandle handle, int size)
+ => new(handle.Pointer, size);
/// <summary>
/// Gets a <see cref="Span{T}"/> over the block of memory pointed to by the supplied handle.
@@ -1427,7 +1443,8 @@ namespace VNLib.Utils.Memory
/// <param name="size">The size of the span (the size of the block)</param>
/// <returns>A span over the block of memory pointed to by the handle of the specified size</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<T> GetSpan<T>(MemoryHandle handle, int size) => new(handle.Pointer, size);
+ public static Span<T> GetSpan<T>(MemoryHandle handle, int size)
+ => new(handle.Pointer, size);
/// <summary>
/// Recovers a reference to the supplied pointer
@@ -1436,7 +1453,8 @@ namespace VNLib.Utils.Memory
/// <param name="address">The base address to cast to a reference</param>
/// <returns>The reference to the supplied address</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ref T GetRef<T>(IntPtr address) => ref Unsafe.AsRef<T>(address.ToPointer());
+ public static ref T GetRef<T>(IntPtr address)
+ => ref Unsafe.AsRef<T>(address.ToPointer());
/// <summary>
/// Recovers a reference to the supplied pointer
@@ -1458,7 +1476,8 @@ namespace VNLib.Utils.Memory
/// <param name="handle">A reference to the handle to get the intpr for</param>
/// <returns>A managed pointer from the handle</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static IntPtr GetIntptr(ref readonly MemoryHandle handle) => new(handle.Pointer);
+ public static IntPtr GetIntptr(ref readonly MemoryHandle handle)
+ => new(handle.Pointer);
/// <summary>
/// Rounds the requested byte size up to the nearest page
diff --git a/lib/Utils/src/Memory/NativeHeap.cs b/lib/Utils/src/Memory/NativeHeap.cs
index fb9612c..9a2e19a 100644
--- a/lib/Utils/src/Memory/NativeHeap.cs
+++ b/lib/Utils/src/Memory/NativeHeap.cs
@@ -62,9 +62,9 @@ namespace VNLib.Utils.Memory
//Create a flags structure with defaults
UnmanagedHeapDescriptor hFlags = new()
{
- CreationFlags = creationFlags,
- Flags = flags,
- HeapPointer = IntPtr.Zero
+ CreationFlags = creationFlags,
+ Flags = flags,
+ HeapPointer = IntPtr.Zero
};
//Create the heap
@@ -117,15 +117,18 @@ namespace VNLib.Utils.Memory
///<inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected override IntPtr AllocBlock(nuint elements, nuint size, bool zero) => MethodTable.Alloc(handle, elements, size, zero);
+ protected override IntPtr AllocBlock(nuint elements, nuint size, bool zero)
+ => MethodTable.Alloc(handle, elements, size, zero);
///<inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected override IntPtr ReAllocBlock(IntPtr block, nuint elements, nuint size, bool zero) => MethodTable.Realloc(handle, block, elements, size, zero);
+ protected override IntPtr ReAllocBlock(IntPtr block, nuint elements, nuint size, bool zero)
+ => MethodTable.Realloc(handle, block, elements, size, zero);
///<inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected override bool FreeBlock(IntPtr block) => MethodTable.Free(handle, block);
+ protected override bool FreeBlock(IntPtr block)
+ => MethodTable.Free(handle, block);
///<inheritdoc/>
protected override bool ReleaseHandle()
@@ -139,7 +142,7 @@ namespace VNLib.Utils.Memory
//Cleanup the method table
MethodTable = default;
- Trace.WriteLine($"Successfully deestroyed user defined heap 0x{handle:x}");
+ Trace.WriteLine($"Successfully destroyed user defined heap 0x{handle:x}");
return ret;
}
diff --git a/lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs b/lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs
index a17a906..8a752f9 100644
--- a/lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs
+++ b/lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -50,7 +50,8 @@ namespace VNLib.Utils.Memory
///<exception cref="OutOfMemoryException"></exception>
///<exception cref="ObjectDisposedException"></exception>
///<exception cref="ArgumentOutOfRangeException"></exception>
- public override IMemoryOwner<T> Rent(int minBufferSize = 0) => Heap.DirectAlloc<T>(minBufferSize, false);
+ public override IMemoryOwner<T> Rent(int minBufferSize = 0)
+ => Heap.DirectAlloc<T>(minBufferSize, zero: false);
/// <summary>
/// Allocates a new <see cref="MemoryManager{T}"/> of a different data type from the pool
@@ -58,13 +59,10 @@ namespace VNLib.Utils.Memory
/// <typeparam name="TDifType">The unmanaged data type to allocate for</typeparam>
/// <param name="minBufferSize">Minumum size of the buffer</param>
/// <returns>The memory owner of a different data type</returns>
- public IMemoryOwner<TDifType> Rent<TDifType>(int minBufferSize = 0) where TDifType : unmanaged => Heap.DirectAlloc<TDifType>(minBufferSize, false);
+ public IMemoryOwner<TDifType> Rent<TDifType>(int minBufferSize = 0) where TDifType : unmanaged
+ => Heap.DirectAlloc<TDifType>(minBufferSize, zero: false);
///<inheritdoc/>
- protected override void Dispose(bool disposing)
- {
- //Dispose the heap
- Heap.Dispose();
- }
+ protected override void Dispose(bool disposing) => Heap.Dispose();
}
}
diff --git a/lib/Utils/src/Memory/PrivateStringManager.cs b/lib/Utils/src/Memory/PrivateStringManager.cs
index 2bc825c..1a7b3cf 100644
--- a/lib/Utils/src/Memory/PrivateStringManager.cs
+++ b/lib/Utils/src/Memory/PrivateStringManager.cs
@@ -61,11 +61,11 @@ namespace VNLib.Utils.Memory
private void SetValue(int index, string? value)
{
//Try to get the old reference and erase it
- StringRef strRef = ProtectedElements[index];
+ ref StringRef strRef = ref ProtectedElements[index];
strRef.Erase();
- //Set the new value and determine if it is interned
- ProtectedElements[index] = StringRef.Create(value);
+ //Assign new string reference
+ strRef = StringRef.Create(value);
}
/// <summary>
@@ -78,7 +78,7 @@ namespace VNLib.Utils.Memory
protected string? CopyStringAtIndex(int index)
{
Check();
- StringRef str = ProtectedElements[index];
+ ref readonly StringRef str = ref ProtectedElements[index];
if(str.Value is null)
{
@@ -101,7 +101,8 @@ namespace VNLib.Utils.Memory
}
///<inheritdoc/>
- protected override void Free() => Array.ForEach(ProtectedElements, static p => p.Erase());
+ protected override void Free()
+ => Array.ForEach(ProtectedElements, static p => p.Erase());
/// <summary>
/// Erases the contents of the supplied string if it
@@ -109,10 +110,14 @@ namespace VNLib.Utils.Memory
/// not be erased, nor will a null string
/// </summary>
/// <param name="str">The reference to the string to zero</param>
- public static void EraseString(string? str) => StringRef.Create(str).Erase();
+ public static void EraseString(string? str)
+ => StringRef.Create(str).Erase();
- private readonly record struct StringRef(string? Value, bool IsInterned)
+ private readonly struct StringRef(string? value, bool isInterned)
{
+ public readonly string? Value = value;
+ public readonly bool IsInterned = isInterned;
+
public readonly void Erase()
{
/*
@@ -125,8 +130,8 @@ namespace VNLib.Utils.Memory
}
}
- internal static StringRef Create(string? str) => str is null ?
- new(null, false)
+ internal static StringRef Create(string? str) => str is null
+ ? new(value: null, isInterned: false)
: new(str, string.IsInterned(str) != null);
}
}
diff --git a/lib/Utils/src/Memory/SubSequence.cs b/lib/Utils/src/Memory/SubSequence.cs
index 80aa084..57c902e 100644
--- a/lib/Utils/src/Memory/SubSequence.cs
+++ b/lib/Utils/src/Memory/SubSequence.cs
@@ -58,12 +58,13 @@ namespace VNLib.Utils.Memory
{
ArgumentNullException.ThrowIfNull(block);
ArgumentOutOfRangeException.ThrowIfNegative(size);
- Size = size;
- Handle = block;
- _offset = offset;
//Check handle bounds
MemoryUtil.CheckBounds(block, offset, (uint)size);
+
+ Size = size;
+ Handle = block;
+ _offset = offset;
}
/// <summary>
diff --git a/lib/Utils/src/Memory/VnString.cs b/lib/Utils/src/Memory/VnString.cs
index 429de43..e0f7283 100644
--- a/lib/Utils/src/Memory/VnString.cs
+++ b/lib/Utils/src/Memory/VnString.cs
@@ -64,7 +64,11 @@ namespace VNLib.Utils.Memory
/// </summary>
public bool IsEmpty => Length == 0;
- private VnString(SubSequence<char> sequence) => _stringSequence = sequence;
+ private VnString(IMemoryHandle<char>? handle, SubSequence<char> sequence)
+ {
+ Handle = handle;
+ _stringSequence = sequence;
+ }
private VnString(IMemoryHandle<char> handle, nuint start, int length)
{
@@ -155,15 +159,8 @@ namespace VNLib.Utils.Memory
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static VnString ConsumeHandle(IMemoryHandle<char> handle, nuint start, int length)
{
- if (handle is null)
- {
- throw new ArgumentNullException(nameof(handle));
- }
-
- if (length < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(length));
- }
+ ArgumentNullException.ThrowIfNull(handle);
+ ArgumentOutOfRangeException.ThrowIfNegative(length);
//Check handle bounts
MemoryUtil.CheckBounds(handle, start, (nuint)length);
@@ -217,37 +214,46 @@ namespace VNLib.Utils.Memory
try
{
int length = 0;
- //span ref to bin buffer
- Span<byte> buffer = binBuffer.Span;
+
//Run in checked context for overflows
checked
{
do
- {
- //read
- int read = stream.Read(buffer);
- //guard
+ {
+ int read = stream.Read(binBuffer.Span);
+
if (read <= 0)
{
break;
}
+
//Slice into only the read data
- ReadOnlySpan<byte> readbytes = buffer[..read];
+ ReadOnlySpan<byte> readbytes = binBuffer.AsSpan(0, read);
+
//get num chars
int numChars = encoding.GetCharCount(readbytes);
+
//Guard for overflow
if (((ulong)(numChars + length)) >= int.MaxValue)
{
throw new OverflowException();
}
+
//Re-alloc buffer
charBuffer.ResizeIfSmaller(length + numChars);
+
//Decode and update position
- _= encoding.GetChars(readbytes, charBuffer.Span.Slice(length, numChars));
+ _= encoding.GetChars(
+ bytes: readbytes,
+ chars: charBuffer.AsSpan(length, numChars)
+ );
+
//Update char count
length += numChars;
+
} while (true);
}
+
return ConsumeHandle(charBuffer, 0, length);
}
catch
@@ -330,11 +336,15 @@ namespace VNLib.Utils.Memory
charBuffer.ResizeIfSmaller(length + numChars);
//Decode and update position
- _ = encoding.GetChars(binBuffer.GetSpan()[..read], charBuffer.Span.Slice(length, numChars));
+ _ = encoding.GetChars(
+ bytes: binBuffer.GetSpan()[..read],
+ chars: charBuffer.AsSpan(length, numChars)
+ );
//Update char count
length += numChars;
} while (true);
+
return ConsumeHandle(charBuffer, 0, length);
}
catch
@@ -355,7 +365,6 @@ namespace VNLib.Utils.Memory
/// <exception cref="ObjectDisposedException"></exception>
public char CharAt(int index)
{
- //Check
Check();
//Check bounds
@@ -377,18 +386,21 @@ namespace VNLib.Utils.Memory
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public VnString Substring(int start, int count)
- {
- //Check
+ {
Check();
+
ArgumentOutOfRangeException.ThrowIfNegative(start, nameof(start));
ArgumentOutOfRangeException.ThrowIfNegative(count, nameof(count));
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(start + count, Length, nameof(start));
- //get sub-sequence slice for the current string
- SubSequence<char> sub = _stringSequence.Slice((nuint)start, count);
-
- //Create new string with offsets pointing to same internal referrence
- return new VnString(sub);
+ /*
+ * Slice the string and do not pass the handle even if we have it because the new
+ * instance does own the buffer
+ */
+ return new VnString(
+ handle: null,
+ _stringSequence.Slice((nuint)start, count)
+ );
}
/// <summary>
@@ -418,12 +430,18 @@ namespace VNLib.Utils.Memory
{
get
{
- //get start
- int start = range.Start.IsFromEnd ? Length - range.Start.Value : range.Start.Value;
- //Get end
- int end = range.End.IsFromEnd ? Length - range.End.Value : range.End.Value;
- //Handle strings with no ending range
- return (end >= start) ? Substring(start, (end - start)) : Substring(start);
+
+ int start = range.Start.IsFromEnd
+ ? (Length - range.Start.Value)
+ : range.Start.Value;
+
+ int end = range.End.IsFromEnd
+ ? (Length - range.End.Value)
+ : range.End.Value;
+
+ return (end >= start)
+ ? Substring(start, (end - start))
+ : Substring(start);
}
}
#pragma warning restore IDE0057 // Use range operator
@@ -461,47 +479,85 @@ namespace VNLib.Utils.Memory
public static explicit operator VnString(string value) => new (value);
public static explicit operator VnString(ReadOnlySpan<char> value) => new (value);
public static explicit operator VnString(char[] value) => new (value);
- ///<inheritdoc/>
+
+ /// <inheritdoc/>
+ /// <remarks>
+ /// NOTE: Avoid this overload if possible. If no explict overload is provided,
+ /// it's assumed the datatype is not supported and will return false
+ /// </remarks>
public override bool Equals(object? obj)
{
- if(obj is null)
- {
- return false;
- }
return obj switch
{
- VnString => Equals(obj as VnString), //Use operator overload
- string => Equals(obj as string), //Use operator overload
- char[] => Equals(obj as char[]), //Use operator overload
+ VnString => Equals(obj as VnString),
+ string => Equals(obj as string),
+ char[] => Equals(obj as char[]),
_ => false,
};
}
+
+ ///<inheritdoc/>
+ public bool Equals(ReadOnlySpan<char> other, StringComparison stringComparison = StringComparison.Ordinal)
+ => Length == other.Length && AsSpan().Equals(other, stringComparison);
+
+ ///<inheritdoc/>
+ public bool Equals(VnString? other)
+ => Equals(other, StringComparison.Ordinal);
+
///<inheritdoc/>
- public bool Equals(VnString? other) => other is not null && Equals(other.AsSpan());
+ public bool Equals(VnString? other, StringComparison stringComparison)
+ => other is not null && Equals(other.AsSpan(), stringComparison);
+
///<inheritdoc/>
- public bool Equals(VnString? other, StringComparison stringComparison) => other is not null && Equals(other.AsSpan(), stringComparison);
+ public bool Equals(string? other)
+ => Equals(other, StringComparison.Ordinal);
+
///<inheritdoc/>
- public bool Equals(string? other) => Equals(other.AsSpan());
+ public bool Equals(string? other, StringComparison stringComparison)
+ => Equals(other.AsSpan(), stringComparison);
+
///<inheritdoc/>
- public bool Equals(string? other, StringComparison stringComparison) => Equals(other.AsSpan(), stringComparison);
+ public bool Equals(char[]? other)
+ => Equals(other, StringComparison.Ordinal);
+
///<inheritdoc/>
- public bool Equals(char[]? other) => Equals(other.AsSpan());
+ public bool Equals(char[]? other, StringComparison stringComparison)
+ => Equals(other.AsSpan(), stringComparison);
+
///<inheritdoc/>
- public bool Equals(char[]? other, StringComparison stringComparison) => Equals(other.AsSpan(), stringComparison);
+ public bool Equals(in SubSequence<char> other)
+ => Equals(in other, StringComparison.Ordinal);
+
///<inheritdoc/>
- public bool Equals(ReadOnlySpan<char> other, StringComparison stringComparison = StringComparison.Ordinal) => Length == other.Length && AsSpan().Equals(other, stringComparison);
+ public bool Equals(in SubSequence<char> other, StringComparison stringComparison)
+ => Length == other.Size && Equals(other.Span, stringComparison);
+
///<inheritdoc/>
- public bool Equals(in SubSequence<char> other) => Length == other.Size && AsSpan().SequenceEqual(other.Span);
+ public int CompareTo(string? other)
+ => CompareTo(other, StringComparison.Ordinal);
+
///<inheritdoc/>
- public int CompareTo(string? other) => AsSpan().CompareTo(other, StringComparison.Ordinal);
+ ///<exception cref="ArgumentNullException"></exception>
+ public int CompareTo(string? other, StringComparison stringComparison)
+ {
+ ArgumentNullException.ThrowIfNull(other);
+ return CompareTo(other.AsSpan(), stringComparison);
+ }
+
///<inheritdoc/>
///<exception cref="ArgumentNullException"></exception>
public int CompareTo(VnString? other)
{
ArgumentNullException.ThrowIfNull(other);
- return AsSpan().CompareTo(other.AsSpan(), StringComparison.Ordinal);
+ return CompareTo(other.AsSpan(), StringComparison.Ordinal);
}
+ public int CompareTo(ReadOnlySpan<char> other)
+ => AsSpan().CompareTo(other, StringComparison.Ordinal);
+
+ public int CompareTo(ReadOnlySpan<char> other, StringComparison comparison)
+ => AsSpan().CompareTo(other, comparison);
+
/// <summary>
/// Gets a hashcode for the underyling string by using the .NET <see cref="string.GetHashCode()"/>
/// method on the character representation of the data
@@ -512,7 +568,8 @@ namespace VNLib.Utils.Memory
/// a character span etc
/// </remarks>
/// <exception cref="ObjectDisposedException"></exception>
- public override int GetHashCode() => GetHashCode(StringComparison.Ordinal);
+ public override int GetHashCode()
+ => GetHashCode(StringComparison.Ordinal);
/// <summary>
/// Gets a hashcode for the underyling string by using the .NET <see cref="string.GetHashCode()"/>
@@ -525,7 +582,8 @@ namespace VNLib.Utils.Memory
/// a character span etc
/// </remarks>
/// <exception cref="ObjectDisposedException"></exception>
- public int GetHashCode(StringComparison stringComparison) => string.GetHashCode(AsSpan(), stringComparison);
+ public int GetHashCode(StringComparison stringComparison)
+ => string.GetHashCode(AsSpan(), stringComparison);
///<inheritdoc/>
protected override void Free() => Handle?.Dispose();
diff --git a/lib/Utils/src/Native/SafeLibraryHandle.cs b/lib/Utils/src/Native/SafeLibraryHandle.cs
index 4b4ead4..263ac0c 100644
--- a/lib/Utils/src/Native/SafeLibraryHandle.cs
+++ b/lib/Utils/src/Native/SafeLibraryHandle.cs
@@ -39,7 +39,8 @@ namespace VNLib.Utils.Native
///<inheritdoc/>
public override bool IsInvalid => handle == IntPtr.Zero;
- private SafeLibraryHandle(IntPtr libHandle, bool ownsHandle) : base(IntPtr.Zero, ownsHandle) => SetHandle(libHandle);
+ private SafeLibraryHandle(IntPtr libHandle, bool ownsHandle) : base(IntPtr.Zero, ownsHandle)
+ => SetHandle(libHandle);
/// <summary>
/// Loads a native function pointer from the library of the specified name and
diff --git a/lib/Utils/src/Resources/ManagedLibrary.cs b/lib/Utils/src/Resources/ManagedLibrary.cs
index c899156..5faaa19 100644
--- a/lib/Utils/src/Resources/ManagedLibrary.cs
+++ b/lib/Utils/src/Resources/ManagedLibrary.cs
@@ -263,7 +263,8 @@ namespace VNLib.Utils.Resources
/// <param name="flags">The optional method binind flags</param>
/// <returns>The delegate if found <see langword="null"/> otherwise</returns>
/// <exception cref="ArgumentNullException"></exception>
- public static TDelegate? TryGetStaticMethod<TDelegate>(Type type, string methodName, BindingFlags flags = BindingFlags.Public) where TDelegate : Delegate
+ public static TDelegate? TryGetStaticMethod<TDelegate>(Type type, string methodName, BindingFlags flags = BindingFlags.Public)
+ where TDelegate : Delegate
=> TryGetMethodInternal<TDelegate>(type, methodName, null, flags | BindingFlags.Static);
/// <summary>
@@ -276,7 +277,8 @@ namespace VNLib.Utils.Resources
/// <param name="flags">The optional method binind flags</param>
/// <returns>The delegate if found <see langword="null"/> otherwise</returns>
/// <exception cref="ArgumentNullException"></exception>
- public static TDelegate? TryGetStaticMethod<TDelegate, TType>(string methodName,BindingFlags flags = BindingFlags.Public) where TDelegate : Delegate
+ public static TDelegate? TryGetStaticMethod<TDelegate, TType>(string methodName,BindingFlags flags = BindingFlags.Public)
+ where TDelegate : Delegate
=> TryGetMethodInternal<TDelegate>(typeof(TType), methodName, null, flags | BindingFlags.Static);
private static TDelegate? TryGetMethodInternal<TDelegate>(Type type, string methodName, object? target, BindingFlags flags) where TDelegate : Delegate
@@ -293,5 +295,79 @@ namespace VNLib.Utils.Resources
return type.GetMethod(methodName, flags, delegateArgs)
?.CreateDelegate<TDelegate>(target);
}
+
+ /*
+ * NOTE: These functions cannot be optimized (condensed) any furhter. IE: static
+ * and instance method searches. This is because the C# compiler will embed the
+ * call to getType() of the object instead of loading reflection if possible
+ * at runtime. This can cause the type to be undefined at runtime and will not
+ * be able to find some members
+ */
+
+ /// <summary>
+ /// Gets an array of methods that have the specified attribute and match the
+ /// delegate signature of the desired type, and returns them as an array of delegates.
+ /// </summary>
+ /// <typeparam name="TAttr">The function attribute type</typeparam>
+ /// <typeparam name="TFunc">The function delegate type</typeparam>
+ /// <param name="obj">The object instance to get the method delegates for</param>
+ /// <param name="flags">The method binding flags to search for</param>
+ /// <returns>An array of function with the desired attribute assigned, an empty array if no methods are found</returns>
+ public static TFunc[] GetMethodsWithAttribute<TAttr, TFunc>(object obj, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance)
+ where TFunc : Delegate
+ where TAttr : Attribute
+ {
+ ArgumentNullException.ThrowIfNull(obj);
+
+ //Get the delegate type
+ Type funcType = typeof(TFunc);
+
+ //Get the delegate method signature
+ Type[] delegateArgs = funcType.GetMethod("Invoke")!
+ .GetParameters()
+ .Select(static p => p.ParameterType)
+ .ToArray();
+
+ //Get the method with the attribute that matches the same signature as the delegate
+ return obj.GetType()
+ .GetMethods(flags)
+ .Where(static m => m.GetCustomAttribute(typeof(TAttr)) != null)
+ .Where(m => m.GetParameters().Select(static p => p.ParameterType).SequenceEqual(delegateArgs))
+ .Select(method => method.CreateDelegate<TFunc>(obj))
+ .ToArray();
+ }
+
+ /// <summary>
+ /// Gets an array of static methods that have the specified attribute and match the
+ /// delegate signature of the desired type, and returns them as an array of delegates.
+ /// </summary>
+ /// <typeparam name="TAttr">The function attribute type</typeparam>
+ /// <typeparam name="TFunc">The function delegate type</typeparam>
+ /// <param name="classType">Type of the static class to get methods for</param>
+ /// <param name="flags">The method binding flags to search for</param>
+ /// <returns>An array of function with the desired attribute assigned, an empty array if no methods are found</returns>
+ public static TFunc[] GetStaticMethodsWithAttribute<TAttr, TFunc>(Type classType, BindingFlags flags = BindingFlags.Public | BindingFlags.Static)
+ where TFunc : Delegate
+ where TAttr : Attribute
+ {
+ ArgumentNullException.ThrowIfNull(classType);
+
+ //Get the delegate type
+ Type funcType = typeof(TFunc);
+
+ //Get the delegate method signature
+ Type[] delegateArgs = funcType.GetMethod("Invoke")!
+ .GetParameters()
+ .Select(static p => p.ParameterType)
+ .ToArray();
+
+ //Get the method with the attribute that matches the same signature as the delegate
+ return classType.GetType()
+ .GetMethods(flags)
+ .Where(static m => m.GetCustomAttribute(typeof(TAttr)) != null)
+ .Where(m => m.GetParameters().Select(static p => p.ParameterType).SequenceEqual(delegateArgs))
+ .Select(method => method.CreateDelegate<TFunc>(null))
+ .ToArray();
+ }
}
}