Added UnsafeQueue;
This commit is contained in:
@@ -1,22 +1,15 @@
|
|||||||
namespace Misaki.HighPerformance.Unsafe.Collections.Contracts;
|
namespace Misaki.HighPerformance.Unsafe.Collections.Contracts;
|
||||||
|
|
||||||
public unsafe interface IUnsafeCollection<T> : IDisposable where T : unmanaged
|
public unsafe interface IUnsafeCollection<T> : IDisposable
|
||||||
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
public T* Buffer
|
public T* Buffer { get; }
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Size
|
public int Size { get; }
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref T this[int index]
|
public T this[int index] { get; }
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear();
|
public void Clear();
|
||||||
public void ReAlloc(int newSize);
|
public void ReAlloc(int newSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
using Misaki.HighPerformance.Unsafe.Collections.Contracts;
|
using System.Collections;
|
||||||
using Misaki.HighPerformance.Unsafe.Helpers;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Misaki.HighPerformance.Unsafe.Collections.Contracts;
|
||||||
|
using Misaki.HighPerformance.Unsafe.Helpers;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Unsafe.Collections;
|
namespace Misaki.HighPerformance.Unsafe.Collections;
|
||||||
|
|
||||||
public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>, IEnumerable<T> where T : unmanaged
|
public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>, IEnumerable<T>
|
||||||
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
public struct Enumerator : IEnumerator<T>
|
private struct Enumerator : IEnumerator<T>
|
||||||
{
|
{
|
||||||
private UnsafeArray<T> _collection;
|
private UnsafeArray<T> _collection;
|
||||||
private int _index;
|
private int _index;
|
||||||
@@ -44,24 +45,16 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
public T Current
|
public T Current
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get
|
get { return _value; }
|
||||||
{
|
|
||||||
return _value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object IEnumerator.Current
|
object IEnumerator.Current
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get
|
get { return Current; }
|
||||||
{
|
|
||||||
return Current;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose() { }
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private T* _buffer;
|
private T* _buffer;
|
||||||
@@ -70,9 +63,10 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
public readonly T* Buffer => _buffer;
|
public readonly T* Buffer => _buffer;
|
||||||
public readonly int Size => _size;
|
public readonly int Size => _size;
|
||||||
|
|
||||||
public readonly ref T this[int index] => ref UnsafeUtilities.AsRef<T>(_buffer + index);
|
public readonly T this[int index] => UnsafeUtilities.ReadArrayElement<T>(_buffer, index);
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator() => new Enumerator(ref this);
|
public IEnumerator<T> GetEnumerator() => new Enumerator(ref this);
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
public UnsafeArray(int size, AllocationType allocationType)
|
public UnsafeArray(int size, AllocationType allocationType)
|
||||||
@@ -93,7 +87,7 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_buffer = (T*)NativeMemory.AlignedRealloc(_buffer, (nuint)(newSize * sizeof(T)), (nuint)AlignOf<T>());
|
_buffer = (T*)NativeMemory.AlignedRealloc(_buffer, (nuint)(newSize * sizeof(T)), AlignOf<T>());
|
||||||
_size = newSize;
|
_size = newSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,3 +105,4 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
_size = 0;
|
_size = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
using Misaki.HighPerformance.Unsafe.Collections.Contracts;
|
using System.Collections;
|
||||||
using Misaki.HighPerformance.Unsafe.Helpers;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using Misaki.HighPerformance.Unsafe.Collections.Contracts;
|
||||||
|
using Misaki.HighPerformance.Unsafe.Helpers;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Unsafe.Collections;
|
namespace Misaki.HighPerformance.Unsafe.Collections;
|
||||||
|
|
||||||
public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where T : unmanaged
|
public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T>
|
||||||
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
public struct Enumerator : IEnumerator<T>
|
private struct Enumerator : IEnumerator<T>
|
||||||
{
|
{
|
||||||
private UnsafeList<T> _collection;
|
private UnsafeList<T> _collection;
|
||||||
private int _index;
|
private int _index;
|
||||||
@@ -44,24 +44,16 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
public readonly T Current
|
public readonly T Current
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get
|
get { return _value; }
|
||||||
{
|
|
||||||
return _value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly object IEnumerator.Current
|
readonly object IEnumerator.Current
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get
|
get { return Current; }
|
||||||
{
|
|
||||||
return Current;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly void Dispose()
|
public readonly void Dispose() { }
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -90,7 +82,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
{
|
{
|
||||||
var idx = Interlocked.Increment(ref listData->_size) - 1;
|
var idx = Interlocked.Increment(ref listData->_size) - 1;
|
||||||
listData->CheckNoResizeCapacity(idx, 1);
|
listData->CheckNoResizeCapacity(idx, 1);
|
||||||
UnsafeUtilities.WriteArrayElement(listData->_buffer, idx, value);
|
UnsafeUtilities.WriteArrayElement(listData->Buffer, idx, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -102,31 +94,31 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
{
|
{
|
||||||
var idx = Interlocked.Add(ref listData->_size, count) - count;
|
var idx = Interlocked.Add(ref listData->_size, count) - count;
|
||||||
listData->CheckNoResizeCapacity(idx, count);
|
listData->CheckNoResizeCapacity(idx, count);
|
||||||
MemCpy(listData->_buffer + idx, ptr, (uint)(count * sizeof(T)));
|
MemCpy(listData->Buffer + idx, ptr, (uint)(count * sizeof(T)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private T* _buffer;
|
private UnsafeArray<T> _array;
|
||||||
|
|
||||||
private int _size;
|
private int _size;
|
||||||
private int _capacity;
|
|
||||||
|
|
||||||
public readonly T* Buffer => _buffer;
|
public readonly T* Buffer => _array.Buffer;
|
||||||
public readonly int Size => _size;
|
public readonly int Size => _size;
|
||||||
public readonly int Capacity => _capacity;
|
public readonly int Capacity => _array.Size;
|
||||||
|
|
||||||
public readonly ref T this[int index] => ref UnsafeUtilities.ReadArrayElementRef<T>(_buffer, index);
|
public readonly T this[int index] => _array[index];
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator() => new Enumerator(ref this);
|
public IEnumerator<T> GetEnumerator() => new Enumerator(ref this);
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
public ParallelWriter AsParallelWriter() => new((UnsafeList<T>*)UnsafeUtilities.AddressOf(ref this));
|
public ParallelWriter AsParallelWriter() =>
|
||||||
|
new((UnsafeList<T>*)UnsafeUtilities.AddressOf(ref this));
|
||||||
|
|
||||||
public UnsafeList(int capacity, AllocationType allocationType)
|
public UnsafeList(int capacity, AllocationType allocationType)
|
||||||
{
|
{
|
||||||
_buffer = (T*)NativeMemory.AlignedAlloc((nuint)(capacity * sizeof(T)), (nuint)AlignOf<T>());
|
_array = new UnsafeArray<T>(capacity, allocationType);
|
||||||
_size = 0;
|
_size = 0;
|
||||||
_capacity = capacity;
|
|
||||||
|
|
||||||
if (allocationType == AllocationType.Clear)
|
if (allocationType == AllocationType.Clear)
|
||||||
{
|
{
|
||||||
@@ -141,9 +133,11 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
|
|
||||||
private readonly void CheckNoResizeCapacity(int index, int count)
|
private readonly void CheckNoResizeCapacity(int index, int count)
|
||||||
{
|
{
|
||||||
if (index + count > _capacity)
|
if (index + count > Capacity)
|
||||||
{
|
{
|
||||||
throw new Exception($"AddNoResize assumes that list capacity is sufficient (Capacity {Capacity}, Size {Size}), requested count {count}!");
|
throw new Exception(
|
||||||
|
$"AddNoResize assumes that list capacity is sufficient (Capacity {Capacity}, Size {Size}), requested count {count}!"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,12 +166,12 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
|
|
||||||
public void Add(T value)
|
public void Add(T value)
|
||||||
{
|
{
|
||||||
if (_size >= _capacity)
|
if (_size >= Capacity)
|
||||||
{
|
{
|
||||||
ReAlloc(_capacity + (int)(_capacity * 0.5f));
|
ReAlloc(Capacity + (int)(Capacity * 0.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsafeUtilities.WriteArrayElement(_buffer, _size, value);
|
UnsafeUtilities.WriteArrayElement(Buffer, _size, value);
|
||||||
_size++;
|
_size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,21 +179,21 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
{
|
{
|
||||||
CheckNoResizeCapacity(1);
|
CheckNoResizeCapacity(1);
|
||||||
|
|
||||||
UnsafeUtilities.WriteArrayElement(_buffer, _size, value);
|
UnsafeUtilities.WriteArrayElement(Buffer, _size, value);
|
||||||
_size++;
|
_size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddRange(Span<T> values, int count)
|
public void AddRange(Span<T> values, int count)
|
||||||
{
|
{
|
||||||
var newSize = _size + count;
|
var newSize = _size + count;
|
||||||
if (newSize > _capacity)
|
if (newSize > Capacity)
|
||||||
{
|
{
|
||||||
ReAlloc(_capacity + count);
|
ReAlloc(Capacity + count);
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (T* ptr = values)
|
fixed (T* ptr = values)
|
||||||
{
|
{
|
||||||
MemCpy(_buffer + _size, ptr, (uint)(count * sizeof(T)));
|
MemCpy(_array.Buffer + _size, ptr, (uint)(count * sizeof(T)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_size += count;
|
_size += count;
|
||||||
@@ -211,7 +205,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
|
|
||||||
fixed (T* ptr = values)
|
fixed (T* ptr = values)
|
||||||
{
|
{
|
||||||
MemCpy(_buffer + _size, ptr, (uint)(values.Length * sizeof(T)));
|
MemCpy(_array.Buffer + _size, ptr, (uint)(values.Length * sizeof(T)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_size += values.Length;
|
_size += values.Length;
|
||||||
@@ -221,7 +215,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
{
|
{
|
||||||
CheckNoResizeCapacity(count);
|
CheckNoResizeCapacity(count);
|
||||||
|
|
||||||
MemCpy(_buffer + _size, ptr, (uint)(count * sizeof(T)));
|
MemCpy(_array.Buffer + _size, ptr, (uint)(count * sizeof(T)));
|
||||||
_size += count;
|
_size += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +229,11 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
}
|
}
|
||||||
|
|
||||||
var copyFrom = Math.Min(start + length, _size);
|
var copyFrom = Math.Min(start + length, _size);
|
||||||
MemCpy(_buffer + start, _buffer + copyFrom, (uint)((_size - copyFrom) * sizeof(T)));
|
MemCpy(
|
||||||
|
_array.Buffer + start,
|
||||||
|
_array.Buffer + copyFrom,
|
||||||
|
(uint)((_size - copyFrom) * sizeof(T))
|
||||||
|
);
|
||||||
_size -= length;
|
_size -= length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +252,11 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
}
|
}
|
||||||
|
|
||||||
var copyFrom = Math.Min(_size - length, start + length);
|
var copyFrom = Math.Min(_size - length, start + length);
|
||||||
MemCpy(_buffer + start, _buffer + copyFrom, (uint)((_size - copyFrom) * sizeof(T)));
|
MemCpy(
|
||||||
|
_array.Buffer + start,
|
||||||
|
_array.Buffer + copyFrom,
|
||||||
|
(uint)((_size - copyFrom) * sizeof(T))
|
||||||
|
);
|
||||||
_size -= length;
|
_size -= length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,26 +267,19 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
|
|
||||||
public void ReAlloc(int newSize)
|
public void ReAlloc(int newSize)
|
||||||
{
|
{
|
||||||
if (newSize == _size)
|
_array.ReAlloc(newSize);
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_buffer = (T*)NativeMemory.AlignedRealloc(_buffer, (nuint)(newSize * sizeof(T)), (nuint)AlignOf<T>());
|
|
||||||
_size = newSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly void Clear()
|
public readonly void Clear()
|
||||||
{
|
{
|
||||||
MemClear(_buffer, (uint)(_size * sizeof(T)));
|
_array.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
NativeMemory.AlignedFree(_buffer);
|
_array.Dispose();
|
||||||
|
|
||||||
_buffer = null;
|
|
||||||
_size = 0;
|
_size = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
71
Misaki.HighPerformance.Unsafe/Collections/UnsafeQueue.cs
Normal file
71
Misaki.HighPerformance.Unsafe/Collections/UnsafeQueue.cs
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Misaki.HighPerformance.Unsafe.Collections.Contracts;
|
||||||
|
using Misaki.HighPerformance.Unsafe.Helpers;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Unsafe.Collections;
|
||||||
|
|
||||||
|
public unsafe struct UnsafeQueue<T> : IUnsafeCollection<T>
|
||||||
|
where T : unmanaged
|
||||||
|
{
|
||||||
|
private UnsafeArray<T> _array;
|
||||||
|
private int _size;
|
||||||
|
private int _offset;
|
||||||
|
|
||||||
|
public T* Buffer => _array.Buffer;
|
||||||
|
public int Size => _size;
|
||||||
|
public int Capacity => _array.Size;
|
||||||
|
|
||||||
|
public T this[int index] => _array[index];
|
||||||
|
|
||||||
|
public void Enqueue(T value)
|
||||||
|
{
|
||||||
|
if (_size >= Capacity)
|
||||||
|
{
|
||||||
|
ReAlloc(Capacity + (int)(Capacity * 0.5f));
|
||||||
|
}
|
||||||
|
|
||||||
|
UnsafeUtilities.WriteArrayElement(Buffer, (_offset + _size) % Capacity, value);
|
||||||
|
_size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Dequeue()
|
||||||
|
{
|
||||||
|
if (_size == 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Queue is empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = UnsafeUtilities.ReadArrayElement<T>(Buffer, _offset);
|
||||||
|
_offset = (_offset + 1) % Capacity;
|
||||||
|
_size--;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryDequeue([MaybeNullWhen(false)] out T? value)
|
||||||
|
{
|
||||||
|
if (_offset > _size)
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = Dequeue();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReAlloc(int newSize)
|
||||||
|
{
|
||||||
|
_array.ReAlloc(newSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_array.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_array.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,10 +2,12 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Unsafe.Helpers;
|
namespace Misaki.HighPerformance.Unsafe.Helpers;
|
||||||
public unsafe static class MemoryUtilities
|
|
||||||
|
public static unsafe class MemoryUtilities
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
private struct AlignOfHelper<T> where T : struct
|
private struct AlignOfHelper<T>
|
||||||
|
where T : struct
|
||||||
{
|
{
|
||||||
public byte dummy;
|
public byte dummy;
|
||||||
public T data;
|
public T data;
|
||||||
@@ -53,7 +55,8 @@ public unsafe static class MemoryUtilities
|
|||||||
/// <typeparam name="T">Represents an unmanaged type for which the size is being calculated.</typeparam>
|
/// <typeparam name="T">Represents an unmanaged type for which the size is being calculated.</typeparam>
|
||||||
/// <returns>Returns the size of the specified type as an unsigned integer.</returns>
|
/// <returns>Returns the size of the specified type as an unsigned integer.</returns>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static nuint SizeOf<T>() where T : unmanaged
|
public static nuint SizeOf<T>()
|
||||||
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
return (nuint)sizeof(T);
|
return (nuint)sizeof(T);
|
||||||
}
|
}
|
||||||
@@ -63,9 +66,10 @@ public unsafe static class MemoryUtilities
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Represents an unmanaged type for which the alignment size is being calculated.</typeparam>
|
/// <typeparam name="T">Represents an unmanaged type for which the alignment size is being calculated.</typeparam>
|
||||||
/// <returns>Returns the difference in size between a helper structure and the specified type.</returns>
|
/// <returns>Returns the difference in size between a helper structure and the specified type.</returns>
|
||||||
public static int AlignOf<T>() where T : unmanaged
|
public static nuint AlignOf<T>()
|
||||||
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
return sizeof(AlignOfHelper<T>) - sizeof(T);
|
return (nuint)(sizeof(AlignOfHelper<T>) - sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -73,8 +77,10 @@ public unsafe static class MemoryUtilities
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Represents a value type that is used to determine the alignment size.</typeparam>
|
/// <typeparam name="T">Represents a value type that is used to determine the alignment size.</typeparam>
|
||||||
/// <returns>Returns the size difference in bytes as an integer.</returns>
|
/// <returns>Returns the size difference in bytes as an integer.</returns>
|
||||||
public static int MarshalAlignOf<T>() where T : struct
|
public static int MarshalAlignOf<T>()
|
||||||
|
where T : struct
|
||||||
{
|
{
|
||||||
return Marshal.SizeOf<AlignOfHelper<T>>() - Marshal.SizeOf<T>();
|
return Marshal.SizeOf<AlignOfHelper<T>>() - Marshal.SizeOf<T>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user