redesign matrix design
This commit is contained in:
@@ -44,6 +44,8 @@ namespace StgSharp.HighPerformance
|
||||
public unsafe struct MatrixKernel<T> where T : unmanaged, INumber<T>
|
||||
{
|
||||
|
||||
public static readonly int Size = 16 * sizeof(T);
|
||||
|
||||
private T c0r0;
|
||||
|
||||
public MatrixKernel()
|
||||
@@ -58,10 +60,10 @@ namespace StgSharp.HighPerformance
|
||||
}
|
||||
}
|
||||
|
||||
public ref T this[int column, int row]
|
||||
public ref T this[int row, int column]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => ref Unsafe.Add(ref c0r0, (column * 4) + row);
|
||||
get => ref Unsafe.Add(ref c0r0, (row * 4) + column);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
# Matrix Coordinate & Naming Conventions (StgSharp)
|
||||
|
||||
This document defines the coordinate terminology and naming rules used across `Matrix<T>`, `MatrixKernel<T>`, and packed/triangular storage layouts.
|
||||
Goal: eliminate ambiguity around `column`/`row` names (e.g., “index **of** a column” vs “index **along** a column”).
|
||||
|
||||
---
|
||||
|
||||
## 1) The key rule: encode prepositions into identifiers (`Of` vs `In`)
|
||||
|
||||
### `...OfX` — “which X” (object identity / ordinal)
|
||||
Use **`Of`** when the value identifies **which object** (which column, which row, which kernel, etc.).
|
||||
|
||||
Examples:
|
||||
- `columnOfElement`: the element is located in **which column**
|
||||
- `rowOfKernel`: the kernel block is located in **which row**
|
||||
|
||||
### `...InX` / `...WithinX` — “inside X” (local coordinate)
|
||||
Use **`In`** (or `Within`) when the value is a **local coordinate inside** another object.
|
||||
|
||||
Examples:
|
||||
- `columnInKernel`: local column coordinate **inside** a kernel block
|
||||
- `rowInKernel`: local row coordinate **inside** a kernel block
|
||||
|
||||
> Quick mental model: **`Of` = identity**, **`In` = inside**.
|
||||
|
||||
---
|
||||
|
||||
## 2) Coordinate levels: `Element`, `KernelGrid`, `InKernel`
|
||||
|
||||
StgSharp commonly uses three coordinate levels:
|
||||
|
||||
1. **Element-level**: final matrix element coordinates (`Matrix<T>[col,row]`)
|
||||
2. **Kernel-grid level**: coordinates of a kernel block in the kernel grid
|
||||
3. **In-kernel level**: local element coordinates within a kernel (e.g., 4×4)
|
||||
|
||||
Recommended names:
|
||||
|
||||
| Level | Column name | Row name | Meaning |
|
||||
|---|---|---|---|
|
||||
| Element | `columnOfElement` | `rowOfElement` | element located in which column/row (0-based) |
|
||||
| Kernel grid | `columnOfKernel` | `rowOfKernel` | kernel block located in which kernel-column/kernel-row (0-based) |
|
||||
| In-kernel | `columnInKernel` | `rowInKernel` | local coordinate inside the kernel (0..KernelSize-1) |
|
||||
|
||||
---
|
||||
|
||||
## 3) Index base: 0-based (mandatory)
|
||||
|
||||
Unless explicitly documented otherwise, all coordinates are **0-based**:
|
||||
|
||||
- `columnOfElement ∈ [0, ColumnLength-1]`
|
||||
- `rowOfElement ∈ [0, RowLength-1]`
|
||||
- `columnOfKernel ∈ [0, KernelColumnLength-1]`
|
||||
- `rowOfKernel ∈ [0, KernelRowLength-1]`
|
||||
- `columnInKernel ∈ [0, KernelSize-1]`
|
||||
- `rowInKernel ∈ [0, KernelSize-1]`
|
||||
|
||||
---
|
||||
|
||||
## 4) Mapping element coordinates to kernel coordinates (KernelSize = 4 example)
|
||||
|
||||
For a fixed kernel size `KernelSize = 4`:
|
||||
|
||||
```csharp
|
||||
int columnOfKernel = columnOfElement / 4;
|
||||
int rowOfKernel = rowOfElement / 4;
|
||||
|
||||
int columnInKernel = columnOfElement % 4;
|
||||
int rowInKernel = rowOfElement % 4;
|
||||
```
|
||||
|
||||
If `columnOfElement` and `rowOfElement` are guaranteed non-negative, bit operations can be used:
|
||||
|
||||
```csharp
|
||||
int columnOfKernel = columnOfElement >> 2;
|
||||
int rowOfKernel = rowOfElement >> 2;
|
||||
|
||||
int columnInKernel = columnOfElement & 3;
|
||||
int rowInKernel = rowOfElement & 3;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5) Packed storage: distinguish `Index` from `Offset`
|
||||
|
||||
Packed layouts do **not** store “empty blocks”; stored blocks are placed contiguously in a packed buffer.
|
||||
|
||||
### Use the correct terms
|
||||
- **`packedKernelIndex`**: “the N-th kernel
|
||||
@@ -25,10 +25,12 @@
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using StgSharp.HighPerformance;
|
||||
using StgSharp.HighPerformance.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -37,21 +39,72 @@ namespace StgSharp.Mathematics.Numeric
|
||||
public unsafe partial class Matrix<T>
|
||||
{
|
||||
|
||||
private const int KernelSideLength = 4;
|
||||
|
||||
public static Matrix<T> Create(
|
||||
int columnLength,
|
||||
int rowLength,
|
||||
MatrixLayout layout,
|
||||
HybridLayerSegregatedFitAllocator allocator)
|
||||
{
|
||||
Matrix<T> matrix = new Matrix<T>();
|
||||
int tSize = sizeof(T);
|
||||
int totalSize = columnLength * rowLength * tSize;
|
||||
HybridLayerSegregatedFitAllocationHandle handle = allocator.Alloc((uint)totalSize);
|
||||
MatrixStorageHLSF<T> storage = new MatrixStorageHLSF<T>(handle);
|
||||
storage._handle = handle;
|
||||
ArgumentNullException.ThrowIfNull(allocator);
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(columnLength);
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(rowLength);
|
||||
|
||||
int kernelColumns = DivideRoundUp(columnLength, KernelSideLength);
|
||||
int kernelRows = DivideRoundUp(rowLength, KernelSideLength);
|
||||
|
||||
if (layout is MatrixLayout.UpperTriangle or MatrixLayout.LowerTriangle)
|
||||
{
|
||||
if (kernelColumns != kernelRows) {
|
||||
throw new ArgumentException("Triangular layouts require square matrices.");
|
||||
}
|
||||
}
|
||||
|
||||
long kernelCount = layout switch
|
||||
{
|
||||
MatrixLayout.DenseSquare => (long)kernelColumns * kernelRows,
|
||||
MatrixLayout.UpperTriangle => TriangularKernelCount(kernelColumns),
|
||||
MatrixLayout.LowerTriangle => TriangularKernelCount(kernelRows),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(layout))
|
||||
};
|
||||
|
||||
long requiredBytes = kernelCount * MatrixKernel<T>.Size;
|
||||
if (requiredBytes <= 0 || requiredBytes > uint.MaxValue) {
|
||||
throw new ArgumentOutOfRangeException(nameof(requiredBytes), "Requested matrix exceeds allocator capacity.");
|
||||
}
|
||||
|
||||
HybridLayerSegregatedFitAllocationHandle handle = allocator.Alloc((uint)requiredBytes);
|
||||
MatrixStorageHLSF<T> storage = new MatrixStorageHLSF<T>(allocator, handle);
|
||||
|
||||
Matrix<T> matrix = new Matrix<T>
|
||||
{
|
||||
Layout = layout,
|
||||
KernelColumnLength = kernelColumns,
|
||||
KernelRowLength = kernelRows,
|
||||
};
|
||||
|
||||
matrix._buffer = storage;
|
||||
matrix._enumeration = new MatrixMetadata(columnLength, rowLength);
|
||||
matrix._boarder = MatrixKernelBoarder.Create(layout);
|
||||
matrix._size = new MatrixSize(columnLength, rowLength, kernelColumns, kernelRows);
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int DivideRoundUp(int value, int divisor)
|
||||
{
|
||||
return (value + (divisor - 1)) / divisor;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static long TriangularKernelCount(int order)
|
||||
{
|
||||
long n = order;
|
||||
return (n * (n + 1L)) / 2L;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ using StgSharp.Mathematics.Numeric;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// using hlsfHandle = global::StgSharp.HighPerformance.Memory.HybridLayerSegregatedFitAllocationHandle;
|
||||
|
||||
@@ -42,17 +41,61 @@ namespace StgSharp.Mathematics.Numeric
|
||||
private protected static readonly int t_count = 16 / sizeof(T);
|
||||
|
||||
private protected static readonly int t_size = sizeof(T);
|
||||
private MatrixMetadata _enumeration;
|
||||
|
||||
private MatrixKernelBoarder _boarder;
|
||||
private MatrixSize _size;
|
||||
private MatrixStorage<T> _buffer;
|
||||
|
||||
private protected Matrix() { }
|
||||
|
||||
public ref T this[int column, int row]
|
||||
public T this[int x, int y]
|
||||
{
|
||||
get => throw new NotImplementedException();
|
||||
get
|
||||
{
|
||||
if (y < 0 || y > _size.ElementColumnLength || x < 0 || x > _size.ElementRowLength) {
|
||||
throw new ArgumentOutOfRangeException($"Index [{x},{y}] is out of matrix index range.");
|
||||
}
|
||||
|
||||
int
|
||||
k_c = y / 4,
|
||||
k_r = x / 4,
|
||||
c = y % 4,
|
||||
r = x % 4;
|
||||
ref MatrixKernel<T> kernel = ref GetMatrixKernel(k_c, k_r);
|
||||
return Unsafe.IsNullRef(ref kernel) ? T.Zero : kernel[c, r];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (y < 0 || y > _size.ElementColumnLength || x < 0 || x > _size.ElementRowLength) {
|
||||
throw new ArgumentOutOfRangeException($"Index [{x},{y}] is out of matrix index range.");
|
||||
}
|
||||
|
||||
int
|
||||
k_c = y / 4,
|
||||
k_r = x / 4,
|
||||
c = y % 4,
|
||||
r = x % 4;
|
||||
ref MatrixKernel<T> kernel = ref GetMatrixKernel(k_c, k_r);
|
||||
if (!Unsafe.IsNullRef(ref kernel)) {
|
||||
kernel[c, r] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Matlab style indexer to generate a new matrix
|
||||
/// </summary>
|
||||
/// <param name="column">
|
||||
///
|
||||
/// </param>
|
||||
/// <param name="row">
|
||||
///
|
||||
/// </param>
|
||||
/// <returns>
|
||||
///
|
||||
/// </returns>
|
||||
/// <exception cref="NotImplementedException">
|
||||
///
|
||||
/// </exception>
|
||||
public unsafe Matrix<T> this[
|
||||
ReadOnlySpan<MatrixIndex> column,
|
||||
ReadOnlySpan<MatrixIndex> row]
|
||||
@@ -64,34 +107,33 @@ namespace StgSharp.Mathematics.Numeric
|
||||
/// <summary>
|
||||
/// Length of the matrix in columns.
|
||||
/// </summary>
|
||||
public int ColumnLength { get; init; }
|
||||
public int ColumnLength => _size.ElementColumnLength;
|
||||
|
||||
/// <summary>
|
||||
/// Length of the matrix in rows.
|
||||
/// </summary>
|
||||
public int RowLength { get; init; }
|
||||
public int RowLength => _size.ElementRowLength;
|
||||
|
||||
public MatrixLayout Layout { get; init; }
|
||||
|
||||
internal MatrixKernel<T>* Buffer { get; }
|
||||
internal MatrixKernel<T>* Buffer
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => (MatrixKernel<T>*)_buffer.BufferPointer;
|
||||
}
|
||||
|
||||
protected internal int KernelColumnLength { get; init; }
|
||||
|
||||
protected internal int KernelRowLength { get; init; }
|
||||
|
||||
public ref MatrixKernel<T> GetMatrixKernel(int column, int row)
|
||||
public unsafe ref MatrixKernel<T> GetMatrixKernel(int x, int y)
|
||||
{
|
||||
if (_enumeration.GetCurrentKernelIndex) { } else { }
|
||||
}
|
||||
|
||||
private protected void AssertIndex(int column, int row)
|
||||
{
|
||||
if (column < 0 || column >= ColumnLength) {
|
||||
throw new ArgumentOutOfRangeException(nameof(column));
|
||||
}
|
||||
|
||||
if (row < 0 || row >= RowLength) {
|
||||
throw new ArgumentOutOfRangeException(nameof(row));
|
||||
fixed (MatrixSize *msPtr = &_size)
|
||||
{
|
||||
MatrixKernelEnumerator* e = (MatrixKernelEnumerator*)msPtr;
|
||||
return ref _boarder.IsInBuffer(x, y, e) ?
|
||||
ref _buffer[_boarder.GetIndexOffset(x, y, e)] :
|
||||
ref Unsafe.NullRef<MatrixKernel<T>>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace StgSharp.Mathematics.Numeric
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct MatrixKernelEnumeration
|
||||
public unsafe struct MatrixKernelBoarder
|
||||
{
|
||||
|
||||
public readonly delegate* unmanaged[Cdecl]
|
||||
@@ -55,9 +55,9 @@ namespace StgSharp.Mathematics.Numeric
|
||||
public readonly delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, bool> IsInBuffer;
|
||||
|
||||
[Obsolete("Do not use constructor, use static method instead", true)]
|
||||
public MatrixKernelEnumeration() { }
|
||||
public MatrixKernelBoarder() { }
|
||||
|
||||
public MatrixKernelEnumeration(
|
||||
public MatrixKernelBoarder(
|
||||
delegate* unmanaged[Cdecl]
|
||||
<int, int, MatrixKernelEnumerator*, long> getOffset,
|
||||
delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, bool> inBuffer)
|
||||
@@ -66,24 +66,128 @@ namespace StgSharp.Mathematics.Numeric
|
||||
IsInBuffer = inBuffer;
|
||||
}
|
||||
|
||||
private static delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, bool> IsInBufferDenseSquarePtr { get; } = (delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, bool>)&IsInBufferDenseSquare;
|
||||
private static delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, long> GetIndexOffsetDenseSquarePtr { get; } =
|
||||
(delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, long>)&GetIndexOffsetDenseSquare;
|
||||
|
||||
public static MatrixKernelEnumeration Create(MatrixLayout layout)
|
||||
private static delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, long> GetIndexOffsetUpperTrianglePtr { get; } =
|
||||
(delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, long>)&GetIndexOffsetUpperTriangle;
|
||||
|
||||
private static delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, long> GetIndexOffsetLowerTrianglePtr { get; } =
|
||||
(delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, long>)&GetIndexOffsetLowerTriangle;
|
||||
|
||||
private static delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, bool> IsInBufferDenseSquarePtr { get; } =
|
||||
(delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, bool>)&IsInBufferDenseSquare;
|
||||
|
||||
private static delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, bool> IsInBufferUpperTrianglePtr { get; } =
|
||||
(delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, bool>)&IsInBufferUpperTriangle;
|
||||
|
||||
private static delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, bool> IsInBufferLowerTrianglePtr { get; } =
|
||||
(delegate* unmanaged[Cdecl]<int, int, MatrixKernelEnumerator*, bool>)&IsInBufferLowerTriangle;
|
||||
|
||||
public static MatrixKernelBoarder Create(MatrixLayout layout)
|
||||
{
|
||||
return layout switch
|
||||
{
|
||||
MatrixLayout.DenseSquare => new MatrixKernelEnumeration(null, IsInBufferDenseSquarePtr),
|
||||
MatrixLayout.DenseSquare => new MatrixKernelBoarder(GetIndexOffsetDenseSquarePtr, IsInBufferDenseSquarePtr),
|
||||
|
||||
MatrixLayout.UpperTriangle => throw new NotImplementedException(),
|
||||
MatrixLayout.UpperTriangle => new MatrixKernelBoarder(GetIndexOffsetUpperTrianglePtr, IsInBufferUpperTrianglePtr),
|
||||
MatrixLayout.LowerTriangle => new MatrixKernelBoarder(GetIndexOffsetLowerTrianglePtr, IsInBufferLowerTrianglePtr),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(layout)),
|
||||
};
|
||||
}
|
||||
|
||||
private static bool IsInBufferDenseSquare(
|
||||
int col,
|
||||
int row,
|
||||
[UnmanagedCallersOnly(CallConvs =[ typeof(CallConvCdecl) ])]
|
||||
private static long GetIndexOffsetDenseSquare(
|
||||
int x_kernel,
|
||||
int y_kernel,
|
||||
MatrixKernelEnumerator* enumerator)
|
||||
{
|
||||
return true;
|
||||
long x = x_kernel;
|
||||
long y = y_kernel;
|
||||
long rows = enumerator->KernelRowLength;
|
||||
return x * rows + y;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs =[ typeof(CallConvCdecl) ])]
|
||||
private static long GetIndexOffsetLowerTriangle(
|
||||
int x_kernel,
|
||||
int y_kernel,
|
||||
MatrixKernelEnumerator* enumerator)
|
||||
{
|
||||
long order = GetTriangularOrder(enumerator);
|
||||
long x = x_kernel;
|
||||
long y = y_kernel;
|
||||
|
||||
long prefixColumns = x * order - (x * (x - 1L)) / 2L;
|
||||
return prefixColumns + (y - x);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs =[ typeof(CallConvCdecl) ])]
|
||||
private static long GetIndexOffsetUpperTriangle(
|
||||
int x_kernel,
|
||||
int y_kernel,
|
||||
MatrixKernelEnumerator* enumerator)
|
||||
{
|
||||
long x = x_kernel;
|
||||
long y = y_kernel;
|
||||
|
||||
long prefixColumns = (x * (x + 1L)) / 2L;
|
||||
return prefixColumns + y;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static long GetTriangularOrder(MatrixKernelEnumerator* enumerator)
|
||||
{
|
||||
return Math.Min(enumerator->KernelColumnLength, enumerator->KernelRowLength);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs =[ typeof(CallConvCdecl) ])]
|
||||
private static bool IsInBufferDenseSquare(
|
||||
int x_kernel,
|
||||
int y_kernel,
|
||||
MatrixKernelEnumerator* enumerator)
|
||||
{
|
||||
return IsWithinKernelDomain(enumerator, x_kernel, y_kernel);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs =[ typeof(CallConvCdecl) ])]
|
||||
private static bool IsInBufferLowerTriangle(
|
||||
int x_kernel,
|
||||
int y_kernel,
|
||||
MatrixKernelEnumerator* enumerator)
|
||||
{
|
||||
return IsWithinTriangularDomain(enumerator, x_kernel, y_kernel) && y_kernel >= x_kernel;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(CallConvs =[ typeof(CallConvCdecl) ])]
|
||||
private static bool IsInBufferUpperTriangle(
|
||||
int x_kernel,
|
||||
int y_kernel,
|
||||
MatrixKernelEnumerator* enumerator)
|
||||
{
|
||||
return IsWithinTriangularDomain(enumerator, x_kernel, y_kernel) && y_kernel <= x_kernel;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool IsWithinKernelDomain(
|
||||
MatrixKernelEnumerator* enumerator,
|
||||
int x_kernel,
|
||||
int y_kernel)
|
||||
{
|
||||
return x_kernel >= 0 &&
|
||||
y_kernel >= 0 &&
|
||||
x_kernel < enumerator->KernelColumnLength &&
|
||||
y_kernel < enumerator->KernelRowLength;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool IsWithinTriangularDomain(
|
||||
MatrixKernelEnumerator* enumerator,
|
||||
int x_kernel,
|
||||
int y_kernel)
|
||||
{
|
||||
long order = GetTriangularOrder(enumerator);
|
||||
return x_kernel >= 0 && y_kernel >= 0 && x_kernel < order && y_kernel < order;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -98,6 +202,18 @@ namespace StgSharp.Mathematics.Numeric
|
||||
[FieldOffset(8)] public readonly int KernelColumnLength;
|
||||
[FieldOffset(12)] public readonly int KernelRowLength;
|
||||
|
||||
public MatrixSize(
|
||||
int elementColumnLength,
|
||||
int elementRowLength,
|
||||
int kernelColumnLength,
|
||||
int kernelRowLength)
|
||||
{
|
||||
ElementColumnLength = elementColumnLength;
|
||||
ElementRowLength = elementRowLength;
|
||||
KernelColumnLength = kernelColumnLength;
|
||||
KernelRowLength = kernelRowLength;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
|
||||
@@ -25,11 +25,13 @@
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using StgSharp.HighPerformance;
|
||||
using StgSharp.HighPerformance.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -41,6 +43,11 @@ namespace StgSharp.Mathematics.Numeric
|
||||
public abstract class MatrixStorage<T> : IDisposable where T : unmanaged, INumber<T>
|
||||
{
|
||||
|
||||
internal unsafe ref MatrixKernel<T> this[long index]
|
||||
{
|
||||
get { return ref Unsafe.AsRef<MatrixKernel<T>>(BufferPointer + MatrixKernel<T>.Size * index); }
|
||||
}
|
||||
|
||||
protected internal abstract unsafe T* BufferPointer { get; }
|
||||
|
||||
public abstract void Dispose();
|
||||
|
||||
Reference in New Issue
Block a user