Graphic mat 44 is now generic; TextRegex source gen will use goto instead of do{}while()

This commit is contained in:
Youmu Liu
2026-09-07 17:51:15 +08:00
parent ee67dfbde1
commit 90c7538639
27 changed files with 805 additions and 713 deletions
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Root Type="DevExpress.CodeRush.Formatting.UI.Options.BracesOptionsContainer">
<Options Language="C#">
<Options>
<Item Id="{3920243c-1bac-46ce-960d-e4186d99c187}" Type="DevExpress.CodeRush.Formatting.UI.Options.Conversion.PropertyBracesOption">
<WrapOpenBrace>
<Option>Wrap</Option>
</WrapOpenBrace>
<WrapCloseBrace>
<Option>Wrap</Option>
</WrapCloseBrace>
</Item>
<Item Id="{692dd27b-3066-4dd3-beac-516a569f5203}" Type="DevExpress.CodeRush.Formatting.UI.Options.Conversion.SimplePropertyBracesOption">
<WrapOpenBrace>
<Option>Wrap</Option>
</WrapOpenBrace>
<WrapCloseBrace>
<Option>Wrap</Option>
</WrapCloseBrace>
</Item>
</Options>
</Options>
</Root>
-12
View File
@@ -1,12 +0,0 @@
[*]
end_of_line = lf
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
[*.{bat,cmd,ps1}]
end_of_line = crlf
[*.cs]
# CS1591: 缺少对公共可见类型或成员的 XML 注释
dotnet_diagnostic.CS1591.severity = suggestion
+32 -32
View File
@@ -15,11 +15,11 @@ namespace Nitload.Mathematics.Numeric.Graphics
{
private bool _isLookAtAvailable;
internal GraphicsMatrix _lookAt;
internal GraphicsMatrix _projection;
internal GraphicsMatrix cameraAtt;
internal GraphicsMatrix rotation;
internal GraphicsMatrix rotationAtt;
internal GMatrix44<float> _lookAt;
internal GMatrix44<float> _projection;
internal GMatrix44<float> cameraAtt;
internal GMatrix44<float> rotation;
internal GMatrix44<float> rotationAtt;
internal Radius _pitch;
internal Radius _row;
internal Radius _yaw;
@@ -27,13 +27,13 @@ namespace Nitload.Mathematics.Numeric.Graphics
public Camera()
{
cameraAtt = GraphicsMatrix.Unit;
cameraAtt = GMatrix44<float>.Unit;
_target = Vec3<float>.Zero;
up = Vec3<float>.Zero;
_isLookAtAvailable = false;
_lookAt = GraphicsMatrix.Unit;
rotationAtt = GraphicsMatrix.Unit;
_projection = new GraphicsMatrix();
_lookAt = GMatrix44<float>.Unit;
rotationAtt = GMatrix44<float>.Unit;
_projection = new GMatrix44<float>();
}
public Camera(
@@ -43,32 +43,32 @@ namespace Nitload.Mathematics.Numeric.Graphics
)
: this()
{
rotationAtt = GraphicsMatrix.Unit;
cameraAtt = new GraphicsMatrix();
rotationAtt = GMatrix44<float>.Unit;
cameraAtt = new GMatrix44<float>();
SetViewDirection(position, target, up);
_pitch = Radius.Zero;
_row = Radius.Zero;
_yaw = Radius.Zero;
}
public GraphicsMatrix Projection => _projection;
public GMatrix44<float> Projection => _projection;
public GraphicsMatrix View
public GMatrix44<float> View
{
get
{
if (_isLookAtAvailable) {
return _lookAt;
}
GraphicsMatrix move = GraphicsMatrix.Unit;
move.column[3] -= cameraAtt.column[3];
GMatrix44<float> move = GMatrix44<float>.Unit;
move[3] = move[3] - cameraAtt[3];
_lookAt = rotationAtt.Transpose * move;
_isLookAtAvailable = true;
return _lookAt;
}
}
public GraphicsMatrix CameraMatrix()
public GMatrix44<float> CameraMatrix()
{
return Projection * View;
}
@@ -77,7 +77,7 @@ namespace Nitload.Mathematics.Numeric.Graphics
float distance
)
{
cameraAtt.column[3].Z -= distance;
cameraAtt[3, 2] -= distance;
_isLookAtAvailable = false;
}
@@ -85,7 +85,7 @@ namespace Nitload.Mathematics.Numeric.Graphics
float distance
)
{
cameraAtt.column[3].X -= distance;
cameraAtt[3, 0] -= distance;
_isLookAtAvailable = false;
}
@@ -93,7 +93,7 @@ namespace Nitload.Mathematics.Numeric.Graphics
float distance
)
{
cameraAtt.column[3].Y -= distance;
cameraAtt[3, 1] -= distance;
_isLookAtAvailable = false;
}
@@ -104,9 +104,9 @@ namespace Nitload.Mathematics.Numeric.Graphics
)
{
Vec3<float> direction = position - target;
if ((position == cameraAtt.column[3].XYZ) &&
if ((position == new Vec3<float>(cameraAtt[3, 0], cameraAtt[3, 1], cameraAtt[3, 2])) &&
(this.up == up) &&
(cameraAtt.column[3].XYZ == direction)) {
(new Vec3<float>(cameraAtt[3, 0], cameraAtt[3, 1], cameraAtt[3, 2]) == direction)) {
return;
}
if (direction.GetLength() == 0)
@@ -126,10 +126,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
Vec3<float> right = Linear.Orthogonalize(Vec3.Cross(up, direction));
cameraAtt.column[0].XYZ = right;
cameraAtt.column[1].XYZ = up;
cameraAtt.column[2].XYZ = direction;
cameraAtt.column[3].XYZ = position;
cameraAtt[0] = new Vec4<float>(right, 0);
cameraAtt[1] = new Vec4<float>(up, 0);
cameraAtt[2] = new Vec4<float>(direction, 0);
cameraAtt[3] = new Vec4<float>(position, 1);
InternalPitch();
InternalRow();
@@ -152,13 +152,13 @@ namespace Nitload.Mathematics.Numeric.Graphics
width = MathF.Abs(GeometryScaler.Tan(fovRadius / 2) * near * 2),
height = (width * size.Y) / size.X;
_projection.column[0].X = (2 * near) / width;
_projection.column[1].Y = (2 * near) / height;
_projection.column[2].X = (2 * offsetX) / width;
_projection.column[2].Y = (2 * offsetY) / height;
_projection.column[2].Z = (far + near) / (near - far);
_projection.column[2].W = -1;
_projection.column[3].Z = (2 * near * far) / (near - far);
_projection[0].X = (2 * near) / width;
_projection[1].Y = (2 * near) / height;
_projection[2].X = (2 * offsetX) / width;
_projection[2].Y = (2 * offsetY) / height;
_projection[2].Z = (far + near) / (near - far);
_projection[2].W = -1;
_projection[3].Z = (2 * near * far) / (near - far);
}
public void Test(
-21
View File
@@ -1,21 +0,0 @@
// -----------------------------------------------------------------------------
// file="EBO"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
namespace Nitload.Graphics.OpenGL
{
/// <summary>A set of OpenGL element-buffer handles.</summary>
public sealed record class ElementBuffer(
GlHandle[] Handles
)
{
public int Count => Handles.Length;
public GlHandle this[int index] => Handles[index];
}
}
-21
View File
@@ -1,21 +0,0 @@
// -----------------------------------------------------------------------------
// file="FBO"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
namespace Nitload.Graphics.OpenGL
{
/// <summary>A set of OpenGL framebuffer handles.</summary>
public sealed record class FrameBuffer(
GlHandle[] Handles
)
{
public int Count => Handles.Length;
public GlHandle this[int index] => Handles[index];
}
}
-21
View File
@@ -1,21 +0,0 @@
// -----------------------------------------------------------------------------
// file="RBO"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
namespace Nitload.Graphics.OpenGL
{
/// <summary>A set of OpenGL renderbuffer handles.</summary>
public sealed record class RenderBuffer(
GlHandle[] Handles
)
{
public int Count => Handles.Length;
public GlHandle this[int index] => Handles[index];
}
}
@@ -1,54 +0,0 @@
// -----------------------------------------------------------------------------
// file="TextureGL"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
namespace Nitload.Graphics.OpenGL
{
/// <summary>A set of OpenGL texture handles.</summary>
public sealed record class TextureGL(
GlHandle[] Handles
)
{
public int Count => Handles.Length;
public GlHandle this[int index] => Handles[index];
}
public readonly record struct TextureProperty(
TextureFilter FilterOnMagnify,
TextureFilter FilterOnMinify,
TextureWrap WrapOnHorizontal,
TextureWrap WrapOnVertical
);
#pragma warning disable CA1008
public enum TextureFilter
#pragma warning restore CA1008
{
Nearest = glConst.NEAREST,
Linear = glConst.LINEAR,
NearestLinearMipmap = glConst.NEAREST_MIPMAP_LINEAR,
LinearLinearMipmap = glConst.LINEAR_MIPMAP_LINEAR,
NearestNearestMipmap = glConst.NEAREST_MIPMAP_NEAREST,
LinearNearestMipmap = glConst.LINEAR_MIPMAP_NEAREST,
}
#pragma warning disable CA1008
public enum TextureWrap
#pragma warning restore CA1008
{
Repeat = glConst.REPEAT,
MirroredRepeat = glConst.MIRRORED_REPEAT,
ClampToEdge = glConst.CLAMP_TO_EDGE,
ClampToBorder = glConst.CLAMP_TO_BORDER,
}
}
-21
View File
@@ -1,21 +0,0 @@
// -----------------------------------------------------------------------------
// file="VAO"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
namespace Nitload.Graphics.OpenGL
{
/// <summary>A set of OpenGL vertex-array handles.</summary>
public sealed record class VertexArray(
GlHandle[] Handles
)
{
public int Count => Handles.Length;
public GlHandle this[int index] => Handles[index];
}
}
-21
View File
@@ -1,21 +0,0 @@
// -----------------------------------------------------------------------------
// file="VBO"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
namespace Nitload.Graphics.OpenGL
{
/// <summary>A set of OpenGL vertex-buffer handles.</summary>
public sealed record class VertexBuffer(
GlHandle[] Handles
)
{
public int Count => Handles.Length;
public GlHandle this[int index] => Handles[index];
}
}
@@ -1783,9 +1783,12 @@ namespace Nitload.Graphics.OpenGL
/// <para>See <see href="https://docs.gl/gl4/glUniform">docs.gl</see>.</para>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Uniform(int location, bool transpose, GraphicsMatrix value)
public void Uniform(int location, bool transpose, GMatrix44<float> value)
{
__context->glUniformMatrix4fv(location, 1, transpose ? (byte)1 : (byte)0, (float*)&value);
fixed (GMatrix44<float>* __value = &value)
{
__context->glUniformMatrix4fv(location, 1, transpose ? (byte)1 : (byte)0, (float*)__value);
}
}
/// <summary>
@@ -1794,9 +1797,9 @@ namespace Nitload.Graphics.OpenGL
/// <para>See <see href="https://docs.gl/gl4/glUniform">docs.gl</see>.</para>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Uniform(int location, bool transpose, ReadOnlySpan<GraphicsMatrix> values)
public void Uniform(int location, bool transpose, ReadOnlySpan<GMatrix44<float>> values)
{
fixed (GraphicsMatrix* __value = values)
fixed (GMatrix44<float>* __value = values)
{
__context->glUniformMatrix4fv(location, values.Length, transpose ? (byte)1 : (byte)0, (float*)__value);
}
@@ -631,9 +631,12 @@ namespace Nitload.Graphics.OpenGL
/// <para>See <see href="https://docs.gl/gl4/glProgramUniform">docs.gl</see>.</para>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ProgramUniform(GlHandle program, int location, bool transpose, GraphicsMatrix value)
public void ProgramUniform(GlHandle program, int location, bool transpose, GMatrix44<float> value)
{
__context->glProgramUniformMatrix4fv(program.Value, location, 1, transpose ? (byte)1 : (byte)0, (float*)&value);
fixed (GMatrix44<float>* __value = &value)
{
__context->glProgramUniformMatrix4fv(program.Value, location, 1, transpose ? (byte)1 : (byte)0, (float*)__value);
}
}
/// <summary>
@@ -642,9 +645,9 @@ namespace Nitload.Graphics.OpenGL
/// <para>See <see href="https://docs.gl/gl4/glProgramUniform">docs.gl</see>.</para>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ProgramUniform(GlHandle program, int location, bool transpose, ReadOnlySpan<GraphicsMatrix> values)
public void ProgramUniform(GlHandle program, int location, bool transpose, ReadOnlySpan<GMatrix44<float>> values)
{
fixed (GraphicsMatrix* __value = values)
fixed (GMatrix44<float>* __value = values)
{
__context->glProgramUniformMatrix4fv(program.Value, location, values.Length, transpose ? (byte)1 : (byte)0, (float*)__value);
}
@@ -16,41 +16,61 @@ namespace Nitload.Geometries
private bool globalCoordAvailable;
private CoordinationBase localCoordination;
private GraphicsMatrix coordMat;
private GMatrix44<float> coordMat;
public CoordinationBase(
CoordinationBase localCoordination
)
{
this.localCoordination = localCoordination;
coordMat = new GraphicsMatrix();
coordMat = new GMatrix44<float>();
}
public virtual Point LocalOrigin
{
get => new Point(coordMat.column[3].XYZ);
internal set => coordMat.column[3].XYZ = value.Coord;
get => new Point(new Vec3<float>(coordMat[3, 0], coordMat[3, 1], coordMat[3, 2]));
internal set
{
coordMat[3, 0] = value.Coord.X;
coordMat[3, 1] = value.Coord.Y;
coordMat[3, 2] = value.Coord.Z;
}
}
public virtual Vec3<float> LocalX
{
get => coordMat.column[3].XYZ;
internal set => coordMat.column[3].XYZ = value;
get => new Vec3<float>(coordMat[3, 0], coordMat[3, 1], coordMat[3, 2]);
internal set
{
coordMat[3, 0] = value.X;
coordMat[3, 1] = value.Y;
coordMat[3, 2] = value.Z;
}
}
public virtual Vec3<float> LocalY
{
get => coordMat.column[3].XYZ;
internal set => coordMat.column[3].XYZ = value;
get => new Vec3<float>(coordMat[3, 0], coordMat[3, 1], coordMat[3, 2]);
internal set
{
coordMat[3, 0] = value.X;
coordMat[3, 1] = value.Y;
coordMat[3, 2] = value.Z;
}
}
public virtual Vec3<float> LocalZ
{
get => coordMat.column[3].XYZ;
set => coordMat.column[3].XYZ = value;
get => new Vec3<float>(coordMat[3, 0], coordMat[3, 1], coordMat[3, 2]);
set
{
coordMat[3, 0] = value.X;
coordMat[3, 1] = value.Y;
coordMat[3, 2] = value.Z;
}
}
protected ref GraphicsMatrix CoordMat => ref coordMat;
protected ref GMatrix44<float> CoordMat => ref coordMat;
}
}
@@ -26,11 +26,11 @@ namespace Nitload.Geometries
)
: base(local)
{
CoordMat = GraphicsMatrix.Unit;
CoordMat = GMatrix44<float>.Unit;
CoordMat.column[0] = new Vec4<float>(xAxis, 0);
CoordMat.column[1] = new Vec4<float>(yAxis, 0);
CoordMat.column[2] = new Vec4<float>(Linear.Normalize(Vec3.Cross(xAxis, yAxis)), 0);
CoordMat[0] = new Vec4<float>(xAxis, 0);
CoordMat[1] = new Vec4<float>(yAxis, 0);
CoordMat[2] = new Vec4<float>(Linear.Normalize(Vec3.Cross(xAxis, yAxis)), 0);
LocalOrigin = origin;
}
@@ -41,13 +41,11 @@ namespace Nitload.Geometries
public Vec3<float> CenterPositionGlobal { get; internal set; }
public Vec3<float> Coord//
{ get => GlobalBuffer.CoordAndRotationList[BufferId].XYZ;//
set
{
Vec4<float> v = new(value, 0);
GlobalBuffer.CoordAndRotationList[BufferId] = v;
} }
public Vec3<float> Coord { get => GlobalBuffer.CoordAndRotationList[BufferId].XYZ; set
{
Vec4<float> v = new(value, 0);
GlobalBuffer.CoordAndRotationList[BufferId] = v;
} }
public void Move()
{
@@ -0,0 +1,190 @@
// -----------------------------------------------------------------------------
// file="GMatrix44_T"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Nitload.Mathematics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Text;
using System.Threading.Tasks;
namespace Nitload.Mathematics.Numeric.Graphics
{
[StructLayout(LayoutKind.Sequential, Pack = 16)]
public struct GMatrix44<T> where T : unmanaged, INumber<T>
{
private Buffer _buffer;
public Vec4<T> this[
int x
]
{
readonly get => _buffer[x];
set => _buffer[x] = value;
}
public T this[
int x,
int y
]
{
readonly get => _buffer[x][y];
set => _buffer[x][y] = value;
}
public static GMatrix44<T> Unit
{
get
{
GMatrix44<T> result = new();
result[0] = new Vec4<T>(T.One, T.Zero, T.Zero, T.Zero);
result[1] = new Vec4<T>(T.Zero, T.One, T.Zero, T.Zero);
result[2] = new Vec4<T>(T.Zero, T.Zero, T.One, T.Zero);
result[3] = new Vec4<T>(T.Zero, T.Zero, T.Zero, T.One);
return result;
}
}
public GMatrix44<T> Transpose
{
get
{
GMatrix44<T> transpose = new();
// Native SK transpose is intentionally deferred until the module
// startup path can guarantee that GlobalContext has been initialized.
if (Unsafe.SizeOf<T>() == 4)
{
Vector128<T> row0Source = _buffer[0].AsVector128Unsafe();
Vector128<T> row1Source = _buffer[1].AsVector128Unsafe();
Vector128<T> row2Source = _buffer[2].AsVector128Unsafe();
Vector128<T> row3Source = _buffer[3].AsVector128Unsafe();
Vector128<int> row0 = Unsafe.As<Vector128<T>, Vector128<int>>(ref row0Source);
Vector128<int> row1 = Unsafe.As<Vector128<T>, Vector128<int>>(ref row1Source);
Vector128<int> row2 = Unsafe.As<Vector128<T>, Vector128<int>>(ref row2Source);
Vector128<int> row3 = Unsafe.As<Vector128<T>, Vector128<int>>(ref row3Source);
Vector128<int> pairMask = Vector128.Create(-1, 0, -1, 0);
Vector128<int> firstPairMask = Vector128.Create(-1, -1, 0, 0);
Vector128<int> lowShuffle = Vector128.Create(0, 0, 1, 1);
Vector128<int> highShuffle = Vector128.Create(2, 2, 3, 3);
Vector128<int> secondLaneShuffle = Vector128.Create(2, 3, 2, 3);
Vector128<int> pair01Low = Vector128.ConditionalSelect(
pairMask,
Vector128.Shuffle(row0, lowShuffle),
Vector128.Shuffle(row1, lowShuffle));
Vector128<int> pair23Low = Vector128.ConditionalSelect(
pairMask,
Vector128.Shuffle(row2, lowShuffle),
Vector128.Shuffle(row3, lowShuffle));
Vector128<int> pair01High = Vector128.ConditionalSelect(
pairMask,
Vector128.Shuffle(row0, highShuffle),
Vector128.Shuffle(row1, highShuffle));
Vector128<int> pair23High = Vector128.ConditionalSelect(
pairMask,
Vector128.Shuffle(row2, highShuffle),
Vector128.Shuffle(row3, highShuffle));
Vector128<int> result0 = Vector128.ConditionalSelect(
firstPairMask, pair01Low, pair23Low);
Vector128<int> result1 = Vector128.ConditionalSelect(
firstPairMask,
Vector128.Shuffle(pair01Low, secondLaneShuffle),
Vector128.Shuffle(pair23Low, secondLaneShuffle));
Vector128<int> result2 = Vector128.ConditionalSelect(
firstPairMask, pair01High, pair23High);
Vector128<int> result3 = Vector128.ConditionalSelect(
firstPairMask,
Vector128.Shuffle(pair01High, secondLaneShuffle),
Vector128.Shuffle(pair23High, secondLaneShuffle));
transpose._buffer[0] = Vec4.FromVector128Unsafe(
Unsafe.As<Vector128<int>, Vector128<T>>(ref result0));
transpose._buffer[1] = Vec4.FromVector128Unsafe(
Unsafe.As<Vector128<int>, Vector128<T>>(ref result1));
transpose._buffer[2] = Vec4.FromVector128Unsafe(
Unsafe.As<Vector128<int>, Vector128<T>>(ref result2));
transpose._buffer[3] = Vec4.FromVector128Unsafe(
Unsafe.As<Vector128<int>, Vector128<T>>(ref result3));
return transpose;
}
if (Unsafe.SizeOf<T>() == 8)
{
Vector256<T> row0Source = _buffer[0].AsVector256Unsafe();
Vector256<T> row1Source = _buffer[1].AsVector256Unsafe();
Vector256<T> row2Source = _buffer[2].AsVector256Unsafe();
Vector256<T> row3Source = _buffer[3].AsVector256Unsafe();
Vector256<long> row0 = Unsafe.As<Vector256<T>, Vector256<long>>(ref row0Source);
Vector256<long> row1 = Unsafe.As<Vector256<T>, Vector256<long>>(ref row1Source);
Vector256<long> row2 = Unsafe.As<Vector256<T>, Vector256<long>>(ref row2Source);
Vector256<long> row3 = Unsafe.As<Vector256<T>, Vector256<long>>(ref row3Source);
Vector256<long> pairMask = Vector256.Create(-1L, 0L, -1L, 0L);
Vector256<long> firstPairMask = Vector256.Create(-1L, -1L, 0L, 0L);
Vector256<long> firstShuffle = Vector256.Create(0L, 0L, 1L, 1L);
Vector256<long> secondShuffle = Vector256.Create(2L, 2L, 3L, 3L);
Vector256<long> pair01First = Vector256.ConditionalSelect(
pairMask,
Vector256.Shuffle(row0, firstShuffle),
Vector256.Shuffle(row1, firstShuffle));
Vector256<long> pair23First = Vector256.ConditionalSelect(
pairMask,
Vector256.Shuffle(row2, firstShuffle),
Vector256.Shuffle(row3, firstShuffle));
Vector256<long> pair01Second = Vector256.ConditionalSelect(
pairMask,
Vector256.Shuffle(row0, secondShuffle),
Vector256.Shuffle(row1, secondShuffle));
Vector256<long> pair23Second = Vector256.ConditionalSelect(
pairMask,
Vector256.Shuffle(row2, secondShuffle),
Vector256.Shuffle(row3, secondShuffle));
Vector256<long> result0 = Vector256.ConditionalSelect(
firstPairMask, pair01First, pair23First);
Vector256<long> result1 = Vector256.ConditionalSelect(
firstPairMask,
Vector256.Shuffle(pair01First, secondShuffle),
Vector256.Shuffle(pair23First, secondShuffle));
Vector256<long> result2 = Vector256.ConditionalSelect(
firstPairMask, pair01Second, pair23Second);
Vector256<long> result3 = Vector256.ConditionalSelect(
firstPairMask,
Vector256.Shuffle(pair01Second, secondShuffle),
Vector256.Shuffle(pair23Second, secondShuffle));
transpose._buffer[0] = Vec4.FromVector256Unsafe(
Unsafe.As<Vector256<long>, Vector256<T>>(ref result0));
transpose._buffer[1] = Vec4.FromVector256Unsafe(
Unsafe.As<Vector256<long>, Vector256<T>>(ref result1));
transpose._buffer[2] = Vec4.FromVector256Unsafe(
Unsafe.As<Vector256<long>, Vector256<T>>(ref result2));
transpose._buffer[3] = Vec4.FromVector256Unsafe(
Unsafe.As<Vector256<long>, Vector256<T>>(ref result3));
return transpose;
}
throw GraphicVector.ThrowUnsupportedTypeException<T>();
}
}
[InlineArray(4)]
private struct Buffer
{
public Vec4<T> _column;
}
}
}
@@ -1,261 +0,0 @@
// -----------------------------------------------------------------------------
// file="GraphicsMatrix"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Nitload.Mathematics;
using Nitload.Mathematics.Internal;
using Nitload.Mathematics.Numeric;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.X86;
namespace Nitload.Mathematics.Numeric.Graphics
{
[StructLayout(LayoutKind.Explicit, Size = 16 * sizeof(float), Pack = 16)]
public unsafe struct GraphicsMatrix : IEquatable<GraphicsMatrix>
{
[FieldOffset(0 * sizeof(float))] internal Column column;
[FieldOffset(0)] internal ColumnSet4 mat;
[FieldOffset(0)] internal MatrixKernel<float> kernel;
internal GraphicsMatrix(
ColumnSet4 mat
)
{
Unsafe.SkipInit(out this);
this.mat = mat;
}
internal GraphicsMatrix(
Vector4 vec0,
Vector4 vec1,
Vector4 vec2,
Vector4 vec3
)
{
Unsafe.SkipInit(out this);
mat.colum0 = vec0;
mat.colum1 = vec1;
mat.colum2 = vec2;
mat.colum3 = vec3;
}
public GraphicsMatrix()
{
Unsafe.SkipInit(out this);
}
public unsafe GraphicsMatrix(
float a00,
float a01,
float a02,
float a03,
float a10,
float a11,
float a12,
float a13,
float a20,
float a21,
float a22,
float a23,
float a30,
float a31,
float a32,
float a33
)
{
Unsafe.SkipInit(out this);
mat.colum0 = new Vector4(a00, a10, a20, a30);
mat.colum1 = new Vector4(a01, a11, a21, a31);
mat.colum2 = new Vector4(a02, a12, a22, a32);
mat.colum3 = new Vector4(a03, a13, a23, a33);
}
public unsafe float this[
int rowNum,
int columNum
]
{
get
{
#if DEBUG
if (rowNum is > 3 or < 0)
{
throw new ArgumentOutOfRangeException(nameof(columNum));
}
if (columNum is > 3 or < 0) {
throw new ArgumentOutOfRangeException(nameof(columNum));
}
#endif
return kernel[rowNum + (4 * columNum)];
}
set
{
#if DEBUG
if (rowNum is > 3 or < 0)
{
throw new ArgumentOutOfRangeException(nameof(columNum));
}
if (columNum is > 3 or < 0) {
throw new ArgumentOutOfRangeException(nameof(columNum));
}
#endif
kernel[rowNum + (4 * columNum)] = value;
}
}
public GraphicsMatrix Transpose
{
get
{
GraphicsMatrix transpose = new();
InternalTranspose(ref transpose);
return transpose;
}
}
public static GraphicsMatrix Unit => new GraphicsMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
0, 0, 0, 1);
public static GraphicsMatrix WNegativeUnit => new GraphicsMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0,
0, 1, 0, 0, 0, 0, -1);
public static GraphicsMatrix XNegativeUnit => new GraphicsMatrix(-1, 0, 0, 0, 0, 1, 0, 0, 0,
0, 1, 0, 0, 0, 0, 1);
public static GraphicsMatrix YNegativeUnit => new GraphicsMatrix(1, 0, 0, 0, 0, -1, 0, 0, 0,
0, 1, 0, 0, 0, 0, 1);
public static GraphicsMatrix ZNegativeUnit => new GraphicsMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0,
0, -1, 0, 0, 0, 0, 1);
public ReadOnlySpan<float> AsSpan()
{
return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<ColumnSet4, float>(ref mat), 16);
}
public override bool Equals(
object? obj
)
{
return (obj is GraphicsMatrix x) && Equals(x);
}
public bool Equals(
GraphicsMatrix other
)
{
return mat.Equals(other.mat);
}
public override int GetHashCode()
{
return HashCode.Combine(mat.colum0.GetHashCode(), mat.colum1.GetHashCode(),
mat.colum2.GetHashCode(), mat.colum3.GetHashCode());
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal unsafe void InternalTranspose(
ref GraphicsMatrix transpose
)
{
const int f32 = 0;
fixed (MatrixKernel<float>* source = &this.kernel, target = &transpose.kernel) {
NumericalModule.GlobalContext.mat_sk[f32].Call(MatrixIntrinsicHandle.Transpose,
null, (MatrixKernel*)source,
(MatrixKernel*)target, 0);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe GraphicsMatrix operator -(
GraphicsMatrix left,
GraphicsMatrix right
)
{
GraphicsMatrix ret = new();
int f32 = MatrixElementType.F32.IntrinsicNode;
NumericalModule.GlobalContext.mat_sk[f32].Call(MatrixIntrinsicHandle.Sub,
(MatrixKernel*)&left.kernel,
(MatrixKernel*)&right.kernel,
(MatrixKernel*)&ret.kernel, 1);
return ret;
}
public static bool operator !=(
GraphicsMatrix left,
GraphicsMatrix right
)
{
return !(left == right);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe GraphicsMatrix operator *(
GraphicsMatrix mat,
float value
)
{
int f32 = MatrixElementType.F32.IntrinsicNode;
return new GraphicsMatrix(mat.mat.colum0 * value, mat.mat.colum1 * value,
mat.mat.colum2 * value, mat.mat.colum3 * value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static GraphicsMatrix operator *(
GraphicsMatrix left,
GraphicsMatrix right
)
{
GraphicsMatrix ret = new();
int f32 = MatrixElementType.F32.IntrinsicNode;
NumericalModule.GlobalContext.mat_sk[f32].Call(MatrixIntrinsicHandle.Fma,
(MatrixKernel*)&left,
(MatrixKernel*)&right,
(MatrixKernel*)&ret, 0);
return ret;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe GraphicsMatrix operator +(
GraphicsMatrix left,
GraphicsMatrix right
)
{
GraphicsMatrix ret = new();
int f32 = MatrixElementType.F32.IntrinsicNode;
NumericalModule.GlobalContext.mat_sk[f32].Call(MatrixIntrinsicHandle.Add,
(MatrixKernel*)&left,
(MatrixKernel*)&right,
(MatrixKernel*)&ret, 1);
return ret;
}
public static bool operator ==(
GraphicsMatrix left,
GraphicsMatrix right
)
{
return left.Equals(right);
}
[InlineArray(4)]
internal struct Column
{
private Vec4<float> value;
}
}
}
@@ -15,13 +15,61 @@ namespace Nitload.Mathematics.Numeric.Graphics
public static class Vec3
{
public static bool IsParallel<T>(Vec3<T> left, Vec3<T> right) where T: unmanaged,INumber<T>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<double> ConvertToDouble(
Vec3<long> source
)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Safe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<double> ConvertToDouble(
Vec3<ulong> source
)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Safe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<float> ConvertToSingle(
Vec3<int> source
)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Safe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<float> ConvertToSingle(
Vec3<uint> source
)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Safe()));
}
public static Vec3<T> FromSpan<T>(
ReadOnlySpan<T> span
) where T : unmanaged, INumber<T>
{
if (span.Length < 3) {
throw new ArgumentException("Span length must be at least 3.", nameof(span));
}
return new(span[0], span[1], span[2]);
}
public static bool IsParallel<T>(
Vec3<T> left,
Vec3<T> right
) where T : unmanaged,INumber<T>
{
return Cross(left, right).Equals(T.Zero);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector128<T> AsVector128Safe<T>(this Vec3<T> source) where T: unmanaged, INumber<T>
internal static Vector128<T> AsVector128Safe<T>(
this Vec3<T> source
) where T : unmanaged, INumber<T>
{
Vector128<T> result = Vector128<T>.Zero;
Unsafe.WriteUnaligned(ref Unsafe.As<Vector128<T>, byte>(ref result), source);
@@ -29,7 +77,9 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector128<T> AsVector128Unsafe<T>(this Vec3<T> source) where T: unmanaged, INumber<T>
internal static Vector128<T> AsVector128Unsafe<T>(
this Vec3<T> source
) where T : unmanaged, INumber<T>
{
Unsafe.SkipInit(out Vector128<T> result);
Unsafe.WriteUnaligned(ref Unsafe.As<Vector128<T>, byte>(ref result), source);
@@ -37,7 +87,9 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector256<T> AsVector256Safe<T>(this Vec3<T> source) where T: unmanaged, INumber<T>
internal static Vector256<T> AsVector256Safe<T>(
this Vec3<T> source
) where T : unmanaged, INumber<T>
{
Vector256<T> result = Vector256<T>.Zero;
Unsafe.WriteUnaligned(ref Unsafe.As<Vector256<T>, byte>(ref result), source);
@@ -45,7 +97,9 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector256<T> AsVector256Unsafe<T>(this Vec3<T> source) where T: unmanaged, INumber<T>
internal static Vector256<T> AsVector256Unsafe<T>(
this Vec3<T> source
) where T : unmanaged, INumber<T>
{
Unsafe.SkipInit(out Vector256<T> result);
Unsafe.WriteUnaligned(ref Unsafe.As<Vector256<T>, byte>(ref result), source);
@@ -53,45 +107,28 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vec3<T> FromVector128Unsafe<T>(Vector128<T> source) where T: unmanaged, INumber<T>
internal static Vec3<T> FromVector128Unsafe<T>(
Vector128<T> source
) where T : unmanaged, INumber<T>
{
return Unsafe.As<Vector128<T>, Vec3<T>>(ref source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vec3<T> FromVector256Unsafe<T>(Vector256<T> source) where T: unmanaged, INumber<T>
internal static Vec3<T> FromVector256Unsafe<T>(
Vector256<T> source
) where T : unmanaged, INumber<T>
{
return Unsafe.As<Vector256<T>, Vec3<T>>(ref source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<float> ConvertToSingle(Vec3<int> source)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Safe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<float> ConvertToSingle(Vec3<uint> source)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Safe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<double> ConvertToDouble(Vec3<long> source)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Safe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<double> ConvertToDouble(Vec3<ulong> source)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Safe()));
}
#region cross
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> Cross<T>(Vec3<T> left, Vec3<T> right) where T: unmanaged, INumber<T>
public static Vec3<T> Cross<T>(
Vec3<T> left,
Vec3<T> right
) where T : unmanaged, INumber<T>
{
if (typeof(T) == typeof(float))
{
@@ -140,7 +177,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vec3<double> CrossDouble(Vec3<double> left, Vec3<double> right)
private static Vec3<double> CrossDouble(
Vec3<double> left,
Vec3<double> right
)
{
Vector256<double> l = left.AsVector256Safe();
Vector256<double> r = right.AsVector256Safe();
@@ -151,7 +191,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vec3<int> CrossInt32(Vec3<int> left, Vec3<int> right)
private static Vec3<int> CrossInt32(
Vec3<int> left,
Vec3<int> right
)
{
Vector128<int> l = left.AsVector128Safe();
Vector128<int> r = right.AsVector128Safe();
@@ -162,7 +205,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vec3<float> CrossSingle(Vec3<float> left, Vec3<float> right)
private static Vec3<float> CrossSingle(
Vec3<float> left,
Vec3<float> right
)
{
Vector128<float> l = left.AsVector128Safe();
Vector128<float> r = right.AsVector128Safe();
@@ -173,7 +219,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vec3<uint> CrossUInt32(Vec3<uint> left, Vec3<uint> right)
private static Vec3<uint> CrossUInt32(
Vec3<uint> left,
Vec3<uint> right
)
{
Vector128<uint> l = left.AsVector128Safe();
Vector128<uint> r = right.AsVector128Safe();
@@ -184,7 +233,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vec3<ulong> CrossUInt64(Vec3<ulong> left, Vec3<ulong> right)
private static Vec3<ulong> CrossUInt64(
Vec3<ulong> left,
Vec3<ulong> right
)
{
Vector256<ulong> l = left.AsVector256Safe();
Vector256<ulong> r = right.AsVector256Safe();
@@ -195,7 +247,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vec3<long> CrossInt64(Vec3<long> left, Vec3<long> right)
private static Vec3<long> CrossInt64(
Vec3<long> left,
Vec3<long> right
)
{
Vector256<long> l = left.AsVector256Safe();
Vector256<long> r = right.AsVector256Safe();
@@ -21,21 +21,28 @@ namespace Nitload.Mathematics.Numeric.Graphics
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 16)]
public struct Vec3<T> : IUnmanagedVector<Vec3<T>>, IEquatable<Vec3<T>>, IEnumerable<T>
where T: unmanaged, INumber<T>
where T : unmanaged, INumber<T>
{
public T X;
public T Y;
public T Z;
public Vec3(Vec2<T> xy, T z)
public Vec3(
Vec2<T> xy,
T z
)
{
X = xy.X;
Y = xy.Y;
Z = z;
}
public Vec3(T x, T y, T z)
public Vec3(
T x,
T y,
T z
)
{
X = x;
Y = y;
@@ -73,7 +80,9 @@ namespace Nitload.Mathematics.Numeric.Graphics
public static Vec3<T> UnitZ => new(T.Zero, T.Zero, T.One);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly T Dot(Vec3<T> right)
public readonly T Dot(
Vec3<T> right
)
{
if (Unsafe.SizeOf<T>() == 8)
{
@@ -89,31 +98,28 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Equals(Vec3<T> other)
public readonly bool Equals(
Vec3<T> other
)
{
if (Unsafe.SizeOf<T>() == 4) {
if (Unsafe.SizeOf<T>() == 4)
{
return this.AsVector128Safe() == other.AsVector128Safe();
}
if (Unsafe.SizeOf<T>() == 8) {
} else if (Unsafe.SizeOf<T>() == 8) {
return this.AsVector256Safe() == other.AsVector256Safe();
}
#pragma warning disable CA1065
throw GraphicVector.ThrowUnsupportedTypeException<T>();
#pragma warning restore CA1065
}
public override readonly bool Equals(object? obj)
public override readonly bool Equals(
object? obj
)
{
return obj is Vec3<T> other && Equals(other);
}
public static Vec3<T> FromSpan(ReadOnlySpan<T> span)
{
if (span.Length < 3) {
throw new ArgumentException("Span length must be at least 3.", nameof(span));
}
return new(span[0], span[1], span[2]);
}
public readonly IEnumerator<T> GetEnumerator()
{
yield return X;
@@ -132,33 +138,40 @@ namespace Nitload.Mathematics.Numeric.Graphics
return T.Max(X, T.Max(Y, Z));
}
public static bool IsParallel(Vec3<T> left, Vec3<T> right)
public static bool IsParallel(
Vec3<T> left,
Vec3<T> right
)
{
return Vec3.Cross(left, right) == Zero;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> operator -(Vec3<T> value)
public static Vec3<T> operator -(
Vec3<T> value
)
{
if (Unsafe.SizeOf<T>() == 4) {
if (Unsafe.SizeOf<T>() == 4)
{
return Vec3.FromVector128Unsafe(Vector128<T>.Zero - value.AsVector128Unsafe());
}
if (Unsafe.SizeOf<T>() == 8) {
} else if (Unsafe.SizeOf<T>() == 8) {
return Vec3.FromVector256Unsafe(Vector256<T>.Zero - value.AsVector256Unsafe());
}
throw GraphicVector.ThrowUnsupportedTypeException<T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> operator -(Vec3<T> left, Vec3<T> right)
public static Vec3<T> operator -(
Vec3<T> left,
Vec3<T> right
)
{
if (Unsafe.SizeOf<T>() == 4)
{
Vector128<T> left_v128 = left.AsVector128Unsafe();
Vector128<T> right_v128 = right.AsVector128Unsafe();
return Vec3.FromVector128Unsafe(left_v128 - right_v128);
}
if (Unsafe.SizeOf<T>() == 8)
} else if (Unsafe.SizeOf<T>() == 8)
{
Vector256<T> left_v256 = left.AsVector256Unsafe();
Vector256<T> right_v256 = right.AsVector256Unsafe();
@@ -168,21 +181,26 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Vec3<T> left, Vec3<T> right)
public static bool operator !=(
Vec3<T> left,
Vec3<T> right
)
{
return !left.Equals(right);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> operator *(Vec3<T> vector, T scalar)
public static Vec3<T> operator *(
Vec3<T> vector,
T scalar
)
{
if (Unsafe.SizeOf<T>() == 4)
{
Vector128<T> vector_v128 = vector.AsVector128Unsafe();
Vector128<T> scalar_v128 = Vector128.Create(scalar);
return Vec3.FromVector128Unsafe(vector_v128 * scalar_v128);
}
if (Unsafe.SizeOf<T>() == 8)
} else if (Unsafe.SizeOf<T>() == 8)
{
Vector256<T> vector_v256 = vector.AsVector256Unsafe();
Vector256<T> scalar_v256 = Vector256.Create(scalar);
@@ -192,27 +210,35 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> operator *(T scalar, Vec3<T> vector)
public static Vec3<T> operator *(
T scalar,
Vec3<T> vector
)
{
return vector * scalar;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T operator *(Vec3<T> left, Vec3<T> right)
public static T operator *(
Vec3<T> left,
Vec3<T> right
)
{
return left.Dot(right);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> operator /(Vec3<T> vector, T scalar)
public static Vec3<T> operator /(
Vec3<T> vector,
T scalar
)
{
if (Unsafe.SizeOf<T>() == 4)
{
Vector128<T> vector_v128 = vector.AsVector128Unsafe();
Vector128<T> scalar_v128 = Vector128.Create(scalar);
return Vec3.FromVector128Unsafe(vector_v128 / scalar_v128);
}
if (Unsafe.SizeOf<T>() == 8)
} else if (Unsafe.SizeOf<T>() == 8)
{
Vector256<T> vector_v256 = vector.AsVector256Unsafe();
Vector256<T> scalar_v256 = Vector256.Create(scalar);
@@ -222,15 +248,17 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> operator +(Vec3<T> left, Vec3<T> right)
public static Vec3<T> operator +(
Vec3<T> left,
Vec3<T> right
)
{
if (Unsafe.SizeOf<T>() == 4)
{
Vector128<T> left_v128 = left.AsVector128Unsafe();
Vector128<T> right_v128 = right.AsVector128Unsafe();
return Vec3.FromVector128Unsafe(left_v128 + right_v128);
}
if (Unsafe.SizeOf<T>() == 8)
} else if (Unsafe.SizeOf<T>() == 8)
{
Vector256<T> left_v256 = left.AsVector256Unsafe();
Vector256<T> right_v256 = right.AsVector256Unsafe();
@@ -240,13 +268,18 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vec3<T> left, Vec3<T> right)
public static bool operator ==(
Vec3<T> left,
Vec3<T> right
)
{
return left.Equals(right);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Vec3<T>((T X, T Y, T Z) tuple)
public static implicit operator Vec3<T>(
(T X, T Y, T Z) tuple
)
{
return new(tuple.X, tuple.Y, tuple.Z);
}
@@ -256,5 +289,13 @@ namespace Nitload.Mathematics.Numeric.Graphics
return GetEnumerator();
}
[InlineArray(3)]
private struct Buffer
{
internal T _element;
}
}
}
@@ -7,6 +7,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
namespace Nitload.Mathematics.Numeric.Graphics
@@ -15,7 +16,55 @@ namespace Nitload.Mathematics.Numeric.Graphics
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector128<T> AsVector128Unsafe<T>(this Vec4<T> source) where T: unmanaged, INumber<T>
public static Vec4<double> ConvertToDouble(
Vec4<long> source
)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Unsafe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<double> ConvertToDouble(
Vec4<ulong> source
)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Unsafe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<float> ConvertToSingle(
Vec4<int> source
)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Unsafe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<float> ConvertToSingle(
Vec4<uint> source
)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Unsafe()));
}
public static Vec4<T> FromSpan<T>(
ReadOnlySpan<T> span
) where T : unmanaged, INumber<T>
{
if (span.Length < 4) {
throw new ArgumentException("Span length must be at least 4.", nameof(span));
}
Unsafe.SkipInit(out Vec4<T> result);
Span<T> target = MemoryMarshal.CreateSpan(ref Unsafe.As<Vec4<T>, T>(ref result), 4);
span[..4].CopyTo(target);
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector128<T> AsVector128Unsafe<T>(
this Vec4<T> source
) where T : unmanaged, INumber<T>
{
Unsafe.SkipInit(out Vector128<T> result);
Unsafe.WriteUnaligned(ref Unsafe.As<Vector128<T>, byte>(ref result), source);
@@ -23,7 +72,9 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector256<T> AsVector256Unsafe<T>(this Vec4<T> source) where T: unmanaged, INumber<T>
internal static Vector256<T> AsVector256Unsafe<T>(
this Vec4<T> source
) where T : unmanaged, INumber<T>
{
Unsafe.SkipInit(out Vector256<T> result);
Unsafe.WriteUnaligned(ref Unsafe.As<Vector256<T>, byte>(ref result), source);
@@ -31,40 +82,20 @@ namespace Nitload.Mathematics.Numeric.Graphics
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vec4<T> FromVector128Unsafe<T>(Vector128<T> source) where T: unmanaged, INumber<T>
internal static Vec4<T> FromVector128Unsafe<T>(
Vector128<T> source
) where T : unmanaged, INumber<T>
{
return Unsafe.As<Vector128<T>, Vec4<T>>(ref source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vec4<T> FromVector256Unsafe<T>(Vector256<T> source) where T: unmanaged, INumber<T>
internal static Vec4<T> FromVector256Unsafe<T>(
Vector256<T> source
) where T : unmanaged, INumber<T>
{
return Unsafe.As<Vector256<T>, Vec4<T>>(ref source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<float> ConvertToSingle(Vec4<int> source)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Unsafe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<float> ConvertToSingle(Vec4<uint> source)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Unsafe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<double> ConvertToDouble(Vec4<long> source)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Unsafe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<double> ConvertToDouble(Vec4<ulong> source)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Unsafe()));
}
}
}
@@ -20,11 +20,7 @@ namespace Nitload.Mathematics.Numeric.Graphics
public struct Vec4<T> : IUnmanagedVector<Vec4<T>> where T : unmanaged, INumber<T>
{
public T W;
public T X;
public T Y;
public T Z;
private Buffer _buffer;
public Vec4(
Vec3<T> v3,
@@ -50,9 +46,41 @@ namespace Nitload.Mathematics.Numeric.Graphics
W = w;
}
public T this[
int index
]
{
get => _buffer[index];
set => _buffer[index] = value;
}
public T X
{
get => _buffer[0];
set => _buffer[0] = value;
}
public T Y
{
get => _buffer[1];
set => _buffer[1] = value;
}
public T Z
{
get => _buffer[2];
set => _buffer[2] = value;
}
public T W
{
get => _buffer[3];
set => _buffer[3] = value;
}
public Vec2<T> XY
{
get => Unsafe.As<T, Vec2<T>>(ref X);
get => Unsafe.As<T, Vec2<T>>(ref _buffer[0]);
set
{
X = value.X;
@@ -62,11 +90,60 @@ namespace Nitload.Mathematics.Numeric.Graphics
public Vec3<T> XYZ
{
get => Unsafe.As<T, Vec3<T>>(ref X);
get => Unsafe.As<T, Vec3<T>>(ref _buffer[0]);
set
{
T w = W;
Unsafe.As<T, Vec3<T>>(ref X) = value;
Unsafe.As<T, Vec3<T>>(ref _buffer[0]) = value;
W = w;
}
}
public Vec3<T> ZXY
{
readonly get
{
if (Unsafe.SizeOf<T>() == 4)
{
Vector128<T> source = this.AsVector128Unsafe();
Vector128<int> bits = Unsafe.As<Vector128<T>, Vector128<int>>(ref source);
Vector128<int> result = Vector128.Shuffle(bits, Vector128.Create(2, 0, 1, 3));
Vector128<T> shuffled = Unsafe.As<Vector128<int>, Vector128<T>>(ref result);
return Vec3.FromVector128Unsafe(shuffled);
}
if (Unsafe.SizeOf<T>() == 8)
{
Vector256<T> source = this.AsVector256Unsafe();
Vector256<long> bits = Unsafe.As<Vector256<T>, Vector256<long>>(ref source);
Vector256<long> result = Vector256.Shuffle(bits, Vector256.Create(2L, 0L, 1L,
3L));
Vector256<T> shuffled = Unsafe.As<Vector256<long>, Vector256<T>>(ref result);
return Vec3.FromVector256Unsafe(shuffled);
}
throw GraphicVector.ThrowUnsupportedTypeException<T>();
}
set
{
T w = W;
if (Unsafe.SizeOf<T>() == 4)
{
Vector128<T> source = value.AsVector128Unsafe();
Vector128<int> bits = Unsafe.As<Vector128<T>, Vector128<int>>(ref source);
Vector128<int> result = Vector128.Shuffle(bits, Vector128.Create(1, 2, 0, 3));
Vector128<T> shuffled = Unsafe.As<Vector128<int>, Vector128<T>>(ref result);
Unsafe.As<T, Vec3<T>>(ref _buffer[0]) = Vec3.FromVector128Unsafe(shuffled);
} else if (Unsafe.SizeOf<T>() == 8)
{
Vector256<T> source = value.AsVector256Unsafe();
Vector256<long> bits = Unsafe.As<Vector256<T>, Vector256<long>>(ref source);
Vector256<long> result = Vector256.Shuffle(bits, Vector256.Create(1L, 2L, 0L,
3L));
Vector256<T> shuffled = Unsafe.As<Vector256<long>, Vector256<T>>(ref result);
Unsafe.As<T, Vec3<T>>(ref _buffer[0]) = Vec3.FromVector256Unsafe(shuffled);
} else
{
throw GraphicVector.ThrowUnsupportedTypeException<T>();
}
W = w;
}
}
@@ -86,7 +163,7 @@ namespace Nitload.Mathematics.Numeric.Graphics
public ReadOnlySpan<T> AsSpan()
{
return MemoryMarshal.CreateReadOnlySpan(ref X, 4);
return MemoryMarshal.CreateReadOnlySpan(ref _buffer[0], 4);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -98,8 +175,7 @@ namespace Nitload.Mathematics.Numeric.Graphics
{
Vec4<T> product = Vec4.FromVector128Unsafe(this.AsVector128Unsafe() * right.AsVector128Unsafe());
return product.X + product.Y + product.Z + product.W;
}
if (Unsafe.SizeOf<T>() == 8)
} else if (Unsafe.SizeOf<T>() == 8)
{
Vec4<T> product = Vec4.FromVector256Unsafe(this.AsVector256Unsafe() * right.AsVector256Unsafe());
return product.X + product.Y + product.Z + product.W;
@@ -114,20 +190,6 @@ namespace Nitload.Mathematics.Numeric.Graphics
return (obj is Vec4<T> v) && (v == this);
}
public static Vec4<T> FromSpan(
ReadOnlySpan<T> span
)
{
if (span.Length < 4) {
throw new ArgumentException("Span length must be at least 4.", nameof(span));
}
Unsafe.SkipInit(out Vec4<T> result);
Span<T> target = MemoryMarshal.CreateSpan(ref result.X, 4);
span[..4].CopyTo(target);
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<T>.Enumerator GetEnumerator()
{
@@ -139,16 +201,41 @@ namespace Nitload.Mathematics.Numeric.Graphics
return HashCode.Combine(X, Y, Z, W);
}
public Vec4<T> Shuffle(
int t0,
int t1,
int t2,
int t3
)
{
if (Unsafe.SizeOf<T>() == 4)
{
Vector128<T> v = this.AsVector128Unsafe();
Vector128<int> bits = Unsafe.As<Vector128<T>, Vector128<int>>(ref v);
Vector128<int> result = Vector128.Shuffle(bits, Vector128.Create(t0, t1, t2, t3));
return Vec4.FromVector128Unsafe(Unsafe.As<Vector128<int>, Vector128<T>>(ref result));
} else if (Unsafe.SizeOf<T>() == 8)
{
Vector256<T> v = this.AsVector256Unsafe();
Vector256<long> bits = Unsafe.As<Vector256<T>, Vector256<long>>(ref v);
Vector256<long> result = Vector256.Shuffle(bits, Vector256.Create(t0, t1, t2, t3));
return Vec4.FromVector256Unsafe(Unsafe.As<Vector256<long>, Vector256<T>>(ref result));
} else
{
throw GraphicVector.ThrowUnsupportedTypeException<T>();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<T> operator -(
Vec4<T> left,
Vec4<T> right
)
{
if (Unsafe.SizeOf<T>() == 4) {
if (Unsafe.SizeOf<T>() == 4)
{
return Vec4.FromVector128Unsafe(left.AsVector128Unsafe() - right.AsVector128Unsafe());
}
if (Unsafe.SizeOf<T>() == 8) {
} else if (Unsafe.SizeOf<T>() == 8) {
return Vec4.FromVector256Unsafe(left.AsVector256Unsafe() - right.AsVector256Unsafe());
}
throw GraphicVector.ThrowUnsupportedTypeException<T>();
@@ -168,10 +255,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
T scalar
)
{
if (Unsafe.SizeOf<T>() == 4) {
if (Unsafe.SizeOf<T>() == 4)
{
return Vec4.FromVector128Unsafe(vector.AsVector128Unsafe() * Vector128.Create(scalar));
}
if (Unsafe.SizeOf<T>() == 8) {
} else if (Unsafe.SizeOf<T>() == 8) {
return Vec4.FromVector256Unsafe(vector.AsVector256Unsafe() * Vector256.Create(scalar));
}
throw GraphicVector.ThrowUnsupportedTypeException<T>();
@@ -186,6 +273,14 @@ namespace Nitload.Mathematics.Numeric.Graphics
return vector * scalar;
}
public static Vec4<T> operator *(
GMatrix44<T> mat,
Vec4<T> vec
)
{
return (mat[0] * vec.X) + (mat[1] * vec.Y) + (mat[2] * vec.Z) + (mat[3] * vec.W);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T operator *(
Vec4<T> left,
@@ -201,10 +296,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
T scalar
)
{
if (Unsafe.SizeOf<T>() == 4) {
if (Unsafe.SizeOf<T>() == 4)
{
return Vec4.FromVector128Unsafe(vector.AsVector128Unsafe() / Vector128.Create(scalar));
}
if (Unsafe.SizeOf<T>() == 8) {
} else if (Unsafe.SizeOf<T>() == 8) {
return Vec4.FromVector256Unsafe(vector.AsVector256Unsafe() / Vector256.Create(scalar));
}
throw GraphicVector.ThrowUnsupportedTypeException<T>();
@@ -216,10 +311,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
Vec4<T> right
)
{
if (Unsafe.SizeOf<T>() == 4) {
if (Unsafe.SizeOf<T>() == 4)
{
return Vec4.FromVector128Unsafe(left.AsVector128Unsafe() + right.AsVector128Unsafe());
}
if (Unsafe.SizeOf<T>() == 8) {
} else if (Unsafe.SizeOf<T>() == 8) {
return Vec4.FromVector256Unsafe(left.AsVector256Unsafe() + right.AsVector256Unsafe());
}
throw GraphicVector.ThrowUnsupportedTypeException<T>();
@@ -230,10 +325,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
Vec4<T> right
)
{
if (Unsafe.SizeOf<T>() == 4) {
if (Unsafe.SizeOf<T>() == 4)
{
return left.AsVector128Unsafe() == right.AsVector128Unsafe();
}
if (Unsafe.SizeOf<T>() == 8) {
} else if (Unsafe.SizeOf<T>() == 8) {
return left.AsVector256Unsafe() == right.AsVector256Unsafe();
}
#pragma warning disable CA1065
@@ -241,5 +336,13 @@ namespace Nitload.Mathematics.Numeric.Graphics
#pragma warning restore CA1065
}
[InlineArray(4)]
private struct Buffer
{
private T _element;
}
}
}
@@ -0,0 +1,47 @@
// -----------------------------------------------------------------------------
// file="TextRegexSourceGen.ExitLabel"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Nitload.RegularAnalysis.Text
{
internal partial class TextRegexSourceGen
{
internal enum ExitMode
{
Break,
Continue,
Goto,
}
internal readonly record struct ExitLabel
{
public ExitLabel(
ExitMode mode,
int order
)
{
Mode = mode;
LabelOrder = order;
}
public ExitMode Mode { get; init; }
public int LabelOrder { get; init; }
}
}
}
@@ -183,6 +183,8 @@ namespace Nitload.RegularAnalysis.Text
)
{
RegexAstNode current = node.Right;
// TODO(NGRA-NAMING): Reserve exclusive names for future ALT cursor/capture snapshots;
// their lifetime extends through retry labels, not just the candidate's emitted block.
string exit_label = context.RequestExitLabel();
// TODO(NGRA): Walk every normalized ALT candidate exactly once. The final traversal
@@ -229,9 +231,10 @@ namespace Nitload.RegularAnalysis.Text
// TODO(NGRA): Advance by code.Length rather than one character and
// preserve the ALT rollback cursor on failure.
_ = sc.AppendLine(@$"if({context.RemainSpan}.{MemoryExtensions.StartsWith}({FormatStringLiteral(code)}))")
string liteal = FormatStringLiteral(code);
_ = sc.AppendLine(@$"if({context.RemainSpan}.{MemoryExtensions.StartsWith}({liteal}))")
.AppendLine("{")
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice({code.Length});")
.AppendLine($@"goto {exit_label};")
.AppendLine("}");
@@ -269,6 +272,9 @@ namespace Nitload.RegularAnalysis.Text
RegexGroupPayload config = node.PayloadAs<RegexGroupPayload>();
// TODO(NGRA-NAMING): Reserve exclusive names for generated group snapshots and capture
// temporaries. A capture's user-provided name is not a unique generated local name.
// TODO(NGRA): Select the owned group body using Empty-sentinel checks, snapshot its
// start cursor, and restore it when the child matcher fails.
if (left is not null)
@@ -343,7 +349,8 @@ namespace Nitload.RegularAnalysis.Text
int max,
bool is_greedy,
[NotNull] in SequenceEmitter<string> sc,
in SourceGenContext context
in SourceGenContext context,
string exit_label
)
{
if (min < 0 || (max >= 0 && max < min)) {
@@ -359,16 +366,16 @@ namespace Nitload.RegularAnalysis.Text
char expected = literal[0];
string expected_literal = FormatCharLiteral(expected);
string remain_span = context.RemainSpan;
int scratch_scope_index = context.RentScratchScopeIndex();
// TODO(NGRA-NAMING): Allocate required_rest, required_matched, required_chunk_index,
// and additional_count through the exclusive-name pool, including loop-local names.
int scratch_scope_index = context.RequestScratchScopeIndex();
string required_rest = $"__required_rest_{scratch_scope_index}";
string required_matched = $"__required_matched_{scratch_scope_index}";
string required_chunk_index = $"__required_chunk_index_{scratch_scope_index}";
string additional_count = $"__additional_count_{scratch_scope_index}";
// TODO(NGRA): Move ownership of this work region to the enclosing CONCAT or match
// method. Until then, break demonstrates the local failure path but cannot prevent a
// later sibling node from being emitted and executed.
_ = sc.AppendLine("do").AppendLine("{");
// TODO(NGRA): Replace this local COUNT exit with the inherited failure ExitLabel.
// The temporary goto preserves the former local exit but still lets siblings execute.
if (min <= flattened_unit_count_threshold)
{
@@ -377,7 +384,7 @@ namespace Nitload.RegularAnalysis.Text
string required_prefix = new(expected, min);
_ = sc.AppendLine($"if (!{remain_span}.{nameof(MemoryExtensions.StartsWith)}({FormatStringLiteral(required_prefix)}))")
.AppendLine("{")
.AppendLine("break;")
.AppendLine($"goto {exit_label};")
.AppendLine("}")
.AppendLine($"{remain_span} = {remain_span}.Slice({min});");
}
@@ -392,7 +399,7 @@ namespace Nitload.RegularAnalysis.Text
_ = sc.AppendLine($"if ({remain_span}.Length < {min})")
.AppendLine("{")
.AppendLine("break;")
.AppendLine($"goto {exit_label};")
.AppendLine("}")
.AppendLine($"{ROS_char} {required_rest} = {remain_span};")
.AppendLine($"bool {required_matched} = true;")
@@ -417,7 +424,7 @@ namespace Nitload.RegularAnalysis.Text
_ = sc.AppendLine($"if (!{required_matched})")
.AppendLine("{")
.AppendLine("break;")
.AppendLine($"goto {exit_label};")
.AppendLine("}")
.AppendLine($"{remain_span} = {remain_span}.Slice({min});");
}
@@ -445,8 +452,6 @@ namespace Nitload.RegularAnalysis.Text
_ = sc.AppendLine("// TODO(NGRA): Retry the lazy COUNT tail from its continuation.");
}
_ = sc.AppendLine("} while (false);");
context.ReturnScratchScopeIndex(scratch_scope_index);
}
private static void GenerateUnitSetCount(
@@ -472,34 +477,53 @@ namespace Nitload.RegularAnalysis.Text
IReadOnlyList<RegexCharSet> charset = payload.Set;
string remain_span = context.RemainSpan;
int scratch_scope_index = context.RentScratchScopeIndex();
// TODO(NGRA-NAMING): Allocate required_matched and additional_count through the
// exclusive-name pool. Reserve required_rest/required_chunk_index if emitted later.
int scratch_scope_index = context.RequestScratchScopeIndex();
string required_rest = $"__required_rest_{scratch_scope_index}";
string required_matched = $"__required_matched_{scratch_scope_index}";
string required_chunk_index = $"__required_chunk_index_{scratch_scope_index}";
string additional_count = $"__additional_count_{scratch_scope_index}";
// TODO(NGRA): Move ownership of this work region to the enclosing CONCAT or match
// method. Until then, break demonstrates the local failure path but cannot prevent a
// later sibling node from being emitted and executed.
// TODO(NGRA): Route a failed minimum check through the inherited failure ExitLabel.
// The break below only stops charset scanning and must remain local to that loop.
bool accept = payload.Accept;
RegexCharSet _set = charset[0];
_ = sc.AppendLine($"{ROS_char} {required_matched} = {remain_span}")
.AppendLine($"int {additional_count} = 0;")
.AppendLine()
.AppendLine() //TODO loop head
.AppendLine($"if({(accept ? string.Empty : "!(")} {GenerateCharSetExpression(_set)} ||");
for (int i = 1; i < charset.Count - 1; i++)
.AppendLine($"for(; {additional_count} < {max}; {additional_count} ++)")
.AppendLine("{");
if (charset.Count == 1)
{
_set = charset[i];
_ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ||");
// single charset rule
_ = sc.AppendLine($"if({(accept ? string.Empty : "!(")} {GenerateCharSetExpression(_set)})");
} else
{
// multi charset rule
_ = sc.AppendLine($"if({(accept ? string.Empty : "!(")} {GenerateCharSetExpression(_set)} ||");
for (int i = 1; i < charset.Count - 1; i++)
{
_set = charset[i];
_ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ||");
}
_set = charset[^1];
_ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ){(accept ? string.Empty : ')')}");
}
_set = charset[^1];
_ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ){(accept ? string.Empty : ')')}")
.AppendLine("{")
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
.AppendLine($@"break;")
.AppendLine("}");
_ = sc .AppendLine("{")
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
.AppendLine("}")
.AppendLine("else")
.AppendLine("{")
.AppendLine($@"break;")
.AppendLine("}")
.AppendLine("}")
.AppendLine($"if({additional_count} < {min})")
.AppendLine("{")
.AppendLine("}")
.AppendLine("else")
.AppendLine("{")
.AppendLine("}");
}
private static void GenerateUnitSpanCount(
@@ -508,7 +532,8 @@ namespace Nitload.RegularAnalysis.Text
int max,
bool is_greedy,
[NotNull] in SequenceEmitter<string> sc,
in SourceGenContext context
in SourceGenContext context,
string exit_label
)
{
if (min < 0 || (max >= 0 && max < min)) {
@@ -523,7 +548,10 @@ namespace Nitload.RegularAnalysis.Text
string expected_literal = FormatStringLiteral(literal);
string remain_span = context.RemainSpan;
int scratch_scope_index = context.RentScratchScopeIndex();
// TODO(NGRA-NAMING): Allocate required_rest, required_matched, required_chunk_index,
// required_count, and additional_count through the exclusive-name pool. Flattened
// sibling COUNT nodes share the declaration space even after their exit labels.
int scratch_scope_index = context.RequestScratchScopeIndex();
string required_rest = $"__required_rest_{scratch_scope_index}";
string required_matched = $"__required_matched_{scratch_scope_index}";
string required_chunk_index = $"__required_chunk_index_{scratch_scope_index}";
@@ -531,10 +559,8 @@ namespace Nitload.RegularAnalysis.Text
string additional_count = $"__additional_count_{scratch_scope_index}";
string starts_with = $"{nameof(MemoryExtensions.StartsWith)}";
// TODO(NGRA): Move ownership of this work region to the enclosing CONCAT or match
// method. Until then, break demonstrates the local failure path but cannot prevent a
// later sibling node from being emitted and executed.
_ = sc.AppendLine("do").AppendLine("{");
// TODO(NGRA): Replace this local COUNT exit with the inherited failure ExitLabel.
// The temporary goto preserves the former local exit but still lets siblings execute.
if (literal.Length > flattened_unit_count_threshold)
{
@@ -549,7 +575,7 @@ namespace Nitload.RegularAnalysis.Text
.AppendLine("}")
.AppendLine($"if ({required_count} != {min})")
.AppendLine("{")
.AppendLine("break;")
.AppendLine($"goto {exit_label};")
.AppendLine("}")
.AppendLine($"{remain_span} = {required_rest};");
} else if (min <= flattened_unit_count_threshold / literal.Length)
@@ -563,7 +589,7 @@ namespace Nitload.RegularAnalysis.Text
string required_prefix = required_prefix_span.ToString();
_ = sc.AppendLine($"if (!{remain_span}.{starts_with}({FormatStringLiteral(required_prefix)}))")
.AppendLine("{")
.AppendLine("break;")
.AppendLine($"goto {exit_label};")
.AppendLine("}")
.AppendLine($"{remain_span} = {remain_span}.Slice({min * literal.Length});");
}
@@ -612,7 +638,7 @@ namespace Nitload.RegularAnalysis.Text
_ = sc.AppendLine($"if (!{required_matched})")
.AppendLine("{")
.AppendLine("break;")
.AppendLine($"goto {exit_label};")
.AppendLine("}")
.AppendLine($"{remain_span} = {required_rest};");
}
@@ -640,8 +666,6 @@ namespace Nitload.RegularAnalysis.Text
_ = sc.AppendLine("// TODO(NGRA): Retry the lazy COUNT tail from its continuation.");
}
_ = sc.AppendLine("} while (false);");
context.ReturnScratchScopeIndex(scratch_scope_index);
}
private static void GenerateCount(
@@ -659,6 +683,8 @@ namespace Nitload.RegularAnalysis.Text
int min = payload.Min;
int max = payload.Max;
bool is_greedy = payload.IsGreedy;
// TODO(NGRA-NAMING): Reserve exclusive names for future repetition/rollback state
// across complex COUNT retries; recursive children must use the same method pool.
string exit_label = context.RequestExitLabel();
if ((value.Label & RegexElementLabel.SEQUENCE) == 0)
{
@@ -670,15 +696,16 @@ namespace Nitload.RegularAnalysis.Text
switch (value.Label & RegexElementLabel.SEQUENCE)
{
case RegexElementLabel.UNIT:
GenerateUnitCount(value, min, max, is_greedy, sc, context);
GenerateUnitCount(value, min, max, is_greedy, sc, context, exit_label);
break;
case RegexElementLabel.UNIT_SET:
GenerateUnitSetCount(value, min, max, is_greedy, sc, context);
// TODO(NGRA): Emit a bounded/unbounded charset counting loop, preferably
// using IndexOfAnyExcept where the charset shape permits it.
break;
case RegexElementLabel.UNIT_SPAN:
GenerateUnitSpanCount(value, min, max, is_greedy, sc, context);
GenerateUnitSpanCount(value, min, max, is_greedy, sc, context, exit_label);
break;
default:
@@ -26,8 +26,8 @@ namespace Nitload.RegularAnalysis.Text
/// <remarks>
/// Method level state is limited to the active cursor and the result of the most recent
/// instruction. Everything else is either a region slot, a line slot, a capture slot, or
/// a block scoped scratch variable. Scratch indices remain unique while rented and are
/// recycled after their generated lexical scope has closed.
/// a scratch variable. Scratch indices remain unique throughout the generated method;
/// flattened regions cannot release their names for reuse by later nodes.
/// </remarks>
internal sealed class SourceGenContext
{
@@ -40,8 +40,6 @@ namespace Nitload.RegularAnalysis.Text
private int _scratch_scope_count;
private readonly Stack<int> _free_scratch_scope_indices = [];
public string RemainSpan { get; } = _remain_span;
public string FirstOfRemain { get; } = $@"{_remain_span}[0]";
@@ -57,36 +55,22 @@ namespace Nitload.RegularAnalysis.Text
public string RequestExitLabel()
{
// TODO(NGRA-NAMING): Route ALT and COUNT labels through the method-wide label pool.
// Keep every emitted label exclusive until method generation is complete.
string code = $@"_exit_alt_{_exit_alt_count}";
_exit_alt_count++;
return code;
}
public int RentScratchScopeIndex()
public int RequestScratchScopeIndex()
{
if (_free_scratch_scope_indices.TryPop(out int recycled_index)) {
return recycled_index;
}
// TODO(NGRA-NAMING): Integrate scratch names with the method-wide exclusive-name
// allocator. Until then, reserve each suffix permanently for this method.
int index = _scratch_scope_count;
_scratch_scope_count++;
return index;
}
public void ReturnScratchScopeIndex(
int index
)
{
if ((uint)index >= (uint)_scratch_scope_count) {
throw new ArgumentOutOfRangeException(nameof(index));
}
if (_free_scratch_scope_indices.Contains(index)) {
throw new InvalidOperationException($"Scratch scope {index} was returned twice.");
}
_free_scratch_scope_indices.Push(index);
}
}
}
@@ -60,7 +60,7 @@ namespace Nitload.RegularAnalysis.Text
string static_modifier;
int brace_count = 0;
do
while (type is not null)
{
_ = file_name_sb.Append(CultureInfo.InvariantCulture, $@"{type.TypeName}.");
string declare_type = type.DeclType switch
@@ -74,7 +74,7 @@ namespace Nitload.RegularAnalysis.Text
.AppendLine("{");
brace_count++;
type = type.InnerType!;
} while (type is not null);
}
static_modifier = gen_source.IsMethodStatic ? "static" : string.Empty;
_ = ce.AppendLine(@$"{ToKeyword(gen_source.MethodAccessibility)} {static_modifier} {Text_Regex} {gen_source.MethodName}({ROS_char} {regex_gen_context.InputString})")
@@ -90,8 +90,7 @@ namespace Nitload.RegularAnalysis.Text
brace_count = 0;
foreach (string line in ce)
{
bool is_right_brace = (line == "}") ||
line.StartsWith("} while", StringComparison.InvariantCulture);
bool is_right_brace = line == "}";
brace_count -= is_right_brace ? 1 : 0;
for (int i = 0; i < brace_count; i++) {
_ = code_source.Append(" ");
@@ -232,13 +232,13 @@ namespace StgSharp.GenerateGL.Generation
List<ManagedParameterDefinition> singleParameters = new List<ManagedParameterDefinition>(prefix)
{
new ManagedParameterDefinition("bool", "transpose", transposeSource),
new ManagedParameterDefinition("GraphicsMatrix", "value", valueSource),
new ManagedParameterDefinition("GMatrix44<float>", "value", valueSource),
};
List<ManagedParameterDefinition> spanParameters = new List<ManagedParameterDefinition>(prefix)
{
new ManagedParameterDefinition("bool", "transpose", transposeSource),
new ManagedParameterDefinition(
"ReadOnlySpan<GraphicsMatrix>",
"ReadOnlySpan<GMatrix44<float>>",
"values",
valueSource),
};
@@ -740,7 +740,7 @@ namespace StgSharp.GenerateGL.Generation
string matrixName = EscapeIdentifier(matrix.Name);
if (invocation.IsSpan)
{
builder.Append(" fixed (GraphicsMatrix* __value = ");
builder.Append(" fixed (GMatrix44<float>* __value = ");
builder.Append(matrixName);
builder.Append(")\n");
builder.Append(" {\n");
+1 -1
View File
@@ -92,7 +92,7 @@ The generator merges a family only when it can validate the resulting signatures
| `glUniform1*v` | `Uniform(..., ReadOnlySpan<T>)` |
| `glUniform4*v` | `Uniform(..., ReadOnlySpan<Vec4<T>>)` |
| `glUniform2*v` and `glUniform3*v` | Omitted because `Vec2` and `Vec3` storage is not a tightly packed C array |
| `glUniformMatrix4fv` | `Uniform(..., GraphicsMatrix)` and matrix-span overloads |
| `glUniformMatrix4fv` | `Uniform(..., GMatrix44<float>)` and matrix-span overloads |
| Other matrix sizes and double matrices | Omitted because only the graphics-oriented 4x4 float layout is defined |
| `glGetBooleanv`, `glGetFloatv`, `glGetIntegerv`, and related queries | `GetValue(..., Span<T>)` |
| `glVertexAttrib1f/2f/3f/4f` and equivalent scalar forms | `VertexAttribute(...)`; component count is expressed by the parameter list |