Blittable strings generator implementation

Improvements to fixed array generator
This commit is contained in:
2026-01-27 14:15:41 +01:00
parent dbdf5cfbe2
commit 2c918cf4a4
3 changed files with 194 additions and 30 deletions
@@ -56,7 +56,7 @@ public class FixedArrayGenerator : IIncrementalGenerator
compilation.Assembly.GetAttributes().Where(a => a.AttributeClass != null &&
(a.AttributeClass.Name == AttributeName || a.AttributeClass.Name == AttributeShortName));
foreach(var attr in assemblyAttributes)
foreach (var attr in assemblyAttributes)
{
// Extract the type argument (T) from GenerateFixedArrayAttribute<T>
var namedTypeSymbol = attr.AttributeClass as INamedTypeSymbol;
@@ -96,47 +96,69 @@ public class FixedArrayGenerator : IIncrementalGenerator
builder.AppendLine($"using {UsingSystem};");
builder.AppendLine($"using {UsingSystemRuntimeInterop};");
builder.AppendLine();
builder.AppendLine($"namespace {AttributeNamespace}");
builder.AppendLine($"namespace {AttributeNamespace};");
builder.AppendLine();
builder.AppendLine("[StructLayout(LayoutKind.Sequential, Pack = 1)]");
builder.AppendLine($"public unsafe struct {structName}");
builder.AppendLine("{");
builder.AppendLine(" [StructLayout(LayoutKind.Sequential, Pack = 1)]");
builder.AppendLine($" public unsafe struct {structName}");
builder.AppendLine($" private const int Size = {size};");
builder.AppendLine();
builder.AppendLine($" private fixed {targetType} elements[Size];");
builder.AppendLine();
builder.AppendLine(" public int Length => Size;");
builder.AppendLine();
builder.AppendLine($" public ref {targetType} this[int index]");
builder.AppendLine(" {");
builder.AppendLine($" private const int Size = {size};");
builder.AppendLine();
builder.AppendLine($" private fixed {targetType} elements[Size];");
builder.AppendLine();
builder.AppendLine(" public int Length => Size;");
builder.AppendLine();
builder.AppendLine($" public ref {targetType} this[int index]");
builder.AppendLine(" get");
builder.AppendLine(" {");
builder.AppendLine(" get");
builder.AppendLine(" {");
builder.AppendLine(" if (index >= Size) throw new IndexOutOfRangeException();");
builder.AppendLine($" fixed ({targetType}* ptr = this.elements)");
builder.AppendLine(" {");
builder.AppendLine(" return ref ptr[index];");
builder.AppendLine(" }");
builder.AppendLine(" }");
builder.AppendLine(" if ((uint)index >= Size) throw new IndexOutOfRangeException();");
builder.AppendLine($" return ref this.elements[index];");
builder.AppendLine(" }");
builder.AppendLine(" }");
builder.AppendLine();
builder.AppendLine($" public Span<{targetType}> AsSpan()");
builder.AppendLine($" public Span<{targetType}> AsSpan()");
builder.AppendLine(" {");
builder.AppendLine($" fixed ({targetType}* ptr = this.elements)");
builder.AppendLine(" {");
builder.AppendLine($" fixed ({targetType}* ptr = this.elements)");
builder.AppendLine(" {");
builder.AppendLine($" return new Span<{targetType}>(ptr, Size);");
builder.AppendLine(" }");
builder.AppendLine($" return MemoryMarshal.CreateSpan(ref *ptr, Size);");
builder.AppendLine(" }");
builder.AppendLine(" }");
builder.AppendLine();
builder.AppendLine($" public static {structName} From{capitalizedType}Array({targetType}[] array)");
builder.AppendLine($" public readonly ReadOnlySpan<{targetType}> AsReadOnlySpan()");
builder.AppendLine(" {");
builder.AppendLine($" fixed ({targetType}* ptr = this.elements)");
builder.AppendLine(" {");
builder.AppendLine($" var arr = default({structName});");
builder.AppendLine(" array.AsSpan().CopyTo(arr.AsSpan());");
builder.AppendLine(" return arr;");
builder.AppendLine($" return new ReadOnlySpan<{targetType}>(ptr, Size);");
builder.AppendLine(" }");
builder.AppendLine(" }");
builder.AppendLine();
builder.AppendLine($" public void Set(ReadOnlySpan<{targetType}> value)");
builder.AppendLine(" {");
builder.AppendLine($" fixed ({targetType}* ptr = this.elements)");
builder.AppendLine(" {");
builder.AppendLine($" var span = MemoryMarshal.CreateSpan(ref *ptr, Size);");
builder.AppendLine(" span.Clear();");
builder.AppendLine(" value[..Math.Min(value.Length, Size)].CopyTo(span);");
builder.AppendLine(" }");
builder.AppendLine(" }");
builder.AppendLine();
builder.AppendLine($" public void Clear()");
builder.AppendLine(" {");
builder.AppendLine($" fixed ({targetType}* ptr = this.elements)");
builder.AppendLine(" {");
builder.AppendLine($" MemoryMarshal.CreateSpan(ref *ptr, Size).Clear();");
builder.AppendLine(" }");
builder.AppendLine(" }");
builder.AppendLine();
builder.AppendLine($" public static {structName} From{capitalizedType}Array({targetType}[] array)");
builder.AppendLine(" {");
builder.AppendLine($" var arr = default({structName});");
builder.AppendLine(" arr.Set(array);");
builder.AppendLine(" return arr;");
builder.AppendLine(" }");
builder.AppendLine("}");
sourceProductionContext.AddSource($"{structName}.g.cs", builder.ToString());
}
}
#nullable disable
#nullable disable