using System.Diagnostics.Contracts; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using StitchATon2.Infra.Buffers; namespace StitchATon2.Domain; public static class Utils { [Pure] public static string GetSBSNotationRow(int row) => row <= 26 ? new string([(char)(row + 'A' - 1)]) : new string(['A', (char)(row + 'A' - 27)]); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] private static int DivCeil(int a, int b) { return (a + b - 1) / b; } [Pure] public static (int Column, int Row) GetSBSCoordinate(string coordinate) { var column = coordinate[^1] - '0'; if(char.IsDigit(coordinate[^2])) column += 10 * (coordinate[^2] - '0'); var row = char.IsLetter(coordinate[1]) ? 26 + coordinate[1] - 'A' + 1 : coordinate[0] - 'A' + 1; return (column, row); } /// /// Performs a SIMD-accelerated calculation that generates a buffer of bounded, scaled indices. /// /// The amount by which to scale the sequence values. /// The total number of scalar values to generate. /// Upper limit (exclusive) for clamping values. /// The offset to apply before clamping. public static IBuffer BoundsMatrix(float scaleFactor, int length, int max, int offset) { var vectorSize = DivCeil(length, Vector.Count); using var buffer = MemoryAllocator.Allocate>(vectorSize); var span = buffer.Span; var vectorMin = Vector.Zero; var vectorOffset = new Vector(offset - 1); var vectorMax = new Vector(max - 1); var vectorScale = new Vector(scaleFactor); var vectorSequence = Vector.CreateSequence(0f, 1f); var seq = 0f; for (var i = 0; i < vectorSize; i++, seq += Vector.Count) { var sequence = new Vector(seq) + vectorSequence; span[i] = Vector.FusedMultiplyAdd(sequence, vectorScale, vectorScale); span[i] = Vector.Ceiling(span[i]); } var result = MemoryAllocator.Allocate(vectorSize * Vector.Count); var resultSpan = MemoryMarshal.Cast>(result.Span); for (var i = 0; i < vectorSize; i++) { resultSpan[i] = Vector.ConvertToInt32(span[i]); resultSpan[i] = Vector.Add(resultSpan[i], vectorOffset); resultSpan[i] = Vector.ClampNative(resultSpan[i], vectorMin, vectorMax); } var negative = float.Ceiling(scaleFactor); return result; } public static (IBuffer, IBuffer) DoubleBoundsMatrix(float scaleFactor, int length, int max, int offset) { var vectorSize = DivCeil(length, Vector.Count); using var startBuffer = MemoryAllocator.Allocate>(vectorSize); using var endBuffer = MemoryAllocator.Allocate>(vectorSize); var startSpan = startBuffer.Span; var endSpan = endBuffer.Span; var vectorMin = Vector.Zero; var vectorOne = Vector.One; var vectorMax = Vector.Create(max); var vectorScale = Vector.Create(scaleFactor); var vectorOffset = new Vector(offset - 1); for (int i = 0, seq = 0; i < vectorSize; i++, seq += Vector.Count) { startSpan[i] = Vector.CreateSequence(seq, 1f); startSpan[i] = Vector.Multiply(startSpan[i], vectorScale); endSpan[i] = Vector.Add(vectorScale, startSpan[i]); endSpan[i] = Vector.Ceiling(endSpan[i]); } var resultStart = MemoryAllocator.Allocate(vectorSize * Vector.Count); var resultEnd = MemoryAllocator.Allocate(vectorSize * Vector.Count); var resultStartSpan = MemoryMarshal.Cast>(resultStart.Span); var resultEndSpan = MemoryMarshal.Cast>(resultEnd.Span); for (var i = 0; i < vectorSize; i++) { resultStartSpan[i] = Vector.ConvertToInt32(startSpan[i]); resultStartSpan[i] = Vector.Subtract(resultStartSpan[i], vectorOne); resultStartSpan[i] = Vector.Add(resultStartSpan[i], vectorOffset); resultStartSpan[i] = Vector.Clamp(resultStartSpan[i], vectorMin, vectorMax); resultEndSpan[i] = Vector.ConvertToInt32(endSpan[i]); resultEndSpan[i] = Vector.Subtract(resultEndSpan[i], vectorOne); resultEndSpan[i] = Vector.Add(resultEndSpan[i], vectorOffset); resultEndSpan[i] = Vector.Clamp(resultEndSpan[i], vectorMin, vectorMax); } return (resultStart, resultEnd); } }