Refactor and enhance math utilities and code generation

Refactored `StbImage` classes to be publicly accessible. Updated namespaces and introduced `NumericTypeAttribute` for metadata. Enhanced `VectorGenerator` with new utility methods (`any`, `all`, `length`, etc.) and improved code generation. Consolidated vector operations in `math` utilities.

Refactored `Plane` and `svd` classes for better encapsulation and readability. Improved `DynamicArray` with `uint` indexer support and cleaner loops. Added SIMD-based benchmarking placeholders in `MathematicsBenchmark`.

Removed redundant code and unused files, including `IUnsafeSet.cs`. Updated project file to include `CodeGen` as an analyzer. Introduced `SupportedVectorMath` and `SupportedMatrixMath` enums for better operation definitions.

Improved code style, fixed minor bugs, and cleaned up unused code in `Program.cs`. Enhanced maintainability and readability across the codebase.
This commit is contained in:
2025-10-04 12:38:53 +09:00
parent ac73e28f26
commit a92ab93731
32 changed files with 405 additions and 888 deletions

View File

@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
namespace Misaki.HighPerformance.Image namespace Misaki.HighPerformance.Image
{ {
unsafe partial class StbImage public unsafe partial class StbImage
{ {
public static int stbi__bmp_test(stbi__context s) public static int stbi__bmp_test(stbi__context s)
{ {

View File

@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
namespace Misaki.HighPerformance.Image namespace Misaki.HighPerformance.Image
{ {
unsafe partial class StbImage public unsafe partial class StbImage
{ {
public const int STBI_default = 0; public const int STBI_default = 0;
public const int STBI_grey = 1; public const int STBI_grey = 1;

View File

@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
namespace Misaki.HighPerformance.Image namespace Misaki.HighPerformance.Image
{ {
unsafe partial class StbImage public unsafe partial class StbImage
{ {
public static int stbi__gif_test(stbi__context s) public static int stbi__gif_test(stbi__context s)
{ {

View File

@@ -6,7 +6,7 @@ using Misaki.HighPerformance.Image.Runtime;
namespace Misaki.HighPerformance.Image namespace Misaki.HighPerformance.Image
{ {
unsafe partial class StbImage public unsafe partial class StbImage
{ {
public static int stbi__hdr_test(stbi__context s) public static int stbi__hdr_test(stbi__context s)
{ {

View File

@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
namespace Misaki.HighPerformance.Image namespace Misaki.HighPerformance.Image
{ {
unsafe partial class StbImage public unsafe partial class StbImage
{ {
public delegate void delegate0(byte* arg0, int arg1, short* arg2); public delegate void delegate0(byte* arg0, int arg1, short* arg2);

View File

@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
namespace Misaki.HighPerformance.Image namespace Misaki.HighPerformance.Image
{ {
unsafe partial class StbImage public unsafe partial class StbImage
{ {
public const int STBI__F_none = 0; public const int STBI__F_none = 0;
public const int STBI__F_sub = 1; public const int STBI__F_sub = 1;

View File

@@ -6,7 +6,7 @@ using Misaki.HighPerformance.Image.Runtime;
namespace Misaki.HighPerformance.Image namespace Misaki.HighPerformance.Image
{ {
unsafe partial class StbImage public unsafe partial class StbImage
{ {
public static int stbi__psd_test(stbi__context s) public static int stbi__psd_test(stbi__context s)
{ {

View File

@@ -6,7 +6,7 @@ using Misaki.HighPerformance.Image.Runtime;
namespace Misaki.HighPerformance.Image namespace Misaki.HighPerformance.Image
{ {
unsafe partial class StbImage public unsafe partial class StbImage
{ {
public static int stbi__tga_test(stbi__context s) public static int stbi__tga_test(stbi__context s)
{ {

View File

@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
namespace Misaki.HighPerformance.Image namespace Misaki.HighPerformance.Image
{ {
unsafe partial class StbImage public unsafe partial class StbImage
{ {
public static byte[] stbi__zdefault_distance = public static byte[] stbi__zdefault_distance =
{ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };

View File

@@ -1,6 +1,4 @@
using Misaki.HighPerformance.LowLevel.Utilities; using System.Runtime.CompilerServices;
using System.Drawing;
using System.Runtime.CompilerServices;
namespace Misaki.HighPerformance.LowLevel.Buffer; namespace Misaki.HighPerformance.LowLevel.Buffer;

View File

@@ -1,5 +0,0 @@
namespace Misaki.HighPerformance.LowLevel.Collections.Contracts;
internal class IUnsafeSet<T>
where T : unmanaged, IEquatable<T>
{
}

View File

@@ -66,7 +66,7 @@ public unsafe interface IAllocator
/// <summary> /// <summary>
/// Gets a reference to the allocation handle associated with this allocator. /// Gets a reference to the allocation handle associated with this allocator.
/// </summary> /// </summary>
public ref AllocationHandle Handle ref AllocationHandle Handle
{ {
get; get;
} }

View File

@@ -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.ReadArrayElement<TValue>(buffer->_buffer, index)); return new KeyValuePair<TKey, TValue>(buffer->_keys[index], UnsafeUtilities.ReadArrayElementRef<TValue>(buffer->_buffer, index));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -1,7 +1,6 @@
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection.Metadata;
using System.Text; using System.Text;
namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators

View File

@@ -2,7 +2,6 @@ using Microsoft.CodeAnalysis;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
@@ -11,6 +10,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{ {
private int _vectorBitsSize; private int _vectorBitsSize;
private int _missingComponents; private int _missingComponents;
private string _componentTypePrefix = null!;
private readonly List<(string signature, string assignment)> _constructorSignatures = new(); private readonly List<(string signature, string assignment)> _constructorSignatures = new();
@@ -34,6 +34,14 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
_vectorBitsSize = vectorBytesSize * 8; _vectorBitsSize = vectorBytesSize * 8;
_missingComponents = (vectorBytesSize - typeSize) / componentSize; _missingComponents = (vectorBytesSize - typeSize) / componentSize;
_componentTypePrefix = typeInfo.ComponentTypeSymbol.SpecialType switch
{
SpecialType.System_UInt16 or SpecialType.System_UInt32 or SpecialType.System_UInt64 => "u",
SpecialType.System_Single => "f",
SpecialType.System_Double => "d",
_ => string.Empty
};
} }
protected override void GenerateBody() protected override void GenerateBody()
@@ -426,8 +434,7 @@ 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)
{{ {{
var vector = lhs.AsVector{_vectorBitsSize}() + rhs.AsVector{_vectorBitsSize}(); return (lhs.AsVector{_vectorBitsSize}() + rhs.AsVector{_vectorBitsSize}()).{asResult};
return vector.{asResult};
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
@@ -462,8 +469,7 @@ 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)
{{ {{
var vector = lhs.AsVector{_vectorBitsSize}() - rhs.AsVector{_vectorBitsSize}(); return (lhs.AsVector{_vectorBitsSize}() - rhs.AsVector{_vectorBitsSize}()).{asResult};
return vector.{asResult};
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
@@ -498,15 +504,13 @@ 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)
{{ {{
var vector = lhs.AsVector{_vectorBitsSize}() * rhs.AsVector{_vectorBitsSize}(); return (lhs.AsVector{_vectorBitsSize}() * rhs.AsVector{_vectorBitsSize}()).{asResult};
return vector.{asResult};
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeName} operator *({typeName} lhs, {componentType} rhs) public static {typeName} operator *({typeName} lhs, {componentType} rhs)
{{ {{
var vector = lhs.AsVector{_vectorBitsSize}() * rhs; return (lhs.AsVector{_vectorBitsSize}() * rhs).{asResult};
return vector.{asResult};
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
@@ -535,15 +539,13 @@ 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)
{{ {{
var vector = lhs.AsVector{_vectorBitsSize}() / rhs.AsVector{_vectorBitsSize}(); return (lhs.AsVector{_vectorBitsSize}() / rhs.AsVector{_vectorBitsSize}()).{asResult};
return vector.{asResult};
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeName} operator /({typeName} lhs, {componentType} rhs) public static {typeName} operator /({typeName} lhs, {componentType} rhs)
{{ {{
var vector = lhs.AsVector{_vectorBitsSize}() / rhs; return (lhs.AsVector{_vectorBitsSize}() / rhs).{asResult};
return vector.{asResult};
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
@@ -613,22 +615,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)
{{ {{
var vector = -value.AsVector{_vectorBitsSize}(); return (-value.AsVector{_vectorBitsSize}()).{asResult};
return vector.{asResult};
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeName} operator ++({typeName} value) public static {typeName} operator ++({typeName} value)
{{ {{
var vector = value.AsVector{_vectorBitsSize}() + global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Create<{componentType}>(1); return (value.AsVector{_vectorBitsSize}() + global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.CreateScalar(1{_componentTypePrefix})).{asResult};
return vector.{asResult};
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeName} operator --({typeName} value) public static {typeName} operator --({typeName} value)
{{ {{
var vector = value.AsVector{_vectorBitsSize}() - global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Create<{componentType}>(1); return (value.AsVector{_vectorBitsSize}() - global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.CreateScalar(1{_componentTypePrefix})).{asResult};
return vector.{asResult};
}}"); }}");
// Comparison operators // Comparison operators
@@ -666,36 +665,31 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeName} operator <<({typeName} x, int n) public static {typeName} operator <<({typeName} x, int n)
{{ {{
var vector = x.AsVector{_vectorBitsSize}() << n; return (x.AsVector{_vectorBitsSize}() << n).{asResult};
return vector.{asResult};
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeName} operator >>({typeName} x, int n) public static {typeName} operator >>({typeName} x, int n)
{{ {{
var vector = x.AsVector{_vectorBitsSize}() >> n; return (x.AsVector{_vectorBitsSize}() >> n).{asResult};
return vector.{asResult};
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeName} operator &({typeName} lhs, {typeName} rhs) public static {typeName} operator &({typeName} lhs, {typeName} rhs)
{{ {{
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.BitwiseAnd(lhs.AsVector{_vectorBitsSize}(), rhs.AsVector{_vectorBitsSize}()); return (global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.BitwiseAnd(lhs.AsVector{_vectorBitsSize}(), rhs.AsVector{_vectorBitsSize}())).{asResult};
return vector.{asResult};
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeName} operator |({typeName} lhs, {typeName} rhs) public static {typeName} operator |({typeName} lhs, {typeName} rhs)
{{ {{
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.BitwiseOr(lhs.AsVector{_vectorBitsSize}(), rhs.AsVector{_vectorBitsSize}()); return (global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.BitwiseOr(lhs.AsVector{_vectorBitsSize}(), rhs.AsVector{_vectorBitsSize}())).{asResult};
return vector.{asResult};
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeName} operator ^({typeName} lhs, {typeName} rhs) public static {typeName} operator ^({typeName} lhs, {typeName} rhs)
{{ {{
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Xor(lhs.AsVector{_vectorBitsSize}(), rhs.AsVector{_vectorBitsSize}()); return (global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Xor(lhs.AsVector{_vectorBitsSize}(), rhs.AsVector{_vectorBitsSize}())).{asResult};
return vector.{asResult};
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
@@ -775,15 +769,15 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
private void GenerateVectorExtension() private void GenerateVectorExtension()
{ {
var typeName = typeInfo.TypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); var typeName = typeInfo.TypeFullName;
var typeSimpleName = typeInfo.TypeSymbol.Name; var typeSimpleName = typeInfo.TypeName;
var componentType = typeInfo.ComponentTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); var componentType = typeInfo.ComponentTypeFullName;
sourceBuilder.Append($@" sourceBuilder.Append($@"
public static partial class VectorInterop public static partial class VectorInterop
{{ {{
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}<{componentType}> AsVector{_vectorBitsSize}(ref this {typeName} value) public unsafe static global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}<{componentType}> AsVector{_vectorBitsSize}(this {typeName} value)
{{"); {{");
if (typeInfo.Row == 4) if (typeInfo.Row == 4)
@@ -794,13 +788,13 @@ 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]}" : "1"))});"); 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"))});");
} }
sourceBuilder.Append($@" sourceBuilder.Append($@"
}} }}
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeName} As{typeSimpleName}(ref this global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}<{componentType}> value) public unsafe static {typeName} As{typeSimpleName}(this global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}<{componentType}> value)
{{"); {{");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
ref var address = ref global::System.Runtime.CompilerServices.Unsafe.As<global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}<{componentType}>, byte>(ref value); ref var address = ref global::System.Runtime.CompilerServices.Unsafe.As<global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}<{componentType}>, byte>(ref value);
@@ -809,9 +803,9 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
}}"); }}");
} }
private string PerComponentAssignments(Func<string, string> func) private string ComponentwiseAssignments(Func<string, string> func, string separator = ", ")
{ {
return string.Join(", ", s_vectorComponents.Take(typeInfo.Row).Select(func)); return string.Join(separator, s_vectorComponents.Take(typeInfo.Row).Select(func));
} }
private void GenerateMathMethod() private void GenerateMathMethod()
@@ -888,16 +882,31 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
}} }}
}}"); }}");
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) if (typeInfo.Arithmetic)
{ {
var componentTypePrefix = typeInfo.ComponentTypeSymbol.SpecialType switch
{
SpecialType.System_UInt16 or SpecialType.System_UInt32 or SpecialType.System_UInt64 => "u",
SpecialType.System_Single => "f",
SpecialType.System_Double => "d",
_ => string.Empty
};
StartRegion("Math Methods"); StartRegion("Math Methods");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -982,7 +991,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} select({typeFullName} falseValue, {typeFullName} trueValue, global::Misaki.HighPerformance.Mathematics.bool{typeInfo.Row} test) public static {typeFullName} select({typeFullName} falseValue, {typeFullName} trueValue, global::Misaki.HighPerformance.Mathematics.bool{typeInfo.Row} test)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"test.{c} ? trueValue.{c} : falseValue.{c}")}); return new {typeFullName}({ComponentwiseAssignments(c => $"test.{c} ? trueValue.{c} : falseValue.{c}")});
}}"); }}");
if (typeInfo.ComponentTypeSymbol.SpecialType != SpecialType.System_UInt16 if (typeInfo.ComponentTypeSymbol.SpecialType != SpecialType.System_UInt16
@@ -996,21 +1005,42 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} sign({typeFullName} v) public static {typeFullName} sign({typeFullName} v)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"sign(v.{c})")}); 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 // Only floating point types support these methods
if (typeInfo.ComponentTypeSymbol.SpecialType == SpecialType.System_Single || typeInfo.ComponentTypeSymbol.SpecialType == SpecialType.System_Double) if (typeInfo.ComponentTypeSymbol.SpecialType == SpecialType.System_Single
|| typeInfo.ComponentTypeSymbol.SpecialType == SpecialType.System_Double)
{ {
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
/// <summary>Returns the result of a componentwise clamping of the {typeFullName} vector v into the interval [0, 1].</summary> /// <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> /// <param name=""v"">Input value.</param>
/// <returns>The componentwise clamping of the input into the interval [0, 1].</returns> /// <returns>The componentwise clamping of the input into the interval [0, 1].</returns>
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} saturate({typeFullName} v) public static {typeFullName} saturate({typeFullName} v)
{{ {{
return clamp(v, new {typeFullName}(0{componentTypePrefix}), new {typeFullName}(1{componentTypePrefix})); return clamp(v, new {typeFullName}(0{_componentTypePrefix}), new {typeFullName}(1{_componentTypePrefix}));
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1090,7 +1120,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} tan({typeFullName} v) public static {typeFullName} tan({typeFullName} v)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"tan(v.{c})")}); return new {typeFullName}({ComponentwiseAssignments(c => $"tan(v.{c})")});
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1100,7 +1130,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} tanh({typeFullName} v) public static {typeFullName} tanh({typeFullName} v)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"tanh(v.{c})")}); return new {typeFullName}({ComponentwiseAssignments(c => $"tanh(v.{c})")});
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1110,7 +1140,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} atan({typeFullName} v) public static {typeFullName} atan({typeFullName} v)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"atan(v.{c})")}); return new {typeFullName}({ComponentwiseAssignments(c => $"atan(v.{c})")});
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1121,7 +1151,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} atan2({typeFullName} x, {typeFullName} y) public static {typeFullName} atan2({typeFullName} x, {typeFullName} y)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"atan2(x.{c}, y.{c})")}); return new {typeFullName}({ComponentwiseAssignments(c => $"atan2(x.{c}, y.{c})")});
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1142,7 +1172,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} cosh({typeFullName} v) public static {typeFullName} cosh({typeFullName} v)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"cosh(v.{c})")}); return new {typeFullName}({ComponentwiseAssignments(c => $"cosh(v.{c})")});
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1152,7 +1182,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} acos({typeFullName} v) public static {typeFullName} acos({typeFullName} v)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"acos(v.{c})")}); return new {typeFullName}({ComponentwiseAssignments(c => $"acos(v.{c})")});
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1173,7 +1203,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} sinh({typeFullName} v) public static {typeFullName} sinh({typeFullName} v)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"sinh(v.{c})")}); return new {typeFullName}({ComponentwiseAssignments(c => $"sinh(v.{c})")});
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1183,7 +1213,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} asin({typeFullName} v) public static {typeFullName} asin({typeFullName} v)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"asin(v.{c})")}); return new {typeFullName}({ComponentwiseAssignments(c => $"asin(v.{c})")});
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1226,7 +1256,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} round({typeFullName} v) public static {typeFullName} round({typeFullName} v)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"round(v.{c})")}); return new {typeFullName}({ComponentwiseAssignments(c => $"round(v.{c})")});
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1247,7 +1277,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} exp2({typeFullName} v) public static {typeFullName} exp2({typeFullName} v)
{{ {{
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Exp(v.AsVector{_vectorBitsSize}() * 0.693147180559945309{componentTypePrefix}); var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Exp(v.AsVector{_vectorBitsSize}() * 0.693147180559945309{_componentTypePrefix});
return vector.As{typeName}(); return vector.As{typeName}();
}}"); }}");
@@ -1258,7 +1288,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} exp10({typeFullName} v) public static {typeFullName} exp10({typeFullName} v)
{{ {{
var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Exp(v.AsVector{_vectorBitsSize}() * 2.302585092994045684{componentTypePrefix}); var vector = global::System.Runtime.Intrinsics.Vector{_vectorBitsSize}.Exp(v.AsVector{_vectorBitsSize}() * 2.302585092994045684{_componentTypePrefix});
return vector.As{typeName}(); return vector.As{typeName}();
}}"); }}");
@@ -1291,7 +1321,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} log10({typeFullName} v) public static {typeFullName} log10({typeFullName} v)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"log10(v.{c})")}); return new {typeFullName}({ComponentwiseAssignments(c => $"log10(v.{c})")});
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1312,7 +1342,49 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} rsqrt({typeFullName} v) public static {typeFullName} rsqrt({typeFullName} v)
{{ {{
return 1{componentTypePrefix} / sqrt(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($@" sourceBuilder.AppendLine($@"
@@ -1343,7 +1415,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} rcp({typeFullName} v) public static {typeFullName} rcp({typeFullName} v)
{{ {{
return 1{componentTypePrefix} / v; return 1{_componentTypePrefix} / v;
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1354,7 +1426,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} pow({typeFullName} x, {typeFullName} y) public static {typeFullName} pow({typeFullName} x, {typeFullName} y)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"pow(x.{c}, y.{c})")}); return new {typeFullName}({ComponentwiseAssignments(c => $"pow(x.{c}, y.{c})")});
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1365,7 +1437,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} fmod({typeFullName} x, {typeFullName} y) public static {typeFullName} fmod({typeFullName} x, {typeFullName} y)
{{ {{
return new {typeFullName}({PerComponentAssignments(c => $"x.{c} % y.{c}")}); return new {typeFullName}({ComponentwiseAssignments(c => $"x.{c} % y.{c}")});
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1418,7 +1490,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
public static {typeFullName} smoothstep({typeFullName} vMin, {typeFullName} vMax, {typeFullName} v) public static {typeFullName} smoothstep({typeFullName} vMin, {typeFullName} vMax, {typeFullName} v)
{{ {{
var t = saturate((v - vMin) / (vMax - vMin)); var t = saturate((v - vMin) / (vMax - vMin));
return t * t * (3{componentTypePrefix} - (2{componentTypePrefix} * t)); return t * t * (3{_componentTypePrefix} - (2{_componentTypePrefix} * t));
}}"); }}");
sourceBuilder.AppendLine($@" sourceBuilder.AppendLine($@"
@@ -1429,7 +1501,84 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen.Generators
{INLINE_METHOD_ATTRIBUTE} {INLINE_METHOD_ATTRIBUTE}
public static {typeFullName} step({typeFullName} threshold, {typeFullName} v) public static {typeFullName} step({typeFullName} threshold, {typeFullName} v)
{{ {{
return select(new {typeFullName}(0{componentTypePrefix}), new {typeFullName}(1{componentTypePrefix}), v == threshold); 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) &lt; 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 else

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace Misaki.HighPerformance.Mathematics.CodeGen.Models namespace Misaki.HighPerformance.Mathematics.CodeGen.Models
{ {
public record NumericTypeInfo internal record NumericTypeInfo
{ {
public INamedTypeSymbol TypeSymbol public INamedTypeSymbol TypeSymbol
{ {

View File

@@ -0,0 +1,109 @@
using System;
namespace Misaki.HighPerformance.Mathematics.CodeGen
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)]
public class NumericTypeAttribute : Attribute
{
public NumericTypeAttribute(Type componentType, int componentSize, int row, int column, string typePrefix, bool arithmetic = true, bool canInverse = true, Type? elementType = default, Type? vectorType = default)
{
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = true)]
public class NumericConvertableAttribute : Attribute
{
public NumericConvertableAttribute(string template, params Type[] types)
{
}
}
[Flags]
public enum SupportedVectorMath
{
None = 0,
Min = 1 << 0,
Max = 1 << 1,
Lerp = 1 << 2,
Unlerp = 1 << 3,
Remap = 1 << 4,
Mad = 1 << 5,
Clamp = 1 << 6,
Saturate = 1 << 7,
Abs = 1 << 8,
Dot = 1 << 9,
Tan = 1 << 10,
TanH = 1 << 11,
Atan = 1 << 12,
Atan2 = 1 << 13,
Cos = 1 << 14,
CosH = 1 << 15,
Acos = 1 << 16,
Sin = 1 << 17,
SinH = 1 << 18,
Asin = 1 << 19,
Floor = 1 << 20,
Ceil = 1 << 21,
Round = 1 << 22,
Trunc = 1 << 23,
Frac = 1 << 24,
Rcp = 1 << 25,
Sign = 1 << 26,
Pow = 1 << 27,
Exp = 1 << 28,
Exp2 = 1 << 29,
Exp10 = 1 << 30,
Log = 1 << 31,
Log2 = 1 << 32,
Log10 = 1 << 33,
Fmod = 1 << 34,
Modf = 1 << 35,
Sqrt = 1 << 36,
Rsqrt = 1 << 37,
Length = 1 << 38,
LengthSq = 1 << 39,
Distance = 1 << 40,
DistanceSq = 1 << 41,
Cross = 1 << 42,
SmoothStep = 1 << 43,
Select = 1 << 44,
Step = 1 << 45,
FaceForward = 1 << 46,
SinCos = 1 << 47,
Any = 1 << 48,
All = 1 << 49,
Normalize = 1 << 50,
Reflect = 1 << 51,
Refract = 1 << 52,
Project = 1 << 53,
CountBits = 1 << 54,
Lzcnt = 1 << 55,
Tzcnt = 1 << 56,
ReverseBits = 1 << 57,
Rol = 1 << 58,
Ror = 1 << 59,
CeilPow2 = 1 << 60,
CeilLog2 = 1 << 61,
FloorLog2 = 1 << 62,
Radians = 1 << 63,
Degrees = 1 << 64,
Cmin = 1 << 65,
Cmax = 1 << 66,
FloatingPointMask = ~0 & ~(CountBits | Lzcnt | Tzcnt | ReverseBits | Rol | Ror | CeilPow2 | CeilLog2 | FloorLog2),
IntegerMask = Min | Max | Mad | Clamp | Abs | Dot | Sign | Any | All | Select | CountBits | Lzcnt | Tzcnt | ReverseBits | Rol | Ror | CeilPow2 | CeilLog2 | FloorLog2 | Cmin | Cmax,
UnsignedIntegerMask = IntegerMask & ~(Sign),
}
[Flags]
public enum SupportedMatrixMath
{
Transpose = 1 << 0,
Determinant = 1 << 1,
Inverse = 1 << 2,
Adjugate = 1 << 3,
Cofactor = 1 << 4,
Minor = 1 << 5,
OuterProduct = 1 << 6,
}
}

View File

@@ -17,7 +17,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen
// Create a provider that finds all types with NumericTypeAttribute // Create a provider that finds all types with NumericTypeAttribute
var typesWithAttribute = context.SyntaxProvider var typesWithAttribute = context.SyntaxProvider
.ForAttributeWithMetadataName( .ForAttributeWithMetadataName(
fullyQualifiedMetadataName: _TARGET_ATTRIBUTE_NAME, fullyQualifiedMetadataName: typeof(NumericTypeAttribute).FullName,
predicate: static (node, _) => node is ClassDeclarationSyntax or StructDeclarationSyntax, predicate: static (node, _) => node is ClassDeclarationSyntax or StructDeclarationSyntax,
transform: static (context, _) => GetTypeInfo(context)) transform: static (context, _) => GetTypeInfo(context))
.Where(static typeInfo => typeInfo is not null); .Where(static typeInfo => typeInfo is not null);
@@ -55,10 +55,10 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen
// Get the attribute data // Get the attribute data
var attribute = typeSymbol.GetAttributes() var attribute = typeSymbol.GetAttributes()
.FirstOrDefault(a => a.AttributeClass?.ToDisplayString() == _TARGET_ATTRIBUTE_NAME); .FirstOrDefault(a => a.AttributeClass?.ToDisplayString() == typeof(NumericTypeAttribute).FullName);
var convertableAttributes = typeSymbol.GetAttributes() var convertableAttributes = typeSymbol.GetAttributes()
.Where(a => a.AttributeClass?.ToDisplayString() == _CONVERTABLE_ATTRIBUTE_NAME); .Where(a => a.AttributeClass?.ToDisplayString() == typeof(NumericConvertableAttribute).FullName);
if (attribute == null) if (attribute == null)
{ {
@@ -88,7 +88,7 @@ namespace Misaki.HighPerformance.Mathematics.CodeGen
.Select(v => (INamedTypeSymbol)v.Value!) .Select(v => (INamedTypeSymbol)v.Value!)
.ToArray(); .ToArray();
info.ConvertableTypes??= new(); info.ConvertableTypes ??= new();
info.ConvertableTypes[template] = types; info.ConvertableTypes[template] = types;
} }
} }

View File

@@ -1,17 +0,0 @@
namespace Misaki.HighPerformance.Mathematics.Attributes;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)]
internal class NumericTypeAttribute : Attribute
{
public NumericTypeAttribute(Type componentType, int componentSize, int row, int column, string typePrefix, bool arithmetic = true, bool canInverse = true, Type? elementType = default, Type? vectorType = default)
{
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = true)]
internal class NumericConvertableAttribute : Attribute
{
public NumericConvertableAttribute(string template, params Type[] types)
{
}
}

View File

@@ -162,7 +162,7 @@ public struct Plane
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float4 Normalize(float4 planeCoefficients) public static float4 Normalize(float4 planeCoefficients)
{ {
float recipLength = math.rsqrt(math.lengthsq(planeCoefficients.xyz)); var recipLength = math.rsqrt(math.lengthsq(planeCoefficients.xyz));
return new Plane { normalAndDistance = planeCoefficients * recipLength }; return new Plane { normalAndDistance = planeCoefficients * recipLength };
} }
@@ -214,9 +214,9 @@ public struct Plane
public static implicit operator float4(Plane plane) => plane.normalAndDistance; public static implicit operator float4(Plane plane) => plane.normalAndDistance;
[Conditional("ENABLE_COLLECTIONS_CHECKS")] [Conditional("ENABLE_COLLECTIONS_CHECKS")]
void CheckPlaneIsNormalized() private void CheckPlaneIsNormalized()
{ {
float ll = math.lengthsq(Normal.xyz); var ll = math.lengthsq(Normal.xyz);
const float lowerBound = 0.999f * 0.999f; const float lowerBound = 0.999f * 0.999f;
const float upperBound = 1.001f * 1.001f; const float upperBound = 1.001f * 1.001f;

View File

@@ -13,7 +13,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Misaki.HighPerformance.Mathematics.CodeGen\Misaki.HighPerformance.Mathematics.CodeGen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" /> <ProjectReference Include="..\Misaki.HighPerformance.Mathematics.CodeGen\Misaki.HighPerformance.Mathematics.CodeGen.csproj" OutputItemType="Analyzer" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1,4 +1,4 @@
using Misaki.HighPerformance.Mathematics.Attributes; using Misaki.HighPerformance.Mathematics.CodeGen;
namespace Misaki.HighPerformance.Mathematics; namespace Misaki.HighPerformance.Mathematics;

View File

@@ -1,4 +1,4 @@
using Misaki.HighPerformance.Mathematics.Attributes; using Misaki.HighPerformance.Mathematics.CodeGen;
namespace Misaki.HighPerformance.Mathematics; namespace Misaki.HighPerformance.Mathematics;

View File

@@ -1,4 +1,7 @@
using Misaki.HighPerformance.Mathematics.Attributes; using Misaki.HighPerformance.Mathematics.CodeGen;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
namespace Misaki.HighPerformance.Mathematics; namespace Misaki.HighPerformance.Mathematics;

View File

@@ -1,4 +1,4 @@
using Misaki.HighPerformance.Mathematics.Attributes; using Misaki.HighPerformance.Mathematics.CodeGen;
namespace Misaki.HighPerformance.Mathematics; namespace Misaki.HighPerformance.Mathematics;

View File

@@ -1890,34 +1890,6 @@ public static partial class math
return abs(x); return abs(x);
} }
/// <summary>Returns the length of a float2 vector.</summary>
/// <param name="x">Vector to use when computing length.</param>
/// <returns>Length of vector x.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float length(float2 x)
{
return sqrt(dot(x, x));
}
/// <summary>Returns the length of a float3 vector.</summary>
/// <param name="x">Vector to use when computing length.</param>
/// <returns>Length of vector x.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float length(float3 x)
{
return sqrt(dot(x, x));
}
/// <summary>Returns the length of a float4 vector.</summary>
/// <param name="x">Vector to use when computing length.</param>
/// <returns>Length of vector x.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float length(float4 x)
{
return sqrt(dot(x, x));
}
/// <summary>Returns the length of a double value. Equivalent to the absolute value.</summary> /// <summary>Returns the length of a double value. Equivalent to the absolute value.</summary>
/// <param name="x">Value to use when computing squared length.</param> /// <param name="x">Value to use when computing squared length.</param>
/// <returns>Squared length of x.</returns> /// <returns>Squared length of x.</returns>
@@ -1927,34 +1899,6 @@ public static partial class math
return abs(x); return abs(x);
} }
/// <summary>Returns the length of a double2 vector.</summary>
/// <param name="x">Vector to use when computing squared length.</param>
/// <returns>Squared length of vector x.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double length(double2 x)
{
return sqrt(dot(x, x));
}
/// <summary>Returns the length of a double3 vector.</summary>
/// <param name="x">Vector to use when computing squared length.</param>
/// <returns>Squared length of vector x.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double length(double3 x)
{
return sqrt(dot(x, x));
}
/// <summary>Returns the length of a double4 vector.</summary>
/// <param name="x">Vector to use when computing squared length.</param>
/// <returns>Squared length of vector x.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double length(double4 x)
{
return sqrt(dot(x, x));
}
/// <summary>Returns the squared length of a float value. Equivalent to squaring the value.</summary> /// <summary>Returns the squared length of a float value. Equivalent to squaring the value.</summary>
/// <param name="x">Value to use when computing squared length.</param> /// <param name="x">Value to use when computing squared length.</param>
/// <returns>Squared length of x.</returns> /// <returns>Squared length of x.</returns>
@@ -1964,34 +1908,6 @@ public static partial class math
return x * x; return x * x;
} }
/// <summary>Returns the squared length of a float2 vector.</summary>
/// <param name="x">Vector to use when computing squared length.</param>
/// <returns>Squared length of vector x.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float lengthsq(float2 x)
{
return dot(x, x);
}
/// <summary>Returns the squared length of a float3 vector.</summary>
/// <param name="x">Vector to use when computing squared length.</param>
/// <returns>Squared length of vector x.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float lengthsq(float3 x)
{
return dot(x, x);
}
/// <summary>Returns the squared length of a float4 vector.</summary>
/// <param name="x">Vector to use when computing squared length.</param>
/// <returns>Squared length of vector x.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float lengthsq(float4 x)
{
return dot(x, x);
}
/// <summary>Returns the squared length of a double value. Equivalent to squaring the value.</summary> /// <summary>Returns the squared length of a double value. Equivalent to squaring the value.</summary>
/// <param name="x">Value to use when computing squared length.</param> /// <param name="x">Value to use when computing squared length.</param>
/// <returns>Squared length of x.</returns> /// <returns>Squared length of x.</returns>
@@ -2001,34 +1917,6 @@ public static partial class math
return x * x; return x * x;
} }
/// <summary>Returns the squared length of a double2 vector.</summary>
/// <param name="x">Vector to use when computing squared length.</param>
/// <returns>Squared length of vector x.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double lengthsq(double2 x)
{
return dot(x, x);
}
/// <summary>Returns the squared length of a double3 vector.</summary>
/// <param name="x">Vector to use when computing squared length.</param>
/// <returns>Squared length of vector x.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double lengthsq(double3 x)
{
return dot(x, x);
}
/// <summary>Returns the squared length of a double4 vector.</summary>
/// <param name="x">Vector to use when computing squared length.</param>
/// <returns>Squared length of vector x.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double lengthsq(double4 x)
{
return dot(x, x);
}
/// <summary>Returns the distance between two float values.</summary> /// <summary>Returns the distance between two float values.</summary>
/// <param name="x">First value to use in distance computation.</param> /// <param name="x">First value to use in distance computation.</param>
/// <param name="y">Second value to use in distance computation.</param> /// <param name="y">Second value to use in distance computation.</param>
@@ -2039,37 +1927,6 @@ public static partial class math
return abs(y - x); return abs(y - x);
} }
/// <summary>Returns the distance between two float2 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float distance(float2 x, float2 y)
{
return length(y - x);
}
/// <summary>Returns the distance between two float3 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float distance(float3 x, float3 y)
{
return length(y - x);
}
/// <summary>Returns the distance between two float4 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float distance(float4 x, float4 y)
{
return length(y - x);
}
/// <summary>Returns the distance between two double values.</summary> /// <summary>Returns the distance between two double values.</summary>
/// <param name="x">First value to use in distance computation.</param> /// <param name="x">First value to use in distance computation.</param>
/// <param name="y">Second value to use in distance computation.</param> /// <param name="y">Second value to use in distance computation.</param>
@@ -2080,37 +1937,6 @@ public static partial class math
return abs(y - x); return abs(y - x);
} }
/// <summary>Returns the distance between two double2 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double distance(double2 x, double2 y)
{
return length(y - x);
}
/// <summary>Returns the distance between two double3 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double distance(double3 x, double3 y)
{
return length(y - x);
}
/// <summary>Returns the distance between two double4 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double distance(double4 x, double4 y)
{
return length(y - x);
}
/// <summary>Returns the squared distance between two float values.</summary> /// <summary>Returns the squared distance between two float values.</summary>
/// <param name="x">First value to use in distance computation.</param> /// <param name="x">First value to use in distance computation.</param>
/// <param name="y">Second value to use in distance computation.</param> /// <param name="y">Second value to use in distance computation.</param>
@@ -2121,37 +1947,6 @@ public static partial class math
return (y - x) * (y - x); return (y - x) * (y - x);
} }
/// <summary>Returns the squared distance between two float2 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float distancesq(float2 x, float2 y)
{
return lengthsq(y - x);
}
/// <summary>Returns the squared distance between two float3 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float distancesq(float3 x, float3 y)
{
return lengthsq(y - x);
}
/// <summary>Returns the squared distance between two float4 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float distancesq(float4 x, float4 y)
{
return lengthsq(y - x);
}
/// <summary>Returns the squared distance between two double values.</summary> /// <summary>Returns the squared distance between two double values.</summary>
/// <param name="x">First value to use in distance computation.</param> /// <param name="x">First value to use in distance computation.</param>
/// <param name="y">Second value to use in distance computation.</param> /// <param name="y">Second value to use in distance computation.</param>
@@ -2162,37 +1957,6 @@ public static partial class math
return (y - x) * (y - x); return (y - x) * (y - x);
} }
/// <summary>Returns the squared distance between two double2 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double distancesq(double2 x, double2 y)
{
return lengthsq(y - x);
}
/// <summary>Returns the squared distance between two double3 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double distancesq(double3 x, double3 y)
{
return lengthsq(y - x);
}
/// <summary>Returns the squared distance between two double4 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double distancesq(double4 x, double4 y)
{
return lengthsq(y - x);
}
/// <summary>Returns the cross product of two float3 vectors.</summary> /// <summary>Returns the cross product of two float3 vectors.</summary>
/// <param name="x">First vector to use in cross product.</param> /// <param name="x">First vector to use in cross product.</param>
/// <param name="y">Second vector to use in cross product.</param> /// <param name="y">Second vector to use in cross product.</param>
@@ -2237,60 +2001,6 @@ public static partial class math
return t * t * (3.0 - (2.0 * t)); return t * t * (3.0 - (2.0 * t));
} }
/// <summary>Returns true if any component of the input bool2 vector is true, false otherwise.</summary>
/// <param name="x">Vector of values to compare.</param>
/// <returns>True if any the components of x are true, false otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool any(bool2 x)
{
return x.x || x.y;
}
/// <summary>Returns true if any component of the input bool3 vector is true, false otherwise.</summary>
/// <param name="x">Vector of values to compare.</param>
/// <returns>True if any the components of x are true, false otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool any(bool3 x)
{
return x.x || x.y || x.z;
}
/// <summary>Returns true if any components of the input bool4 vector is true, false otherwise.</summary>
/// <param name="x">Vector of values to compare.</param>
/// <returns>True if any the components of x are true, false otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool any(bool4 x)
{
return x.x || x.y || x.z || x.w;
}
/// <summary>Returns true if all components of the input bool2 vector are true, false otherwise.</summary>
/// <param name="x">Vector of values to compare.</param>
/// <returns>True if all the components of x are true, false otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool all(bool2 x)
{
return x.x && x.y;
}
/// <summary>Returns true if all components of the input bool3 vector are true, false otherwise.</summary>
/// <param name="x">Vector of values to compare.</param>
/// <returns>True if all the components of x are true, false otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool all(bool3 x)
{
return x.x && x.y && x.z;
}
/// <summary>Returns true if all components of the input bool4 vector are true, false otherwise.</summary>
/// <param name="x">Vector of values to compare.</param>
/// <returns>True if all the components of x are true, false otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool all(bool4 x)
{
return x.x && x.y && x.z && x.w;
}
/// <summary>Returns trueValue if test is true, falseValue otherwise.</summary> /// <summary>Returns trueValue if test is true, falseValue otherwise.</summary>
/// <param name="falseValue">Value to use if test is false.</param> /// <param name="falseValue">Value to use if test is false.</param>
/// <param name="trueValue">Value to use if test is true.</param> /// <param name="trueValue">Value to use if test is true.</param>
@@ -2378,449 +2088,6 @@ public static partial class math
return select(0.0, 1.0, x >= threshold); return select(0.0, 1.0, x >= threshold);
} }
/// <summary>Given an incident vector i and a normal vector n, returns the reflection vector r = i - 2.0f * dot(i, n) * n.</summary>
/// <param name="i">Incident vector.</param>
/// <param name="n">Normal vector.</param>
/// <returns>Reflection vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float2 reflect(float2 i, float2 n)
{
return i - 2f * n * dot(i, n);
}
/// <summary>Given an incident vector i and a normal vector n, returns the reflection vector r = i - 2.0f * dot(i, n) * n.</summary>
/// <param name="i">Incident vector.</param>
/// <param name="n">Normal vector.</param>
/// <returns>Reflection vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float3 reflect(float3 i, float3 n)
{
return i - 2f * n * dot(i, n);
}
/// <summary>Given an incident vector i and a normal vector n, returns the reflection vector r = i - 2.0f * dot(i, n) * n.</summary>
/// <param name="i">Incident vector.</param>
/// <param name="n">Normal vector.</param>
/// <returns>Reflection vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float4 reflect(float4 i, float4 n)
{
return i - 2f * n * dot(i, n);
}
/// <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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double2 reflect(double2 i, double2 n)
{
return i - 2 * n * dot(i, n);
}
/// <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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double3 reflect(double3 i, double3 n)
{
return i - 2 * n * dot(i, n);
}
/// <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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double4 reflect(double4 i, double4 n)
{
return i - 2 * n * dot(i, n);
}
/// <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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float2 refract(float2 i, float2 n, float indexOfRefraction)
{
var ni = dot(n, i);
var k = 1.0f - indexOfRefraction * indexOfRefraction * (1.0f - ni * ni);
return select(new(0.0f), indexOfRefraction * i - (indexOfRefraction * ni + sqrt(k)) * n, k >= 0);
}
/// <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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float3 refract(float3 i, float3 n, float indexOfRefraction)
{
var ni = dot(n, i);
var k = 1.0f - indexOfRefraction * indexOfRefraction * (1.0f - ni * ni);
return select(new(0.0f), indexOfRefraction * i - (indexOfRefraction * ni + sqrt(k)) * n, k >= 0);
}
/// <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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float4 refract(float4 i, float4 n, float indexOfRefraction)
{
var ni = dot(n, i);
var k = 1.0f - indexOfRefraction * indexOfRefraction * (1.0f - ni * ni);
return select(new(0.0f), indexOfRefraction * i - (indexOfRefraction * ni + sqrt(k)) * n, k >= 0);
}
/// <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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double2 refract(double2 i, double2 n, double indexOfRefraction)
{
var ni = dot(n, i);
var k = 1.0 - indexOfRefraction * indexOfRefraction * (1.0 - ni * ni);
return select(new(0.0), indexOfRefraction * i - (indexOfRefraction * ni + sqrt(k)) * n, k >= 0);
}
/// <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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double3 refract(double3 i, double3 n, double indexOfRefraction)
{
var ni = dot(n, i);
var k = 1.0 - indexOfRefraction * indexOfRefraction * (1.0 - ni * ni);
return select(new(0.0), indexOfRefraction * i - (indexOfRefraction * ni + sqrt(k)) * n, k >= 0);
}
/// <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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double4 refract(double4 i, double4 n, double indexOfRefraction)
{
var ni = dot(n, i);
var k = 1.0 - indexOfRefraction * indexOfRefraction * (1.0 - ni * ni);
return select(new(0.0), indexOfRefraction * i - (indexOfRefraction * ni + sqrt(k)) * n, k >= 0);
}
/// <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(Unity.Mathematics.float2,Unity.Mathematics.float2,Unity.Mathematics.float2)"/>
/// 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float2 project(float2 a, float2 ontoB)
{
return (dot(a, ontoB) / dot(ontoB, ontoB)) * ontoB;
}
/// <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(Unity.Mathematics.float3,Unity.Mathematics.float3,Unity.Mathematics.float3)"/>
/// 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float3 project(float3 a, float3 ontoB)
{
return (dot(a, ontoB) / dot(ontoB, ontoB)) * ontoB;
}
/// <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(Unity.Mathematics.float4,Unity.Mathematics.float4,Unity.Mathematics.float4)"/>
/// 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float4 project(float4 a, float4 ontoB)
{
return (dot(a, ontoB) / dot(ontoB, ontoB)) * ontoB;
}
/// <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(Unity.Mathematics.float2,Unity.Mathematics.float2)"/> 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float2 projectsafe(float2 a, float2 ontoB, float2 defaultValue = new float2())
{
var proj = project(a, ontoB);
return select(defaultValue, proj, all(isfinite(proj)));
}
/// <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(Unity.Mathematics.float3,Unity.Mathematics.float3)"/> 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float3 projectsafe(float3 a, float3 ontoB, float3 defaultValue = new float3())
{
var proj = project(a, ontoB);
return select(defaultValue, proj, all(isfinite(proj)));
}
/// <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(Unity.Mathematics.float4,Unity.Mathematics.float4)"/> 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float4 projectsafe(float4 a, float4 ontoB, float4 defaultValue = new float4())
{
var proj = project(a, ontoB);
return select(defaultValue, proj, all(isfinite(proj)));
}
/// <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 Double.MaxValue) or when b's components are very small (close to DBL_MIN_NORMAL).
/// In these cases, you can call <see cref="projectsafe(Unity.Mathematics.double2,Unity.Mathematics.double2,Unity.Mathematics.double2)"/>
/// 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double2 project(double2 a, double2 ontoB)
{
return (dot(a, ontoB) / dot(ontoB, ontoB)) * ontoB;
}
/// <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 Double.MaxValue) or when b's components are very small (close to DBL_MIN_NORMAL).
/// In these cases, you can call <see cref="projectsafe(Unity.Mathematics.double3,Unity.Mathematics.double3,Unity.Mathematics.double3)"/>
/// 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double3 project(double3 a, double3 ontoB)
{
return (dot(a, ontoB) / dot(ontoB, ontoB)) * ontoB;
}
/// <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 Double.MaxValue) or when b's components are very small (close to DBL_MIN_NORMAL).
/// In these cases, you can call <see cref="projectsafe(Unity.Mathematics.double4,Unity.Mathematics.double4,Unity.Mathematics.double4)"/>
/// 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double4 project(double4 a, double4 ontoB)
{
return (dot(a, ontoB) / dot(ontoB, ontoB)) * ontoB;
}
/// <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(Unity.Mathematics.double2,Unity.Mathematics.double2)"/> 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double2 projectsafe(double2 a, double2 ontoB, double2 defaultValue = new double2())
{
var proj = project(a, ontoB);
return select(defaultValue, proj, all(isfinite(proj)));
}
/// <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(Unity.Mathematics.double3,Unity.Mathematics.double3)"/> 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double3 projectsafe(double3 a, double3 ontoB, double3 defaultValue = new double3())
{
var proj = project(a, ontoB);
return select(defaultValue, proj, all(isfinite(proj)));
}
/// <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(Unity.Mathematics.double4,Unity.Mathematics.double4)"/> 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double4 projectsafe(double4 a, double4 ontoB, double4 defaultValue = new double4())
{
var proj = project(a, ontoB);
return select(defaultValue, proj, all(isfinite(proj)));
}
/// <summary>Conditionally flips a vector n if two vectors i and ng are pointing in the same direction. Returns n if dot(i, ng) &lt; 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float2 faceforward(float2 n, float2 i, float2 ng)
{
return select(n, -n, dot(ng, i) >= 0.0f);
}
/// <summary>Conditionally flips a vector n if two vectors i and ng are pointing in the same direction. Returns n if dot(i, ng) &lt; 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float3 faceforward(float3 n, float3 i, float3 ng)
{
return select(n, -n, dot(ng, i) >= 0.0f);
}
/// <summary>Conditionally flips a vector n if two vectors i and ng are pointing in the same direction. Returns n if dot(i, ng) &lt; 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float4 faceforward(float4 n, float4 i, float4 ng)
{
return select(n, -n, dot(ng, i) >= 0.0f);
}
/// <summary>Conditionally flips a vector n if two vectors i and ng are pointing in the same direction. Returns n if dot(i, ng) &lt; 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double2 faceforward(double2 n, double2 i, double2 ng)
{
return select(n, -n, dot(ng, i) >= 0.0f);
}
/// <summary>Conditionally flips a vector n if two vectors i and ng are pointing in the same direction. Returns n if dot(i, ng) &lt; 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double3 faceforward(double3 n, double3 i, double3 ng)
{
return select(n, -n, dot(ng, i) >= 0.0f);
}
/// <summary>Conditionally flips a vector n if two vectors i and ng are pointing in the same direction. Returns n if dot(i, ng) &lt; 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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double4 faceforward(double4 n, double4 i, double4 ng)
{
return select(n, -n, dot(ng, i) >= 0.0f);
}
/// <summary>Returns the sine and cosine of the input float value x through the out parameters s and c.</summary> /// <summary>Returns the sine and cosine of the input float value x through the out parameters s and c.</summary>
/// <remarks>When Burst compiled, his method is faster than calling sin() and cos() separately.</remarks> /// <remarks>When Burst compiled, his method is faster than calling sin() and cos() separately.</remarks>
/// <param name="x">Input angle in radians.</param> /// <param name="x">Input angle in radians.</param>

View File

@@ -15,7 +15,7 @@ public static class svd
public const float EPSILON_NORMAL = 1e-30f; public const float EPSILON_NORMAL = 1e-30f;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
static void condSwap(bool c, ref float x, ref float y) private static void condSwap(bool c, ref float x, ref float y)
{ {
var tmp = x; var tmp = x;
x = math.select(x, y, c); x = math.select(x, y, c);
@@ -23,7 +23,7 @@ public static class svd
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
static void condNegSwap(bool c, ref float3 x, ref float3 y) private static void condNegSwap(bool c, ref float3 x, ref float3 y)
{ {
var tmp = -x; var tmp = -x;
x = math.select(x, y, c); x = math.select(x, y, c);
@@ -31,14 +31,14 @@ public static class svd
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
static quaternion condNegSwapQuat(bool c, quaternion q, float4 mask) private static quaternion condNegSwapQuat(bool c, quaternion q, float4 mask)
{ {
const float halfSqrt2 = 0.707106781186548f; const float halfSqrt2 = 0.707106781186548f;
return math.mul(q, math.select(quaternion.identity.value, mask * halfSqrt2, c)); return math.mul(q, math.select(quaternion.identity.value, mask * halfSqrt2, c));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
static void sortSingularValues(ref float3x3 b, ref quaternion v) private static void sortSingularValues(ref float3x3 b, ref quaternion v)
{ {
var l0 = math.lengthsq(b.c0); var l0 = math.lengthsq(b.c0);
var l1 = math.lengthsq(b.c1); var l1 = math.lengthsq(b.c1);
@@ -60,7 +60,7 @@ public static class svd
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
static quaternion approxGivensQuat(float3 pq, float4 mask) private static quaternion approxGivensQuat(float3 pq, float4 mask)
{ {
const float c8 = 0.923879532511287f; // cos(pi/8) const float c8 = 0.923879532511287f; // cos(pi/8)
const float s8 = 0.38268343236509f; // sin(pi/8) const float s8 = 0.38268343236509f; // sin(pi/8)
@@ -73,7 +73,7 @@ public static class svd
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
static quaternion qrGivensQuat(float2 pq, float4 mask) private static quaternion qrGivensQuat(float2 pq, float4 mask)
{ {
var l = math.sqrt(pq.x * pq.x + pq.y * pq.y); var l = math.sqrt(pq.x * pq.x + pq.y * pq.y);
var sh = math.select(0f, pq.y, l > EPSILON_NORMAL_SQRT); var sh = math.select(0f, pq.y, l > EPSILON_NORMAL_SQRT);
@@ -84,7 +84,7 @@ public static class svd
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
static quaternion givensQRFactorization(float3x3 b, out float3x3 r) private static quaternion givensQRFactorization(float3x3 b, out float3x3 r)
{ {
var u = qrGivensQuat(new float2(b.c0.x, b.c0.y), new float4(0f, 0f, 1f, 1f)); var u = qrGivensQuat(new float2(b.c0.x, b.c0.y), new float4(0f, 0f, 1f, 1f));
var qmt = new float3x3(math.conjugate(u)); var qmt = new float3x3(math.conjugate(u));
@@ -103,7 +103,7 @@ public static class svd
return u; return u;
} }
static quaternion jacobiIteration(ref float3x3 s, int iterations = 5) private static quaternion jacobiIteration(ref float3x3 s, int iterations = 5)
{ {
float3x3 qm; float3x3 qm;
quaternion q; quaternion q;
@@ -131,7 +131,7 @@ public static class svd
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
static float3 singularValuesDecomposition(float3x3 a, out quaternion u, out quaternion v) private static float3 singularValuesDecomposition(float3x3 a, out quaternion u, out quaternion v)
{ {
u = quaternion.identity; u = quaternion.identity;
v = quaternion.identity; v = quaternion.identity;
@@ -147,7 +147,7 @@ public static class svd
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
static float3 rcpsafe(float3 x, float epsilon = EPSILON_RCP) => private static float3 rcpsafe(float3 x, float epsilon = EPSILON_RCP) =>
math.select(math.rcp(x), float3.zero, math.abs(x) < epsilon); math.select(math.rcp(x), float3.zero, math.abs(x) < epsilon);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -1,4 +1,4 @@
using Misaki.HighPerformance.Mathematics.Attributes; using Misaki.HighPerformance.Mathematics.CodeGen;
namespace Misaki.HighPerformance.Mathematics; namespace Misaki.HighPerformance.Mathematics;

View File

@@ -1,6 +1,9 @@
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using Misaki.HighPerformance.Mathematics; using Misaki.HighPerformance.Mathematics;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Misaki.HighPerformance.Test.Benchmark; namespace Misaki.HighPerformance.Test.Benchmark;
@@ -9,6 +12,11 @@ public class MathematicsBenchmark
[Params(10)] [Params(10)]
public int count = 10; public int count = 10;
private unsafe static Vector128<float> CreateVector128(float2 value)
{
return Vector128.AsSingle(Sse2.LoadScalarVector128((double*)&value));
}
[Benchmark] [Benchmark]
public void Vector2Add() public void Vector2Add()
{ {
@@ -28,14 +36,18 @@ public class MathematicsBenchmark
var a = new float2(1, 2); var a = new float2(1, 2);
var b = new float2(5, 6); var b = new float2(5, 6);
var result = new float2(); var result = new float2();
//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; result += a + b;
//vr = Sse.Add(va, vb);
} }
} }
[Benchmark] //[Benchmark]
public void Vector4Add() public void Vector4Add()
{ {
var a = new Vector4(1, 2, 3, 4); var a = new Vector4(1, 2, 3, 4);
@@ -48,7 +60,7 @@ public class MathematicsBenchmark
} }
} }
[Benchmark] //[Benchmark]
public void Float4Add() public void Float4Add()
{ {
var a = new float4(1, 2, 3, 4); var a = new float4(1, 2, 3, 4);

View File

@@ -18,23 +18,24 @@
//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;
//using Misaki.HighPerformance.LowLevel.Utilities;
var scope = AllocationManager.CreateStackScope(); //using (AllocationManager.CreateStackScope())
var array = new UnsafeArray<int>(10, Allocator.Stack); //{
for (var i = 0; i < array.Count; i++) // var array = new UnsafeArray<int>(10, Allocator.Stack);
{ // for (var i = 0; i < array.Count; i++)
array[i] = i; // {
} // array[i] = i;
// }
foreach (var item in array) // foreach (var item in array.AsSpan())
{ // {
Console.WriteLine(item); // Console.WriteLine(item);
} // }
//}
scope.Dispose();

View File

@@ -1,4 +1,3 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Misaki.HighPerformance.Mathematics; using Misaki.HighPerformance.Mathematics;
namespace Misaki.HighPerformance.Test.UnitTest.Mathematics; namespace Misaki.HighPerformance.Test.UnitTest.Mathematics;

View File

@@ -8,6 +8,7 @@ public class DynamicArray<T> : IEnumerable<T>, IList<T>
private int _count; private int _count;
public ref T this[int index] => ref _array[index]; public ref T this[int index] => ref _array[index];
public ref T this[uint index] => ref _array[index];
public int Count => _count; public int Count => _count;
public bool IsReadOnly => false; public bool IsReadOnly => false;
@@ -48,7 +49,7 @@ public class DynamicArray<T> : IEnumerable<T>, IList<T>
public IEnumerator<T> GetEnumerator() public IEnumerator<T> GetEnumerator()
{ {
for (int i = 0; i < _count; i++) for (var i = 0; i < _count; i++)
{ {
yield return _array[i]; yield return _array[i];
} }
@@ -63,8 +64,9 @@ public class DynamicArray<T> : IEnumerable<T>, IList<T>
{ {
if (_array.Length < min) if (_array.Length < min)
{ {
int newCapacity = _array.Length == 0 ? 4 : _array.Length * 2; var newCapacity = _array.Length == 0 ? 4 : _array.Length * 2;
if (newCapacity < min) newCapacity = min; if (newCapacity < min)
newCapacity = min;
Array.Resize(ref _array, newCapacity); Array.Resize(ref _array, newCapacity);
} }
} }
@@ -102,7 +104,7 @@ public class DynamicArray<T> : IEnumerable<T>, IList<T>
public int IndexOf(T item) public int IndexOf(T item)
{ {
for (int i = 0; i < _count; i++) for (var i = 0; i < _count; i++)
{ {
if (EqualityComparer<T>.Default.Equals(_array[i], item)) if (EqualityComparer<T>.Default.Equals(_array[i], item))
{ {
@@ -120,7 +122,7 @@ public class DynamicArray<T> : IEnumerable<T>, IList<T>
public bool Remove(T item) public bool Remove(T item)
{ {
for (int i = 0; i < _count; i++) for (var i = 0; i < _count; i++)
{ {
if (EqualityComparer<T>.Default.Equals(_array[i], item)) if (EqualityComparer<T>.Default.Equals(_array[i], item))
{ {