Readme for new namespace; New file for special expression format in text regex.
Signed-off-by: Nitload <Nitload_Creater@outlook.com>
This commit is contained in:
@@ -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>
|
||||
@@ -1,16 +1,18 @@
|
||||
# StgSharp
|
||||
# Nitload
|
||||
|
||||

|
||||

|
||||
|
||||
StgSharp is an experimental .NET framework for graphics, numerical computing, language analysis, and other performance-sensitive applications. It began as the foundation of a next-generation STG (shoot 'em up) engine, but the current repository focuses on reusable low-level infrastructure rather than a complete, ready-to-use game engine.
|
||||
Nitload (formerly StgSharp) is an experimental .NET framework for graphics, numerical computing, language analysis, and other performance-sensitive applications. It began as the foundation of a next-generation STG (shoot 'em up) engine, but the current repository focuses on reusable low-level infrastructure rather than a complete, ready-to-use game engine.
|
||||
|
||||
The managed libraries now use the `Nitload.*` namespace and project prefix. Repository URLs, the logo filename, and some legacy test artifacts still retain the StgSharp name.
|
||||
|
||||
## Overview
|
||||
|
||||
The framework combines managed C# APIs with a C native library. Its current work includes OpenGL bindings and rendering infrastructure, generic matrix and vector types, SIMD-accelerated native kernels, custom allocators and collections, regular-language analysis, and state-oriented UI infrastructure. StgSharp targets .NET 8; platform and architecture coverage varies by module, with Windows and Linux as the principal native targets.
|
||||
The framework combines managed C# APIs with a C native library. Its current work includes OpenGL bindings and rendering infrastructure, generic matrix and vector types, SIMD-accelerated native kernels, custom allocators and collections, regular-language analysis, and state-oriented UI infrastructure. Nitload targets .NET 8; platform and architecture coverage varies by module, with Windows and Linux as the principal native targets.
|
||||
|
||||
## Core Modules
|
||||
|
||||
### StgSharp.Common
|
||||
### Nitload.Common
|
||||
|
||||
The foundational library containing shared functionality:
|
||||
|
||||
@@ -20,7 +22,7 @@ The foundational library containing shared functionality:
|
||||
- **Pipeline and State**: Processing pipelines and reusable state-machine primitives
|
||||
- **Environment**: Platform abstraction and system integration
|
||||
|
||||
### StgSharp.Mathematics (Numeric)
|
||||
### Nitload.Mathematics (Numeric)
|
||||
|
||||
Numerics and linear algebra built on top of the core library:
|
||||
|
||||
@@ -28,7 +30,7 @@ Numerics and linear algebra built on top of the core library:
|
||||
- **Numeric Utilities**: Core numeric helpers and algorithms
|
||||
- **SIMD-Friendly Kernels**: Data layouts optimized for hardware acceleration
|
||||
|
||||
### StgSharp.RegularAnalysis
|
||||
### Nitload.RegularAnalysis
|
||||
|
||||
Nitload General Regular Analysis (NGRA) infrastructure for recognizing and processing regular languages:
|
||||
|
||||
@@ -36,9 +38,9 @@ Nitload General Regular Analysis (NGRA) infrastructure for recognizing and proce
|
||||
- **Parsing Primitives**: Reusable tokenizer and grammar building blocks
|
||||
- **Analysis Pipeline**: Structured processing for language-like inputs
|
||||
|
||||
NGRA is a foundation for higher-level language tooling. It does not replace `StgSharp.Script`; the planned Script implementation depends on NGRA and has not started yet. The source currently under `StgSharp.Script` is retained from the earlier EXPRESS implementation and is not part of the active core solution.
|
||||
NGRA is a foundation for higher-level language tooling. It does not replace `Nitload.Script`; the planned Script implementation depends on NGRA and has not started yet. The source currently under `Nitload.Script` is retained from the earlier EXPRESS implementation and is not part of the active core solution.
|
||||
|
||||
### StgSharp.Graphics
|
||||
### Nitload.Graphics
|
||||
|
||||
Managed graphics infrastructure built on Common and Mathematics:
|
||||
|
||||
@@ -47,7 +49,7 @@ Managed graphics infrastructure built on Common and Mathematics:
|
||||
- **Shader Support**: Shader compilation, program management, and shader-generation utilities
|
||||
- **Window Integration**: GLFW-based window and input access
|
||||
|
||||
### StgSharp.Native
|
||||
### Nitload.Native
|
||||
|
||||
Native library integration:
|
||||
|
||||
@@ -56,7 +58,7 @@ Native library integration:
|
||||
- **Matrix Kernels**: Optimized matrix computation routines
|
||||
- **Platform Runtime**: Native thread and platform support for Windows and Linux
|
||||
|
||||
### StgSharp.TerminalDialogue
|
||||
### Nitload.TerminalDialogue
|
||||
|
||||
Terminal-based user interface application and components:
|
||||
|
||||
@@ -64,7 +66,7 @@ Terminal-based user interface application and components:
|
||||
- **Dialogue System**: User interaction and input handling
|
||||
- **Terminal Graphics**: Text-based UI rendering
|
||||
|
||||
> Note: `StgSharp.Script` is planned as a consumer of NGRA and has not started yet. Its existing EXPRESS sources belong to the earlier implementation. `StgSharp.Model` is currently an empty placeholder while its design is being reconsidered.
|
||||
> Note: `Nitload.Script` is planned as a consumer of NGRA and has not started yet. Its existing EXPRESS sources belong to the earlier implementation. `Nitload.Model` is currently an empty placeholder while its design is being reconsidered.
|
||||
|
||||
## Key Features
|
||||
|
||||
@@ -113,7 +115,7 @@ The benchmark reports normalized time per allocation/free operation. Each iterat
|
||||
### Data Processing
|
||||
|
||||
- **NGRA**: Regex analysis, intermediate representation, optimization, and source generation
|
||||
- **EXPRESS (legacy/inactive)**: The repository retains an earlier experimental EXPRESS parser/compiler under `StgSharp.Script`
|
||||
- **EXPRESS (legacy/inactive)**: The repository retains an earlier experimental EXPRESS parser/compiler under `Nitload.Script`
|
||||
- **Script (planned)**: A future language layer intended to build on NGRA; development has not started
|
||||
|
||||
## Requirements
|
||||
@@ -125,7 +127,7 @@ The benchmark reports normalized time per allocation/free operation. Each iterat
|
||||
|
||||
## Installation
|
||||
|
||||
StgSharp is currently in development and requires compilation from source. **NuGet packages are not yet available** - you must build the project from source code.
|
||||
Nitload is currently in development and requires compilation from source. **NuGet packages are not yet available** - you must build the project from source code.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
@@ -159,7 +161,7 @@ StgSharp is currently in development and requires compilation from source. **NuG
|
||||
dotnet build Nitload.sln
|
||||
```
|
||||
|
||||
Managed builds copy an existing native binary into their output directory. They do not invoke CMake automatically, so build `StgSharp.Native` first when native functionality is required.
|
||||
Managed builds copy an existing native binary into their output directory. They do not invoke CMake automatically, so build `Nitload.Native` first when native functionality is required.
|
||||
|
||||
### Build Configuration
|
||||
|
||||
@@ -168,7 +170,7 @@ StgSharp is currently in development and requires compilation from source. **NuG
|
||||
|
||||
### Notes
|
||||
|
||||
- CMake is the maintained build path for `StgSharp.Native`; the checked-in presets primarily target Clang
|
||||
- CMake is the maintained build path for `Nitload.Native`; the checked-in presets primarily target Clang
|
||||
- The Visual Studio C project may be opened with MSVC tooling, but MSVC IntelliSense behavior and MSVC-produced binaries are not maintained or guaranteed
|
||||
- Windows and Linux platform implementations exist; actual feature and architecture coverage may differ
|
||||
- x86-64 currently has the most complete optimized kernel coverage
|
||||
@@ -187,8 +189,8 @@ StgSharp is currently in development and requires compilation from source. **NuG
|
||||
### Matrix Operations
|
||||
|
||||
```csharp
|
||||
using StgSharp.HighPerformance.Memory;
|
||||
using StgSharp.Mathematics.Numeric;
|
||||
using Nitload.Common.HighPerformance.Memory;
|
||||
using Nitload.Mathematics.Numeric;
|
||||
|
||||
// Matrix storage is allocated explicitly from a native-memory arena.
|
||||
using var allocator = new TwoLayerSegregatedFitAllocator(64 * 1024 * 1024);
|
||||
@@ -207,7 +209,7 @@ General matrix arithmetic does not currently provide operator overloads. Because
|
||||
### Memory Management
|
||||
|
||||
```csharp
|
||||
using StgSharp.HighPerformance.Memory;
|
||||
using Nitload.Common.HighPerformance.Memory;
|
||||
|
||||
// Create a 64 MiB TLSF arena
|
||||
using var allocator = new TwoLayerSegregatedFitAllocator(64 * 1024 * 1024);
|
||||
@@ -231,7 +233,7 @@ allocator.Free(handle);
|
||||
|
||||
## Contributing
|
||||
|
||||
StgSharp is developed by Nitload Space. Contributions are welcome, particularly in:
|
||||
Nitload is developed by Nitload Space. Contributions are welcome, particularly in:
|
||||
|
||||
- Performance optimizations
|
||||
- Cross-platform compatibility
|
||||
@@ -240,7 +242,7 @@ StgSharp is developed by Nitload Space. Contributions are welcome, particularly
|
||||
|
||||
## License
|
||||
|
||||
StgSharp is licensed under the MIT License. See [LICENSE](LICENSE) for details.
|
||||
Nitload is licensed under the MIT License. See [LICENSE](LICENSE) for details.
|
||||
|
||||
## Future Plans
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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];
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,38 +16,83 @@ namespace Nitload.Mathematics.Numeric.Graphics
|
||||
{
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
<<<<<<< HEAD
|
||||
public static Vec3<double> ConvertToDouble(Vec3<long> source)
|
||||
=======
|
||||
public static Vec3<double> ConvertToDouble(
|
||||
Vec3<long> source
|
||||
)
|
||||
>>>>>>> 8755185e78a8091ca252c1342249110180446be3
|
||||
{
|
||||
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Safe()));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
<<<<<<< HEAD
|
||||
public static Vec3<double> ConvertToDouble(Vec3<ulong> source)
|
||||
=======
|
||||
public static Vec3<double> ConvertToDouble(
|
||||
Vec3<ulong> source
|
||||
)
|
||||
>>>>>>> 8755185e78a8091ca252c1342249110180446be3
|
||||
{
|
||||
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Safe()));
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
#region cast
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vec3<float> ConvertToSingle(Vec3<int> source)
|
||||
=======
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vec3<float> ConvertToSingle(
|
||||
Vec3<int> source
|
||||
)
|
||||
>>>>>>> 8755185e78a8091ca252c1342249110180446be3
|
||||
{
|
||||
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Safe()));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
<<<<<<< HEAD
|
||||
public static Vec3<float> ConvertToSingle(Vec3<uint> source)
|
||||
=======
|
||||
public static Vec3<float> ConvertToSingle(
|
||||
Vec3<uint> source
|
||||
)
|
||||
>>>>>>> 8755185e78a8091ca252c1342249110180446be3
|
||||
{
|
||||
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Safe()));
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
public static bool IsParallel<T>(Vec3<T> left, Vec3<T> right) where T: unmanaged,INumber<T>
|
||||
=======
|
||||
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>
|
||||
>>>>>>> 8755185e78a8091ca252c1342249110180446be3
|
||||
{
|
||||
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);
|
||||
@@ -55,7 +100,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);
|
||||
@@ -63,7 +110,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);
|
||||
@@ -71,7 +120,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);
|
||||
@@ -79,23 +130,33 @@ 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);
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
#ednregion
|
||||
|
||||
=======
|
||||
>>>>>>> 8755185e78a8091ca252c1342249110180446be3
|
||||
#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))
|
||||
{
|
||||
@@ -144,7 +205,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();
|
||||
@@ -155,7 +219,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();
|
||||
@@ -166,7 +233,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();
|
||||
@@ -177,7 +247,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();
|
||||
@@ -188,7 +261,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();
|
||||
@@ -199,7 +275,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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# StgSharp.Native
|
||||
# Nitload.Native
|
||||
|
||||
## COMPILE
|
||||
|
||||
|
||||
@@ -101,6 +101,27 @@ namespace Nitload.RegularAnalysis.Text
|
||||
{
|
||||
return node is null || ReferenceEquals(node, Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recognizes zero-or-more repetitions of one non-negated Any atom, including lazy
|
||||
/// repetition. Callers inspect the COUNT payload's IsGreedy flag separately.
|
||||
/// </summary>
|
||||
public static bool IsDotStar(RegexAstNode? node)
|
||||
{
|
||||
if (node?.Payload is not RegexCountPayload { IsStar: true }) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool left_empty = IsNullOrEmpty(node.Left);
|
||||
bool right_empty = IsNullOrEmpty(node.Right);
|
||||
if (left_empty == right_empty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RegexAstNode operand = left_empty ? node.Right : node.Left;
|
||||
return operand.Payload is RegexCharSetPayload { IsAny: true, Accept: true } set &&
|
||||
set.Set[0].Accept;
|
||||
}
|
||||
/**/
|
||||
|
||||
public void PrependNode(RegexAstNode previousNode)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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; }
|
||||
|
||||
public string GetLabelName()
|
||||
{
|
||||
return Mode switch
|
||||
{
|
||||
ExitMode.Break => $@"__break_{LabelOrder}",
|
||||
ExitMode.Continue => $@"__continue_{LabelOrder}",
|
||||
ExitMode.Goto => $@"__goto_{LabelOrder}",
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -7,15 +7,7 @@
|
||||
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Nitload.RegularAnalysis.Abstraction;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nitload.RegularAnalysis.Text
|
||||
{
|
||||
@@ -27,21 +19,24 @@ namespace Nitload.RegularAnalysis.Text
|
||||
in SequenceEmitter<string> sc,
|
||||
in List<SequenceEmitter<string>> func_list,
|
||||
in SourceGenContext context,
|
||||
in ExitLabel exit_label = default,
|
||||
bool is_find = false
|
||||
|
||||
)
|
||||
{
|
||||
RegexAstNode root = ast;
|
||||
if (root.Label == RegexElementLabel.EPSILON) {
|
||||
return;
|
||||
}
|
||||
if (TryGenerateSpecialSource(root, sc, func_list, context, exit_label)) {
|
||||
return;
|
||||
}
|
||||
RegexElementLabel op = root.Label & (RegexElementLabel.VAST_OPERATOR);
|
||||
if (op != 0)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case RegexElementLabel.CONCAT:
|
||||
GenerateConcat(root, sc, func_list, context);
|
||||
GenerateConcat(root, sc, func_list, context, exit_label);
|
||||
break;
|
||||
case RegexElementLabel.COUNT:
|
||||
GenerateCount(root, sc, func_list, context);
|
||||
@@ -64,25 +59,20 @@ namespace Nitload.RegularAnalysis.Text
|
||||
switch (op)
|
||||
{
|
||||
case RegexElementLabel.UNIT:
|
||||
|
||||
// TODO(NGRA): Emit the remaining-span length guard, literal comparison,
|
||||
// cursor advance, and failure transfer for one character.
|
||||
GenerateUnit(root, sc, context, exit_label);
|
||||
break;
|
||||
case RegexElementLabel.UNIT_SET:
|
||||
|
||||
// TODO(NGRA): Emit the remaining-span length guard, charset predicate,
|
||||
// cursor advance, and failure transfer.
|
||||
GenerateUnitSet(root, sc, context, exit_label);
|
||||
break;
|
||||
case RegexElementLabel.UNIT_SPAN:
|
||||
|
||||
// TODO(NGRA): Emit StartsWith for the complete literal span and advance by
|
||||
// the literal length; integrate is_find candidate retry semantics.
|
||||
GenerateUnitSpan(root, sc, context, exit_label);
|
||||
break;
|
||||
default:
|
||||
|
||||
// TODO(NGRA): Diagnose malformed leaf nodes instead of generating no code.
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(NGRA): Integrate is_find candidate search and continuation retries.
|
||||
// Leaf emission currently matches only at the active cursor.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,221 +110,105 @@ namespace Nitload.RegularAnalysis.Text
|
||||
case RegexCharSetType.Single:
|
||||
return $"{accept}({FormatStringLiteral(set.Value)}.{nameof(MemoryExtensions.Contains)}({remain_span}[0]))";
|
||||
case RegexCharSetType.Range:
|
||||
if (set.Value.Length != 2) {
|
||||
throw new InvalidOperationException("A charset range requires two endpoints.");
|
||||
}
|
||||
return $"{accept}({remain_span}[0] >= {FormatCharLiteral(set.Value[0])} && {remain_span}[0] <= {FormatCharLiteral(set.Value[1])})";
|
||||
case RegexCharSetType.Set:
|
||||
switch (set.Value[0])
|
||||
switch (set.Value)
|
||||
{
|
||||
case 's':
|
||||
case "s":
|
||||
return $"{accept}char.IsWhiteSpace({remain_span}[0])";
|
||||
case 'w':
|
||||
return $"{accept}{nameof(TextRegex.IsCharWord)}({remain_span}[0])";
|
||||
case 'd':
|
||||
case "w":
|
||||
return $"{accept}{Text_Regex}.{nameof(TextRegex.IsCharWord)}({remain_span}[0])";
|
||||
case "d":
|
||||
return $"{accept}char.IsDigit({remain_span}[0])";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
goto default;
|
||||
case RegexCharSetType.Any:
|
||||
return set.Accept ? "true" : "false";
|
||||
default:
|
||||
|
||||
// TODO(NGRA): Unsupported/empty charset rules must become an analyzer
|
||||
// diagnostic; returning an empty expression produces invalid generated C#.
|
||||
return string.Empty;
|
||||
throw new NotSupportedException($"Unsupported charset rule: {set.Type} ({set.Value}).");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsNamedFind(
|
||||
RegexAstNode node
|
||||
)
|
||||
{
|
||||
// (?<name>.*)abc
|
||||
|
||||
if (node is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((node.Label & RegexElementLabel.CONCAT) != 0) {
|
||||
return false;
|
||||
}
|
||||
RegexAstNode group = node.Left;
|
||||
|
||||
// TODO(NGRA): Validate the normalized CONCAT/GROUP/COUNT shape with Empty sentinels
|
||||
// before dereferencing children; this helper currently assumes every edge exists.
|
||||
if ((group.Label & RegexElementLabel.GROUP_BEGIN) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
RegexAstNode count = group.Right;
|
||||
|
||||
// .*
|
||||
return (count.Label & RegexElementLabel.COUNT) != 0 &&
|
||||
(count.Right.Label & RegexElementLabel.UNIT_SINGLE) != 0 &&
|
||||
count.Right.Source.Source == ".";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region basic verb generate
|
||||
#region UNIT direct matching
|
||||
|
||||
private static void GenerateAlt(
|
||||
RegexAstNode node,
|
||||
private static void GenerateUnit(
|
||||
RegexAstNode value,
|
||||
[NotNull] in SequenceEmitter<string> sc,
|
||||
in List<SequenceEmitter<string>> func_list,
|
||||
in SourceGenContext context
|
||||
in SourceGenContext context,
|
||||
in ExitLabel exit
|
||||
)
|
||||
{
|
||||
RegexAstNode current = node.Right;
|
||||
string exit_label = context.RequestExitLabel();
|
||||
|
||||
// TODO(NGRA): Walk every normalized ALT candidate exactly once. The final traversal
|
||||
// shape and failure continuation are not wired yet.
|
||||
while (RegexAstNode.IsNullOrEmpty(current))
|
||||
{
|
||||
RegexElementLabel op = current.Label & RegexElementLabel.SEQUENCE;
|
||||
if (op != 0)
|
||||
{
|
||||
string code = current.SourceCode;
|
||||
switch (op)
|
||||
{
|
||||
case RegexElementLabel.UNIT:
|
||||
|
||||
// TODO(NGRA): Guard against an empty remaining span before indexing it.
|
||||
_ = sc.AppendLine(@$"if({context.RemainSpan}[0] == {FormatCharLiteral(code[0])})")
|
||||
.AppendLine("{")
|
||||
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
|
||||
.AppendLine($@"goto {exit_label};")
|
||||
.AppendLine("}");
|
||||
break;
|
||||
case RegexElementLabel.UNIT_SET:
|
||||
|
||||
// TODO(NGRA): Guard the remaining span, handle empty/Any sets, and
|
||||
// validate negated-set composition before emitting this predicate.
|
||||
RegexCharSetPayload payload = current.PayloadAs<RegexCharSetPayload>();
|
||||
IReadOnlyList<RegexCharSet> split = payload.Set;
|
||||
bool accept = payload.Accept;
|
||||
RegexCharSet _set = split[0];
|
||||
_ = sc.AppendLine($"if({(accept ? string.Empty : "!(")} {GenerateCharSetExpression(_set)} ||");
|
||||
for (int i = 1; i < split.Count - 1; i++)
|
||||
{
|
||||
_set = split[i];
|
||||
_ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ||");
|
||||
}
|
||||
_set = split[^1];
|
||||
_ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ){(accept ? string.Empty : ')')}")
|
||||
.AppendLine("{")
|
||||
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
|
||||
.AppendLine($@"goto {exit_label};")
|
||||
.AppendLine("}");
|
||||
break;
|
||||
case RegexElementLabel.UNIT_SPAN:
|
||||
|
||||
// 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)}))")
|
||||
.AppendLine("{")
|
||||
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
|
||||
.AppendLine($@"goto {exit_label};")
|
||||
.AppendLine("}");
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
// TODO(NGRA): Route unsupported ALT candidates through the recursive
|
||||
// matcher or report a source-generation diagnostic.
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(NGRA): Advance to the next ALT candidate after a scalar candidate
|
||||
// misses; the current sequence branch does not update current.
|
||||
} else
|
||||
{
|
||||
GenerateMethodSource(current, sc, func_list, context);
|
||||
current = current.Next;
|
||||
}
|
||||
string literal = value.Value;
|
||||
if (literal.Length != 1) {
|
||||
throw new InvalidOperationException(
|
||||
$"UNIT requires one decoded character, but received {literal.Length}.");
|
||||
}
|
||||
|
||||
// TODO(NGRA): Emit the all-alternatives-failed continuation before the shared success
|
||||
// label, including restoration of the entry cursor and capture state.
|
||||
_ = sc.AppendLine($@"{exit_label}: {{ }}");
|
||||
string remain_span = context.RemainSpan;
|
||||
_ = sc.AppendLine($"if ({remain_span}.IsEmpty || {remain_span}[0] != {FormatCharLiteral(literal[0])})")
|
||||
.AppendLine("{")
|
||||
.AppendLine($"goto {exit.GetLabelName()};")
|
||||
.AppendLine("}")
|
||||
.AppendLine($"{remain_span} = {remain_span}.Slice(1);");
|
||||
}
|
||||
|
||||
private static void GenerateGroup(
|
||||
RegexAstNode node,
|
||||
private static void GenerateUnitSet(
|
||||
RegexAstNode value,
|
||||
[NotNull] in SequenceEmitter<string> sc,
|
||||
in List<SequenceEmitter<string>> func_list,
|
||||
in SourceGenContext context
|
||||
in SourceGenContext context,
|
||||
in ExitLabel exit
|
||||
)
|
||||
{
|
||||
RegexAstNode left = node.Left;
|
||||
RegexAstNode right = node.Right;
|
||||
|
||||
RegexGroupPayload config = node.PayloadAs<RegexGroupPayload>();
|
||||
|
||||
// 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)
|
||||
{
|
||||
GenerateMethodSource(left, sc, func_list, context);
|
||||
} else
|
||||
if (right is not null) {
|
||||
GenerateMethodSource(right, sc, func_list, context);
|
||||
RegexCharSetPayload payload = value.PayloadAs<RegexCharSetPayload>();
|
||||
string[] rules = new string[payload.Set.Count];
|
||||
for (int i = 0; i < rules.Length; i++) {
|
||||
rules[i] = GenerateCharSetExpression(payload.Set[i]);
|
||||
}
|
||||
|
||||
string group_name = config.Name;
|
||||
|
||||
// TODO(NGRA): Allocate numeric/named capture slots and emit the successful capture
|
||||
// span. Non-capturing groups still need a rollback scope but no stored capture.
|
||||
throw new NotImplementedException();
|
||||
// Combine rule-level complements before applying the enclosing charset complement.
|
||||
// An empty union accepts nothing; its complement accepts any available character.
|
||||
string predicate = rules.Length == 0 ? "false" : string.Join(" || ", rules);
|
||||
string mismatch = payload.Accept ? $"!({predicate})" : $"({predicate})";
|
||||
string remain_span = context.RemainSpan;
|
||||
_ = sc.AppendLine($"if ({remain_span}.IsEmpty || {mismatch})")
|
||||
.AppendLine("{")
|
||||
.AppendLine($"goto {exit.GetLabelName()};")
|
||||
.AppendLine("}")
|
||||
.AppendLine($"{remain_span} = {remain_span}.Slice(1);");
|
||||
}
|
||||
|
||||
private static void GenerateConcat(
|
||||
RegexAstNode node,
|
||||
private static void GenerateUnitSpan(
|
||||
RegexAstNode value,
|
||||
[NotNull] in SequenceEmitter<string> sc,
|
||||
in List<SequenceEmitter<string>> func_list,
|
||||
in SourceGenContext context
|
||||
in SourceGenContext context,
|
||||
in ExitLabel exit
|
||||
)
|
||||
{
|
||||
RegexAstNode left = node.Left;
|
||||
RegexAstNode right = node.Right;
|
||||
|
||||
if (left is not null)
|
||||
{
|
||||
// find
|
||||
if ((left.Label & RegexElementLabel.COUNT) == RegexElementLabel.COUNT &&
|
||||
(left.Right.Label & RegexElementLabel.UNIT_SINGLE) == RegexElementLabel.UNIT_SINGLE &&
|
||||
left.Right.Source.Source == "." &&
|
||||
right is not null)
|
||||
{
|
||||
// TODO(NGRA): Emit the unnamed FIND candidate loop and retry the right subtree
|
||||
// until it succeeds or no anchor candidate remains.
|
||||
GenerateMethodSource(right, sc, func_list, context, true);
|
||||
} else if (IsNamedFind(node))
|
||||
{
|
||||
if (right is not null)
|
||||
{
|
||||
// TODO(NGRA): Emit named FIND retry and capture the text preceding the
|
||||
// successful anchor candidate.
|
||||
GenerateMethodSource(right, sc, func_list, context, true);
|
||||
} else
|
||||
{
|
||||
// TODO(NGRA): Capture the remaining input for a terminal named dot-star.
|
||||
}
|
||||
} else
|
||||
{
|
||||
GenerateMethodSource(left, sc, func_list, context);
|
||||
if (right is not null) {
|
||||
GenerateMethodSource(right, sc, func_list, context);
|
||||
}
|
||||
}
|
||||
string literal = value.Value;
|
||||
if (literal.Length == 0) {
|
||||
throw new InvalidOperationException("UNIT_SPAN requires a non-empty literal.");
|
||||
}
|
||||
|
||||
// TODO(NGRA): Normalize ownership so the right subtree is emitted exactly once. It is
|
||||
// currently reachable both inside the ordinary CONCAT branch and here.
|
||||
if (right is not null)
|
||||
{
|
||||
GenerateMethodSource(right, sc, func_list, context);
|
||||
}
|
||||
// StartsWith also rejects input shorter than the decoded literal.
|
||||
string remain_span = context.RemainSpan;
|
||||
_ = sc.AppendLine($"if (!{remain_span}.{nameof(MemoryExtensions.StartsWith)}({FormatStringLiteral(literal)}))")
|
||||
.AppendLine("{")
|
||||
.AppendLine($"goto {exit.GetLabelName()};")
|
||||
.AppendLine("}")
|
||||
.AppendLine($"{remain_span} = {remain_span}.Slice({literal.Length});");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UNIT count matching
|
||||
|
||||
private const int flattened_unit_count_threshold = 32;
|
||||
|
||||
private static void GenerateUnitCount(
|
||||
@@ -343,7 +217,8 @@ namespace Nitload.RegularAnalysis.Text
|
||||
int max,
|
||||
bool is_greedy,
|
||||
[NotNull] in SequenceEmitter<string> sc,
|
||||
in SourceGenContext context
|
||||
in SourceGenContext context,
|
||||
in ExitLabel exit
|
||||
)
|
||||
{
|
||||
if (min < 0 || (max >= 0 && max < min)) {
|
||||
@@ -359,16 +234,18 @@ 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 exit_label_node = exit.GetLabelName();
|
||||
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 +254,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_node};")
|
||||
.AppendLine("}")
|
||||
.AppendLine($"{remain_span} = {remain_span}.Slice({min});");
|
||||
}
|
||||
@@ -392,7 +269,7 @@ namespace Nitload.RegularAnalysis.Text
|
||||
|
||||
_ = sc.AppendLine($"if ({remain_span}.Length < {min})")
|
||||
.AppendLine("{")
|
||||
.AppendLine("break;")
|
||||
.AppendLine($"goto {exit_label_node};")
|
||||
.AppendLine("}")
|
||||
.AppendLine($"{ROS_char} {required_rest} = {remain_span};")
|
||||
.AppendLine($"bool {required_matched} = true;")
|
||||
@@ -417,7 +294,7 @@ namespace Nitload.RegularAnalysis.Text
|
||||
|
||||
_ = sc.AppendLine($"if (!{required_matched})")
|
||||
.AppendLine("{")
|
||||
.AppendLine("break;")
|
||||
.AppendLine($"goto {exit_label_node};")
|
||||
.AppendLine("}")
|
||||
.AppendLine($"{remain_span} = {remain_span}.Slice({min});");
|
||||
}
|
||||
@@ -425,28 +302,21 @@ namespace Nitload.RegularAnalysis.Text
|
||||
int additional_limit = max < 0 ? -1 : max - min;
|
||||
if (is_greedy && additional_limit != 0)
|
||||
{
|
||||
if (additional_limit < 0)
|
||||
{
|
||||
_ = sc.AppendLine($"while (!{remain_span}.IsEmpty && {remain_span}[0] == {expected_literal})")
|
||||
.AppendLine("{")
|
||||
.AppendLine($"{remain_span} = {remain_span}.Slice(1);")
|
||||
.AppendLine("}");
|
||||
} else
|
||||
{
|
||||
_ = sc.AppendLine($"for (int {additional_count} = 0; {additional_count} < {additional_limit} && !{remain_span}.IsEmpty && {remain_span}[0] == {expected_literal}; {additional_count}++)")
|
||||
.AppendLine("{")
|
||||
.AppendLine($"{remain_span} = {remain_span}.Slice(1);")
|
||||
.AppendLine("}");
|
||||
}
|
||||
_ = additional_limit < 0 ?
|
||||
sc.AppendLine($"while (!{remain_span}.IsEmpty && {remain_span}[0] == {expected_literal})")
|
||||
.AppendLine("{")
|
||||
.AppendLine($"{remain_span} = {remain_span}.Slice(1);")
|
||||
.AppendLine("}") :
|
||||
sc.AppendLine($"for (int {additional_count} = 0; {additional_count} < {additional_limit} && !{remain_span}.IsEmpty && {remain_span}[0] == {expected_literal}; {additional_count}++)")
|
||||
.AppendLine("{")
|
||||
.AppendLine($"{remain_span} = {remain_span}.Slice(1);")
|
||||
.AppendLine("}");
|
||||
} else if (!is_greedy && additional_limit != 0)
|
||||
{
|
||||
// Lazy COUNT deliberately stops at Min. Its optional tail is consumed only when
|
||||
// a future continuation attempt fails and requests another repetition.
|
||||
_ = 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(
|
||||
@@ -455,7 +325,8 @@ namespace Nitload.RegularAnalysis.Text
|
||||
int max,
|
||||
bool is_greedy,
|
||||
[NotNull] in SequenceEmitter<string> sc,
|
||||
in SourceGenContext context
|
||||
in SourceGenContext context,
|
||||
in ExitLabel exit_label
|
||||
)
|
||||
{
|
||||
if (min < 0 || (max >= 0 && max < min)) {
|
||||
@@ -472,34 +343,54 @@ 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 +399,8 @@ namespace Nitload.RegularAnalysis.Text
|
||||
int max,
|
||||
bool is_greedy,
|
||||
[NotNull] in SequenceEmitter<string> sc,
|
||||
in SourceGenContext context
|
||||
in SourceGenContext context,
|
||||
in ExitLabel exit
|
||||
)
|
||||
{
|
||||
if (min < 0 || (max >= 0 && max < min)) {
|
||||
@@ -523,7 +415,12 @@ 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 exit_label_node = exit.GetLabelName();
|
||||
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 +428,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 +444,7 @@ namespace Nitload.RegularAnalysis.Text
|
||||
.AppendLine("}")
|
||||
.AppendLine($"if ({required_count} != {min})")
|
||||
.AppendLine("{")
|
||||
.AppendLine("break;")
|
||||
.AppendLine($"goto {exit_label_node};")
|
||||
.AppendLine("}")
|
||||
.AppendLine($"{remain_span} = {required_rest};");
|
||||
} else if (min <= flattened_unit_count_threshold / literal.Length)
|
||||
@@ -563,7 +458,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_node};")
|
||||
.AppendLine("}")
|
||||
.AppendLine($"{remain_span} = {remain_span}.Slice({min * literal.Length});");
|
||||
}
|
||||
@@ -612,7 +507,7 @@ namespace Nitload.RegularAnalysis.Text
|
||||
|
||||
_ = sc.AppendLine($"if (!{required_matched})")
|
||||
.AppendLine("{")
|
||||
.AppendLine("break;")
|
||||
.AppendLine($"goto {exit_label_node};")
|
||||
.AppendLine("}")
|
||||
.AppendLine($"{remain_span} = {required_rest};");
|
||||
}
|
||||
@@ -639,9 +534,151 @@ namespace Nitload.RegularAnalysis.Text
|
||||
// a future continuation attempt fails and requests another repetition.
|
||||
_ = sc.AppendLine("// TODO(NGRA): Retry the lazy COUNT tail from its continuation.");
|
||||
}
|
||||
}
|
||||
|
||||
_ = sc.AppendLine("} while (false);");
|
||||
context.ReturnScratchScopeIndex(scratch_scope_index);
|
||||
#endregion
|
||||
|
||||
#region UNIT find matching
|
||||
|
||||
// TODO(NGRA): Add UNIT, UNIT_SET, and UNIT_SPAN candidate search emitters here.
|
||||
// Wire is_find dispatch and continuation retries when FIND matching is implemented.
|
||||
|
||||
#endregion
|
||||
|
||||
#region Operator generation
|
||||
|
||||
private static void GenerateAlt(
|
||||
RegexAstNode node,
|
||||
[NotNull] in SequenceEmitter<string> sc,
|
||||
in List<SequenceEmitter<string>> func_list,
|
||||
in SourceGenContext context
|
||||
)
|
||||
{
|
||||
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.
|
||||
ExitLabel exit_label = context.RequestExitLabel(ExitMode.Goto);
|
||||
|
||||
// TODO(NGRA): Walk every normalized ALT candidate exactly once. The final traversal
|
||||
// shape and failure continuation are not wired yet.
|
||||
while (RegexAstNode.IsNullOrEmpty(current))
|
||||
{
|
||||
RegexElementLabel op = current.Label & RegexElementLabel.SEQUENCE;
|
||||
if (op != 0)
|
||||
{
|
||||
string code = current.SourceCode;
|
||||
switch (op)
|
||||
{
|
||||
case RegexElementLabel.UNIT:
|
||||
|
||||
// TODO(NGRA): Guard against an empty remaining span before indexing it.
|
||||
_ = sc.AppendLine(@$"if({context.RemainSpan}[0] == {FormatCharLiteral(code[0])})")
|
||||
.AppendLine("{")
|
||||
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
|
||||
.AppendLine($@"goto {exit_label};")
|
||||
.AppendLine("}");
|
||||
break;
|
||||
case RegexElementLabel.UNIT_SET:
|
||||
|
||||
// TODO(NGRA): Guard the remaining span, handle empty/Any sets, and
|
||||
// validate negated-set composition before emitting this predicate.
|
||||
RegexCharSetPayload payload = current.PayloadAs<RegexCharSetPayload>();
|
||||
IReadOnlyList<RegexCharSet> split = payload.Set;
|
||||
bool accept = payload.Accept;
|
||||
RegexCharSet _set = split[0];
|
||||
_ = sc.AppendLine($"if({(accept ? string.Empty : "!(")} {GenerateCharSetExpression(_set)} ||");
|
||||
for (int i = 1; i < split.Count - 1; i++)
|
||||
{
|
||||
_set = split[i];
|
||||
_ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ||");
|
||||
}
|
||||
_set = split[^1];
|
||||
_ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ){(accept ? string.Empty : ')')}")
|
||||
.AppendLine("{")
|
||||
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
|
||||
.AppendLine($@"goto {exit_label};")
|
||||
.AppendLine("}");
|
||||
break;
|
||||
case RegexElementLabel.UNIT_SPAN:
|
||||
|
||||
// TODO(NGRA): Advance by code.Length rather than one character and
|
||||
// preserve the ALT rollback cursor on failure.
|
||||
string literal = FormatStringLiteral(code);
|
||||
_ = sc.AppendLine(@$"if({context.RemainSpan}.{MemoryExtensions.StartsWith}({literal}))")
|
||||
.AppendLine("{")
|
||||
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice({code.Length});")
|
||||
.AppendLine($@"goto {exit_label};")
|
||||
.AppendLine("}");
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
// TODO(NGRA): Route unsupported ALT candidates through the recursive
|
||||
// matcher or report a source-generation diagnostic.
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(NGRA): Advance to the next ALT candidate after a scalar candidate
|
||||
// misses; the current sequence branch does not update current.
|
||||
} else
|
||||
{
|
||||
GenerateMethodSource(current, sc, func_list, context);
|
||||
current = current.Next;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(NGRA): Emit the all-alternatives-failed continuation before the shared success
|
||||
// label, including restoration of the entry cursor and capture state.
|
||||
_ = sc.AppendLine($@"{exit_label}: {{ }}");
|
||||
}
|
||||
|
||||
private static void GenerateGroup(
|
||||
RegexAstNode node,
|
||||
[NotNull] in SequenceEmitter<string> sc,
|
||||
in List<SequenceEmitter<string>> func_list,
|
||||
in SourceGenContext context
|
||||
)
|
||||
{
|
||||
RegexAstNode left = node.Left;
|
||||
RegexAstNode right = node.Right;
|
||||
|
||||
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)
|
||||
{
|
||||
GenerateMethodSource(left, sc, func_list, context);
|
||||
} else
|
||||
if (right is not null) {
|
||||
GenerateMethodSource(right, sc, func_list, context);
|
||||
}
|
||||
|
||||
string group_name = config.Name;
|
||||
|
||||
// TODO(NGRA): Allocate numeric/named capture slots and emit the successful capture
|
||||
// span. Non-capturing groups still need a rollback scope but no stored capture.
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static void GenerateConcat(
|
||||
RegexAstNode node,
|
||||
[NotNull] in SequenceEmitter<string> sc,
|
||||
in List<SequenceEmitter<string>> func_list,
|
||||
in SourceGenContext context,
|
||||
in ExitLabel exit_label = default
|
||||
)
|
||||
{
|
||||
if (!RegexAstNode.IsNullOrEmpty(node.Left)) {
|
||||
GenerateMethodSource(node.Left, sc, func_list, context, exit_label);
|
||||
}
|
||||
if (!RegexAstNode.IsNullOrEmpty(node.Right)) {
|
||||
GenerateMethodSource(node.Right, sc, func_list, context, exit_label);
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateCount(
|
||||
@@ -659,7 +696,10 @@ namespace Nitload.RegularAnalysis.Text
|
||||
int min = payload.Min;
|
||||
int max = payload.Max;
|
||||
bool is_greedy = payload.IsGreedy;
|
||||
string exit_label = context.RequestExitLabel();
|
||||
|
||||
// TODO(NGRA-NAMING): Reserve exclusive names for future repetition/rollback state
|
||||
// across complex COUNT retries; recursive children must use the same method pool.
|
||||
ExitLabel exit_label = context.RequestExitLabel(ExitMode.Goto);
|
||||
if ((value.Label & RegexElementLabel.SEQUENCE) == 0)
|
||||
{
|
||||
// TODO(NGRA): Emit min/max repetition, zero-width progress protection, greedy vs.
|
||||
@@ -670,15 +710,13 @@ 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:
|
||||
|
||||
// TODO(NGRA): Emit a bounded/unbounded charset counting loop, preferably
|
||||
// using IndexOfAnyExcept where the charset shape permits it.
|
||||
GenerateUnitSetCount(value, min, max, is_greedy, sc, context, exit_label);
|
||||
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
|
||||
{
|
||||
@@ -36,12 +36,10 @@ namespace Nitload.RegularAnalysis.Text
|
||||
|
||||
public const string _remain_span = "__remain";
|
||||
|
||||
private int _exit_alt_count;
|
||||
private int _max_exit_lable;
|
||||
|
||||
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]";
|
||||
@@ -55,38 +53,24 @@ namespace Nitload.RegularAnalysis.Text
|
||||
return sc.AppendLine($@"{ROS_char} {RemainSpan};");
|
||||
}
|
||||
|
||||
public string RequestExitLabel()
|
||||
public ExitLabel RequestExitLabel(
|
||||
ExitMode exitMode
|
||||
)
|
||||
{
|
||||
string code = $@"_exit_alt_{_exit_alt_count}";
|
||||
_exit_alt_count++;
|
||||
return code;
|
||||
int index = _max_exit_lable;
|
||||
_max_exit_lable++;
|
||||
return new(exitMode, index);
|
||||
}
|
||||
|
||||
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(" ");
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// file="TextRegexSourceGen.GenSpecial"
|
||||
// Project: Nitload
|
||||
// Copyright (c) Nitload.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using Nitload.RegularAnalysis.Abstraction;
|
||||
|
||||
namespace Nitload.RegularAnalysis.Text
|
||||
{
|
||||
internal partial class TextRegexSourceGen
|
||||
{
|
||||
|
||||
private static bool TryGenerateSpecialSource(
|
||||
RegexAstNode node,
|
||||
in SequenceEmitter<string> sc,
|
||||
in List<SequenceEmitter<string>> func_list,
|
||||
in SourceGenContext context,
|
||||
in ExitLabel exit_label
|
||||
)
|
||||
{
|
||||
// A special rule owns the entire matched subtree. Returning false leaves emission
|
||||
// to the general path; returning true prevents that subtree from being emitted twice.
|
||||
return node.Label switch
|
||||
{
|
||||
RegexElementLabel.CONCAT => TryGenerateFindConcat(node, sc, func_list, context, exit_label),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
#region FIND concatenation
|
||||
|
||||
private static bool TryGenerateFindConcat(
|
||||
RegexAstNode node,
|
||||
in SequenceEmitter<string> sc,
|
||||
in List<SequenceEmitter<string>> func_list,
|
||||
in SourceGenContext context,
|
||||
in ExitLabel exit_label
|
||||
)
|
||||
{
|
||||
RegexAstNode left = node.Left;
|
||||
RegexAstNode right = node.Right;
|
||||
if (RegexAstNode.IsNullOrEmpty(left)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Existing FIND dispatch scaffold; candidate search and retries are not implemented.
|
||||
// TODO(NGRA): Use the COUNT payload's IsGreedy flag to order FIND candidates.
|
||||
if (RegexAstNode.IsDotStar(left) && !RegexAstNode.IsNullOrEmpty(right))
|
||||
{
|
||||
// TODO(NGRA): Emit the unnamed FIND candidate loop and retry the right subtree
|
||||
// until it succeeds or no anchor candidate remains.
|
||||
GenerateMethodSource(right, sc, func_list, context, exit_label, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsNamedFind(node))
|
||||
{
|
||||
if (!RegexAstNode.IsNullOrEmpty(right))
|
||||
{
|
||||
// TODO(NGRA): Emit named FIND retry and capture the text preceding the
|
||||
// successful anchor candidate.
|
||||
GenerateMethodSource(right, sc, func_list, context, exit_label, true);
|
||||
} else
|
||||
{
|
||||
// TODO(NGRA): Capture the remaining input for a terminal named dot-star.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsNamedFind(
|
||||
RegexAstNode node
|
||||
)
|
||||
{
|
||||
// (?<name>.*)abc
|
||||
|
||||
if (RegexAstNode.IsNullOrEmpty(node) || node.Label != RegexElementLabel.CONCAT) {
|
||||
return false;
|
||||
}
|
||||
RegexAstNode group = node.Left;
|
||||
if (RegexAstNode.IsNullOrEmpty(group) ||
|
||||
group.Payload is not RegexGroupPayload { IsCapturing: true } config ||
|
||||
string.IsNullOrEmpty(config.Name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool left_empty = RegexAstNode.IsNullOrEmpty(group.Left);
|
||||
bool right_empty = RegexAstNode.IsNullOrEmpty(group.Right);
|
||||
return left_empty != right_empty &&
|
||||
RegexAstNode.IsDotStar(left_empty ? group.Right : group.Left);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Repeated capture rules
|
||||
|
||||
// TODO(NGRA): Recognize and implement repeated captures such as (?<name>.*){m,n}
|
||||
// and (?<name>.*a){m,n}. Keep these distinct from (?<name>.*)a FIND concatenation.
|
||||
// A later repetition may need to reopen an earlier repetition's inner search, restoring
|
||||
// its cursor, candidate position, and capture state. Do not claim these subtrees in
|
||||
// TryGenerateSpecialSource until the complete retry/rollback strategy is implemented.
|
||||
// An escaped star is a literal and must not be classified as dot-star repetition.
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
+12
-12
@@ -1,22 +1,22 @@
|
||||
# Source Projects
|
||||
|
||||
This directory contains the production source code, native runtime, supporting applications, and benchmarks for StgSharp. Most managed projects target .NET 8. The native project is built separately with CMake and provides platform and SIMD functionality consumed by managed projects.
|
||||
This directory contains the production source code, native runtime, supporting applications, and benchmarks for Nitload. Most managed projects target .NET 8. The native project is built separately with CMake and provides platform and SIMD functionality consumed by managed projects.
|
||||
|
||||
## Directory map
|
||||
|
||||
| Directory | Purpose |
|
||||
| --- | --- |
|
||||
| `StgSharp.Common` | Shared collections, memory management, threading, pipelines, platform abstractions, and other foundational APIs. |
|
||||
| `StgSharp.Mathematics` | Numeric types, vectors, matrices, geometry, and managed access to accelerated math operations. |
|
||||
| `StgSharp.Graphics` | OpenGL bindings, rendering infrastructure, shaders, textures, windows, and input integration. |
|
||||
| `StgSharp.Native` | C native runtime, GLFW/STBI integration, allocators, platform code, and optimized SIMD/matrix kernels. See its own `README.md` for native build details. |
|
||||
| `StgSharp.RegularAnalysis` | NGRA regular-language analysis, regex processing, intermediate representations, and source-generation infrastructure. |
|
||||
| `StgSharp.UserInterface` | State-oriented user-interface framework and its incremental source generator. |
|
||||
| `StgSharp.TerminalDialogue` | Terminal user-interface components and an interactive terminal application. |
|
||||
| `StgSharp.Benchmark` | BenchmarkDotNet workloads for measuring selected runtime and allocation behavior. |
|
||||
| `StgSharp.Script` | Retained sources from the earlier EXPRESS implementation. The planned Script layer has not started and is expected to build on NGRA. |
|
||||
| `StgSharp.Model` | Placeholder project whose design is being reconsidered. |
|
||||
| `StgSharp.Tools` | Small retained comparison and inspection artifacts; it is not currently a buildable project. |
|
||||
| `Nitload.Common` | Shared collections, memory management, threading, pipelines, platform abstractions, and other foundational APIs. |
|
||||
| `Nitload.Mathematics` | Numeric types, vectors, matrices, geometry, and managed access to accelerated math operations. |
|
||||
| `Nitload.Graphics` | OpenGL bindings, rendering infrastructure, shaders, textures, windows, and input integration. |
|
||||
| `Nitload.Native` | C native runtime, GLFW/STBI integration, allocators, platform code, and optimized SIMD/matrix kernels. See its own `README.md` for native build details. |
|
||||
| `Nitload.RegularAnalysis` | NGRA regular-language analysis, regex processing, intermediate representations, and source-generation infrastructure. |
|
||||
| `Nitload.UserInterface` | State-oriented user-interface framework and its incremental source generator. |
|
||||
| `Nitload.TerminalDialogue` | Terminal user-interface components and an interactive terminal application. |
|
||||
| `Nitload.Benchmark` | BenchmarkDotNet workloads for measuring selected runtime and allocation behavior. |
|
||||
| `Nitload.Script` | Retained sources from the earlier EXPRESS implementation. The planned Script layer has not started and is expected to build on NGRA. |
|
||||
| `Nitload.Model` | Placeholder project whose design is being reconsidered. |
|
||||
| `Nitload.Tools` | Small retained comparison and inspection artifacts; it is not currently a buildable project. |
|
||||
|
||||
## Build notes
|
||||
|
||||
|
||||
@@ -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,9 +1,13 @@
|
||||
# StgSharp.GenerateGL
|
||||
# Nitload.GenerateGL
|
||||
|
||||
`StgSharp.GenerateGL` generates the StgSharp desktop OpenGL C# bindings from the Khronos `gl.xml` registry.
|
||||
`Nitload.GenerateGL` generates the Nitload desktop OpenGL C# bindings from the Khronos `gl.xml` registry.
|
||||
|
||||
The current target is OpenGL 4.6 Core. The generator does not emit OpenGL ES or mix extension entry points into the core API. `gl.xml` is the authoritative generation input; the retained `gl.h` is reference material only.
|
||||
|
||||
## Namespace migration
|
||||
|
||||
The project and directory are named `Nitload.GenerateGL`, but the implementation namespace and generated-source templates still contain `StgSharp.*`. Update the templates in `Generation/OpenGlGenerator.cs` to emit `Nitload.Graphics.OpenGL` and import `Nitload.Mathematics.Numeric.Graphics` before regenerating the renamed graphics library. The CLI commands below use the current project paths; they do not automatically migrate generated namespaces.
|
||||
|
||||
## Usage
|
||||
|
||||
Start the interactive CLI:
|
||||
@@ -92,7 +96,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 |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Khronos OpenGL Registry input
|
||||
|
||||
This directory intentionally does not track the third-party Khronos registry files. Before building or running `StgSharp.GenerateGL`, supply a registry snapshot from the canonical [KhronosGroup/OpenGL-Registry](https://github.com/KhronosGroup/OpenGL-Registry) repository.
|
||||
This directory intentionally does not track the third-party Khronos registry files. Before building or running `Nitload.GenerateGL`, supply a registry snapshot from the canonical [KhronosGroup/OpenGL-Registry](https://github.com/KhronosGroup/OpenGL-Registry) repository.
|
||||
|
||||
1. Clone or download one coherent revision of `KhronosGroup/OpenGL-Registry`.
|
||||
2. Copy the contents of its `xml/` directory directly into this directory.
|
||||
|
||||
+3
-3
@@ -1,14 +1,14 @@
|
||||
# Development Tools
|
||||
|
||||
This directory contains repository-maintenance and source-generation programs. Tools are kept outside `src` because they help build or maintain StgSharp but are not shipped as part of the runtime libraries.
|
||||
This directory contains repository-maintenance and source-generation programs. Tools are kept outside `src` because they help build or maintain Nitload but are not shipped as part of the runtime libraries.
|
||||
|
||||
## Directory map
|
||||
|
||||
| Directory | Purpose |
|
||||
| --- | --- |
|
||||
| `StgSharp.GenerateGL` | Reads the Khronos `gl.xml` registry, projects the OpenGL 4.6 Core API, analyzes function families, and generates the managed OpenGL bindings used by `StgSharp.Graphics`. |
|
||||
| `Nitload.GenerateGL` | Reads the Khronos `gl.xml` registry, projects the OpenGL 4.6 Core API, analyzes function families, and generates the managed OpenGL bindings used by `Nitload.Graphics`. |
|
||||
|
||||
`StgSharp.GenerateGL` has its own `README.md` with its pipeline, naming rules, and interactive commands. The common direct-generation command is:
|
||||
`Nitload.GenerateGL` has its own `README.md` with its pipeline, naming rules, and interactive commands. The common direct-generation command is:
|
||||
|
||||
```powershell
|
||||
dotnet run --project tools/Nitload.GenerateGL/Nitload.GenerateGL.csproj -- generate all src/Nitload.Graphics/OpenGL/Generated
|
||||
|
||||
Reference in New Issue
Block a user