Refactor and enhance math and utility libraries
Some checks failed
Publish NuGet Packages / publish (push) Failing after 3m12s
Some checks failed
Publish NuGet Packages / publish (push) Failing after 3m12s
Refactored `sincos` usage across `quaternion` and `random` to use `out` parameters for improved performance. Enhanced `random` struct with updated random direction generation methods. Added new benchmarks in `MathematicsBenchmark` for vector operations, including SIMD-based `f4` struct. Downgraded target framework to `net9.0` for compatibility. Introduced `ReadOnlyUnsafeCollection` for low-level memory management. Added utility methods in `CollectionUtility` for span creation and optimized list operations. Renamed `MemoryUtilities` to `MemoryUtility` and updated all references. Enhanced `ObjectPool` with `Rent` and `TryRent` methods. Enabled `AllowUnsafeBlocks` and AOT compatibility in project configuration. Performed general code cleanup, including removal of unused methods, improved formatting, and alignment with modern coding practices.
This commit is contained in:
0
.zed/settings.json
Normal file
0
.zed/settings.json
Normal file
@@ -244,7 +244,7 @@ public unsafe sealed class JobScheduler : IDisposable
|
|||||||
public JobHandle Schedule<T>(ref T job, int threadIndex, JobHandle dependency)
|
public JobHandle Schedule<T>(ref T job, int threadIndex, JobHandle dependency)
|
||||||
where T : unmanaged, IJob
|
where T : unmanaged, IJob
|
||||||
{
|
{
|
||||||
var jobData = _jobDataAllocator.Allocate(MemoryUtilities.SizeOf<T>(), MemoryUtilities.AlignOf<T>());
|
var jobData = _jobDataAllocator.Allocate(MemoryUtility.SizeOf<T>(), MemoryUtility.AlignOf<T>());
|
||||||
if (jobData == null)
|
if (jobData == null)
|
||||||
{
|
{
|
||||||
return JobHandle.Invalid;
|
return JobHandle.Invalid;
|
||||||
@@ -252,7 +252,7 @@ public unsafe sealed class JobScheduler : IDisposable
|
|||||||
|
|
||||||
fixed (T* pJob = &job)
|
fixed (T* pJob = &job)
|
||||||
{
|
{
|
||||||
MemoryUtilities.MemCpy(pJob, jobData, MemoryUtilities.SizeOf<T>());
|
MemoryUtility.MemCpy(pJob, jobData, MemoryUtility.SizeOf<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
var jobInfo = new JobInfo
|
var jobInfo = new JobInfo
|
||||||
@@ -320,7 +320,7 @@ public unsafe sealed class JobScheduler : IDisposable
|
|||||||
public JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize, int threadIndex, JobHandle dependency)
|
public JobHandle ScheduleParallel<T>(ref T job, int totalIteration, int batchSize, int threadIndex, JobHandle dependency)
|
||||||
where T : unmanaged, IJobParallelFor
|
where T : unmanaged, IJobParallelFor
|
||||||
{
|
{
|
||||||
var jobData = _jobDataAllocator.Allocate(MemoryUtilities.SizeOf<T>(), MemoryUtilities.AlignOf<T>());
|
var jobData = _jobDataAllocator.Allocate(MemoryUtility.SizeOf<T>(), MemoryUtility.AlignOf<T>());
|
||||||
if (jobData == null)
|
if (jobData == null)
|
||||||
{
|
{
|
||||||
return JobHandle.Invalid;
|
return JobHandle.Invalid;
|
||||||
@@ -328,7 +328,7 @@ public unsafe sealed class JobScheduler : IDisposable
|
|||||||
|
|
||||||
fixed (T* pJob = &job)
|
fixed (T* pJob = &job)
|
||||||
{
|
{
|
||||||
MemoryUtilities.MemCpy(pJob, jobData, MemoryUtilities.SizeOf<T>());
|
MemoryUtility.MemCpy(pJob, jobData, MemoryUtility.SizeOf<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
var optimalBatchSize = Math.Max(1, batchSize);
|
var optimalBatchSize = Math.Max(1, batchSize);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
global using static Misaki.HighPerformance.LowLevel.Utilities.MemoryUtilities;
|
global using static Misaki.HighPerformance.LowLevel.Utilities.MemoryUtility;
|
||||||
|
|
||||||
|
|
||||||
global using unsafe AllocFunc = delegate*<void*, nuint, nuint, Misaki.HighPerformance.LowLevel.Buffer.AllocationOption, void*>;
|
global using unsafe AllocFunc = delegate*<void*, nuint, nuint, Misaki.HighPerformance.LowLevel.Buffer.AllocationOption, void*>;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public unsafe struct Stack : IDisposable
|
|||||||
{
|
{
|
||||||
private const nuint _DEFAULT_SIZE = 1024 * 1024; // 1MB
|
private const nuint _DEFAULT_SIZE = 1024 * 1024; // 1MB
|
||||||
|
|
||||||
public readonly ref struct Scope
|
public readonly struct Scope : IDisposable
|
||||||
{
|
{
|
||||||
private readonly Stack* _allocator;
|
private readonly Stack* _allocator;
|
||||||
private readonly nuint _originalOffset;
|
private readonly nuint _originalOffset;
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ namespace Misaki.HighPerformance.LowLevel.Collections;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
||||||
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 32 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedString32"/>.
|
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 32 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedText32"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 32)]
|
[StructLayout(LayoutKind.Sequential, Size = 32)]
|
||||||
public unsafe struct FixedString32
|
public unsafe struct FixedText32
|
||||||
{
|
{
|
||||||
private ushort _length;
|
private ushort _length;
|
||||||
private fixed byte _buffer[30];
|
private fixed byte _buffer[30];
|
||||||
@@ -38,7 +38,7 @@ public unsafe struct FixedString32
|
|||||||
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
||||||
if (maxBytes > 30)
|
if (maxBytes > 30)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString32.");
|
throw new ArgumentException("Input string is too long to fit in FixedText32.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (byte* bufferPtr = _buffer)
|
fixed (byte* bufferPtr = _buffer)
|
||||||
@@ -48,12 +48,12 @@ public unsafe struct FixedString32
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString32(ReadOnlySpan<char> input)
|
public FixedText32(ReadOnlySpan<char> input)
|
||||||
{
|
{
|
||||||
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
||||||
if (maxBytes > 30)
|
if (maxBytes > 30)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString32.");
|
throw new ArgumentException("Input string is too long to fit in FixedText32.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (char* inputPtr = input)
|
fixed (char* inputPtr = input)
|
||||||
@@ -64,21 +64,21 @@ public unsafe struct FixedString32
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString32(string input)
|
public FixedText32(string input)
|
||||||
: this(input.AsSpan())
|
: this(input.AsSpan())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString32(char* input, ushort length)
|
public FixedText32(char* input, ushort length)
|
||||||
: this(new Span<char>(input, length))
|
: this(new Span<char>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString32(ReadOnlySpan<byte> input)
|
public FixedText32(ReadOnlySpan<byte> input)
|
||||||
{
|
{
|
||||||
if (input.Length > 30)
|
if (input.Length > 30)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input byte array is too long to fit in FixedString32.");
|
throw new ArgumentException("Input byte array is too long to fit in FixedText32.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_length = (ushort)input.Length;
|
_length = (ushort)input.Length;
|
||||||
@@ -90,7 +90,7 @@ public unsafe struct FixedString32
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString32(byte* input, ushort length)
|
public FixedText32(byte* input, ushort length)
|
||||||
: this(new ReadOnlySpan<byte>(input, length))
|
: this(new ReadOnlySpan<byte>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -124,10 +124,10 @@ public unsafe struct FixedString32
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
||||||
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 64 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedString64"/>.
|
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 64 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedText64"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 64)]
|
[StructLayout(LayoutKind.Sequential, Size = 64)]
|
||||||
public unsafe struct FixedString64
|
public unsafe struct FixedText64
|
||||||
{
|
{
|
||||||
private ushort _length;
|
private ushort _length;
|
||||||
private fixed byte _buffer[62];
|
private fixed byte _buffer[62];
|
||||||
@@ -153,7 +153,7 @@ public unsafe struct FixedString64
|
|||||||
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
||||||
if (maxBytes > 62)
|
if (maxBytes > 62)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString64.");
|
throw new ArgumentException("Input string is too long to fit in FixedText64.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (byte* bufferPtr = _buffer)
|
fixed (byte* bufferPtr = _buffer)
|
||||||
@@ -163,12 +163,12 @@ public unsafe struct FixedString64
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString64(ReadOnlySpan<char> input)
|
public FixedText64(ReadOnlySpan<char> input)
|
||||||
{
|
{
|
||||||
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
||||||
if (maxBytes > 62)
|
if (maxBytes > 62)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString64.");
|
throw new ArgumentException("Input string is too long to fit in FixedText64.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (char* inputPtr = input)
|
fixed (char* inputPtr = input)
|
||||||
@@ -179,21 +179,21 @@ public unsafe struct FixedString64
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString64(string input)
|
public FixedText64(string input)
|
||||||
: this(input.AsSpan())
|
: this(input.AsSpan())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString64(char* input, ushort length)
|
public FixedText64(char* input, ushort length)
|
||||||
: this(new Span<char>(input, length))
|
: this(new Span<char>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString64(ReadOnlySpan<byte> input)
|
public FixedText64(ReadOnlySpan<byte> input)
|
||||||
{
|
{
|
||||||
if (input.Length > 62)
|
if (input.Length > 62)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input byte array is too long to fit in FixedString64.");
|
throw new ArgumentException("Input byte array is too long to fit in FixedText64.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_length = (ushort)input.Length;
|
_length = (ushort)input.Length;
|
||||||
@@ -205,7 +205,7 @@ public unsafe struct FixedString64
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString64(byte* input, ushort length)
|
public FixedText64(byte* input, ushort length)
|
||||||
: this(new ReadOnlySpan<byte>(input, length))
|
: this(new ReadOnlySpan<byte>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -239,10 +239,10 @@ public unsafe struct FixedString64
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
||||||
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 128 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedString128"/>.
|
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 128 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedText128"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 128)]
|
[StructLayout(LayoutKind.Sequential, Size = 128)]
|
||||||
public unsafe struct FixedString128
|
public unsafe struct FixedText128
|
||||||
{
|
{
|
||||||
private ushort _length;
|
private ushort _length;
|
||||||
private fixed byte _buffer[126];
|
private fixed byte _buffer[126];
|
||||||
@@ -268,7 +268,7 @@ public unsafe struct FixedString128
|
|||||||
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
||||||
if (maxBytes > 126)
|
if (maxBytes > 126)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString128.");
|
throw new ArgumentException("Input string is too long to fit in FixedText128.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (byte* bufferPtr = _buffer)
|
fixed (byte* bufferPtr = _buffer)
|
||||||
@@ -278,12 +278,12 @@ public unsafe struct FixedString128
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString128(ReadOnlySpan<char> input)
|
public FixedText128(ReadOnlySpan<char> input)
|
||||||
{
|
{
|
||||||
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
||||||
if (maxBytes > 126)
|
if (maxBytes > 126)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString128.");
|
throw new ArgumentException("Input string is too long to fit in FixedText128.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (char* inputPtr = input)
|
fixed (char* inputPtr = input)
|
||||||
@@ -294,21 +294,21 @@ public unsafe struct FixedString128
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString128(string input)
|
public FixedText128(string input)
|
||||||
: this(input.AsSpan())
|
: this(input.AsSpan())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString128(char* input, ushort length)
|
public FixedText128(char* input, ushort length)
|
||||||
: this(new Span<char>(input, length))
|
: this(new Span<char>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString128(ReadOnlySpan<byte> input)
|
public FixedText128(ReadOnlySpan<byte> input)
|
||||||
{
|
{
|
||||||
if (input.Length > 126)
|
if (input.Length > 126)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input byte array is too long to fit in FixedString128.");
|
throw new ArgumentException("Input byte array is too long to fit in FixedText128.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_length = (ushort)input.Length;
|
_length = (ushort)input.Length;
|
||||||
@@ -320,7 +320,7 @@ public unsafe struct FixedString128
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString128(byte* input, ushort length)
|
public FixedText128(byte* input, ushort length)
|
||||||
: this(new ReadOnlySpan<byte>(input, length))
|
: this(new ReadOnlySpan<byte>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -354,10 +354,10 @@ public unsafe struct FixedString128
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
||||||
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 256 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedString256"/>.
|
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 256 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedText256"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 256)]
|
[StructLayout(LayoutKind.Sequential, Size = 256)]
|
||||||
public unsafe struct FixedString256
|
public unsafe struct FixedText256
|
||||||
{
|
{
|
||||||
private ushort _length;
|
private ushort _length;
|
||||||
private fixed byte _buffer[254];
|
private fixed byte _buffer[254];
|
||||||
@@ -383,7 +383,7 @@ public unsafe struct FixedString256
|
|||||||
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
||||||
if (maxBytes > 254)
|
if (maxBytes > 254)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString256.");
|
throw new ArgumentException("Input string is too long to fit in FixedText256.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (byte* bufferPtr = _buffer)
|
fixed (byte* bufferPtr = _buffer)
|
||||||
@@ -393,12 +393,12 @@ public unsafe struct FixedString256
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString256(ReadOnlySpan<char> input)
|
public FixedText256(ReadOnlySpan<char> input)
|
||||||
{
|
{
|
||||||
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
||||||
if (maxBytes > 254)
|
if (maxBytes > 254)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString256.");
|
throw new ArgumentException("Input string is too long to fit in FixedText256.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (char* inputPtr = input)
|
fixed (char* inputPtr = input)
|
||||||
@@ -409,21 +409,21 @@ public unsafe struct FixedString256
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString256(string input)
|
public FixedText256(string input)
|
||||||
: this(input.AsSpan())
|
: this(input.AsSpan())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString256(char* input, ushort length)
|
public FixedText256(char* input, ushort length)
|
||||||
: this(new Span<char>(input, length))
|
: this(new Span<char>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString256(ReadOnlySpan<byte> input)
|
public FixedText256(ReadOnlySpan<byte> input)
|
||||||
{
|
{
|
||||||
if (input.Length > 254)
|
if (input.Length > 254)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input byte array is too long to fit in FixedString256.");
|
throw new ArgumentException("Input byte array is too long to fit in FixedText256.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_length = (ushort)input.Length;
|
_length = (ushort)input.Length;
|
||||||
@@ -435,7 +435,7 @@ public unsafe struct FixedString256
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString256(byte* input, ushort length)
|
public FixedText256(byte* input, ushort length)
|
||||||
: this(new ReadOnlySpan<byte>(input, length))
|
: this(new ReadOnlySpan<byte>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -469,10 +469,10 @@ public unsafe struct FixedString256
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
||||||
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 512 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedString512"/>.
|
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 512 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedText512"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 512)]
|
[StructLayout(LayoutKind.Sequential, Size = 512)]
|
||||||
public unsafe struct FixedString512
|
public unsafe struct FixedText512
|
||||||
{
|
{
|
||||||
private ushort _length;
|
private ushort _length;
|
||||||
private fixed byte _buffer[510];
|
private fixed byte _buffer[510];
|
||||||
@@ -498,7 +498,7 @@ public unsafe struct FixedString512
|
|||||||
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
||||||
if (maxBytes > 510)
|
if (maxBytes > 510)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString512.");
|
throw new ArgumentException("Input string is too long to fit in FixedText512.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (byte* bufferPtr = _buffer)
|
fixed (byte* bufferPtr = _buffer)
|
||||||
@@ -508,12 +508,12 @@ public unsafe struct FixedString512
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString512(ReadOnlySpan<char> input)
|
public FixedText512(ReadOnlySpan<char> input)
|
||||||
{
|
{
|
||||||
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
||||||
if (maxBytes > 510)
|
if (maxBytes > 510)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString512.");
|
throw new ArgumentException("Input string is too long to fit in FixedText512.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (char* inputPtr = input)
|
fixed (char* inputPtr = input)
|
||||||
@@ -524,21 +524,21 @@ public unsafe struct FixedString512
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString512(string input)
|
public FixedText512(string input)
|
||||||
: this(input.AsSpan())
|
: this(input.AsSpan())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString512(char* input, ushort length)
|
public FixedText512(char* input, ushort length)
|
||||||
: this(new Span<char>(input, length))
|
: this(new Span<char>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString512(ReadOnlySpan<byte> input)
|
public FixedText512(ReadOnlySpan<byte> input)
|
||||||
{
|
{
|
||||||
if (input.Length > 510)
|
if (input.Length > 510)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input byte array is too long to fit in FixedString512.");
|
throw new ArgumentException("Input byte array is too long to fit in FixedText512.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_length = (ushort)input.Length;
|
_length = (ushort)input.Length;
|
||||||
@@ -550,7 +550,7 @@ public unsafe struct FixedString512
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString512(byte* input, ushort length)
|
public FixedText512(byte* input, ushort length)
|
||||||
: this(new ReadOnlySpan<byte>(input, length))
|
: this(new ReadOnlySpan<byte>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -584,10 +584,10 @@ public unsafe struct FixedString512
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
||||||
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 1024 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedString1024"/>.
|
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 1024 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedText1024"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 1024)]
|
[StructLayout(LayoutKind.Sequential, Size = 1024)]
|
||||||
public unsafe struct FixedString1024
|
public unsafe struct FixedText1024
|
||||||
{
|
{
|
||||||
private ushort _length;
|
private ushort _length;
|
||||||
private fixed byte _buffer[1022];
|
private fixed byte _buffer[1022];
|
||||||
@@ -613,7 +613,7 @@ public unsafe struct FixedString1024
|
|||||||
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
||||||
if (maxBytes > 1022)
|
if (maxBytes > 1022)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString1024.");
|
throw new ArgumentException("Input string is too long to fit in FixedText1024.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (byte* bufferPtr = _buffer)
|
fixed (byte* bufferPtr = _buffer)
|
||||||
@@ -623,12 +623,12 @@ public unsafe struct FixedString1024
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString1024(ReadOnlySpan<char> input)
|
public FixedText1024(ReadOnlySpan<char> input)
|
||||||
{
|
{
|
||||||
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
||||||
if (maxBytes > 1022)
|
if (maxBytes > 1022)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString1024.");
|
throw new ArgumentException("Input string is too long to fit in FixedText1024.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (char* inputPtr = input)
|
fixed (char* inputPtr = input)
|
||||||
@@ -639,21 +639,21 @@ public unsafe struct FixedString1024
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString1024(string input)
|
public FixedText1024(string input)
|
||||||
: this(input.AsSpan())
|
: this(input.AsSpan())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString1024(char* input, ushort length)
|
public FixedText1024(char* input, ushort length)
|
||||||
: this(new Span<char>(input, length))
|
: this(new Span<char>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString1024(ReadOnlySpan<byte> input)
|
public FixedText1024(ReadOnlySpan<byte> input)
|
||||||
{
|
{
|
||||||
if (input.Length > 1022)
|
if (input.Length > 1022)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input byte array is too long to fit in FixedString1024.");
|
throw new ArgumentException("Input byte array is too long to fit in FixedText1024.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_length = (ushort)input.Length;
|
_length = (ushort)input.Length;
|
||||||
@@ -665,7 +665,7 @@ public unsafe struct FixedString1024
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString1024(byte* input, ushort length)
|
public FixedText1024(byte* input, ushort length)
|
||||||
: this(new ReadOnlySpan<byte>(input, length))
|
: this(new ReadOnlySpan<byte>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -699,10 +699,10 @@ public unsafe struct FixedString1024
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
||||||
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 2048 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedString2048"/>.
|
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 2048 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedText2048"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 2048)]
|
[StructLayout(LayoutKind.Sequential, Size = 2048)]
|
||||||
public unsafe struct FixedString2048
|
public unsafe struct FixedText2048
|
||||||
{
|
{
|
||||||
private ushort _length;
|
private ushort _length;
|
||||||
private fixed byte _buffer[2046];
|
private fixed byte _buffer[2046];
|
||||||
@@ -728,7 +728,7 @@ public unsafe struct FixedString2048
|
|||||||
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
||||||
if (maxBytes > 2046)
|
if (maxBytes > 2046)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString2048.");
|
throw new ArgumentException("Input string is too long to fit in FixedText2048.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (byte* bufferPtr = _buffer)
|
fixed (byte* bufferPtr = _buffer)
|
||||||
@@ -738,12 +738,12 @@ public unsafe struct FixedString2048
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString2048(ReadOnlySpan<char> input)
|
public FixedText2048(ReadOnlySpan<char> input)
|
||||||
{
|
{
|
||||||
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
||||||
if (maxBytes > 2046)
|
if (maxBytes > 2046)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString2048.");
|
throw new ArgumentException("Input string is too long to fit in FixedText2048.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (char* inputPtr = input)
|
fixed (char* inputPtr = input)
|
||||||
@@ -754,21 +754,21 @@ public unsafe struct FixedString2048
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString2048(string input)
|
public FixedText2048(string input)
|
||||||
: this(input.AsSpan())
|
: this(input.AsSpan())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString2048(char* input, ushort length)
|
public FixedText2048(char* input, ushort length)
|
||||||
: this(new Span<char>(input, length))
|
: this(new Span<char>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString2048(ReadOnlySpan<byte> input)
|
public FixedText2048(ReadOnlySpan<byte> input)
|
||||||
{
|
{
|
||||||
if (input.Length > 2046)
|
if (input.Length > 2046)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input byte array is too long to fit in FixedString2048.");
|
throw new ArgumentException("Input byte array is too long to fit in FixedText2048.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_length = (ushort)input.Length;
|
_length = (ushort)input.Length;
|
||||||
@@ -780,7 +780,7 @@ public unsafe struct FixedString2048
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString2048(byte* input, ushort length)
|
public FixedText2048(byte* input, ushort length)
|
||||||
: this(new ReadOnlySpan<byte>(input, length))
|
: this(new ReadOnlySpan<byte>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -814,10 +814,10 @@ public unsafe struct FixedString2048
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
||||||
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 4096 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedString4096"/>.
|
/// If you need a heap allocated fixed-size UTF-8 encoded string of length 4096 bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedText4096"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 4096)]
|
[StructLayout(LayoutKind.Sequential, Size = 4096)]
|
||||||
public unsafe struct FixedString4096
|
public unsafe struct FixedText4096
|
||||||
{
|
{
|
||||||
private ushort _length;
|
private ushort _length;
|
||||||
private fixed byte _buffer[4094];
|
private fixed byte _buffer[4094];
|
||||||
@@ -843,7 +843,7 @@ public unsafe struct FixedString4096
|
|||||||
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
||||||
if (maxBytes > 4094)
|
if (maxBytes > 4094)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString4096.");
|
throw new ArgumentException("Input string is too long to fit in FixedText4096.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (byte* bufferPtr = _buffer)
|
fixed (byte* bufferPtr = _buffer)
|
||||||
@@ -853,12 +853,12 @@ public unsafe struct FixedString4096
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString4096(ReadOnlySpan<char> input)
|
public FixedText4096(ReadOnlySpan<char> input)
|
||||||
{
|
{
|
||||||
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
||||||
if (maxBytes > 4094)
|
if (maxBytes > 4094)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString4096.");
|
throw new ArgumentException("Input string is too long to fit in FixedText4096.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (char* inputPtr = input)
|
fixed (char* inputPtr = input)
|
||||||
@@ -869,21 +869,21 @@ public unsafe struct FixedString4096
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString4096(string input)
|
public FixedText4096(string input)
|
||||||
: this(input.AsSpan())
|
: this(input.AsSpan())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString4096(char* input, ushort length)
|
public FixedText4096(char* input, ushort length)
|
||||||
: this(new Span<char>(input, length))
|
: this(new Span<char>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString4096(ReadOnlySpan<byte> input)
|
public FixedText4096(ReadOnlySpan<byte> input)
|
||||||
{
|
{
|
||||||
if (input.Length > 4094)
|
if (input.Length > 4094)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input byte array is too long to fit in FixedString4096.");
|
throw new ArgumentException("Input byte array is too long to fit in FixedText4096.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_length = (ushort)input.Length;
|
_length = (ushort)input.Length;
|
||||||
@@ -895,7 +895,7 @@ public unsafe struct FixedString4096
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString4096(byte* input, ushort length)
|
public FixedText4096(byte* input, ushort length)
|
||||||
: this(new ReadOnlySpan<byte>(input, length))
|
: this(new ReadOnlySpan<byte>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -16,10 +16,10 @@ namespace Misaki.HighPerformance.LowLevel.Collections;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
/// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data.
|
||||||
/// If you need a heap allocated fixed-size UTF-8 encoded string of length <#= i #> bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedString<#= i #>"/>.
|
/// If you need a heap allocated fixed-size UTF-8 encoded string of length <#= i #> bytes, consider using <see cref="Misaki.HighPerformance.Unsafe.Buffer.FixedText<#= i #>"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[StructLayout(LayoutKind.Sequential, Size = <#= i #>)]
|
[StructLayout(LayoutKind.Sequential, Size = <#= i #>)]
|
||||||
public unsafe struct FixedString<#= i #>
|
public unsafe struct FixedText<#= i #>
|
||||||
{
|
{
|
||||||
private ushort _length;
|
private ushort _length;
|
||||||
private fixed byte _buffer[<#= i - 2 #>];
|
private fixed byte _buffer[<#= i - 2 #>];
|
||||||
@@ -45,7 +45,7 @@ public unsafe struct FixedString<#= i #>
|
|||||||
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
var maxBytes = Encoding.UTF8.GetByteCount(value);
|
||||||
if (maxBytes > <#= i - 2 #>)
|
if (maxBytes > <#= i - 2 #>)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString<#= i #>.");
|
throw new ArgumentException("Input string is too long to fit in FixedText<#= i #>.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (byte* bufferPtr = _buffer)
|
fixed (byte* bufferPtr = _buffer)
|
||||||
@@ -55,12 +55,12 @@ public unsafe struct FixedString<#= i #>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString<#= i #>(ReadOnlySpan<char> input)
|
public FixedText<#= i #>(ReadOnlySpan<char> input)
|
||||||
{
|
{
|
||||||
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
var maxBytes = Encoding.UTF8.GetByteCount(input);
|
||||||
if (maxBytes > <#= i - 2 #>)
|
if (maxBytes > <#= i - 2 #>)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input string is too long to fit in FixedString<#= i #>.");
|
throw new ArgumentException("Input string is too long to fit in FixedText<#= i #>.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (char* inputPtr = input)
|
fixed (char* inputPtr = input)
|
||||||
@@ -71,21 +71,21 @@ public unsafe struct FixedString<#= i #>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString<#= i #>(string input)
|
public FixedText<#= i #>(string input)
|
||||||
: this(input.AsSpan())
|
: this(input.AsSpan())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString<#= i #>(char* input, ushort length)
|
public FixedText<#= i #>(char* input, ushort length)
|
||||||
: this(new Span<char>(input, length))
|
: this(new Span<char>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString<#= i #>(ReadOnlySpan<byte> input)
|
public FixedText<#= i #>(ReadOnlySpan<byte> input)
|
||||||
{
|
{
|
||||||
if (input.Length > <#= i - 2 #>)
|
if (input.Length > <#= i - 2 #>)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Input byte array is too long to fit in FixedString<#= i #>.");
|
throw new ArgumentException("Input byte array is too long to fit in FixedText<#= i #>.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_length = (ushort)input.Length;
|
_length = (ushort)input.Length;
|
||||||
@@ -97,7 +97,7 @@ public unsafe struct FixedString<#= i #>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedString<#= i #>(byte* input, ushort length)
|
public FixedText<#= i #>(byte* input, ushort length)
|
||||||
: this(new ReadOnlySpan<byte>(input, length))
|
: this(new ReadOnlySpan<byte>(input, length))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.LowLevel.Collections;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a read-only, unsafe view over a contiguous region of unmanaged memory as an array of elements of type T.
|
||||||
|
/// Enables efficient, low-level access to memory without copying or additional safety checks.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This read only collection does not own the memory it points to. The user is responsible for ensuring the memory remains valid for the lifetime of this structure.
|
||||||
|
/// The goal of this struc is similar to <see cref="ReadOnlySpan{T}"/>, but it can be used in contexts where spans are not allowed, such as fields in structs and shared across threads.
|
||||||
|
/// </remarks>
|
||||||
|
/// <typeparam name="T">The type of elements in the collection. Must be an unmanaged type.</typeparam>
|
||||||
|
public readonly unsafe struct ReadOnlyUnsafeCollection<T> : IEnumerable<T>
|
||||||
|
where T : unmanaged
|
||||||
|
{
|
||||||
|
public struct Enumerator : IEnumerator<T>
|
||||||
|
{
|
||||||
|
private readonly ReadOnlyUnsafeCollection<T> _collection;
|
||||||
|
private int _index;
|
||||||
|
private T _value;
|
||||||
|
|
||||||
|
public readonly T Current
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly object IEnumerator.Current => Current;
|
||||||
|
|
||||||
|
public Enumerator(ref readonly ReadOnlyUnsafeCollection<T> array)
|
||||||
|
{
|
||||||
|
_collection = array;
|
||||||
|
_index = -1;
|
||||||
|
_value = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
_index++;
|
||||||
|
|
||||||
|
if (_index < _collection.Count)
|
||||||
|
{
|
||||||
|
_value = UnsafeUtility.ReadArrayElement<T>(_collection._buffer, _index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_value = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly T* _buffer;
|
||||||
|
private readonly int _count;
|
||||||
|
|
||||||
|
public readonly int Count => _count;
|
||||||
|
|
||||||
|
public readonly T this[int index]
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => UnsafeUtility.ReadArrayElement<T>(_buffer, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly T this[uint index]
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => UnsafeUtility.ReadArrayElement<T>(_buffer, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<T> GetEnumerator() => new Enumerator(in this);
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
|
public ReadOnlyUnsafeCollection(T* buffer, int count)
|
||||||
|
{
|
||||||
|
_buffer = buffer;
|
||||||
|
_count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a read-only span that represents the valid elements in the underlying buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A <see cref="ReadOnlySpan{T}"/> containing the elements of the buffer up to the current count.</returns>
|
||||||
|
public ReadOnlySpan<T> AsSpan()
|
||||||
|
{
|
||||||
|
return new ReadOnlySpan<T>(_buffer, _count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reinterprets the underlying collection as a read-only collection of a different unmanaged type without copying the data.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="U">The unmanaged type to reinterpret the collection elements as.</typeparam>
|
||||||
|
/// <returns>A new ReadOnlyUnsafeCollection<U> that provides a read-only view of the same memory, interpreted as elements of type U.</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown if the total size of the underlying collection is not a multiple of the size of type U, making the reinterpretation invalid.</exception>
|
||||||
|
public ReadOnlyUnsafeCollection<U> Reinterpret<U>()
|
||||||
|
where U : unmanaged
|
||||||
|
{
|
||||||
|
var totalSize = (nuint)(Count * sizeof(T));
|
||||||
|
if (totalSize % (nuint)sizeof(U) != 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Cannot reinterpret collection: size mismatch.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var newCount = (int)(totalSize / (nuint)sizeof(U));
|
||||||
|
return new ReadOnlyUnsafeCollection<U>((U*)_buffer, newCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -75,7 +75,7 @@ public unsafe struct UnTypedArray : IUnTypedCollection
|
|||||||
public readonly ref T GetElementAt<T>(uint index)
|
public readonly ref T GetElementAt<T>(uint index)
|
||||||
where T : unmanaged
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
return ref UnsafeUtilities.ReadArrayElementRef<T>(_buffer, index);
|
return ref UnsafeUtility.ReadArrayElementRef<T>(_buffer, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|||||||
@@ -18,26 +18,25 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
|||||||
{
|
{
|
||||||
private readonly UnsafeArray<T>* _collection;
|
private readonly UnsafeArray<T>* _collection;
|
||||||
private int _index;
|
private int _index;
|
||||||
private T _value;
|
|
||||||
|
|
||||||
public Enumerator(UnsafeArray<T>* collection)
|
public Enumerator(UnsafeArray<T>* collection)
|
||||||
{
|
{
|
||||||
_collection = collection;
|
_collection = collection;
|
||||||
_index = -1;
|
_index = -1;
|
||||||
_value = default;
|
Current = default;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
_index++;
|
_index++;
|
||||||
if (_index < _collection->_count)
|
if (_index < _collection->Count)
|
||||||
{
|
{
|
||||||
_value = UnsafeUtilities.ReadArrayElement<T>(_collection->_buffer, _index);
|
Current = UnsafeUtility.ReadArrayElement<T>(_collection->_buffer, _index);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_value = default;
|
Current = default;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,10 +46,10 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Let NativeArray indexer check for out of range.
|
// Let NativeArray indexer check for out of range.
|
||||||
public readonly T Current
|
public T Current
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => _value;
|
get; private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly object IEnumerator.Current
|
readonly object IEnumerator.Current
|
||||||
@@ -66,7 +65,6 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
|||||||
|
|
||||||
private T* _buffer;
|
private T* _buffer;
|
||||||
private int _count;
|
private int _count;
|
||||||
|
|
||||||
private AllocationHandle* _handle;
|
private AllocationHandle* _handle;
|
||||||
|
|
||||||
public readonly int Count => _count;
|
public readonly int Count => _count;
|
||||||
@@ -83,7 +81,7 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return ref UnsafeUtilities.ReadArrayElementRef<T>(_buffer, index);
|
return ref UnsafeUtility.ReadArrayElementRef<T>(_buffer, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +97,7 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return ref UnsafeUtilities.ReadArrayElementRef<T>(_buffer, index);
|
return ref UnsafeUtility.ReadArrayElementRef<T>(_buffer, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +107,7 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
|||||||
get => _buffer != null;
|
get => _buffer != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator() => new Enumerator((UnsafeArray<T>*)UnsafeUtilities.AddressOf(ref this));
|
public IEnumerator<T> GetEnumerator() => new Enumerator((UnsafeArray<T>*)UnsafeUtility.AddressOf(ref this));
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -167,16 +165,21 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
|||||||
_count = count;
|
_count = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReadOnlyUnsafeCollection<T> AsReadOnly()
|
||||||
|
{
|
||||||
|
return new ReadOnlyUnsafeCollection<T>(_buffer, _count);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Resize(int newSize, AllocationOption option = AllocationOption.None)
|
public void Resize(int newSize, AllocationOption option = AllocationOption.None)
|
||||||
{
|
{
|
||||||
if (newSize == _count)
|
if (newSize == Count)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var elemSize = SizeOf<T>();
|
var elemSize = SizeOf<T>();
|
||||||
_buffer = (T*)_handle->Realloc(_handle->Allocator, _buffer, (nuint)_count * elemSize, (nuint)newSize * elemSize, AlignOf<T>(), option);
|
_buffer = (T*)_handle->Realloc(_handle->Allocator, _buffer, (nuint)Count * elemSize, (nuint)newSize * elemSize, AlignOf<T>(), option);
|
||||||
_count = newSize;
|
_count = newSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +187,7 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly void Clear()
|
public readonly void Clear()
|
||||||
{
|
{
|
||||||
MemClear(_buffer, (nuint)(_count * sizeof(T)));
|
MemClear(_buffer, (nuint)(Count * sizeof(T)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -194,6 +197,25 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>
|
|||||||
return _buffer;
|
return _buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reinterprets the underlying buffer as an array of a different unmanaged type without copying the data.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="U">The unmanaged type to reinterpret the buffer as.</typeparam>
|
||||||
|
/// <returns>An UnsafeArray<U> that views the same memory as the original array, but as elements of type U.</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown if the total size of the buffer in bytes is not a multiple of the size of type U.</exception>
|
||||||
|
public readonly UnsafeArray<U> Reinterpret<U>()
|
||||||
|
where U : unmanaged
|
||||||
|
{
|
||||||
|
var totalSize = (nuint)(Count * sizeof(T));
|
||||||
|
if (totalSize % (nuint)sizeof(U) != 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Cannot reinterpret array: size mismatch.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var newCount = (int)(totalSize / (nuint)sizeof(U));
|
||||||
|
return new UnsafeArray<U>((U*)_buffer, newCount);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -53,25 +53,25 @@ public struct UnsafeBitSet : IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public UnsafeBitSet()
|
public UnsafeBitSet()
|
||||||
{
|
{
|
||||||
_bits = new UnsafeArray<uint>(s_padding, Allocator.Persistent);
|
_bits = new UnsafeArray<uint>(s_padding, Allocator.Persistent, AllocationOption.Clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="UnsafeBitSet" /> class.
|
/// Initializes a new instance of the <see cref="UnsafeBitSet" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public UnsafeBitSet(int minimalLength)
|
public UnsafeBitSet(int minimalLength, Allocator allocator, AllocationOption option = AllocationOption.Clear)
|
||||||
{
|
{
|
||||||
var uints = (minimalLength >> _INDEX_SIZE) + int.Sign(minimalLength & _BIT_SIZE);
|
var uints = (minimalLength >> _INDEX_SIZE) + int.Sign(minimalLength & _BIT_SIZE);
|
||||||
var length = RoundToPadding(uints);
|
var length = RoundToPadding(uints);
|
||||||
_bits = new UnsafeArray<uint>(length, Allocator.Persistent);
|
_bits = new UnsafeArray<uint>(length, allocator, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="UnsafeBitSet" /> class.
|
/// Initializes a new instance of the <see cref="UnsafeBitSet" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public UnsafeBitSet(params Span<uint> bits)
|
public UnsafeBitSet(Span<uint> bits, Allocator allocator, AllocationOption option = AllocationOption.Clear)
|
||||||
{
|
{
|
||||||
_bits = new UnsafeArray<uint>(bits.Length, Allocator.Persistent);
|
_bits = new UnsafeArray<uint>(bits.Length, allocator, option);
|
||||||
_bits.CopyFrom(bits);
|
_bits.CopyFrom(bits);
|
||||||
|
|
||||||
_highestBit = 0;
|
_highestBit = 0;
|
||||||
@@ -109,6 +109,11 @@ public struct UnsafeBitSet : IDisposable
|
|||||||
get => _bits.Count;
|
get => _bits.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsCreated
|
||||||
|
{
|
||||||
|
get => _bits.IsCreated;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks whether a bit is set at the index.
|
/// Checks whether a bit is set at the index.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -443,10 +448,88 @@ public struct UnsafeBitSet : IDisposable
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public unsafe void AndOperation(UnsafeBitSet other)
|
||||||
|
{
|
||||||
|
var min = Math.Min(Length, other.Length);
|
||||||
|
var temp = stackalloc uint[min];
|
||||||
|
|
||||||
|
if (!Vector.IsHardwareAccelerated || min < s_padding)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < min; i++)
|
||||||
|
{
|
||||||
|
temp[i] = _bits[i] & other._bits[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (var i = 0; i < min; i += s_padding)
|
||||||
|
{
|
||||||
|
var vectorLeft = new Vector<uint>(_bits.AsSpan()[i..]);
|
||||||
|
var vectorRight = new Vector<uint>(other._bits.AsSpan()[i..]);
|
||||||
|
var resultVector = Vector.BitwiseAnd(vectorLeft, vectorRight);
|
||||||
|
resultVector.CopyTo(new Span<uint>(temp + i, s_padding));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_bits.CopyFrom(new Span<uint>(temp, min));
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe void OrOperation(UnsafeBitSet other)
|
||||||
|
{
|
||||||
|
var min = Math.Min(Length, other.Length);
|
||||||
|
var temp = stackalloc uint[min];
|
||||||
|
|
||||||
|
if (!Vector.IsHardwareAccelerated || min < s_padding)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < min; i++)
|
||||||
|
{
|
||||||
|
temp[i] = _bits[i] | other._bits[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (var i = 0; i < min; i += s_padding)
|
||||||
|
{
|
||||||
|
var vectorLeft = new Vector<uint>(_bits.AsSpan()[i..]);
|
||||||
|
var vectorRight = new Vector<uint>(other._bits.AsSpan()[i..]);
|
||||||
|
var resultVector = Vector.BitwiseOr(vectorLeft, vectorRight);
|
||||||
|
resultVector.CopyTo(new Span<uint>(temp + i, s_padding));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_bits.CopyFrom(new Span<uint>(temp, min));
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe void XorOperation(UnsafeBitSet other)
|
||||||
|
{
|
||||||
|
var min = Math.Min(Length, other.Length);
|
||||||
|
var temp = stackalloc uint[min];
|
||||||
|
|
||||||
|
if (!Vector.IsHardwareAccelerated || min < s_padding)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < min; i++)
|
||||||
|
{
|
||||||
|
temp[i] = _bits[i] ^ other._bits[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (var i = 0; i < min; i += s_padding)
|
||||||
|
{
|
||||||
|
var vectorLeft = new Vector<uint>(_bits.AsSpan()[i..]);
|
||||||
|
var vectorRight = new Vector<uint>(other._bits.AsSpan()[i..]);
|
||||||
|
var resultVector = Vector.Xor(vectorLeft, vectorRight);
|
||||||
|
resultVector.CopyTo(new Span<uint>(temp + i, s_padding));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_bits.CopyFrom(new Span<uint>(temp, min));
|
||||||
|
}
|
||||||
|
|
||||||
public static UnsafeBitSet operator &(UnsafeBitSet left, UnsafeBitSet right)
|
public static UnsafeBitSet operator &(UnsafeBitSet left, UnsafeBitSet right)
|
||||||
{
|
{
|
||||||
var min = Math.Min(left.Length, right.Length);
|
var min = Math.Min(left.Length, right.Length);
|
||||||
var result = new UnsafeBitSet(min);
|
var result = new UnsafeBitSet(min, Allocator.Persistent);
|
||||||
if (!Vector.IsHardwareAccelerated || min < s_padding)
|
if (!Vector.IsHardwareAccelerated || min < s_padding)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < min; i++)
|
for (var i = 0; i < min; i++)
|
||||||
@@ -470,7 +553,7 @@ public struct UnsafeBitSet : IDisposable
|
|||||||
public static UnsafeBitSet operator |(UnsafeBitSet left, UnsafeBitSet right)
|
public static UnsafeBitSet operator |(UnsafeBitSet left, UnsafeBitSet right)
|
||||||
{
|
{
|
||||||
var min = Math.Min(left.Length, right.Length);
|
var min = Math.Min(left.Length, right.Length);
|
||||||
var result = new UnsafeBitSet(min);
|
var result = new UnsafeBitSet(min, Allocator.Persistent);
|
||||||
if (!Vector.IsHardwareAccelerated || min < s_padding)
|
if (!Vector.IsHardwareAccelerated || min < s_padding)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < min; i++)
|
for (var i = 0; i < min; i++)
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ public unsafe struct UnsafeHashMap<TKey, TValue> : IUnsafeCollection<KeyValuePai
|
|||||||
var idx = _hashMap.Find(key);
|
var idx = _hashMap.Find(key);
|
||||||
if (-1 != idx)
|
if (-1 != idx)
|
||||||
{
|
{
|
||||||
UnsafeUtilities.WriteArrayElement(_hashMap.Buffer, idx, value);
|
UnsafeUtility.WriteArrayElement(_hashMap.Buffer, idx, value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ public unsafe struct UnsafeHashMap<TKey, TValue> : IUnsafeCollection<KeyValuePai
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => new Enumerator((HashMapHelper<TKey>*)UnsafeUtilities.AddressOf(ref _hashMap));
|
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => new Enumerator((HashMapHelper<TKey>*)UnsafeUtility.AddressOf(ref _hashMap));
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -125,7 +125,7 @@ public unsafe struct UnsafeHashMap<TKey, TValue> : IUnsafeCollection<KeyValuePai
|
|||||||
var idx = _hashMap.TryAdd(key);
|
var idx = _hashMap.TryAdd(key);
|
||||||
if (idx != -1)
|
if (idx != -1)
|
||||||
{
|
{
|
||||||
UnsafeUtilities.WriteArrayElement(_hashMap.Buffer, idx, item);
|
UnsafeUtility.WriteArrayElement(_hashMap.Buffer, idx, item);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public unsafe struct UnsafeHashSet<T> : IUnsafeCollection<T>, IEnumerable<T>
|
|||||||
public readonly int Capacity => _hashMap.Capacity;
|
public readonly int Capacity => _hashMap.Capacity;
|
||||||
public readonly bool IsCreated => _hashMap.IsCreated;
|
public readonly bool IsCreated => _hashMap.IsCreated;
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator() => new Enumerator((HashMapHelper<T>*)UnsafeUtilities.AddressOf(ref _hashMap));
|
public IEnumerator<T> GetEnumerator() => new Enumerator((HashMapHelper<T>*)UnsafeUtility.AddressOf(ref _hashMap));
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
_index++;
|
_index++;
|
||||||
if (_index < _collection->_count)
|
if (_index < _collection->_count)
|
||||||
{
|
{
|
||||||
_value = UnsafeUtilities.ReadArrayElement<T>(_collection->_array.GetUnsafePtr(), _index);
|
_value = UnsafeUtility.ReadArrayElement<T>(_collection->_array.GetUnsafePtr(), _index);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
{
|
{
|
||||||
var idx = Interlocked.Increment(ref listData->_count) - 1;
|
var idx = Interlocked.Increment(ref listData->_count) - 1;
|
||||||
listData->CheckNoResizeCapacity(idx, 1);
|
listData->CheckNoResizeCapacity(idx, 1);
|
||||||
UnsafeUtilities.WriteArrayElement(listData->_array.GetUnsafePtr(), idx, value);
|
UnsafeUtility.WriteArrayElement(listData->_array.GetUnsafePtr(), idx, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -111,7 +111,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
|
|
||||||
fixed (T* pCollection = collection)
|
fixed (T* pCollection = collection)
|
||||||
{
|
{
|
||||||
MemCpy(UnsafeUtilities.ReadArrayElementUnsafe<T>(listData->_array.GetUnsafePtr(), index), pCollection, (uint)(count * sizeof(T)));
|
MemCpy(UnsafeUtility.ReadArrayElementUnsafe<T>(listData->_array.GetUnsafePtr(), index), pCollection, (uint)(count * sizeof(T)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,14 +136,14 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
get => ref _array[index];
|
get => ref _array[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator() => new Enumerator((UnsafeList<T>*)UnsafeUtilities.AddressOf(ref this));
|
public IEnumerator<T> GetEnumerator() => new Enumerator((UnsafeList<T>*)UnsafeUtility.AddressOf(ref this));
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides a parallel writer for the current list, enabling thread-safe additions to the list.
|
/// Provides a parallel writer for the current list, enabling thread-safe additions to the list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A <see cref="ParallelWriter"/> instance that can be used to add items to the list in a thread-safe manner.</returns>
|
/// <returns>A <see cref="ParallelWriter"/> instance that can be used to add items to the list in a thread-safe manner.</returns>
|
||||||
public ParallelWriter AsParallelWriter() => new((UnsafeList<T>*)UnsafeUtilities.AddressOf(ref this));
|
public ParallelWriter AsParallelWriter() => new((UnsafeList<T>*)UnsafeUtility.AddressOf(ref this));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts the current list to an UnsafeArray representation.
|
/// Converts the current list to an UnsafeArray representation.
|
||||||
@@ -221,6 +221,11 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly ReadOnlyUnsafeCollection<T> AsReadOnly()
|
||||||
|
{
|
||||||
|
return new ReadOnlyUnsafeCollection<T>((T*)_array.GetUnsafePtr(), _count);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a new element to the end of the list, resizing the internal array if necessary.
|
/// Adds a new element to the end of the list, resizing the internal array if necessary.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -232,7 +237,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
Resize(Capacity + (int)(Capacity * 0.5f));
|
Resize(Capacity + (int)(Capacity * 0.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsafeUtilities.WriteArrayElement(_array.GetUnsafePtr(), _count, value);
|
UnsafeUtility.WriteArrayElement(_array.GetUnsafePtr(), _count, value);
|
||||||
_count++;
|
_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +249,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
{
|
{
|
||||||
CheckNoResizeCapacity(1);
|
CheckNoResizeCapacity(1);
|
||||||
|
|
||||||
UnsafeUtilities.WriteArrayElement(_array.GetUnsafePtr(), _count, value);
|
UnsafeUtility.WriteArrayElement(_array.GetUnsafePtr(), _count, value);
|
||||||
_count++;
|
_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +269,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
|
|
||||||
fixed (T* ptr = values)
|
fixed (T* ptr = values)
|
||||||
{
|
{
|
||||||
MemCpy(UnsafeUtilities.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), _count), ptr, (uint)(count * sizeof(T)));
|
MemCpy(UnsafeUtility.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), _count), ptr, (uint)(count * sizeof(T)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_count += count;
|
_count += count;
|
||||||
@@ -280,7 +285,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
|
|
||||||
fixed (T* pCollection = collection)
|
fixed (T* pCollection = collection)
|
||||||
{
|
{
|
||||||
MemCpy(UnsafeUtilities.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), _count), pCollection, (uint)(collection.Length * sizeof(T)));
|
MemCpy(UnsafeUtility.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), _count), pCollection, (uint)(collection.Length * sizeof(T)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_count += collection.Length;
|
_count += collection.Length;
|
||||||
@@ -295,7 +300,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
{
|
{
|
||||||
CheckNoResizeCapacity(count);
|
CheckNoResizeCapacity(count);
|
||||||
|
|
||||||
MemCpy(UnsafeUtilities.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), _count), ptr, (uint)(count * sizeof(T)));
|
MemCpy(UnsafeUtility.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), _count), ptr, (uint)(count * sizeof(T)));
|
||||||
_count += count;
|
_count += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,8 +319,8 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
var copyFrom = Math.Min(start + length, _count);
|
var copyFrom = Math.Min(start + length, _count);
|
||||||
MemCpy(UnsafeUtilities.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), start),
|
MemCpy(UnsafeUtility.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), start),
|
||||||
UnsafeUtilities.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), copyFrom),
|
UnsafeUtility.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), copyFrom),
|
||||||
(uint)((_count - copyFrom) * sizeof(T))
|
(uint)((_count - copyFrom) * sizeof(T))
|
||||||
);
|
);
|
||||||
_count -= length;
|
_count -= length;
|
||||||
@@ -345,8 +350,8 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
var copyFrom = Math.Min(_count - length, start + length);
|
var copyFrom = Math.Min(_count - length, start + length);
|
||||||
MemCpy(UnsafeUtilities.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), start),
|
MemCpy(UnsafeUtility.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), start),
|
||||||
UnsafeUtilities.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), copyFrom),
|
UnsafeUtility.ReadArrayElementUnsafe<T>(_array.GetUnsafePtr(), copyFrom),
|
||||||
(uint)((_count - copyFrom) * sizeof(T))
|
(uint)((_count - copyFrom) * sizeof(T))
|
||||||
);
|
);
|
||||||
_count -= length;
|
_count -= length;
|
||||||
@@ -390,4 +395,3 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>
|
|||||||
_count = 0;
|
_count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public unsafe struct UnsafeQueue<T> : IUnsafeCollection<T>
|
|||||||
_index++;
|
_index++;
|
||||||
if (_index < _collection->_count)
|
if (_index < _collection->_count)
|
||||||
{
|
{
|
||||||
_value = UnsafeUtilities.ReadArrayElement<T>(_collection->_array.GetUnsafePtr(), _index);
|
_value = UnsafeUtility.ReadArrayElement<T>(_collection->_array.GetUnsafePtr(), _index);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ public unsafe struct UnsafeQueue<T> : IUnsafeCollection<T>
|
|||||||
set => _array[index] = value;
|
set => _array[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator() => new Enumerator((UnsafeQueue<T>*)UnsafeUtilities.AddressOf(ref this));
|
public IEnumerator<T> GetEnumerator() => new Enumerator((UnsafeQueue<T>*)UnsafeUtility.AddressOf(ref this));
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -115,7 +115,7 @@ public unsafe struct UnsafeQueue<T> : IUnsafeCollection<T>
|
|||||||
throw new InvalidOperationException("Queue is empty.");
|
throw new InvalidOperationException("Queue is empty.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ref UnsafeUtilities.ReadArrayElementRef<T>(_array.GetUnsafePtr(), _offset);
|
return ref UnsafeUtility.ReadArrayElementRef<T>(_array.GetUnsafePtr(), _offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -130,7 +130,7 @@ public unsafe struct UnsafeQueue<T> : IUnsafeCollection<T>
|
|||||||
Resize(Capacity + (int)(Capacity * 0.5f));
|
Resize(Capacity + (int)(Capacity * 0.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsafeUtilities.WriteArrayElement(_array.GetUnsafePtr(), (_offset + _count) % Capacity, value);
|
UnsafeUtility.WriteArrayElement(_array.GetUnsafePtr(), (_offset + _count) % Capacity, value);
|
||||||
_count++;
|
_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ public unsafe struct UnsafeQueue<T> : IUnsafeCollection<T>
|
|||||||
throw new InvalidOperationException("Queue is empty.");
|
throw new InvalidOperationException("Queue is empty.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var value = UnsafeUtilities.ReadArrayElement<T>(_array.GetUnsafePtr(), _offset);
|
var value = UnsafeUtility.ReadArrayElement<T>(_array.GetUnsafePtr(), _offset);
|
||||||
_offset = (_offset + 1) % Capacity;
|
_offset = (_offset + 1) % Capacity;
|
||||||
_count--;
|
_count--;
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public unsafe struct UnsafeSlotMap<T> : IUnsafeCollection<T>
|
|||||||
|
|
||||||
public readonly bool IsCreated => _data.IsCreated && _freeSlots.IsCreated;
|
public readonly bool IsCreated => _data.IsCreated && _freeSlots.IsCreated;
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator() => new Enumerator((UnsafeSlotMap<T>*)UnsafeUtilities.AddressOf(ref this));
|
public IEnumerator<T> GetEnumerator() => new Enumerator((UnsafeSlotMap<T>*)UnsafeUtility.AddressOf(ref this));
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public unsafe struct UnsafeSparseSet<T> : IUnsafeCollection<T>
|
|||||||
public readonly int Capacity => _capacity;
|
public readonly int Capacity => _capacity;
|
||||||
public readonly bool IsCreated => _dense.IsCreated && _sparse.IsCreated && _reverse.IsCreated;
|
public readonly bool IsCreated => _dense.IsCreated && _sparse.IsCreated && _reverse.IsCreated;
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator() => new Enumerator((UnsafeSparseSet<T>*)UnsafeUtilities.AddressOf(ref this));
|
public IEnumerator<T> GetEnumerator() => new Enumerator((UnsafeSparseSet<T>*)UnsafeUtility.AddressOf(ref this));
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public unsafe struct UnsafeStack<T> : IUnsafeCollection<T>
|
|||||||
Resize(_array.Count + (int)(_array.Count * 0.5f));
|
Resize(_array.Count + (int)(_array.Count * 0.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsafeUtilities.WriteArrayElement(_array.GetUnsafePtr(), _count, value);
|
UnsafeUtility.WriteArrayElement(_array.GetUnsafePtr(), _count, value);
|
||||||
_count++;
|
_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="Collections\FixedString.tt">
|
<None Update="Collections\FixedText.tt">
|
||||||
<Generator>TextTemplatingFileGenerator</Generator>
|
<Generator>TextTemplatingFileGenerator</Generator>
|
||||||
<LastGenOutput>FixedString.cs</LastGenOutput>
|
<LastGenOutput>FixedText.cs</LastGenOutput>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@@ -32,10 +32,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Update="Collections\FixedString.cs">
|
<Compile Update="Collections\FixedText.cs">
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
<DependentUpon>FixedString.tt</DependentUpon>
|
<DependentUpon>FixedText.tt</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public unsafe struct HashMapHelper<TKey> : IDisposable
|
|||||||
public KeyValuePair<TKey, TValue> GetCurrent<TValue>()
|
public KeyValuePair<TKey, TValue> GetCurrent<TValue>()
|
||||||
where TValue : unmanaged
|
where TValue : unmanaged
|
||||||
{
|
{
|
||||||
return new KeyValuePair<TKey, TValue>(buffer->_keys[index], UnsafeUtilities.ReadArrayElementRef<TValue>(buffer->_buffer, index));
|
return new KeyValuePair<TKey, TValue>(buffer->_keys[index], UnsafeUtility.ReadArrayElementRef<TValue>(buffer->_buffer, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -246,7 +246,7 @@ public unsafe struct HashMapHelper<TKey> : IDisposable
|
|||||||
if ((uint)entryIdx < (uint)_capacity)
|
if ((uint)entryIdx < (uint)_capacity)
|
||||||
{
|
{
|
||||||
var nextPtrs = _next;
|
var nextPtrs = _next;
|
||||||
while (!UnsafeUtilities.ReadArrayElement<TKey>(_keys, entryIdx).Equals(key))
|
while (!UnsafeUtility.ReadArrayElement<TKey>(_keys, entryIdx).Equals(key))
|
||||||
{
|
{
|
||||||
entryIdx = nextPtrs[entryIdx];
|
entryIdx = nextPtrs[entryIdx];
|
||||||
if ((uint)entryIdx >= (uint)_capacity)
|
if ((uint)entryIdx >= (uint)_capacity)
|
||||||
@@ -292,7 +292,7 @@ public unsafe struct HashMapHelper<TKey> : IDisposable
|
|||||||
|
|
||||||
CheckIndexOutOfBounds(idx);
|
CheckIndexOutOfBounds(idx);
|
||||||
|
|
||||||
UnsafeUtilities.WriteArrayElement(_keys, idx, key);
|
UnsafeUtility.WriteArrayElement(_keys, idx, key);
|
||||||
var bucket = GetBucket(key);
|
var bucket = GetBucket(key);
|
||||||
|
|
||||||
// Add the index to the hash-map
|
// Add the index to the hash-map
|
||||||
@@ -321,7 +321,7 @@ public unsafe struct HashMapHelper<TKey> : IDisposable
|
|||||||
|
|
||||||
while (entryIdx >= 0 && entryIdx < _capacity)
|
while (entryIdx >= 0 && entryIdx < _capacity)
|
||||||
{
|
{
|
||||||
if (UnsafeUtilities.ReadArrayElement<TKey>(_keys, entryIdx).Equals(key))
|
if (UnsafeUtility.ReadArrayElement<TKey>(_keys, entryIdx).Equals(key))
|
||||||
{
|
{
|
||||||
removed++;
|
removed++;
|
||||||
|
|
||||||
@@ -361,7 +361,7 @@ public unsafe struct HashMapHelper<TKey> : IDisposable
|
|||||||
|
|
||||||
if (idx != -1)
|
if (idx != -1)
|
||||||
{
|
{
|
||||||
item = UnsafeUtilities.ReadArrayElement<TValue>(_buffer, idx);
|
item = UnsafeUtility.ReadArrayElement<TValue>(_buffer, idx);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,7 +414,7 @@ public unsafe struct HashMapHelper<TKey> : IDisposable
|
|||||||
|
|
||||||
while (bucket != -1)
|
while (bucket != -1)
|
||||||
{
|
{
|
||||||
result[count++] = UnsafeUtilities.ReadArrayElement<TKey>(_keys, bucket);
|
result[count++] = UnsafeUtility.ReadArrayElement<TKey>(_keys, bucket);
|
||||||
bucket = _next[bucket];
|
bucket = _next[bucket];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -433,7 +433,7 @@ public unsafe struct HashMapHelper<TKey> : IDisposable
|
|||||||
|
|
||||||
while (bucket != -1)
|
while (bucket != -1)
|
||||||
{
|
{
|
||||||
result[count++] = UnsafeUtilities.ReadArrayElement<TValue>(_buffer, bucket);
|
result[count++] = UnsafeUtility.ReadArrayElement<TValue>(_buffer, bucket);
|
||||||
bucket = _next[bucket];
|
bucket = _next[bucket];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -452,8 +452,8 @@ public unsafe struct HashMapHelper<TKey> : IDisposable
|
|||||||
|
|
||||||
while (bucket != -1)
|
while (bucket != -1)
|
||||||
{
|
{
|
||||||
result[count] = new(UnsafeUtilities.ReadArrayElement<TKey>(_keys, bucket),
|
result[count] = new(UnsafeUtility.ReadArrayElement<TKey>(_keys, bucket),
|
||||||
UnsafeUtilities.ReadArrayElement<TValue>(_buffer, bucket));
|
UnsafeUtility.ReadArrayElement<TValue>(_buffer, bucket));
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
bucket = _next[bucket];
|
bucket = _next[bucket];
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Runtime.Intrinsics;
|
|||||||
|
|
||||||
namespace Misaki.HighPerformance.LowLevel.Utilities;
|
namespace Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
|
|
||||||
public static unsafe partial class MemoryUtilities
|
public static unsafe partial class MemoryUtility
|
||||||
{
|
{
|
||||||
[DoesNotReturn]
|
[DoesNotReturn]
|
||||||
private static void ThrowMustBeNullTerminatedString()
|
private static void ThrowMustBeNullTerminatedString()
|
||||||
@@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Misaki.HighPerformance.LowLevel.Utilities;
|
namespace Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
|
|
||||||
public static unsafe partial class MemoryUtilities
|
public static unsafe partial class MemoryUtility
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
private struct AlignOfHelper<T>
|
private struct AlignOfHelper<T>
|
||||||
@@ -3,7 +3,7 @@ using System.Runtime.CompilerServices;
|
|||||||
|
|
||||||
namespace Misaki.HighPerformance.LowLevel.Utilities;
|
namespace Misaki.HighPerformance.LowLevel.Utilities;
|
||||||
|
|
||||||
public static unsafe class UnsafeUtilities
|
public static unsafe class UnsafeUtility
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts a pointer to a reference of a specified type.
|
/// Converts a pointer to a reference of a specified type.
|
||||||
@@ -6,7 +6,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
{
|
{
|
||||||
internal abstract class GeneratorBase
|
internal abstract class GeneratorBase
|
||||||
{
|
{
|
||||||
protected const string INLINE_METHOD_ATTRIBUTE = "[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]";
|
protected const string INLINE_METHOD_ATTRIBUTE = "[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining | global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveOptimization)]";
|
||||||
|
|
||||||
protected static readonly string[] s_matrixComponents = new[] { "c0", "c1", "c2", "c3" };
|
protected static readonly string[] s_matrixComponents = new[] { "c0", "c1", "c2", "c3" };
|
||||||
protected static readonly string[] s_vectorComponents = new[] { "x", "y", "z", "w" };
|
protected static readonly string[] s_vectorComponents = new[] { "x", "y", "z", "w" };
|
||||||
@@ -70,7 +70,7 @@ namespace {typeInfo.TypeSymbol.ContainingNamespace.ToDisplayString()}
|
|||||||
protected virtual void GenerateTypeStart()
|
protected virtual void GenerateTypeStart()
|
||||||
{
|
{
|
||||||
sourceBuilder.Append($@"
|
sourceBuilder.Append($@"
|
||||||
[global::System.Runtime.CompilerServices.SkipLocalsInit]
|
//[global::System.Runtime.CompilerServices.SkipLocalsInit]
|
||||||
public partial struct {typeInfo.TypeSymbol.Name} : global::System.IEquatable<{typeInfo.TypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>
|
public partial struct {typeInfo.TypeSymbol.Name} : global::System.IEquatable<{typeInfo.TypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>
|
||||||
{{");
|
{{");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -515,13 +515,6 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
}
|
}
|
||||||
|
|
||||||
GenerateMulMethod();
|
GenerateMulMethod();
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeInfo.TypeFullName} abs({typeInfo.TypeFullName} value)
|
|
||||||
{{
|
|
||||||
return new({string.Join(", ", s_matrixComponents.Take(typeInfo.Column).Select(c => $"abs(value.{c})"))});
|
|
||||||
}}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceBuilder.Append($@"
|
sourceBuilder.Append($@"
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
private int _missingComponents;
|
private int _missingComponents;
|
||||||
private string _componentTypePrefix = null!;
|
private string _componentTypePrefix = null!;
|
||||||
|
|
||||||
private readonly List<(string signature, string assignment)> _constructorSignatures = new();
|
private readonly List<(string signature, List<string> assignment)> _constructorSignatures = new();
|
||||||
|
|
||||||
private string GetConversionFromTemplate(string template, int componentIndex)
|
private string GetConversionFromTemplate(string template, int componentIndex)
|
||||||
{
|
{
|
||||||
@@ -209,7 +209,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
|
|
||||||
_constructorSignatures.Add((
|
_constructorSignatures.Add((
|
||||||
signature: $"{componentType} value",
|
signature: $"{componentType} value",
|
||||||
assignment: string.Join(", ", Enumerable.Range(0, typeInfo.Row).Select(_ => "value"))));
|
assignment: Enumerable.Range(0, typeInfo.Row).Select(_ => "value").ToList()));
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(typeInfo.TypePrefix))
|
if (string.IsNullOrEmpty(typeInfo.TypePrefix))
|
||||||
{
|
{
|
||||||
@@ -253,8 +253,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var assignment = string.Join(", ", assignments);
|
_constructorSignatures.Add((signature, assignments));
|
||||||
_constructorSignatures.Add((signature, assignment));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,58 +264,34 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
var targetTemplate = kv.Key;
|
var targetTemplate = kv.Key;
|
||||||
var targetTypes = kv.Value;
|
var targetTypes = kv.Value;
|
||||||
|
|
||||||
var tempSB = new StringBuilder();
|
|
||||||
foreach (var type in targetTypes)
|
foreach (var type in targetTypes)
|
||||||
{
|
{
|
||||||
|
var assignments = new List<string>();
|
||||||
for (var i = 0; i < typeInfo.Row; i++)
|
for (var i = 0; i < typeInfo.Row; i++)
|
||||||
{
|
{
|
||||||
tempSB.Append(GetConversionFromTemplate(targetTemplate, i));
|
assignments.Add(GetConversionFromTemplate(targetTemplate, i));
|
||||||
if (i < typeInfo.Row - 1)
|
|
||||||
{
|
|
||||||
tempSB.Append(", ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_constructorSignatures.Add((
|
_constructorSignatures.Add((
|
||||||
signature: $"{type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} v",
|
signature: $"{type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} v",
|
||||||
assignment: tempSB.ToString()));
|
assignment: assignments));
|
||||||
|
|
||||||
tempSB.Clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (signature, assignment) in _constructorSignatures)
|
foreach (var (signature, assignment) in _constructorSignatures)
|
||||||
{
|
{
|
||||||
sourceBuilder.AppendLine($@"
|
sourceBuilder.Append($@"
|
||||||
public {typeName}({signature})
|
public {typeName}({signature})
|
||||||
{{
|
|
||||||
this = Create({assignment});
|
|
||||||
}}");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sourceBuilder.Append($@"
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeName} Create({string.Join(", ", Enumerable.Range(0, typeInfo.Row).Select((_, i) => $"{typeInfo.ComponentTypeFullName} {s_vectorComponents[i]}"))})
|
|
||||||
{{");
|
{{");
|
||||||
|
for (var i = 0; i < typeInfo.Row; i++)
|
||||||
if (typeInfo.VectorType != null)
|
|
||||||
{
|
{
|
||||||
sourceBuilder.Append($@"
|
sourceBuilder.Append($@"
|
||||||
global::System.Span<{typeInfo.ComponentTypeFullName}> span = [{string.Join(", ", Enumerable.Range(0, typeInfo.Row + _missingComponents).Select(i => i < typeInfo.Row ? $"{s_vectorComponents[i]}" : "default"))}];
|
this.{s_vectorComponents[i]} = {assignment[i]};");
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Create(global::System.Runtime.CompilerServices.Unsafe.As<global::System.Span<{typeInfo.ComponentTypeFullName}>, global::System.ReadOnlySpan<{typeInfo.VectorTypeFullName}>>(ref span));");
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
sourceBuilder.Append($@"
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Create({string.Join(", ", Enumerable.Range(0, typeInfo.Row + _missingComponents).Select(i => i < typeInfo.Row ? $"{s_vectorComponents[i]}" : "default"))});");
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
sourceBuilder.AppendLine($@"
|
||||||
ref var address = ref global::System.Runtime.CompilerServices.Unsafe.As<global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}<{typeInfo.VectorTypeFullName}>, byte>(ref vector);
|
|
||||||
return global::System.Runtime.CompilerServices.Unsafe.ReadUnaligned<{typeInfo.TypeFullName}>(ref address);
|
|
||||||
}}");
|
}}");
|
||||||
|
}
|
||||||
|
|
||||||
EndRegion();
|
EndRegion();
|
||||||
}
|
}
|
||||||
@@ -434,23 +409,22 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator +({typeName} lhs, {typeName} rhs)
|
public static {typeName} operator +({typeName} lhs, {typeName} rhs)
|
||||||
{{
|
{{
|
||||||
return (lhs.AsVector{_vectorBitsSize}() + rhs.AsVector{_vectorBitsSize}()).{asResult};
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs.{c} + rhs.{c}"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator +({typeName} lhs, {componentType} rhs)
|
public static {typeName} operator +({typeName} lhs, {componentType} rhs)
|
||||||
{{
|
{{
|
||||||
return lhs + new {typeName}(rhs);
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs.{c} + rhs"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator +({componentType} lhs, {typeName} rhs)
|
public static {typeName} operator +({componentType} lhs, {typeName} rhs)
|
||||||
{{
|
{{
|
||||||
return new {typeName}(lhs) + rhs;
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs + rhs.{c}"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#if NET10_0_OR_GREATER
|
#if false //NET10_0_OR_GREATER
|
||||||
// Use scaler here to let JIT handle the simd optimization since we can not do a in-place vectorlization manually.
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public void operator +=({typeName} other)
|
public void operator +=({typeName} other)
|
||||||
{{");
|
{{");
|
||||||
@@ -469,23 +443,22 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator -({typeName} lhs, {typeName} rhs)
|
public static {typeName} operator -({typeName} lhs, {typeName} rhs)
|
||||||
{{
|
{{
|
||||||
return (lhs.AsVector{_vectorBitsSize}() - rhs.AsVector{_vectorBitsSize}()).{asResult};
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs.{c} - rhs.{c}"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator -({typeName} lhs, {componentType} rhs)
|
public static {typeName} operator -({typeName} lhs, {componentType} rhs)
|
||||||
{{
|
{{
|
||||||
return lhs - new {typeName}(rhs);
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs.{c} - rhs"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator -({componentType} lhs, {typeName} rhs)
|
public static {typeName} operator -({componentType} lhs, {typeName} rhs)
|
||||||
{{
|
{{
|
||||||
return new {typeName}(lhs) - rhs;
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs - rhs.{c}"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#if NET10_0_OR_GREATER
|
#if NET10_0_OR_GREATER
|
||||||
// Use scaler here to let JIT handle the simd optimization since we can not do a in-place vectorlization manually.
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public void operator -=({typeName} other)
|
public void operator -=({typeName} other)
|
||||||
{{");
|
{{");
|
||||||
@@ -504,19 +477,19 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator *({typeName} lhs, {typeName} rhs)
|
public static {typeName} operator *({typeName} lhs, {typeName} rhs)
|
||||||
{{
|
{{
|
||||||
return (lhs.AsVector{_vectorBitsSize}() * rhs.AsVector{_vectorBitsSize}()).{asResult};
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs.{c} * rhs.{c}"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator *({typeName} lhs, {componentType} rhs)
|
public static {typeName} operator *({typeName} lhs, {componentType} rhs)
|
||||||
{{
|
{{
|
||||||
return (lhs.AsVector{_vectorBitsSize}() * rhs).{asResult};
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs.{c} * rhs"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator *({componentType} lhs, {typeName} rhs)
|
public static {typeName} operator *({componentType} lhs, {typeName} rhs)
|
||||||
{{
|
{{
|
||||||
return new {typeName}(lhs) * rhs;
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs * rhs.{c}"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#if NET10_0_OR_GREATER
|
#if NET10_0_OR_GREATER
|
||||||
@@ -539,19 +512,19 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator /({typeName} lhs, {typeName} rhs)
|
public static {typeName} operator /({typeName} lhs, {typeName} rhs)
|
||||||
{{
|
{{
|
||||||
return (lhs.AsVector{_vectorBitsSize}() / rhs.AsVector{_vectorBitsSize}()).{asResult};
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs.{c} / rhs.{c}"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator /({typeName} lhs, {componentType} rhs)
|
public static {typeName} operator /({typeName} lhs, {componentType} rhs)
|
||||||
{{
|
{{
|
||||||
return (lhs.AsVector{_vectorBitsSize}() / rhs).{asResult};
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs.{c} / rhs"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator /({componentType} lhs, {typeName} rhs)
|
public static {typeName} operator /({componentType} lhs, {typeName} rhs)
|
||||||
{{
|
{{
|
||||||
return new {typeName}(lhs) / rhs;
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs / rhs.{c}"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#if NET10_0_OR_GREATER
|
#if NET10_0_OR_GREATER
|
||||||
@@ -580,13 +553,13 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator %({typeName} lhs, {componentType} rhs)
|
public static {typeName} operator %({typeName} lhs, {componentType} rhs)
|
||||||
{{
|
{{
|
||||||
return lhs % new {typeName}(rhs);
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs.{c} % rhs"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator %({componentType} lhs, {typeName} rhs)
|
public static {typeName} operator %({componentType} lhs, {typeName} rhs)
|
||||||
{{
|
{{
|
||||||
return new {typeName}(lhs) % rhs;
|
return new {typeName}({string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(c => $"lhs % rhs.{c}"))});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#if NET10_0_OR_GREATER
|
#if NET10_0_OR_GREATER
|
||||||
@@ -615,19 +588,19 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator -({typeName} value)
|
public static {typeName} operator -({typeName} value)
|
||||||
{{
|
{{
|
||||||
return (-value.AsVector{_vectorBitsSize}()).{asResult};
|
return new {typeName}(0{_componentTypePrefix}) - value;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator ++({typeName} value)
|
public static {typeName} operator ++({typeName} value)
|
||||||
{{
|
{{
|
||||||
return (value.AsVector{_vectorBitsSize}() + global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.CreateScalar(1{_componentTypePrefix})).{asResult};
|
return value + new {typeName}(1{_componentTypePrefix});
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeName} operator --({typeName} value)
|
public static {typeName} operator --({typeName} value)
|
||||||
{{
|
{{
|
||||||
return (value.AsVector{_vectorBitsSize}() - global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.CreateScalar(1{_componentTypePrefix})).{asResult};
|
return value - new {typeName}(1{_componentTypePrefix});
|
||||||
}}");
|
}}");
|
||||||
|
|
||||||
// Comparison operators
|
// Comparison operators
|
||||||
@@ -788,7 +761,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
sourceBuilder.Append($@"
|
sourceBuilder.Append($@"
|
||||||
return global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Create({string.Join(", ", Enumerable.Range(0, typeInfo.Row + _missingComponents).Select(i => i < typeInfo.Row ? $"value.{s_vectorComponents[i]}" : "0"))});");
|
return global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Create({string.Join(", ", Enumerable.Range(0, typeInfo.Row + _missingComponents).Select(i => i < typeInfo.Row ? $"value.{s_vectorComponents[i]}" : "default"))});");
|
||||||
}
|
}
|
||||||
sourceBuilder.Append($@"
|
sourceBuilder.Append($@"
|
||||||
}}
|
}}
|
||||||
@@ -803,11 +776,6 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
}}");
|
}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ComponentwiseAssignments(Func<string, string> func, string separator = ", ")
|
|
||||||
{
|
|
||||||
return string.Join(separator, s_vectorComponents.Take(typeInfo.Row).Select(func));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GenerateMathMethod()
|
private void GenerateMathMethod()
|
||||||
{
|
{
|
||||||
var typeName = typeInfo.TypeName;
|
var typeName = typeInfo.TypeName;
|
||||||
@@ -824,7 +792,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
{INLINE_METHOD_ATTRIBUTE}
|
{INLINE_METHOD_ATTRIBUTE}
|
||||||
public static {typeFullName} {typeName}({signature})
|
public static {typeFullName} {typeName}({signature})
|
||||||
{{
|
{{
|
||||||
return {typeFullName}.Create({assignment});
|
return new {typeFullName}({string.Join(", ", assignment)});
|
||||||
}}");
|
}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -881,724 +849,6 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
|
|||||||
throw new System.ArgumentException(""Invalid shuffle component: "" + component);
|
throw new System.ArgumentException(""Invalid shuffle component: "" + component);
|
||||||
}}
|
}}
|
||||||
}}");
|
}}");
|
||||||
|
|
||||||
if (typeInfo.ComponentTypeSymbol.SpecialType == SpecialType.System_Boolean)
|
|
||||||
{
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns true if any component of the input {typeName} vector is true, false otherwise.</summary>
|
|
||||||
/// <param name=""v"">Vector of values to compare.</param>
|
|
||||||
/// <returns>True if any the components of v are true, false otherwise.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static bool any({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return {ComponentwiseAssignments(c => $"v.{c}", " ||")};
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns true if all component of the input {typeName} vector is true, false otherwise.</summary>
|
|
||||||
/// <param name=""v"">Vector of values to compare.</param>
|
|
||||||
/// <returns>True if all the components of v are true, false otherwise.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static bool all({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return {ComponentwiseAssignments(c => $"v.{c}", " && ")};
|
|
||||||
}}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeInfo.Arithmetic)
|
|
||||||
{
|
|
||||||
StartRegion("Math Methods");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise minimum of two {typeName} vectors.</summary>
|
|
||||||
/// <param name=""x"">The first vector to compare.</param>
|
|
||||||
/// <param name=""y"">The second vector to compare.</param>
|
|
||||||
/// <returns>The componentwise minimum of the two vectors.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} min({typeFullName} x, {typeFullName} y)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Min(x.AsVector{_vectorBitsSize}(), y.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise maximum of two {typeName} vectors.</summary>
|
|
||||||
/// <param name=""x"">The first vector to compare.</param>
|
|
||||||
/// <param name=""y"">The second vector to compare.</param>
|
|
||||||
/// <returns>The componentwise maximum of the two vectors.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} max({typeFullName} x, {typeFullName} y)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Max(x.AsVector{_vectorBitsSize}(), y.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise absolute value of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise absolute value of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} abs({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return max(v, -v);
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the result of a componentwise clamping of the value v into the interval (inclusive) [min, max], where v, min and max are {typeName} vectors.</summary>
|
|
||||||
/// <param name=""v"">Input value to be clamped.</param>
|
|
||||||
/// <param name=""min"">Lower bound of the interval.</param>
|
|
||||||
/// <param name=""max"">Upper bound of the interval.</param>
|
|
||||||
/// <returns>The componentwise clamping of the input valueToClamp into the interval (inclusive) [min, max].</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} clamp({typeFullName} v, {typeFullName} min, {typeFullName} max)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Clamp(v.AsVector{_vectorBitsSize}(), min.AsVector{_vectorBitsSize}(), max.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the dot product of two {typeName} vectors.</summary>
|
|
||||||
/// <param name=""x"">The first vector to dot.</param>
|
|
||||||
/// <param name=""y"">The second vector to dot.</param>
|
|
||||||
/// <returns>The dot product of the two vectors.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {componentTypeFullName} dot({typeFullName} x, {typeFullName} y)
|
|
||||||
{{
|
|
||||||
return global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Dot(x.AsVector{_vectorBitsSize}(), y.AsVector{_vectorBitsSize}());
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns trueValue if test is true, falseValue otherwise.</summary>
|
|
||||||
/// <param name=""falseValue"">Value to use if test is false.</param>
|
|
||||||
/// <param name=""trueValue"">Value to use if test is true.</param>
|
|
||||||
/// <param name=""test"">Bool value to choose between falseValue and trueValue.</param>
|
|
||||||
/// <returns>The selection between falseValue and trueValue according to bool test.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} select({typeFullName} falseValue, {typeFullName} trueValue, bool test)
|
|
||||||
{{
|
|
||||||
return test ? trueValue : falseValue;
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a componentwise selection between two {typeName} vectors falseValue and trueValue based on a bool{typeInfo.Row} selection mask test.
|
|
||||||
/// Per component, the component from trueValue is selected when test is true, otherwise the component from falseValue is selected.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name=""falseValue"">Values to use if test is false.</param>
|
|
||||||
/// <param name=""trueValue"">Values to use if test is true.</param>
|
|
||||||
/// <param name=""test"">Selection mask to choose between falseValue and trueValue.</param>
|
|
||||||
/// <returns>The componentwise selection between falseValue and trueValue according to selection mask test.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} select({typeFullName} falseValue, {typeFullName} trueValue, global::Misaki.HighPerformance.Mathematics.bool{typeInfo.Row} test)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"test.{c} ? trueValue.{c} : falseValue.{c}")});
|
|
||||||
}}");
|
|
||||||
|
|
||||||
if (typeInfo.ComponentTypeSymbol.SpecialType != SpecialType.System_UInt16
|
|
||||||
&& typeInfo.ComponentTypeSymbol.SpecialType != SpecialType.System_UInt32
|
|
||||||
&& typeInfo.ComponentTypeSymbol.SpecialType != SpecialType.System_UInt64)
|
|
||||||
{
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise sign of a {typeName} vector. 1 for positive components, 0 for zero components and -1 for negative components.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise sign of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} sign({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"sign(v.{c})")});
|
|
||||||
}}");
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns true if any component of the input {typeName} vector is true, false otherwise.</summary>
|
|
||||||
/// <param name=""v"">Vector of values to compare.</param>
|
|
||||||
/// <returns>True if any the components of v are true, false otherwise.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static bool any({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return {ComponentwiseAssignments(c => $"v.{c} != 0", " || ")};
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns true if all component of the input {typeName} vector is true, false otherwise.</summary>
|
|
||||||
/// <param name=""v"">Vector of values to compare.</param>
|
|
||||||
/// <returns>True if all the components of v are true, false otherwise.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static bool all({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return {ComponentwiseAssignments(c => $"v.{c} != 0", " && ")};
|
|
||||||
}}");
|
|
||||||
|
|
||||||
// Only floating point types support these methods
|
|
||||||
if (typeInfo.ComponentTypeSymbol.SpecialType == SpecialType.System_Single
|
|
||||||
|| typeInfo.ComponentTypeSymbol.SpecialType == SpecialType.System_Double)
|
|
||||||
{
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the result of a componentwise clamping of the {typeName} vector v into the interval [0, 1].</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise clamping of the input into the interval [0, 1].</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} saturate({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return clamp(v, new {typeFullName}(0{_componentTypePrefix}), new {typeFullName}(1{_componentTypePrefix}));
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the linear interpolation between two {typeName} vectors x and y by the interpolant t.</summary>
|
|
||||||
/// <param name=""x"">The vector when t is 0.</param>
|
|
||||||
/// <param name=""y"">The vector when t is 1.</param>
|
|
||||||
/// <param name=""t"">The interpolation factor.</param>
|
|
||||||
/// <returns>The linearly interpolated vector.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} lerp({typeFullName} x, {typeFullName} y, {componentTypeFullName} t)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Lerp(x.AsVector{_vectorBitsSize}(), y.AsVector{_vectorBitsSize}(), global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Create(t));
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the result of a componentwise linear interpolation between two {typeName} vectors x and y using a {typeName} vector t.</summary>
|
|
||||||
/// <param name=""x"">The value to interpolate from.</param>
|
|
||||||
/// <param name=""y"">The value to interpolate to.</param>
|
|
||||||
/// <param name=""t"">The interpolation factor.</param>
|
|
||||||
/// <returns>The linearly interpolated vector.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} lerp({typeFullName} x, {typeFullName} y, {typeFullName} t)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Lerp(x.AsVector{_vectorBitsSize}(), y.AsVector{_vectorBitsSize}(), t.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise result of normalizing a value x to a range [a, b]. The opposite of lerp. Equivalent to (v - a) / (b - a).</summary>
|
|
||||||
/// <param name=""start"">The start point of the range.</param>
|
|
||||||
/// <param name=""end"">The end point of the range.</param>
|
|
||||||
/// <param name=""v""> The value to normalize to the range.</param>
|
|
||||||
/// <returns>The componentwise interpolation parameter of x with respect to the input range [a, b].</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} unlerp({typeFullName} start, {typeFullName} end, {typeFullName} v)
|
|
||||||
{{
|
|
||||||
return (v - start) / (end - start);
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise result of a non-clamping linear remapping of a value x from source range [srcStart, srcEnd] to the destination range [dstStart, dstEnd].</summary>
|
|
||||||
/// <param name=""srcStart"">The start point of the source range [srcStart, srcEnd].</param>
|
|
||||||
/// <param name=""srcEnd"">The end point of the source range [srcStart, srcEnd].</param>
|
|
||||||
/// <param name=""dstStart"">The start point of the destination range [dstStart, dstEnd].</param>
|
|
||||||
/// <param name=""dstEnd"">The end point of the destination range [dstStart, dstEnd].</param>
|
|
||||||
/// <param name=""v"">The value to remap from the source to destination range.</param>
|
|
||||||
/// <returns>The componentwise remap of input x from the source range to the destination range.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} remap({typeFullName} srcStart, {typeFullName} srcEnd, {typeFullName} dstStart, {typeFullName} dstEnd, {typeFullName} v)
|
|
||||||
{{
|
|
||||||
return lerp(dstStart, dstEnd, unlerp(srcStart, srcEnd, v));
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the result of a componentwise multiply-add operation (a * b + c) on 3 {typeName} vectors.</summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// When fast math enabled on some architectures, this could be converted to a fused multiply add (FMA).
|
|
||||||
/// FMA is more accurate due to rounding once at the end of the computation rather than twice that is required when
|
|
||||||
/// this computation is not fused.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name=""mulA"">First value to multiply.</param>
|
|
||||||
/// <param name=""mulB"">Second value to multiply.</param>
|
|
||||||
/// <param name=""addC"">Third value to add to the product of a and b.</param>
|
|
||||||
/// <returns>The componentwise multiply-add of the inputs.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} mad({typeFullName} mulA, {typeFullName} mulB, {typeFullName} addC)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.FusedMultiplyAdd(mulA.AsVector{_vectorBitsSize}(), mulB.AsVector{_vectorBitsSize}(), addC.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise tangent of a {typeFullName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise tangent of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} tan({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"tan(v.{c})")});
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise hyperbolic tangent of a {typeFullName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise hyperbolic tangent of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} tanh({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"tanh(v.{c})")});
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise arctangent of a {typeFullName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise arctangent of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} atan({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"atan(v.{c})")});
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise 2-argument arctangent of a {typeFullName} vector.</summary>
|
|
||||||
/// <param name=""x"">Input value x.</param>
|
|
||||||
/// <param name=""y"">Input value y.</param>
|
|
||||||
/// <returns>The componentwise 2-argument arctangent of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} atan2({typeFullName} x, {typeFullName} y)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"atan2(x.{c}, y.{c})")});
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise cosine of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise cosine of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} cos({typeFullName} v)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Cos(v.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise hyperbolic cosine of a {typeFullName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise hyperbolic cosine of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} cosh({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"cosh(v.{c})")});
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise arccosine of a {typeFullName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise arccosine of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} acos({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"acos(v.{c})")});
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise sine of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise sine of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} sin({typeFullName} v)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Sin(v.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise hyperbolic sine of a {typeFullName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise hyperbolic sine of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} sinh({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"sinh(v.{c})")});
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise arcsine of a {typeFullName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise arcsine of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} asin({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"asin(v.{c})")});
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise sine and cosine of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise sine and cosine of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static ({typeFullName} sin, {typeFullName} cos) sincos({typeFullName} v)
|
|
||||||
{{
|
|
||||||
var vectors = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.SinCos(v.AsVector{_vectorBitsSize}());
|
|
||||||
return (vectors.Sin.As{typeName}(), vectors.Cos.As{typeName}());
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise floor of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise floor of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} floor({typeFullName} v)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Floor(v.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise ceiling of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise ceiling of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} ceil({typeFullName} v)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Ceiling(v.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the result of rounding each component of a {typeName} vector value to the nearest integral value.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise round to nearest integral value of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} round({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"round(v.{c})")});
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise base-e exponential of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise base-e exponential of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} exp({typeFullName} v)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Exp(v.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise base-2 exponential of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise base-2 exponential of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} exp2({typeFullName} v)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Exp(v.AsVector{_vectorBitsSize}() * 0.693147180559945309{_componentTypePrefix});
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise base-10 exponential of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise base-10 exponential of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} exp10({typeFullName} v)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Exp(v.AsVector{_vectorBitsSize}() * 2.302585092994045684{_componentTypePrefix});
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise natural logarithm (base-e) of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise natural logarithm of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} log({typeFullName} v)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Log(v.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise base-2 logarithm of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise base-2 logarithm of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} log2({typeFullName} v)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Log2(v.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise base-10 logarithm of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise base-10 logarithm of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} log10({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"log10(v.{c})")});
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise quadratic root of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise quadratic root of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} sqrt({typeFullName} v)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Sqrt(v.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the reciprocal square root of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Value to use when computing reciprocal square root.</param>
|
|
||||||
/// <returns>The reciprocal square root.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} rsqrt({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return 1{_componentTypePrefix} / sqrt(v);
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the length of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Vector to use when computing length.</param>
|
|
||||||
/// <returns>Length of vector v.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {componentTypeFullName} length({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return sqrt(dot(v, v));
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the squared length of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Vector to use when computing squared length.</param>
|
|
||||||
/// <returns>Squared length of vector v.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {componentTypeFullName} lengthsq({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return dot(v, v);
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the distance between two {typeName} vectors.</summary>
|
|
||||||
/// <param name=""x"">First vector to use in distance computation.</param>
|
|
||||||
/// <param name=""y"">Second vector to use in distance computation.</param>
|
|
||||||
/// <returns>The distance between x and y.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {componentTypeFullName} distance({typeFullName} x, {typeFullName} y)
|
|
||||||
{{
|
|
||||||
return length(y - x);
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the squared distance between two {typeName} vectors.</summary>
|
|
||||||
/// <param name=""x"">First vector to use in distance computation.</param>
|
|
||||||
/// <param name=""y"">Second vector to use in distance computation.</param>
|
|
||||||
/// <returns>The squared distance between x and y.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {componentTypeFullName} distancesq({typeFullName} x, {typeFullName} y)
|
|
||||||
{{
|
|
||||||
return lengthsq(y - x);
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise truncate of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise truncate of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} trunc({typeFullName} v)
|
|
||||||
{{
|
|
||||||
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Truncate(v.AsVector{_vectorBitsSize}());
|
|
||||||
return vector.As{typeName}();
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise fractional parts of a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The componentwise fractional part of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} frac({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return v - floor(v);
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the reciprocal a {typeName} vector.</summary>
|
|
||||||
/// <param name=""v"">Input value.</param>
|
|
||||||
/// <returns>The reciprocal of the input.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} rcp({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return 1{_componentTypePrefix} / v;
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise result of raising v to the power p.</summary>
|
|
||||||
/// <param name=""x"">The exponent base.</param>
|
|
||||||
/// <param name=""y"">The exponent power.</param>
|
|
||||||
/// <returns>The componentwise result of raising x to the power y.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} pow({typeFullName} x, {typeFullName} y)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"pow(x.{c}, y.{c})")});
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the componentwise floating point remainder of x/y.</summary>
|
|
||||||
/// <param name=""x"">The dividend in x/y.</param>
|
|
||||||
/// <param name=""y"">The divisor in x/y.</param>
|
|
||||||
/// <returns>The componentwise remainder of x/y.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} fmod({typeFullName} x, {typeFullName} y)
|
|
||||||
{{
|
|
||||||
return new {typeFullName}({ComponentwiseAssignments(c => $"x.{c} % y.{c}")});
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>
|
|
||||||
/// Performs a componentwise split of a {typeName} vector into an integral part i and a fractional part that gets returned.
|
|
||||||
/// Both parts take the sign of the corresponding input component.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name=""x"">Value to split into integral and fractional part.</param>
|
|
||||||
/// <param name=""i"">Output value containing integral part of x.</param>
|
|
||||||
/// <returns>The componentwise fractional part of x.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} modf({typeFullName} x, out {typeFullName} i)
|
|
||||||
{{
|
|
||||||
i = trunc(x);
|
|
||||||
return x - i;
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns a normalized version of the {typeName} vector v by scaling it by 1 / length(v).</summary>
|
|
||||||
/// <param name=""v"">Vector to normalize.</param>
|
|
||||||
/// <returns>The normalized vector.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} normalize({typeFullName} v)
|
|
||||||
{{
|
|
||||||
return rsqrt(dot(v, v)) * v;
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a safe normalized version of the {typeName} vector v by scaling it by 1 / length(v).
|
|
||||||
/// Returns the given default value when 1 / length(v) does not produce a finite number.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name=""v"">Vector to normalize.</param>
|
|
||||||
/// <param name=""defaultvalue"">Vector to return if normalized vector is not finite.</param>
|
|
||||||
/// <returns>The normalized vector or the default value if the normalized vector is not finite.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
static public {typeFullName} normalizesafe({typeFullName} v, {typeFullName} defaultvalue = default)
|
|
||||||
{{
|
|
||||||
var len = dot(v, v);
|
|
||||||
return select(defaultvalue, v * rsqrt(len), len > FLT_MIN_NORMAL);
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns a componentwise smooth Hermite interpolation between 0.0f and 1.0f when v is in the interval (inclusive) [vMin, vMax].</summary>
|
|
||||||
/// <param name=""vMin"">The minimum range of the v parameter.</param>
|
|
||||||
/// <param name=""vMax"">The maximum range of the v parameter.</param>
|
|
||||||
/// <param name=""v"">The value to be interpolated.</param>
|
|
||||||
/// <returns>Returns component values camped to the range [0, 1].</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} smoothstep({typeFullName} vMin, {typeFullName} vMax, {typeFullName} v)
|
|
||||||
{{
|
|
||||||
var t = saturate((v - vMin) / (vMax - vMin));
|
|
||||||
return t * t * (3{_componentTypePrefix} - (2{_componentTypePrefix} * t));
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the result of a componentwise step function where each component is 1.0f when v = threshold and 0.0f otherwise.</summary>
|
|
||||||
/// <param name=""threshold"">Vector of values to be used as a threshold for returning 1.</param>
|
|
||||||
/// <param name=""v"">Vector of values to compare against threshold.</param>
|
|
||||||
/// <returns>1 if the componentwise comparison v = threshold is true, otherwise 0.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} step({typeFullName} threshold, {typeFullName} v)
|
|
||||||
{{
|
|
||||||
return select(new {typeFullName}(0{_componentTypePrefix}), new {typeFullName}(1{_componentTypePrefix}), v == threshold);
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Given an incident vector i and a normal vector n, returns the reflection vector r = i - 2.0 * dot(i, n) * n.</summary>
|
|
||||||
/// <param name=""i"">Incident vector.</param>
|
|
||||||
/// <param name=""n"">Normal vector.</param>
|
|
||||||
/// <returns>Reflection vector.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} reflect({typeFullName} i, {typeFullName} n)
|
|
||||||
{{
|
|
||||||
return i - 2{_componentTypePrefix} * n * dot(i, n);
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the refraction vector given the incident vector i, the normal vector n and the refraction index.</summary>
|
|
||||||
/// <param name=""i"">Incident vector.</param>
|
|
||||||
/// <param name=""n"">Normal vector.</param>
|
|
||||||
/// <param name=""indexOfRefraction"">Index of refraction.</param>
|
|
||||||
/// <returns>Refraction vector.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} refract({typeFullName} i, {typeFullName} n, {componentTypeFullName} indexOfRefraction)
|
|
||||||
{{
|
|
||||||
var ni = dot(n, i);
|
|
||||||
var k = 1.0f - indexOfRefraction * indexOfRefraction * (1{_componentTypePrefix} - ni * ni);
|
|
||||||
return select(new(0{_componentTypePrefix}), indexOfRefraction * i - (indexOfRefraction * ni + sqrt(k)) * n, k >= 0);
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>
|
|
||||||
/// Compute vector projection of a onto b.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Some finite vectors a and b could generate a non-finite result. This is most likely when a's components
|
|
||||||
/// are very large (close to Single.MaxValue) or when b's components are very small (close to FLT_MIN_NORMAL).
|
|
||||||
/// In these cases, you can call <see cref=""projectsafe({typeFullName},{typeFullName},{typeFullName})""/>
|
|
||||||
/// which will use a given default value if the result is not finite.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name=""a"">Vector to project.</param>
|
|
||||||
/// <param name=""ontoB"">Non-zero vector to project onto.</param>
|
|
||||||
/// <returns>Vector projection of a onto b.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} project({typeFullName} a, {typeFullName} ontoB)
|
|
||||||
{{
|
|
||||||
return (dot(a, ontoB) / dot(ontoB, ontoB)) * ontoB;
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>
|
|
||||||
/// Compute vector projection of a onto b. If result is not finite, then return the default value instead.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This function performs extra checks to see if the result of projecting a onto b is finite. If you know that
|
|
||||||
/// your inputs will generate a finite result or you don't care if the result is finite, then you can call
|
|
||||||
/// <see cref=""project({typeFullName},{typeFullName})""/> instead which is faster than this function.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name=""a"">Vector to project.</param>
|
|
||||||
/// <param name=""ontoB"">Non-zero vector to project onto.</param>
|
|
||||||
/// <param name=""defaultValue"">Default value to return if projection is not finite.</param>
|
|
||||||
/// <returns>Vector projection of a onto b or the default value.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} projectsafe({typeFullName} a, {typeFullName} ontoB, {typeFullName} defaultValue = default)
|
|
||||||
{{
|
|
||||||
var proj = project(a, ontoB);
|
|
||||||
|
|
||||||
return select(defaultValue, proj, all(isfinite(proj)));
|
|
||||||
}}");
|
|
||||||
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Conditionally flips a vector n if two vectors i and ng are pointing in the same direction. Returns n if dot(i, ng) < 0, -n otherwise.</summary>
|
|
||||||
/// <param name=""n"">Vector to conditionally flip.</param>
|
|
||||||
/// <param name=""i"">First vector in direction comparison.</param>
|
|
||||||
/// <param name=""ng"">Second vector in direction comparison.</param>
|
|
||||||
/// <returns>-n if i and ng point in the same direction; otherwise return n unchanged.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} faceforward({typeFullName} n, {typeFullName} i, {typeFullName} ng)
|
|
||||||
{{
|
|
||||||
return select(n, -n, dot(ng, i) >= 0.0f);
|
|
||||||
}}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sourceBuilder.AppendLine($@"
|
|
||||||
/// <summary>Returns the result of a componentwise multiply-add operation (a * b + c) on 3 {typeName} vectors.</summary>
|
|
||||||
/// <param name=""mulA"">First value to multiply.</param>
|
|
||||||
/// <param name=""mulB"">Second value to multiply.</param>
|
|
||||||
/// <param name=""addC"">Third value to add to the product of a and b.</param>
|
|
||||||
/// <returns>The componentwise multiply-add of the inputs.</returns>
|
|
||||||
{INLINE_METHOD_ATTRIBUTE}
|
|
||||||
public static {typeFullName} mad({typeFullName} mulA, {typeFullName} mulB, {typeFullName} addC)
|
|
||||||
{{
|
|
||||||
return mulA * mulB + addC;
|
|
||||||
}}");
|
|
||||||
}
|
|
||||||
|
|
||||||
EndRegion();
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceBuilder.Append($@"
|
sourceBuilder.Append($@"
|
||||||
}}");
|
}}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,6 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen
|
|||||||
[Generator]
|
[Generator]
|
||||||
internal class NumericTypeGenerator : IIncrementalGenerator
|
internal class NumericTypeGenerator : IIncrementalGenerator
|
||||||
{
|
{
|
||||||
private const string _TARGET_ATTRIBUTE_NAME = "Misaki.HighPerformance.Mathematics.Attributes.NumericTypeAttribute";
|
|
||||||
private const string _CONVERTABLE_ATTRIBUTE_NAME = "Misaki.HighPerformance.Mathematics.Attributes.NumericConvertableAttribute";
|
|
||||||
|
|
||||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||||
{
|
{
|
||||||
// Create a provider that finds all types with NumericTypeAttribute
|
// Create a provider that finds all types with NumericTypeAttribute
|
||||||
|
|||||||
@@ -94,7 +94,12 @@ public struct OBB : IEquatable<OBB>
|
|||||||
|
|
||||||
public readonly AABB ToAABB()
|
public readonly AABB ToAABB()
|
||||||
{
|
{
|
||||||
var absRotation = math.abs(new float3x3(Rotation));
|
var absRotation = new float3x3
|
||||||
|
{
|
||||||
|
c0 = math.abs(Rotation.value.x),
|
||||||
|
c1 = math.abs(Rotation.value.y),
|
||||||
|
c2 = math.abs(Rotation.value.z)
|
||||||
|
};
|
||||||
var worldExtents = absRotation.c0 * Extents.x + absRotation.c1 * Extents.y + absRotation.c2 * Extents.z;
|
var worldExtents = absRotation.c0 * Extents.x + absRotation.c1 * Extents.y + absRotation.c2 * Extents.z;
|
||||||
return new AABB(Center - worldExtents, Center + worldExtents);
|
return new AABB(Center - worldExtents, Center + worldExtents);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
using Misaki.HighPerformance.Mathematics.CodeGen;
|
using Misaki.HighPerformance.Mathematics.CodeGen;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Intrinsics;
|
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Mathematics;
|
namespace Misaki.HighPerformance.Mathematics;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -106,8 +106,8 @@ public partial struct quaternion : IEquatable<quaternion>
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static quaternion AxisAngle(float3 axis, float angle)
|
public static quaternion AxisAngle(float3 axis, float angle)
|
||||||
{
|
{
|
||||||
var (sina, cosa) = sincos(0.5f * angle);
|
sincos(0.5f * angle, out var s, out var c);
|
||||||
return new quaternion(new float4(axis * sina, cosa));
|
return new quaternion(new float4(axis * s, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -120,7 +120,7 @@ public partial struct quaternion : IEquatable<quaternion>
|
|||||||
public static quaternion EulerXYZ(float3 xyz)
|
public static quaternion EulerXYZ(float3 xyz)
|
||||||
{
|
{
|
||||||
// return mul(rotateZ(xyz.z), mul(rotateY(xyz.y), rotateX(xyz.x)));
|
// return mul(rotateZ(xyz.z), mul(rotateY(xyz.y), rotateX(xyz.x)));
|
||||||
var (s, c) = sincos(0.5f * xyz);
|
sincos(0.5f * xyz, out var s, out var c);
|
||||||
return new quaternion(
|
return new quaternion(
|
||||||
// s.x * c.y * c.z - s.y * s.z * c.x,
|
// s.x * c.y * c.z - s.y * s.z * c.x,
|
||||||
// s.y * c.x * c.z + s.x * s.z * c.y,
|
// s.y * c.x * c.z + s.x * s.z * c.y,
|
||||||
@@ -139,7 +139,7 @@ public partial struct quaternion : IEquatable<quaternion>
|
|||||||
public static quaternion EulerXZY(float3 xyz)
|
public static quaternion EulerXZY(float3 xyz)
|
||||||
{
|
{
|
||||||
// return mul(rotateY(xyz.y), mul(rotateZ(xyz.z), rotateX(xyz.x)));
|
// return mul(rotateY(xyz.y), mul(rotateZ(xyz.z), rotateX(xyz.x)));
|
||||||
var (s, c) = sincos(0.5f * xyz);
|
sincos(0.5f * xyz, out var s, out var c);
|
||||||
return new quaternion(
|
return new quaternion(
|
||||||
// s.x * c.y * c.z + s.y * s.z * c.x,
|
// s.x * c.y * c.z + s.y * s.z * c.x,
|
||||||
// s.y * c.x * c.z + s.x * s.z * c.y,
|
// s.y * c.x * c.z + s.x * s.z * c.y,
|
||||||
@@ -158,7 +158,7 @@ public partial struct quaternion : IEquatable<quaternion>
|
|||||||
public static quaternion EulerYXZ(float3 xyz)
|
public static quaternion EulerYXZ(float3 xyz)
|
||||||
{
|
{
|
||||||
// return mul(rotateZ(xyz.z), mul(rotateX(xyz.x), rotateY(xyz.y)));
|
// return mul(rotateZ(xyz.z), mul(rotateX(xyz.x), rotateY(xyz.y)));
|
||||||
var (s, c) = sincos(0.5f * xyz);
|
sincos(0.5f * xyz, out var s, out var c);
|
||||||
return new quaternion(
|
return new quaternion(
|
||||||
// s.x * c.y * c.z - s.y * s.z * c.x,
|
// s.x * c.y * c.z - s.y * s.z * c.x,
|
||||||
// s.y * c.x * c.z + s.x * s.z * c.y,
|
// s.y * c.x * c.z + s.x * s.z * c.y,
|
||||||
@@ -177,7 +177,7 @@ public partial struct quaternion : IEquatable<quaternion>
|
|||||||
public static quaternion EulerYZX(float3 xyz)
|
public static quaternion EulerYZX(float3 xyz)
|
||||||
{
|
{
|
||||||
// return mul(rotateX(xyz.x), mul(rotateZ(xyz.z), rotateY(xyz.y)));
|
// return mul(rotateX(xyz.x), mul(rotateZ(xyz.z), rotateY(xyz.y)));
|
||||||
var (s, c) = sincos(0.5f * xyz);
|
sincos(0.5f * xyz, out var s, out var c);
|
||||||
return new quaternion(
|
return new quaternion(
|
||||||
// s.x * c.y * c.z - s.y * s.z * c.x,
|
// s.x * c.y * c.z - s.y * s.z * c.x,
|
||||||
// s.y * c.x * c.z - s.x * s.z * c.y,
|
// s.y * c.x * c.z - s.x * s.z * c.y,
|
||||||
@@ -197,7 +197,7 @@ public partial struct quaternion : IEquatable<quaternion>
|
|||||||
public static quaternion EulerZXY(float3 xyz)
|
public static quaternion EulerZXY(float3 xyz)
|
||||||
{
|
{
|
||||||
// return mul(rotateY(xyz.y), mul(rotateX(xyz.x), rotateZ(xyz.z)));
|
// return mul(rotateY(xyz.y), mul(rotateX(xyz.x), rotateZ(xyz.z)));
|
||||||
var (s, c) = sincos(0.5f * xyz);
|
sincos(0.5f * xyz, out var s, out var c);
|
||||||
return new quaternion(
|
return new quaternion(
|
||||||
// s.x * c.y * c.z + s.y * s.z * c.x,
|
// s.x * c.y * c.z + s.y * s.z * c.x,
|
||||||
// s.y * c.x * c.z - s.x * s.z * c.y,
|
// s.y * c.x * c.z - s.x * s.z * c.y,
|
||||||
@@ -216,7 +216,7 @@ public partial struct quaternion : IEquatable<quaternion>
|
|||||||
public static quaternion EulerZYX(float3 xyz)
|
public static quaternion EulerZYX(float3 xyz)
|
||||||
{
|
{
|
||||||
// return mul(rotateX(xyz.x), mul(rotateY(xyz.y), rotateZ(xyz.z)));
|
// return mul(rotateX(xyz.x), mul(rotateY(xyz.y), rotateZ(xyz.z)));
|
||||||
var (s, c) = sincos(0.5f * xyz);
|
sincos(0.5f * xyz, out var s, out var c);
|
||||||
return new quaternion(
|
return new quaternion(
|
||||||
// s.x * c.y * c.z + s.y * s.z * c.x,
|
// s.x * c.y * c.z + s.y * s.z * c.x,
|
||||||
// s.y * c.x * c.z - s.x * s.z * c.y,
|
// s.y * c.x * c.z - s.x * s.z * c.y,
|
||||||
@@ -364,8 +364,8 @@ public partial struct quaternion : IEquatable<quaternion>
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static quaternion RotateX(float angle)
|
public static quaternion RotateX(float angle)
|
||||||
{
|
{
|
||||||
var (sina, cosa) = sincos(0.5f * angle);
|
sincos(0.5f * angle, out var s, out var c);
|
||||||
return new quaternion(sina, 0.0f, 0.0f, cosa);
|
return new quaternion(s, 0.0f, 0.0f, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Returns a quaternion that rotates around the y-axis by a given number of radians.</summary>
|
/// <summary>Returns a quaternion that rotates around the y-axis by a given number of radians.</summary>
|
||||||
@@ -374,8 +374,8 @@ public partial struct quaternion : IEquatable<quaternion>
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static quaternion RotateY(float angle)
|
public static quaternion RotateY(float angle)
|
||||||
{
|
{
|
||||||
var (sina, cosa) = sincos(0.5f * angle);
|
sincos(0.5f * angle, out var s, out var c);
|
||||||
return new quaternion(0.0f, sina, 0.0f, cosa);
|
return new quaternion(0.0f, s, 0.0f, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Returns a quaternion that rotates around the z-axis by a given number of radians.</summary>
|
/// <summary>Returns a quaternion that rotates around the z-axis by a given number of radians.</summary>
|
||||||
@@ -384,8 +384,8 @@ public partial struct quaternion : IEquatable<quaternion>
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static quaternion RotateZ(float angle)
|
public static quaternion RotateZ(float angle)
|
||||||
{
|
{
|
||||||
var (sina, cosa) = sincos(0.5f * angle);
|
sincos(0.5f * angle, out var s, out var c);
|
||||||
return new quaternion(0.0f, 0.0f, sina, cosa);
|
return new quaternion(0.0f, 0.0f, s, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -585,8 +585,8 @@ public static partial class math
|
|||||||
{
|
{
|
||||||
var v_rcp_len = rsqrt(dot(q.value.xyz, q.value.xyz));
|
var v_rcp_len = rsqrt(dot(q.value.xyz, q.value.xyz));
|
||||||
var v_len = rcp(v_rcp_len);
|
var v_len = rcp(v_rcp_len);
|
||||||
var (sin_v_len, cos_v_len) = sincos(v_len);
|
sincos(v_len, out var s, out var c);
|
||||||
return quaternion(new float4(q.value.xyz * v_rcp_len * sin_v_len, cos_v_len));
|
return quaternion(new float4(q.value.xyz * v_rcp_len * s, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Returns the natural exponent of a quaternion.</summary>
|
/// <summary>Returns the natural exponent of a quaternion.</summary>
|
||||||
@@ -597,8 +597,8 @@ public static partial class math
|
|||||||
{
|
{
|
||||||
var v_rcp_len = rsqrt(dot(q.value.xyz, q.value.xyz));
|
var v_rcp_len = rsqrt(dot(q.value.xyz, q.value.xyz));
|
||||||
var v_len = rcp(v_rcp_len);
|
var v_len = rcp(v_rcp_len);
|
||||||
var (sin_v_len, cos_v_len) = sincos(v_len);
|
sincos(v_len, out var s, out var c);
|
||||||
return quaternion(new float4(q.value.xyz * v_rcp_len * sin_v_len, cos_v_len) * exp(q.value.w));
|
return quaternion(new float4(q.value.xyz * v_rcp_len * s, c) * exp(q.value.w));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Returns the natural logarithm of a unit length quaternion.</summary>
|
/// <summary>Returns the natural logarithm of a unit length quaternion.</summary>
|
||||||
|
|||||||
@@ -642,7 +642,7 @@ public struct random
|
|||||||
public float2 NextFloat2Direction()
|
public float2 NextFloat2Direction()
|
||||||
{
|
{
|
||||||
var angle = NextFloat() * PI * 2.0f;
|
var angle = NextFloat() * PI * 2.0f;
|
||||||
var (s, c) = sincos(angle);
|
sincos(angle, out var s, out var c);
|
||||||
return float2(c, s);
|
return float2(c, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,7 +652,7 @@ public struct random
|
|||||||
public double2 NextDouble2Direction()
|
public double2 NextDouble2Direction()
|
||||||
{
|
{
|
||||||
var angle = NextDouble() * PI_DBL * 2.0;
|
var angle = NextDouble() * PI_DBL * 2.0;
|
||||||
var (s, c) = sincos(angle);
|
sincos(angle, out var s, out var c);
|
||||||
return double2(c, s);
|
return double2(c, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -665,7 +665,7 @@ public struct random
|
|||||||
var z = rnd.x * 2.0f - 1.0f;
|
var z = rnd.x * 2.0f - 1.0f;
|
||||||
var r = sqrt(max(1.0f - z * z, 0.0f));
|
var r = sqrt(max(1.0f - z * z, 0.0f));
|
||||||
var angle = rnd.y * PI * 2.0f;
|
var angle = rnd.y * PI * 2.0f;
|
||||||
var (s, c) = sincos(angle);
|
sincos(angle, out var s, out var c);
|
||||||
return float3(c * r, s * r, z);
|
return float3(c * r, s * r, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,7 +678,7 @@ public struct random
|
|||||||
var z = rnd.x * 2.0 - 1.0;
|
var z = rnd.x * 2.0 - 1.0;
|
||||||
var r = sqrt(max(1.0 - z * z, 0.0));
|
var r = sqrt(max(1.0 - z * z, 0.0));
|
||||||
var angle = rnd.y * PI_DBL * 2.0;
|
var angle = rnd.y * PI_DBL * 2.0;
|
||||||
var (s, c) = sincos(angle);
|
sincos(angle, out var s, out var c);
|
||||||
return double3(c * r, s * r, z);
|
return double3(c * r, s * r, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -694,7 +694,7 @@ public struct random
|
|||||||
var i = sqrt(1.0f - u1);
|
var i = sqrt(1.0f - u1);
|
||||||
var j = sqrt(u1);
|
var j = sqrt(u1);
|
||||||
|
|
||||||
var (sin_theta_rho, cos_theta_rho) = sincos(theta_rho);
|
sincos(theta_rho, out var sin_theta_rho, out var cos_theta_rho);
|
||||||
|
|
||||||
var q = quaternion(i * sin_theta_rho.x, i * cos_theta_rho.x, j * sin_theta_rho.y, j * cos_theta_rho.y);
|
var q = quaternion(i * sin_theta_rho.x, i * cos_theta_rho.x, j * sin_theta_rho.y, j * cos_theta_rho.y);
|
||||||
return quaternion(select(q.value, -q.value, q.value.w < 0.0f));
|
return quaternion(select(q.value, -q.value, q.value.w < 0.0f));
|
||||||
|
|||||||
@@ -3,52 +3,67 @@ using Misaki.HighPerformance.Mathematics;
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.Intrinsics;
|
using System.Runtime.Intrinsics;
|
||||||
using System.Runtime.Intrinsics.X86;
|
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Test.Benchmark;
|
namespace Misaki.HighPerformance.Test.Benchmark;
|
||||||
|
|
||||||
public class MathematicsBenchmark
|
public unsafe class MathematicsBenchmark
|
||||||
{
|
{
|
||||||
[Params(10)]
|
public struct f4
|
||||||
public int count = 10;
|
|
||||||
|
|
||||||
private unsafe static Vector128<float> CreateVector128(float2 value)
|
|
||||||
{
|
{
|
||||||
return Vector128.AsSingle(Sse2.LoadScalarVector128((double*)&value));
|
private Vector128<float> _vec;
|
||||||
|
|
||||||
|
public f4(float x, float y, float z, float w)
|
||||||
|
{
|
||||||
|
_vec = Vector128.Create(x, y, z, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public f4(Vector128<float> vec)
|
||||||
|
{
|
||||||
|
_vec = vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static f4 operator +(f4 a, f4 b)
|
||||||
|
{
|
||||||
|
var result = a._vec + b._vec;
|
||||||
|
return Unsafe.As<Vector128<float>, f4>(ref result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Params(100)]
|
||||||
|
public int count;
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void Vector2Add()
|
public Vector2 Vector2Add()
|
||||||
{
|
{
|
||||||
var a = new Vector2(1, 2);
|
var a = new Vector2(1, 2);
|
||||||
var b = new Vector2(5, 6);
|
var b = new Vector2(3, 4);
|
||||||
var result = new Vector2();
|
var c = new Vector2(5, 6);
|
||||||
|
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
result += a + b;
|
c += a + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void Float2Add()
|
public float2 Float2Add()
|
||||||
{
|
{
|
||||||
var a = new float2(1, 2);
|
var a = new float2(1, 2);
|
||||||
var b = new float2(5, 6);
|
var b = new float2(3, 4);
|
||||||
var result = new float2();
|
var c = new float2(5, 6);
|
||||||
//var vr = CreateVector128(result);
|
|
||||||
//var va = CreateVector128(a);
|
|
||||||
//var vb = CreateVector128(b);
|
|
||||||
|
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
result += a + b;
|
c += a + b;
|
||||||
//vr = Sse.Add(va, vb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//[Benchmark]
|
return c;
|
||||||
public void Vector4Add()
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public Vector4 Vector4Add()
|
||||||
{
|
{
|
||||||
var a = new Vector4(1, 2, 3, 4);
|
var a = new Vector4(1, 2, 3, 4);
|
||||||
var b = new Vector4(5, 6, 7, 8);
|
var b = new Vector4(5, 6, 7, 8);
|
||||||
@@ -58,10 +73,12 @@ public class MathematicsBenchmark
|
|||||||
{
|
{
|
||||||
result += a + b;
|
result += a + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//[Benchmark]
|
[Benchmark]
|
||||||
public void Float4Add()
|
public float4 Float4Add()
|
||||||
{
|
{
|
||||||
var a = new float4(1, 2, 3, 4);
|
var a = new float4(1, 2, 3, 4);
|
||||||
var b = new float4(5, 6, 7, 8);
|
var b = new float4(5, 6, 7, 8);
|
||||||
@@ -71,5 +88,37 @@ public class MathematicsBenchmark
|
|||||||
{
|
{
|
||||||
result += a + b;
|
result += a + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public f4 f4Add()
|
||||||
|
{
|
||||||
|
var a = new f4(1, 2, 3, 4);
|
||||||
|
var b = new f4(5, 6, 7, 8);
|
||||||
|
var result = new f4(0, 0, 0, 0);
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
result += a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public unsafe Vector128<float> v128Add()
|
||||||
|
{
|
||||||
|
var a = Vector128.Create(1f, 2f, 3f, 4f);
|
||||||
|
var b = Vector128.Create(5f, 6f, 7f, 8f);
|
||||||
|
var result = Vector128<float>.Zero;
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
result += a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<PublishAot>True</PublishAot>
|
<PublishAot>True</PublishAot>
|
||||||
|
|||||||
@@ -18,9 +18,9 @@
|
|||||||
|
|
||||||
//Console.WriteLine($"Count should be {threadCount * 990}, actual: {map.Count}");
|
//Console.WriteLine($"Count should be {threadCount * 990}, actual: {map.Count}");
|
||||||
|
|
||||||
using Misaki.HighPerformance.Test.Benchmark;
|
//using Misaki.HighPerformance.Test.Benchmark;
|
||||||
|
|
||||||
BenchmarkDotNet.Running.BenchmarkRunner.Run<MathematicsBenchmark>();
|
//BenchmarkDotNet.Running.BenchmarkRunner.Run<MathematicsBenchmark>();
|
||||||
|
|
||||||
//using Misaki.HighPerformance.LowLevel.Buffer;
|
//using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
//using Misaki.HighPerformance.LowLevel.Collections;
|
//using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
@@ -39,3 +39,8 @@ BenchmarkDotNet.Running.BenchmarkRunner.Run<MathematicsBenchmark>();
|
|||||||
// Console.WriteLine(item);
|
// Console.WriteLine(item);
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
|
|
||||||
|
var array = new UnsafeArray<int>(10, Allocator.Persistent);
|
||||||
@@ -130,7 +130,7 @@ public unsafe class TestJobSystem
|
|||||||
{
|
{
|
||||||
const int size = 1000;
|
const int size = 1000;
|
||||||
var result = stackalloc float[size];
|
var result = stackalloc float[size];
|
||||||
MemoryUtilities.MemSet(result, 0, sizeof(float) * size);
|
MemoryUtility.MemSet(result, 0, sizeof(float) * size);
|
||||||
var job = new ParallelAddJob
|
var job = new ParallelAddJob
|
||||||
{
|
{
|
||||||
value = 1.0f,
|
value = 1.0f,
|
||||||
|
|||||||
@@ -42,6 +42,17 @@ namespace Misaki.HighPerformance.Buffer
|
|||||||
Dispose();
|
Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T Rent()
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
if (_objects.TryDequeue(out var obj))
|
||||||
|
{
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _factory();
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryRent([MaybeNullWhen(false)] out T obj)
|
public bool TryRent([MaybeNullWhen(false)] out T obj)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<IsPackable>True</IsPackable>
|
<IsPackable>True</IsPackable>
|
||||||
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
|||||||
46
Misaki.HighPerformance/Utilities/CollectionUtility.cs
Normal file
46
Misaki.HighPerformance/Utilities/CollectionUtility.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Misaki.HighPerformance.Utilities;
|
||||||
|
|
||||||
|
public static class CollectionUtility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a span over the elements of the specified list.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The span will become invalid if the list is modified (e.g., elements are added or removed).
|
||||||
|
/// </remarks>
|
||||||
|
/// <typeparam name="T">The type of elements in the list.</typeparam>
|
||||||
|
/// <param name="list">The list whose elements the span will cover. Can be null.</param>
|
||||||
|
/// <returns>A span over the elements of the list, or an empty span if the list is null or empty.</returns>
|
||||||
|
public static Span<T> AsSpan<T>(this List<T>? list)
|
||||||
|
{
|
||||||
|
return CollectionsMarshal.AsSpan(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the element at the specified index from the list by replacing it with the last element, then removing
|
||||||
|
/// the last element. This operation does not preserve the order of elements.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of elements in the list.</typeparam>
|
||||||
|
/// <param name="list">The list from which to remove the element. Cannot be null.</param>
|
||||||
|
/// <param name="index">The zero-based index of the element to remove. Must be within the bounds of the list.</param>
|
||||||
|
/// <returns>The modified list after the element has been removed.</returns>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if index is less than 0 or greater than or equal to the number of elements in the list.</exception>
|
||||||
|
public static List<T> RemoveAndSwapBack<T>(this List<T> list, int index)
|
||||||
|
{
|
||||||
|
var lastIndex = list.Count - 1;
|
||||||
|
if (index < 0 || index > lastIndex)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index != lastIndex)
|
||||||
|
{
|
||||||
|
list[index] = list[lastIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
list.RemoveAt(lastIndex);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user