<#@ template debug="false" hostspecific="false" language="C#" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".gen.cs" #> using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; namespace Misaki.HighPerformance.LowLevel.Collections; <# for (int i = 32; i <= 4096; i *= 2) { #> /// /// Represents a stack allocated fixed-size UTF-8 encoded string of length <#= i #> bytes. /// /// /// This struct is designed to hold data on the stack. Every copy of this struct causes a copy of the underlying data. /// If you need a heap allocated fixed-size UTF-8 encoded string of length <#= i #> bytes, consider using . /// [StructLayout(LayoutKind.Sequential, Size = <#= i #>)] public unsafe struct FixedString<#= i #> { public const int MAX_LENGTH = <#= (i - 2) / 2 #>; private ushort _length; private fixed char _buffer[MAX_LENGTH]; public readonly ushort Length => _length; public string Value { get { fixed (char* bufferPtr = _buffer) { return new string(bufferPtr, 0, _length); } } set { if (string.IsNullOrEmpty(value)) { _length = 0; return; } if (value.Length > MAX_LENGTH) { throw new ArgumentException("Input string is too long to fit in FixedString<#= i #>."); } _length = (ushort)value.Length; fixed (char* bufferPtr = _buffer) fixed (char* valuePtr = value) { Unsafe.CopyBlockUnaligned(bufferPtr, valuePtr, (uint)(_length * sizeof(char))); } } } public FixedString<#= i #>(string input) : this(input.AsSpan()) { } public FixedString<#= i #>(ReadOnlySpan input) { if (input.Length > MAX_LENGTH) { throw new ArgumentException("Input byte array is too long to fit in FixedString<#= i #>."); } _length = (ushort)input.Length; fixed (char* inputPtr = input) fixed (char* bufferPtr = _buffer) { Unsafe.CopyBlockUnaligned(bufferPtr, inputPtr, (uint)(_length * sizeof(char))); } } public FixedString<#= i #>(char* input, ushort length) : this(new ReadOnlySpan(input, length)) { } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Span AsSpan() { fixed (char* ptr = _buffer) { return new(ptr, _length); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly char* GetUnsafePtr() { return (char*)((ushort*)Unsafe.AsPointer(in this) + 1); } public override string ToString() { return Value; } } <# } #>