From 310e76b2959a5830afc72eb491e59889fd2b4a48 Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Fri, 27 Oct 2023 21:47:15 -0700 Subject: [PATCH 01/16] experimental variadic source generator --- src/Arch.SourceGen/Arch.SourceGen.csproj | 8 +- src/Arch.SourceGen/VariadicGenerator.cs | 277 +++++++++++++++++++++++ src/Arch/VariadicAttribute.cs | 15 ++ 3 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 src/Arch.SourceGen/VariadicGenerator.cs create mode 100644 src/Arch/VariadicAttribute.cs diff --git a/src/Arch.SourceGen/Arch.SourceGen.csproj b/src/Arch.SourceGen/Arch.SourceGen.csproj index 5a76d2dd..b35f22de 100644 --- a/src/Arch.SourceGen/Arch.SourceGen.csproj +++ b/src/Arch.SourceGen/Arch.SourceGen.csproj @@ -6,6 +6,7 @@ true + true enable Debug;Release;Release-Pure;Release-PureECS;Release-Events;Debug-PureECS;Debug-Events @@ -25,7 +26,12 @@ - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/src/Arch.SourceGen/VariadicGenerator.cs b/src/Arch.SourceGen/VariadicGenerator.cs new file mode 100644 index 00000000..febe5757 --- /dev/null +++ b/src/Arch.SourceGen/VariadicGenerator.cs @@ -0,0 +1,277 @@ +using System.Text.RegularExpressions; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Arch.SourceGen; + +[Generator] +public class VariadicGenerator : IIncrementalGenerator +{ + private class VariadicInfo + { + public string Type { get; set; } = string.Empty; + public string Code { get; set; } = string.Empty; + public string Name { get; set; } = string.Empty; + public string EnclosingType { get; set; } = string.Empty; + public string EnclosingTypeName { get; set; } = string.Empty; + public string Namespace { get; set; } = string.Empty; + public string Usings { get; set; } = string.Empty; + public int Count { get; set; } = 0; + } + + public void Initialize(IncrementalGeneratorInitializationContext context) + { + //if (!Debugger.IsAttached) + //{ + // //Debugger.Launch(); + //} + + var infos = context.SyntaxProvider.ForAttributeWithMetadataName("Arch.Core.VariadicAttribute", + (node, token) => + { + return true; + }, + (ctx, token) => + { + VariadicInfo info = new(); + + // note: doesn't support mulilevel nesting + if (ctx.TargetSymbol.ContainingType is not null) + { + info.EnclosingTypeName = ctx.TargetSymbol.ContainingType.Name; + var accessibility = ctx.TargetSymbol.ContainingType.DeclaredAccessibility switch + { + Accessibility.Public => "public", + _ => "internal", + }; + + var reference = ctx.TargetSymbol.ContainingType.IsReferenceType ? "class" : "struct"; + + info.EnclosingType = $"{accessibility} partial {reference} {ctx.TargetSymbol.ContainingType.Name}"; + } + + string ns = string.Empty; + var containingNamespace = ctx.TargetSymbol.ContainingNamespace; + while (containingNamespace is not null && !string.IsNullOrEmpty(containingNamespace.Name)) + { + ns = ns != string.Empty ? containingNamespace.Name + "." + ns : containingNamespace.Name; + containingNamespace = containingNamespace.ContainingNamespace; + } + info.Namespace = ns; + info.Name = ctx.TargetSymbol.Name; + info.Code = ctx.TargetNode.ToString(); + foreach (var use in (ctx.TargetNode.SyntaxTree.GetRoot() as CompilationUnitSyntax)!.Usings) + { + info.Usings += use.ToString() + "\n"; + } + + // default count is 26 + info.Count = 26; + foreach (var attr in ctx.TargetSymbol.GetAttributes()) + { + if (attr.AttributeClass?.Name == "VariadicAttribute") + { + info.Type = attr.ConstructorArguments[0].Value as string ?? throw new InvalidOperationException(); + info.Count = Convert.ToInt32(attr.ConstructorArguments[1].Value); + break; + } + } + + if (info.Type == string.Empty) + { + throw new InvalidOperationException(); + } + + return info; + }).Collect(); + + context.RegisterSourceOutput(infos, (ctx, infos) => + { + foreach (var info in infos) + { + var text = CSharpSyntaxTree.ParseText(MakeVariadic(info)).GetRoot().NormalizeWhitespace().ToFullString(); + if (info.EnclosingType != string.Empty) + { + ctx.AddSource($"{info.EnclosingTypeName}.{info.Name}.Variadic.g.cs", text); + } + else + { + ctx.AddSource($"{info.Name}.Variadic.g.cs", text); + } + } + }); + } + + private string MakeVariadic(VariadicInfo info) + { + var tokens = Tokenize(info).ToList(); + StringBuilder combined = new(); + + for (var i = 1; i < info.Count; i++) + { + foreach (var token in tokens) + { + combined.AppendLine(token.Transform(i, info.Type)); + } + } + + return $$""" + {{info.Usings}} + + namespace {{info.Namespace}}; + + {{info.EnclosingType}} + { + {{combined}} + } + """; + } + + private struct LineInfo + { + public LineInfo() { } + public enum Operation + { + None, + // [Variadic: CopyLines(variableName)] + CopyLines, + // [Variadic: CopyParams(variableName)] + CopyParams + } + + public Operation Op { get; set; } = Operation.None; + public string Line { get; set; } = string.Empty; + public string Variable { get; set; } = string.Empty; + + public readonly string Transform(int variations, string type) + { + if (Op == Operation.None) + { + // apply type constraints + StringBuilder transformed = new(); + var constraints = Regex.Match(Line, @$"where\s+{type}\s*:\s*(?.*?)(?:where|{{|$)"); + if (constraints.Success) + { + transformed.Append(Line.Substring(0, constraints.Index)); + for (int i = 1; i < variations; i++) + { + transformed.Append($" where {VaryType(type, i)} : {constraints.Groups["Constraints"].Value} "); + } + + transformed.Append(Line.Substring(constraints.Index, Line.Length - constraints.Index)); + } + else + { + transformed.Append(Line); + } + + StringBuilder variadics = new(); + + for (int i = 0; i < variations; i++) + { + variadics.Append(VaryType(type, i)); + if (i != variations - 1) + { + variadics.Append(", "); + } + } + + variadics.Append(">"); + + // apply generics: expand T0> to T0, T1...> + transformed.Replace(type + ">", variadics.ToString()); + return transformed.ToString(); + } + if (Op == Operation.CopyLines) + { + StringBuilder transformed = new(); + transformed.AppendLine(Line); + + for (int i = 1; i < variations; i++) + { + StringBuilder next = new(); + next.AppendLine(Line); + var variadic = VaryType(type, i); + next.Replace(Variable + "__" + type, Variable + "__" + variadic); + next.Replace(type, variadic); + transformed.AppendLine(next.ToString()); + } + return transformed.ToString(); + } + if (Op == Operation.CopyParams) + { + StringBuilder transformed = new(); + transformed.AppendLine(Line); + StringBuilder newVariables = new(); + newVariables.Append(Variable + "__" + type); + for (int i = 1; i < variations; i++) + { + var variadic = VaryType(type, i); + newVariables.Append(", " + Variable + "__ " + variadic); + } + + transformed.Replace(Variable + "__" + type, newVariables.ToString()); + return transformed.ToString(); + } + + throw new NotImplementedException(); + } + } + + private static string VaryType(string typeName, int i) + { + var match = Regex.Match(typeName, @"(?\w+)0"); + if (!match.Success) + { + throw new InvalidOperationException("Variadic type must be of TypeName0"); + } + return $"{match.Groups["PrunedName"]}{i}"; + } + + private IEnumerable Tokenize(VariadicInfo info) + { + // NOTE: does not support multiline operations, for example this would break: + // // [Variadic: CopyParams(a)] + // MyMethod( + // a_T0); + var lines = SplitLines(info.Code); + + LineInfo.Operation nextOperation = LineInfo.Operation.None; + string nextVariable = string.Empty; + foreach (var line in lines) + { + if (line.StartsWith("//")) + { + var match = Regex.Match(line, @"\[Variadic:\s*(?\w+)\((?\w+)\)\]"); + if (!match.Success) + { + continue; + } + + nextOperation = match.Groups["Operation"].Value switch + { + "CopyLines" => LineInfo.Operation.CopyLines, + "CopyParams" => LineInfo.Operation.CopyParams, + _ => throw new NotImplementedException() + }; + nextVariable = match.Groups["Variable"].Value; + + continue; + } + + var lineInfo = new LineInfo() + { + Line = line, + Variable = nextVariable, + Op = nextOperation + }; + nextVariable = string.Empty; + nextOperation = LineInfo.Operation.None; + yield return lineInfo; + } + } + + private IEnumerable SplitLines(string code) + { + return code.Split('\n').Select(line => line.Trim()); + } +} diff --git a/src/Arch/VariadicAttribute.cs b/src/Arch/VariadicAttribute.cs new file mode 100644 index 00000000..ee10bf18 --- /dev/null +++ b/src/Arch/VariadicAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace Arch.Core; + +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct)] +internal class VariadicAttribute : Attribute +{ + public string Name { get; } + public int Count { get; } + public VariadicAttribute(string name, int count = 26) + { + Name = name; + Count = count; + } +} From f9a43c30c5d9cb79bdbbd7302d685d544b2944d1 Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Fri, 27 Oct 2023 23:08:17 -0700 Subject: [PATCH 02/16] Apply Varaidics to EntityExtensions --- src/Arch.SourceGen/QueryGenerator.cs | 2 + src/Arch.SourceGen/VariadicGenerator.cs | 76 +++++++++++++------ .../Variadics/EntityExtensions.Variadics.cs | 49 ++++++++++++ src/Arch/VariadicAttribute.cs | 26 +++++-- 4 files changed, 124 insertions(+), 29 deletions(-) create mode 100644 src/Arch/Core/Variadics/EntityExtensions.Variadics.cs diff --git a/src/Arch.SourceGen/QueryGenerator.cs b/src/Arch.SourceGen/QueryGenerator.cs index 23b8f9e6..349f930a 100644 --- a/src/Arch.SourceGen/QueryGenerator.cs +++ b/src/Arch.SourceGen/QueryGenerator.cs @@ -126,6 +126,7 @@ public partial struct QueryDescription namespace Arch.Core.Extensions { + /* public static partial class EntityExtensions { #if !PURE_ECS @@ -136,6 +137,7 @@ public static partial class EntityExtensions {{new StringBuilder().AppendEntityRemoves(25)}} #endif } + */ } """ diff --git a/src/Arch.SourceGen/VariadicGenerator.cs b/src/Arch.SourceGen/VariadicGenerator.cs index febe5757..f4da72cc 100644 --- a/src/Arch.SourceGen/VariadicGenerator.cs +++ b/src/Arch.SourceGen/VariadicGenerator.cs @@ -16,6 +16,7 @@ private class VariadicInfo public string Namespace { get; set; } = string.Empty; public string Usings { get; set; } = string.Empty; public int Count { get; set; } = 0; + public int Start { get; internal set; } } public void Initialize(IncrementalGeneratorInitializationContext context) @@ -26,10 +27,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) //} var infos = context.SyntaxProvider.ForAttributeWithMetadataName("Arch.Core.VariadicAttribute", - (node, token) => - { - return true; - }, + // TODO: slow, make better filter + (node, token) => true, (ctx, token) => { VariadicInfo info = new(); @@ -56,6 +55,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) ns = ns != string.Empty ? containingNamespace.Name + "." + ns : containingNamespace.Name; containingNamespace = containingNamespace.ContainingNamespace; } + info.Namespace = ns; info.Name = ctx.TargetSymbol.Name; info.Code = ctx.TargetNode.ToString(); @@ -64,14 +64,13 @@ public void Initialize(IncrementalGeneratorInitializationContext context) info.Usings += use.ToString() + "\n"; } - // default count is 26 - info.Count = 26; foreach (var attr in ctx.TargetSymbol.GetAttributes()) { if (attr.AttributeClass?.Name == "VariadicAttribute") { info.Type = attr.ConstructorArguments[0].Value as string ?? throw new InvalidOperationException(); - info.Count = Convert.ToInt32(attr.ConstructorArguments[1].Value); + info.Start = Convert.ToInt32(attr.ConstructorArguments[1].Value); + info.Count = Convert.ToInt32(attr.ConstructorArguments[2].Value); break; } } @@ -106,11 +105,11 @@ private string MakeVariadic(VariadicInfo info) var tokens = Tokenize(info).ToList(); StringBuilder combined = new(); - for (var i = 1; i < info.Count; i++) + for (var i = info.Start; i < info.Count; i++) { foreach (var token in tokens) { - combined.AppendLine(token.Transform(i, info.Type)); + combined.AppendLine(token.Transform(info.Start, i + 1, info.Type)); } } @@ -134,15 +133,15 @@ public enum Operation None, // [Variadic: CopyLines(variableName)] CopyLines, - // [Variadic: CopyParams(variableName)] - CopyParams + // [Variadic: CopyArgs(variableName)] + CopyArgs } public Operation Op { get; set; } = Operation.None; public string Line { get; set; } = string.Empty; public string Variable { get; set; } = string.Empty; - public readonly string Transform(int variations, string type) + public readonly string Transform(int start, int variations, string type) { if (Op == Operation.None) { @@ -166,7 +165,7 @@ public readonly string Transform(int variations, string type) StringBuilder variadics = new(); - for (int i = 0; i < variations; i++) + for (int i = start - 1; i < variations; i++) { variadics.Append(VaryType(type, i)); if (i != variations - 1) @@ -177,16 +176,40 @@ public readonly string Transform(int variations, string type) variadics.Append(">"); - // apply generics: expand T0> to T0, T1...> + // apply generics: expand T0> -> T0, T1...> transformed.Replace(type + ">", variadics.ToString()); + + // expand params in header (i.e. T0 component__T0 -> T0 component__T0, T1 component__t1... + var exp = $@"[(,\s]{type}\s+(?\w+)__{type}"; + var paramMatch = Regex.Match(transformed.ToString(), exp); + if (paramMatch.Success) + { + var name = paramMatch.Groups["ParamName"].Value; + + StringBuilder newParams = new(); + for (int i = start - 1; i < variations; i++) + { + var varied = VaryType(type, i); + newParams.Append($"{varied} {name}__{varied}"); + if (i != variations - 1) + { + newParams.Append(", "); + } + } + + transformed.Remove(paramMatch.Index + 1, paramMatch.Length - 1); + transformed.Insert(paramMatch.Index + 1, newParams); + } + return transformed.ToString(); } + if (Op == Operation.CopyLines) { StringBuilder transformed = new(); transformed.AppendLine(Line); - for (int i = 1; i < variations; i++) + for (int i = start; i < variations; i++) { StringBuilder next = new(); next.AppendLine(Line); @@ -195,18 +218,20 @@ public readonly string Transform(int variations, string type) next.Replace(type, variadic); transformed.AppendLine(next.ToString()); } + return transformed.ToString(); } - if (Op == Operation.CopyParams) + + if (Op == Operation.CopyArgs) { StringBuilder transformed = new(); transformed.AppendLine(Line); StringBuilder newVariables = new(); newVariables.Append(Variable + "__" + type); - for (int i = 1; i < variations; i++) + for (int i = start; i < variations; i++) { var variadic = VaryType(type, i); - newVariables.Append(", " + Variable + "__ " + variadic); + newVariables.Append(", " + Variable + "__" + variadic); } transformed.Replace(Variable + "__" + type, newVariables.ToString()); @@ -219,18 +244,19 @@ public readonly string Transform(int variations, string type) private static string VaryType(string typeName, int i) { - var match = Regex.Match(typeName, @"(?\w+)0"); + var match = Regex.Match(typeName, @"(?\w+)[0-9]+"); if (!match.Success) { - throw new InvalidOperationException("Variadic type must be of TypeName0"); + throw new InvalidOperationException("Variadic type must be of TypeName{N}"); } + return $"{match.Groups["PrunedName"]}{i}"; } private IEnumerable Tokenize(VariadicInfo info) { // NOTE: does not support multiline operations, for example this would break: - // // [Variadic: CopyParams(a)] + // // [Variadic: CopyArgs(a)] // MyMethod( // a_T0); var lines = SplitLines(info.Code); @@ -239,6 +265,12 @@ private IEnumerable Tokenize(VariadicInfo info) string nextVariable = string.Empty; foreach (var line in lines) { + if (line.StartsWith("[Variadic(")) + { + // don't include variadic attrs + continue; + } + if (line.StartsWith("//")) { var match = Regex.Match(line, @"\[Variadic:\s*(?\w+)\((?\w+)\)\]"); @@ -250,7 +282,7 @@ private IEnumerable Tokenize(VariadicInfo info) nextOperation = match.Groups["Operation"].Value switch { "CopyLines" => LineInfo.Operation.CopyLines, - "CopyParams" => LineInfo.Operation.CopyParams, + "CopyArgs" => LineInfo.Operation.CopyArgs, _ => throw new NotImplementedException() }; nextVariable = match.Groups["Variable"].Value; diff --git a/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs new file mode 100644 index 00000000..ab5e1609 --- /dev/null +++ b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs @@ -0,0 +1,49 @@ +using System.Diagnostics.Contracts; + +namespace Arch.Core.Variadics; +public static partial class EntityExtensions +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Pure] + [Variadic(nameof(T1), 2)] + public static bool Has(this Entity entity) + { + var world = World.Worlds[entity.WorldId]; + return world.Has(entity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T1), 2)] + public static void Set(this Entity entity, T0 component__T0, T1 component__T1) + { + var world = World.Worlds[entity.WorldId]; + // [Variadic: CopyArgs(component)] + world.Set(entity, component__T0, component__T1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Pure] + [Variadic(nameof(T1), 2)] + public static Components Get(this Entity entity) + { + var world = World.Worlds[entity.WorldId]; + return world.Get(entity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T1), 2)] + public static void Add(this Entity entity, in T0 component__T0, in T1 component__T1) + { + var world = World.Worlds[entity.WorldId]; + // [Variadic: CopyArgs(component)] + world.Add(entity, component__T0, component__T1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T1), 2)] + public static void Remove(this Entity entity) + { + var world = World.Worlds[entity.WorldId]; + world.Remove(entity); + } +} diff --git a/src/Arch/VariadicAttribute.cs b/src/Arch/VariadicAttribute.cs index ee10bf18..e8172c1a 100644 --- a/src/Arch/VariadicAttribute.cs +++ b/src/Arch/VariadicAttribute.cs @@ -2,14 +2,26 @@ namespace Arch.Core; +/// +/// Tags a method or type as being variadic; i.e. generating many generic parameters. +/// [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct)] internal class VariadicAttribute : Attribute { - public string Name { get; } - public int Count { get; } - public VariadicAttribute(string name, int count = 26) - { - Name = name; - Count = count; - } + /// + /// Tag a method or type as being variadic; i.e. generating many generic parameters. + /// + /// + /// The name of the type to begin. For example, if your method is Add<T0, T1>, it would be nameof(T1). + /// + /// + /// The current template after which to begin generating. + /// For example, if you've already defined signatures T0 and T0, T1, and have the latter annotated as [Variadic], + /// mark the current template as start = 2. + /// + /// + /// The end template to generate. For example, if there should be up to T0, ... T24 variadics, would be 25. + /// + [SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Instance params not necessary for sourcegen.")] + public VariadicAttribute(string name, int start = 2, int count = 25) { } } From 30b883b847726ec8a6ebea5c3151a97cf20a09f7 Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Sat, 28 Oct 2023 00:09:44 -0700 Subject: [PATCH 03/16] add jobs variadics --- src/Arch.SourceGen/QueryGenerator.cs | 2 + src/Arch.SourceGen/VariadicGenerator.cs | 58 +++++++++--- .../Variadics/EntityExtensions.Variadics.cs | 2 +- src/Arch/Core/Variadics/Jobs.Variadics.cs | 93 +++++++++++++++++++ src/Arch/VariadicAttribute.cs | 8 +- 5 files changed, 142 insertions(+), 21 deletions(-) create mode 100644 src/Arch/Core/Variadics/Jobs.Variadics.cs diff --git a/src/Arch.SourceGen/QueryGenerator.cs b/src/Arch.SourceGen/QueryGenerator.cs index 349f930a..46ca1105 100644 --- a/src/Arch.SourceGen/QueryGenerator.cs +++ b/src/Arch.SourceGen/QueryGenerator.cs @@ -48,10 +48,12 @@ public void Initialize(IncrementalGeneratorInitializationContext context) jobs.AppendLine("using System.Runtime.CompilerServices;"); jobs.AppendLine("using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;"); jobs.AppendLine("namespace Arch.Core;"); + jobs.AppendLine("/*"); jobs.AppendForEachJobs(25); jobs.AppendEntityForEachJobs(25); jobs.AppendIForEachJobs(25); jobs.AppendIForEachWithEntityJobs(25); + jobs.AppendLine("*/"); var accessors = new StringBuilder(); accessors.AppendLine("using System;"); diff --git a/src/Arch.SourceGen/VariadicGenerator.cs b/src/Arch.SourceGen/VariadicGenerator.cs index f4da72cc..d55f2280 100644 --- a/src/Arch.SourceGen/VariadicGenerator.cs +++ b/src/Arch.SourceGen/VariadicGenerator.cs @@ -1,5 +1,6 @@ using System.Text.RegularExpressions; using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Linq; namespace Arch.SourceGen; @@ -113,15 +114,18 @@ private string MakeVariadic(VariadicInfo info) } } + if (info.EnclosingType != string.Empty) + { + combined.Insert(0, info.EnclosingType + "{"); + combined.AppendLine("}"); + } + return $$""" {{info.Usings}} namespace {{info.Namespace}}; - {{info.EnclosingType}} - { - {{combined}} - } + {{combined}} """; } @@ -131,7 +135,7 @@ public LineInfo() { } public enum Operation { None, - // [Variadic: CopyLines(variableName)] + // [Variadic: CopyLines(variableName, variableName2)] CopyLines, // [Variadic: CopyArgs(variableName)] CopyArgs @@ -139,7 +143,7 @@ public enum Operation public Operation Op { get; set; } = Operation.None; public string Line { get; set; } = string.Empty; - public string Variable { get; set; } = string.Empty; + public string[] Variables { get; set; } = Array.Empty(); public readonly string Transform(int start, int variations, string type) { @@ -214,7 +218,11 @@ public readonly string Transform(int start, int variations, string type) StringBuilder next = new(); next.AppendLine(Line); var variadic = VaryType(type, i); - next.Replace(Variable + "__" + type, Variable + "__" + variadic); + foreach (var variable in Variables) + { + next.Replace(variable + "__" + type, variable + "__" + variadic); + } + next.Replace(type, variadic); transformed.AppendLine(next.ToString()); } @@ -224,17 +232,33 @@ public readonly string Transform(int start, int variations, string type) if (Op == Operation.CopyArgs) { + if (Variables.Length != 1) + { + throw new InvalidOperationException($"{nameof(Operation.CopyArgs)} only supports 1 variable."); + } + StringBuilder transformed = new(); transformed.AppendLine(Line); StringBuilder newVariables = new(); - newVariables.Append(Variable + "__" + type); + + // match ref, in, out + var modifiersMatch = Regex.Match(Line, $@"[(,]\s*(?\w+?)?\s*{Variables[0]}__{type}"); + if (!modifiersMatch.Success) + { + throw new InvalidOperationException($"Can't find variable {Variables[0]}__{type} in a parameter list."); + } + + var modifiers = modifiersMatch.Groups["Modifiers"].Value; + + newVariables.Append($"{modifiers} {Variables[0]}__{type}"); for (int i = start; i < variations; i++) { var variadic = VaryType(type, i); - newVariables.Append(", " + Variable + "__" + variadic); + newVariables.Append($", {modifiers} {Variables[0]}__{variadic}"); } - transformed.Replace(Variable + "__" + type, newVariables.ToString()); + transformed.Remove(modifiersMatch.Index + 1, modifiersMatch.Length - 1); + transformed.Insert(modifiersMatch.Index + 1, newVariables.ToString()); return transformed.ToString(); } @@ -262,7 +286,7 @@ private IEnumerable Tokenize(VariadicInfo info) var lines = SplitLines(info.Code); LineInfo.Operation nextOperation = LineInfo.Operation.None; - string nextVariable = string.Empty; + List nextVariables = new(); foreach (var line in lines) { if (line.StartsWith("[Variadic(")) @@ -273,7 +297,7 @@ private IEnumerable Tokenize(VariadicInfo info) if (line.StartsWith("//")) { - var match = Regex.Match(line, @"\[Variadic:\s*(?\w+)\((?\w+)\)\]"); + var match = Regex.Match(line, @"\[Variadic:\s*(?\w+)\((?:(?\w+),?\s*)+\)\]"); if (!match.Success) { continue; @@ -285,7 +309,11 @@ private IEnumerable Tokenize(VariadicInfo info) "CopyArgs" => LineInfo.Operation.CopyArgs, _ => throw new NotImplementedException() }; - nextVariable = match.Groups["Variable"].Value; + + foreach (Capture capture in match.Groups["Variable"].Captures) + { + nextVariables.Add(capture.Value); + } continue; } @@ -293,10 +321,10 @@ private IEnumerable Tokenize(VariadicInfo info) var lineInfo = new LineInfo() { Line = line, - Variable = nextVariable, + Variables = nextVariables.ToArray(), Op = nextOperation }; - nextVariable = string.Empty; + nextVariables.Clear(); nextOperation = LineInfo.Operation.None; yield return lineInfo; } diff --git a/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs index ab5e1609..61edd139 100644 --- a/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs +++ b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs @@ -1,6 +1,6 @@ using System.Diagnostics.Contracts; -namespace Arch.Core.Variadics; +namespace Arch.Core; public static partial class EntityExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Arch/Core/Variadics/Jobs.Variadics.cs b/src/Arch/Core/Variadics/Jobs.Variadics.cs new file mode 100644 index 00000000..7a09c4b8 --- /dev/null +++ b/src/Arch/Core/Variadics/Jobs.Variadics.cs @@ -0,0 +1,93 @@ +namespace Arch.Core; + +[Variadic(nameof(T0), 1, 25)] +public struct ForEachJob : IChunkJob +{ + public ForEach ForEach; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly void Execute(int index, ref Chunk chunk) + { + var chunkSize = chunk.Size; + // [Variadic: CopyLines(firstElement)] + ref var firstElement__T0 = ref chunk.GetFirst(); + + for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) + { + // [Variadic: CopyLines(component, firstElement)] + ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + // [Variadic: CopyArgs(component)] + ForEach(ref component__T0); + } + } +} + +[Variadic(nameof(T0), 1, 25)] +public struct ForEachWithEntityJob : IChunkJob +{ + public ForEachWithEntity ForEach; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly void Execute(int index, ref Chunk chunk) + { + ref var entityFirstElement = ref chunk.Entity(0); + var chunkSize = chunk.Size; + // [Variadic: CopyLines(firstElement)] + ref var firstElement__T0 = ref chunk.GetFirst(); + + for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) + { + var entity = Unsafe.Add(ref entityFirstElement, entityIndex); + // [Variadic: CopyLines(component, firstElement)] + ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + // [Variadic: CopyArgs(component)] + ForEach(entity, ref component__T0); + } + } +} + +[Variadic(nameof(T0), 1, 25)] +public struct IForEachJob : IChunkJob where T : struct, IForEach +{ + public T ForEach; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Execute(int index, ref Chunk chunk) + { + var chunkSize = chunk.Size; + // [Variadic: CopyLines(firstElement)] + ref var firstElement__T0 = ref chunk.GetFirst(); + + for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) + { + // [Variadic: CopyLines(component, firstElement)] + ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + // [Variadic: CopyArgs(component)] + ForEach.Update(ref component__T0); + } + } +} + +[Variadic(nameof(T0), 1, 25)] +public struct IForEachWithEntityJob : IChunkJob where T : struct, IForEachWithEntity +{ + public T ForEach; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Execute(int index, ref Chunk chunk) + { + var chunkSize = chunk.Size; + ref var entityFirstElement = ref chunk.Entity(0); + // [Variadic: CopyLines(firstElement)] + ref var firstElement__T0 = ref chunk.GetFirst(); + + for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) + { + var entity = Unsafe.Add(ref entityFirstElement, entityIndex); + // [Variadic: CopyLines(component, firstElement)] + ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + // [Variadic: CopyArgs(component)] + ForEach.Update(entity, ref component__T0); + } + } +} diff --git a/src/Arch/VariadicAttribute.cs b/src/Arch/VariadicAttribute.cs index e8172c1a..237e7ebc 100644 --- a/src/Arch/VariadicAttribute.cs +++ b/src/Arch/VariadicAttribute.cs @@ -1,11 +1,9 @@ -using System; - -namespace Arch.Core; +namespace Arch.Core; /// /// Tags a method or type as being variadic; i.e. generating many generic parameters. /// -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct)] +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Delegate)] internal class VariadicAttribute : Attribute { /// @@ -23,5 +21,5 @@ internal class VariadicAttribute : Attribute /// The end template to generate. For example, if there should be up to T0, ... T24 variadics, would be 25. /// [SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Instance params not necessary for sourcegen.")] - public VariadicAttribute(string name, int start = 2, int count = 25) { } + public VariadicAttribute(string name, int start = 1, int count = 25) { } } From 4203315f7972e2a6a6c762f5ae1c9ad0cb57de24 Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Sat, 28 Oct 2023 00:14:12 -0700 Subject: [PATCH 04/16] disable entity extension variadics for pure ecs --- src/Arch/Core/Variadics/EntityExtensions.Variadics.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs index 61edd139..f3d93616 100644 --- a/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs +++ b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs @@ -1,6 +1,7 @@ using System.Diagnostics.Contracts; namespace Arch.Core; +#if !PURE_ECS public static partial class EntityExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -47,3 +48,4 @@ public static void Remove(this Entity entity) world.Remove(entity); } } +#endif From 928ce2defeaff6dd09c2cb2a35c66c7feac95e09 Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Tue, 31 Oct 2023 04:03:32 -0700 Subject: [PATCH 05/16] convert more sourcegen to variadics --- src/Arch.Benchmarks/QueryBenchmark.cs | 12 +- src/Arch.SourceGen/QueryGenerator.cs | 16 ++- src/Arch.SourceGen/VariadicGenerator.cs | 129 ++++++++++++++--- src/Arch.Tests/EntityTest.cs | 8 +- src/Arch.Tests/WorldTest.cs | 8 +- .../Core/Variadics/Archetype.Variadics.cs | 67 +++++++++ src/Arch/Core/Variadics/Chunk.Variadics.cs | 136 ++++++++++++++++++ .../Core/Variadics/Components.Variadics.cs | 75 ++++++++++ src/Arch/Core/Variadics/ForEach.Variadics.cs | 15 ++ src/Arch/Core/Variadics/Group.Variadics.cs | 30 ++++ .../Core/Variadics/Interfaces.Variadics.cs | 17 +++ src/Arch/Core/Variadics/Jobs.Variadics.cs | 16 +-- src/Arch/Core/Variadics/World.Variadics.cs | 43 ++++++ src/Arch/VariadicAttribute.cs | 2 +- 14 files changed, 531 insertions(+), 43 deletions(-) create mode 100644 src/Arch/Core/Variadics/Archetype.Variadics.cs create mode 100644 src/Arch/Core/Variadics/Chunk.Variadics.cs create mode 100644 src/Arch/Core/Variadics/Components.Variadics.cs create mode 100644 src/Arch/Core/Variadics/ForEach.Variadics.cs create mode 100644 src/Arch/Core/Variadics/Group.Variadics.cs create mode 100644 src/Arch/Core/Variadics/Interfaces.Variadics.cs create mode 100644 src/Arch/Core/Variadics/World.Variadics.cs diff --git a/src/Arch.Benchmarks/QueryBenchmark.cs b/src/Arch.Benchmarks/QueryBenchmark.cs index 206e10cd..3908c044 100644 --- a/src/Arch.Benchmarks/QueryBenchmark.cs +++ b/src/Arch.Benchmarks/QueryBenchmark.cs @@ -37,8 +37,8 @@ public void WorldEntityQuery() { var refs = _world.Get(entity); - refs.t0.X += refs.t1.X; - refs.t0.Y += refs.t1.Y; + refs.Component__T0.X += refs.Component__T1.X; + refs.Component__T0.Y += refs.Component__T1.Y; }); } @@ -49,8 +49,8 @@ public void EntityExtensionQuery() _world.Query(in _queryDescription, (Entity entity) => { var refs = entity.Get(); - refs.t0.X += refs.t1.X; - refs.t0.Y += refs.t1.Y; + refs.Component__T0.X += refs.Component__T1.X; + refs.Component__T0.Y += refs.Component__T1.Y; }); } #endif @@ -84,8 +84,8 @@ public void Iterator() var refs = chunk.GetFirst(); foreach (var entity in chunk) { - ref var pos = ref Unsafe.Add(ref refs.t0, entity); - ref var vel = ref Unsafe.Add(ref refs.t1, entity); + ref var pos = ref Unsafe.Add(ref refs.Component__T0, entity); + ref var vel = ref Unsafe.Add(ref refs.Component__T1, entity); pos.X += vel.X; pos.Y += vel.Y; diff --git a/src/Arch.SourceGen/QueryGenerator.cs b/src/Arch.SourceGen/QueryGenerator.cs index 46ca1105..8cc285de 100644 --- a/src/Arch.SourceGen/QueryGenerator.cs +++ b/src/Arch.SourceGen/QueryGenerator.cs @@ -15,33 +15,41 @@ public void Initialize(IncrementalGeneratorInitializationContext context) context.RegisterPostInitializationOutput(initializationContext => { - + // DONE var compileTimeStatics = new StringBuilder(); compileTimeStatics.AppendLine("using System;"); compileTimeStatics.AppendLine("using System.Threading;"); compileTimeStatics.AppendLine("namespace Arch.Core.Utils;"); + compileTimeStatics.AppendLine("/*"); compileTimeStatics.AppendGroups(25); + compileTimeStatics.AppendLine("*/"); var delegates = new StringBuilder(); delegates.AppendLine("using System;"); delegates.AppendLine("namespace Arch.Core;"); + delegates.AppendLine("/*"); delegates.AppendForEachDelegates(25); delegates.AppendForEachEntityDelegates(25); + delegates.AppendLine("*/"); var interfaces = new StringBuilder(); interfaces.AppendLine("using System;"); interfaces.AppendLine("using System.Runtime.CompilerServices;"); interfaces.AppendLine("namespace Arch.Core;"); + interfaces.AppendLine("/*"); interfaces.AppendInterfaces(25); interfaces.AppendEntityInterfaces(25); + interfaces.AppendLine("*/"); var references = new StringBuilder(); references.AppendLine("using System;"); references.AppendLine("using System.Runtime.CompilerServices;"); references.AppendLine("using CommunityToolkit.HighPerformance;"); references.AppendLine("namespace Arch.Core;"); + references.AppendLine("/*"); references.AppendComponents(25); references.AppendEntityComponents(25); + references.AppendLine("*/"); var jobs = new StringBuilder(); jobs.AppendLine("using System;"); @@ -73,6 +81,7 @@ namespace Arch.Core { public partial struct Chunk { + /* {{new StringBuilder().AppendChunkIndexes(25)}} {{new StringBuilder().AppendChunkHases(25)}} {{new StringBuilder().AppendChunkIndexGets(25)}} @@ -82,19 +91,24 @@ public partial struct Chunk {{new StringBuilder().AppendChunkGetArrays(25)}} {{new StringBuilder().AppendChunkGetSpans(25)}} {{new StringBuilder().AppendChunkGetFirsts(25)}} + */ } public partial class Archetype { + /* {{new StringBuilder().AppendArchetypeHases(25)}} {{new StringBuilder().AppendArchetypeGets(25)}} {{new StringBuilder().AppendArchetypeSets(25)}} {{new StringBuilder().AppendArchetypeSetRanges(25)}} + */ } public partial class World { + /* {{new StringBuilder().AppendCreates(25)}} + */ {{new StringBuilder().AppendWorldHases(25)}} {{new StringBuilder().AppendWorldGets(25)}} {{new StringBuilder().AppendWorldSets(25)}} diff --git a/src/Arch.SourceGen/VariadicGenerator.cs b/src/Arch.SourceGen/VariadicGenerator.cs index d55f2280..6403daed 100644 --- a/src/Arch.SourceGen/VariadicGenerator.cs +++ b/src/Arch.SourceGen/VariadicGenerator.cs @@ -22,11 +22,8 @@ private class VariadicInfo public void Initialize(IncrementalGeneratorInitializationContext context) { - //if (!Debugger.IsAttached) - //{ - // //Debugger.Launch(); - //} + //Debugger.Launch(); var infos = context.SyntaxProvider.ForAttributeWithMetadataName("Arch.Core.VariadicAttribute", // TODO: slow, make better filter (node, token) => true, @@ -135,10 +132,15 @@ public LineInfo() { } public enum Operation { None, - // [Variadic: CopyLines(variableName, variableName2)] + // [Variadic: CopyLines] CopyLines, // [Variadic: CopyArgs(variableName)] - CopyArgs + CopyArgs, + // [Variadic: CopyParams(enclosingTypeName)] + // necessary for params like Span span__T0... + // or nullables, or defaults. + // But the default behavior Operation.None works for most methods. + CopyParams } public Operation Op { get; set; } = Operation.None; @@ -180,21 +182,24 @@ public readonly string Transform(int start, int variations, string type) variadics.Append(">"); - // apply generics: expand T0> -> T0, T1...> + // Apply generics: expand T0> -> T0, T1...> transformed.Replace(type + ">", variadics.ToString()); - // expand params in header (i.e. T0 component__T0 -> T0 component__T0, T1 component__t1... - var exp = $@"[(,\s]{type}\s+(?\w+)__{type}"; + // Expand params in header (i.e. T0 component__T0 -> T0 component__T0, T1 component__t1... + // This is the 90% case. Occasionally there needs to be special handling for a method header. + // Those cases are handled by Operation.CopyParams + var exp = $@"[(,]\s*(?(?:in|out|ref|ref\s+readonly)\s+)?{type}\s+(?\w+)__{type}"; var paramMatch = Regex.Match(transformed.ToString(), exp); if (paramMatch.Success) { var name = paramMatch.Groups["ParamName"].Value; + var modifiers = paramMatch.Groups["Modifiers"].Value; StringBuilder newParams = new(); for (int i = start - 1; i < variations; i++) { var varied = VaryType(type, i); - newParams.Append($"{varied} {name}__{varied}"); + newParams.Append($"{modifiers} {varied} {name}__{varied}"); if (i != variations - 1) { newParams.Append(", "); @@ -210,6 +215,11 @@ public readonly string Transform(int start, int variations, string type) if (Op == Operation.CopyLines) { + if (Variables.Length != 0) + { + throw new InvalidOperationException($"{nameof(Operation.CopyLines)} does not support variables."); + } + StringBuilder transformed = new(); transformed.AppendLine(Line); @@ -218,11 +228,6 @@ public readonly string Transform(int start, int variations, string type) StringBuilder next = new(); next.AppendLine(Line); var variadic = VaryType(type, i); - foreach (var variable in Variables) - { - next.Replace(variable + "__" + type, variable + "__" + variadic); - } - next.Replace(type, variadic); transformed.AppendLine(next.ToString()); } @@ -242,7 +247,7 @@ public readonly string Transform(int start, int variations, string type) StringBuilder newVariables = new(); // match ref, in, out - var modifiersMatch = Regex.Match(Line, $@"[(,]\s*(?\w+?)?\s*{Variables[0]}__{type}"); + var modifiersMatch = Regex.Match(Line, $@"[(,]\s*(?(ref|out ref|out var|out {type}\??|in|ref {type}\??))?\s*{Variables[0]}__{type}"); if (!modifiersMatch.Success) { throw new InvalidOperationException($"Can't find variable {Variables[0]}__{type} in a parameter list."); @@ -259,6 +264,88 @@ public readonly string Transform(int start, int variations, string type) transformed.Remove(modifiersMatch.Index + 1, modifiersMatch.Length - 1); transformed.Insert(modifiersMatch.Index + 1, newVariables.ToString()); + + // expand any remaining generics + // note that this'll break if the user uses Span instead of var or something. + StringBuilder variadics = new(); + for (int i = start - 1; i < variations; i++) + { + variadics.Append(VaryType(type, i)); + if (i != variations - 1) + { + variadics.Append(", "); + } + } + + variadics.Append(">"); + + // Apply generics: expand T0> -> T0, T1...> + transformed.Replace(type + ">", variadics.ToString()); + + + return transformed.ToString(); + } + + if (Op == Operation.CopyParams) + { + if (Variables.Length != 1) + { + throw new InvalidOperationException($"{nameof(Operation.CopyParams)} only supports 1 type variable."); + } + + // This is a special algorithm denotion for method headers. + // This grabs the first param that matches the passed in type (in Variables[0]), like "Span? paramName__T0 = default" + // it extracts paramName, the initializer if it exists, any ref/out/in modifiers, and repeats it according to the type params. + var headerMatch = Regex.Match(Line, $@"[(,]\s*(?(ref|out|ref readonly|in)\s+)?{Regex.Escape(Variables[0])}\s+(?\w+)__{type}\s*(?=\s*default)?"); + + if (!headerMatch.Success) + { + throw new InvalidOperationException($"Malformed method header for {nameof(Operation.CopyParams)}."); + } + + bool hasDefault = headerMatch.Groups["Assignment"].Success; + string modifiers = headerMatch.Groups["Modifiers"].Success ? headerMatch.Groups["Modifiers"].Value : string.Empty; + string param = headerMatch.Groups["ParamName"].Value; + + List additionalParams = new(); + for (int i = start; i < variations; i++) + { + var variadic = VaryType(type, i); + // One issue with this approach... if we had a wrapper type of SomethingT1 (which is bad name but whatever) then this would break. + // but so far we don't have anything like that. + var fullType = Variables[0].Replace(type, variadic); + additionalParams.Add($"{modifiers} {fullType} {param}__{variadic} {(hasDefault ? "= default" : "")}"); + } + + StringBuilder transformed = new(); + transformed.Append(Line); + + StringBuilder @params = new(); + // +1 to exclude the opening parenthesis or comma + @params.Append(Line.Substring(headerMatch.Index + 1, headerMatch.Length - 1)); + foreach (var additionalParam in additionalParams) + { + @params.Append(", " + additionalParam); + } + + // For the rest of the line, we do a trick: we want to apply the regular op on the rest of the header, so we remove all args and re-add them after. + // We do this so we don't have to process constraints separately. + transformed.Remove(headerMatch.Index + 1, headerMatch.Length - 1); + var fakeLine = new LineInfo() + { + Line = transformed.ToString(), + Op = Operation.None + }; + transformed.Clear(); + var fakeLineTf = fakeLine.Transform(start, variations, type); + transformed.Append(fakeLineTf); + + // find where we left off; we either left a hanging comma or an () + var match = Regex.Match(transformed.ToString(), @"(,\s*\)|\(\s*\))"); + Debug.Assert(match.Success); + // stick our params back in there + transformed.Insert(match.Index + 1, @params); + return transformed.ToString(); } @@ -297,7 +384,7 @@ private IEnumerable Tokenize(VariadicInfo info) if (line.StartsWith("//")) { - var match = Regex.Match(line, @"\[Variadic:\s*(?\w+)\((?:(?\w+),?\s*)+\)\]"); + var match = Regex.Match(line, @"\[Variadic:\s*(?\w+)(?:\((?:(?[?\w\[\]<>]+),?\s*)+\)\])?"); if (!match.Success) { continue; @@ -307,12 +394,16 @@ private IEnumerable Tokenize(VariadicInfo info) { "CopyLines" => LineInfo.Operation.CopyLines, "CopyArgs" => LineInfo.Operation.CopyArgs, + "CopyParams" => LineInfo.Operation.CopyParams, _ => throw new NotImplementedException() }; - foreach (Capture capture in match.Groups["Variable"].Captures) + if (match.Groups["Variable"].Success) { - nextVariables.Add(capture.Value); + foreach (Capture capture in match.Groups["Variable"].Captures) + { + nextVariables.Add(capture.Value); + } } continue; diff --git a/src/Arch.Tests/EntityTest.cs b/src/Arch.Tests/EntityTest.cs index adbccff8..de28c2ba 100644 --- a/src/Arch.Tests/EntityTest.cs +++ b/src/Arch.Tests/EntityTest.cs @@ -155,10 +155,10 @@ public void GeneratedSetAndGet() _entity.Set(new Transform { X = 10, Y = 10 }, new Rotation { X = 10, Y = 10 }); var refs = _entity.Get(); - AreEqual(10, refs.t0.X); - AreEqual(10, refs.t0.Y); - AreEqual(10, refs.t1.X); - AreEqual(10, refs.t1.Y); + AreEqual(10, refs.Component__T0.X); + AreEqual(10, refs.Component__T0.Y); + AreEqual(10, refs.Component__T1.X); + AreEqual(10, refs.Component__T1.Y); } /// diff --git a/src/Arch.Tests/WorldTest.cs b/src/Arch.Tests/WorldTest.cs index 6b46709a..91376f2c 100644 --- a/src/Arch.Tests/WorldTest.cs +++ b/src/Arch.Tests/WorldTest.cs @@ -622,10 +622,10 @@ public void GeneratedSetGetAndHas() _world.Set(entity, new Transform { X = 20, Y = 20 }, new Rotation { X = 20, Y = 20 }); var references = _world.Get(entity); - That(references.t0.X, Is.EqualTo(20)); - That(references.t0.Y, Is.EqualTo(20)); - That(references.t1.X, Is.EqualTo(20)); - That(references.t1.Y, Is.EqualTo(20)); + That(references.Component__T0.X, Is.EqualTo(20)); + That(references.Component__T0.Y, Is.EqualTo(20)); + That(references.Component__T1.X, Is.EqualTo(20)); + That(references.Component__T1.Y, Is.EqualTo(20)); } /// diff --git a/src/Arch/Core/Variadics/Archetype.Variadics.cs b/src/Arch/Core/Variadics/Archetype.Variadics.cs new file mode 100644 index 00000000..c4b83cb3 --- /dev/null +++ b/src/Arch/Core/Variadics/Archetype.Variadics.cs @@ -0,0 +1,67 @@ +using Arch.Core.Utils; + +namespace Arch.Core; +public partial class Archetype +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T1), 2, 25)] + public bool Has() + { + var componentId__T0 = Component.ComponentType.Id; + // [Variadic: CopyLines] + var componentId__T1 = Component.ComponentType.Id; + return BitSet.IsSet(componentId__T0) && + // [Variadic: CopyLines] + BitSet.IsSet(componentId__T1) && + true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T1), 2, 25)] + internal unsafe Components Get(scoped ref Slot slot) + { + ref var chunk = ref GetChunk(slot.ChunkIndex); + return chunk.Get(slot.Index); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T1), 2, 25)] + internal void Set(ref Slot slot, in T0 component__T0, in T1 component__T1) + { + ref var chunk = ref GetChunk(slot.ChunkIndex); + // [Variadic: CopyArgs(component)] + chunk.Set(slot.Index, in component__T0, in component__T1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T1), 2, 25)] + // [Variadic: CopyParams(T1)] + internal void SetRange(in Slot from, in Slot to, in T0 componentValue__T0 = default, in T1 componentValue__T1 = default) + { + // Set the added component, start from the last slot and move down + for (var chunkIndex = from.ChunkIndex; chunkIndex >= to.ChunkIndex; --chunkIndex) + { + ref var chunk = ref GetChunk(chunkIndex); + ref var firstElement__T0 = ref chunk.GetFirst(); + // [Variadic: CopyLines] + ref var firstElement__T1 = ref chunk.GetFirst(); + + // Only move within the range, depening on which chunk we are at. + var isStart = chunkIndex == from.ChunkIndex; + var isEnd = chunkIndex == to.ChunkIndex; + + var upper = isStart ? from.Index : chunk.Size - 1; + var lower = isEnd ? to.Index : 0; + + for (var entityIndex = upper; entityIndex >= lower; --entityIndex) + { + ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + // [Variadic: CopyLines] + ref var component__T1 = ref Unsafe.Add(ref firstElement__T1, entityIndex); + component__T0 = componentValue__T0; + // [Variadic: CopyLines] + component__T1 = componentValue__T1; + } + } + } +} diff --git a/src/Arch/Core/Variadics/Chunk.Variadics.cs b/src/Arch/Core/Variadics/Chunk.Variadics.cs new file mode 100644 index 00000000..64d7eba7 --- /dev/null +++ b/src/Arch/Core/Variadics/Chunk.Variadics.cs @@ -0,0 +1,136 @@ +using System.Diagnostics.Contracts; +using Arch.Core.Utils; +using CommunityToolkit.HighPerformance; + +namespace Arch.Core; + +public partial struct Chunk +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T1), 2, 25)] + [Pure] + // [Variadic: CopyParams(int)] + private readonly void Index(out int index__T0, out int index__T1) + { + ref var componentIdToArrayFirstElement = ref ComponentIdToArrayIndex.DangerousGetReference(); + index__T0 = Unsafe.Add(ref componentIdToArrayFirstElement, Component.ComponentType.Id); + // [Variadic: CopyLines] + index__T1 = Unsafe.Add(ref componentIdToArrayFirstElement, Component.ComponentType.Id); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Pure] + [Variadic(nameof(T1), 2, 25)] + [SuppressMessage("Style", "IDE0011:Add braces", Justification = "Enables single-line statements")] + [SuppressMessage("Style", "IDE2001:Embedded statements must be on their own line", Justification = "Enables single-line statements")] + public readonly bool Has() + { + var componentId__T0 = Component.ComponentType.Id; + // [Variadic: CopyLines] + var componentId__T1 = Component.ComponentType.Id; + + if (componentId__T0 >= ComponentIdToArrayIndex.Length) return false; + // [Variadic: CopyLines] + if (componentId__T1 >= ComponentIdToArrayIndex.Length) return false; + + if (ComponentIdToArrayIndex[componentId__T0] == -1) return false; + // [Variadic: CopyLines] + if (ComponentIdToArrayIndex[componentId__T1] == -1) return false; + + return true; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Pure] + [Variadic(nameof(T1), 2, 25)] + public Components Get(int index) + { + // [Variadic: CopyArgs(array)] + GetArray(out var array__T0, out var array__T1); + ref var component__T0 = ref array__T0[index]; + // [Variadic: CopyLines] + ref var component__T1 = ref array__T1[index]; + + // [Variadic: CopyArgs(component)] + return new Components(ref component__T0, ref component__T1); + } + + /// + [Variadic(nameof(T1), 2, 25)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Pure] + public EntityComponents GetRow(int index) + { + // [Variadic: CopyArgs(array)] + GetArray(out var array__T0, out var array__T1); + + ref var entity = ref Entities[index]; + ref var component__T0 = ref array__T0[index]; + // [Variadic: CopyLines] + ref var component__T1 = ref array__T1[index]; + + // [Variadic: CopyArgs(component)] + return new EntityComponents(ref entity, ref component__T0, ref component__T1); + } + + /// + [Variadic(nameof(T1), 2, 25)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Set(int index, in T0 component__T0, in T1 component__T1) + { + // [Variadic: CopyArgs(array)] + GetArray(out var array__T0, out var array__T1); + + array__T0[index] = component__T0; + // [Variadic: CopyLines] + array__T1[index] = component__T1; + } + + /// + [Variadic(nameof(T1), 2, 25)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Pure] + // [Variadic: CopyParams(T1[])] + public void GetArray(out T0[] array__T0, out T1[] array__T1) + { + // [Variadic: CopyArgs(index)] + Index(out var index__T0, out var index__T1); + ref var arrays = ref Components.DangerousGetReference(); + array__T0 = Unsafe.As(Unsafe.Add(ref arrays, index__T0)); + + // [Variadic: CopyLines] + array__T1 = Unsafe.As(Unsafe.Add(ref arrays, index__T1)); + } + + [Variadic(nameof(T1), 2, 25)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Pure] + // [Variadic: CopyParams(Span)] + public void GetSpan(out Span span__T0, out Span span__T1) + { + // [Variadic: CopyArgs(array)] + GetArray(out var array__T0, out var array__T1); + span__T0 = new Span(array__T0); + + // [Variadic: CopyLines] + span__T1 = new Span(array__T1); + } + + [Variadic(nameof(T1), 2, 25)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Pure] + public Components GetFirst() + { + // [Variadic: CopyArgs(array)] + GetArray(out var array__T0, out var array__T1); + + ref var arrayRef__T0 = ref array__T0.DangerousGetReference(); + // [Variadic: CopyLines]; + ref var arrayRef__T1 = ref array__T1.DangerousGetReference(); + + // [Variadic: CopyArgs(arrayRef)] + return new Components(ref arrayRef__T0, ref arrayRef__T1); + } +} diff --git a/src/Arch/Core/Variadics/Components.Variadics.cs b/src/Arch/Core/Variadics/Components.Variadics.cs new file mode 100644 index 00000000..88a63259 --- /dev/null +++ b/src/Arch/Core/Variadics/Components.Variadics.cs @@ -0,0 +1,75 @@ +using CommunityToolkit.HighPerformance; + +namespace Arch.Core; + +/// +/// Stores a reference group of up to 25 components. +/// +[SkipLocalsInit] +[Variadic(nameof(T0), 1, 25)] +public ref struct Components +{ + /// + /// A component. + /// +#if NETSTANDARD2_1 || NET6_0 + // [Variadic: CopyLines] + public Ref Component__T0; +#else + // [Variadic: CopyLines] + public ref T0 Component__T0; +#endif + + /// + /// Creates a new instance of the struct. + /// + [SkipLocalsInit] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Components(ref T0 component__T0) + { +#if NETSTANDARD2_1 || NET6_0 + // [Variadic: CopyLines] + Component__T0 = new Ref(ref component__T0); +#else + // [Variadic: CopyLines] + Component__T0 = ref component__T0; +#endif + } +} + +/// +/// Stores a reference group of up to 25 components, as well as an entity. +/// +[SkipLocalsInit] +[Variadic(nameof(T0), 1, 25)] +public ref struct EntityComponents +{ + +#if NETSTANDARD2_1 || NET6_0 + public ReadOnlyRef Entity; + // [Variadic: CopyLines] + public Ref Component__T0; +#else + public ref readonly Entity Entity; + // [Variadic: CopyLines] + public ref T0 Component__T0; +#endif + + /// + /// Creates a new instance of the struct. + /// + [SkipLocalsInit] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EntityComponents(ref Entity entity, ref T0 component__T0) + { +#if NETSTANDARD2_1 || NET6_0 + Entity = new ReadOnlyRef(in entity); + // [Variadic: CopyLines] + Component__T0 = new Ref(ref component__T0); +#else + Entity = ref entity; + // [Variadic: CopyLines] + Component__T0 = ref component__T0; +#endif + } +} diff --git a/src/Arch/Core/Variadics/ForEach.Variadics.cs b/src/Arch/Core/Variadics/ForEach.Variadics.cs new file mode 100644 index 00000000..64db8c7c --- /dev/null +++ b/src/Arch/Core/Variadics/ForEach.Variadics.cs @@ -0,0 +1,15 @@ +namespace Arch.Core; + +/// +/// The delegate +/// provides a callback to execute logic on up to 25 component types. +/// +[Variadic(nameof(T0), 1, 25)] +public delegate void ForEach(ref T0 component__T0); + +/// +/// The delegate +/// provides a callback to execute logic on an and up to 25 component types. +/// +[Variadic(nameof(T0), 1, 25)] +public delegate void ForEachWithEntity(Entity entity, ref T0 component__T0); diff --git a/src/Arch/Core/Variadics/Group.Variadics.cs b/src/Arch/Core/Variadics/Group.Variadics.cs new file mode 100644 index 00000000..2a8a3403 --- /dev/null +++ b/src/Arch/Core/Variadics/Group.Variadics.cs @@ -0,0 +1,30 @@ +using System.Threading; +using Arch.Core.Utils; + +namespace Arch.Core; + +/// +[Variadic(nameof(T0), 1, 25)] +public static class Group +{ + internal static readonly int Id; + /// + /// The global array of for this given type group. Must not be modified in any way. + /// + public static readonly ComponentType[] Types; + /// + /// The hash code for this given type group. + /// + public static readonly int Hash; + + static Group() + { + Id = Interlocked.Increment(ref Id); + Types = new ComponentType[] + { + // [Variadic: CopyLines] + Component.ComponentType, + }; + Hash = Component.GetHashCode(Types); + } +} diff --git a/src/Arch/Core/Variadics/Interfaces.Variadics.cs b/src/Arch/Core/Variadics/Interfaces.Variadics.cs new file mode 100644 index 00000000..ccc7584d --- /dev/null +++ b/src/Arch/Core/Variadics/Interfaces.Variadics.cs @@ -0,0 +1,17 @@ +namespace Arch.Core; + +/// +[Variadic(nameof(T0), 1, 26)] // TODO change this to 25??? +public interface IForEach +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + void Update(ref T0 component__T0); +} + +/// +[Variadic(nameof(T0), 1, 26)] +public interface IForEachWithEntity +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + void Update(Entity entity, ref T0 component__T0); +} diff --git a/src/Arch/Core/Variadics/Jobs.Variadics.cs b/src/Arch/Core/Variadics/Jobs.Variadics.cs index 7a09c4b8..f98fca9d 100644 --- a/src/Arch/Core/Variadics/Jobs.Variadics.cs +++ b/src/Arch/Core/Variadics/Jobs.Variadics.cs @@ -9,12 +9,12 @@ public struct ForEachJob : IChunkJob public readonly void Execute(int index, ref Chunk chunk) { var chunkSize = chunk.Size; - // [Variadic: CopyLines(firstElement)] + // [Variadic: CopyLines] ref var firstElement__T0 = ref chunk.GetFirst(); for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) { - // [Variadic: CopyLines(component, firstElement)] + // [Variadic: CopyLines] ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); // [Variadic: CopyArgs(component)] ForEach(ref component__T0); @@ -32,13 +32,13 @@ public readonly void Execute(int index, ref Chunk chunk) { ref var entityFirstElement = ref chunk.Entity(0); var chunkSize = chunk.Size; - // [Variadic: CopyLines(firstElement)] + // [Variadic: CopyLines] ref var firstElement__T0 = ref chunk.GetFirst(); for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) { var entity = Unsafe.Add(ref entityFirstElement, entityIndex); - // [Variadic: CopyLines(component, firstElement)] + // [Variadic: CopyLines] ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); // [Variadic: CopyArgs(component)] ForEach(entity, ref component__T0); @@ -55,12 +55,12 @@ public struct IForEachJob : IChunkJob where T : struct, IForEach public void Execute(int index, ref Chunk chunk) { var chunkSize = chunk.Size; - // [Variadic: CopyLines(firstElement)] + // [Variadic: CopyLines] ref var firstElement__T0 = ref chunk.GetFirst(); for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) { - // [Variadic: CopyLines(component, firstElement)] + // [Variadic: CopyLines] ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); // [Variadic: CopyArgs(component)] ForEach.Update(ref component__T0); @@ -78,13 +78,13 @@ public void Execute(int index, ref Chunk chunk) { var chunkSize = chunk.Size; ref var entityFirstElement = ref chunk.Entity(0); - // [Variadic: CopyLines(firstElement)] + // [Variadic: CopyLines] ref var firstElement__T0 = ref chunk.GetFirst(); for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) { var entity = Unsafe.Add(ref entityFirstElement, entityIndex); - // [Variadic: CopyLines(component, firstElement)] + // [Variadic: CopyLines] ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); // [Variadic: CopyArgs(component)] ForEach.Update(entity, ref component__T0); diff --git a/src/Arch/Core/Variadics/World.Variadics.cs b/src/Arch/Core/Variadics/World.Variadics.cs new file mode 100644 index 00000000..ab46da6e --- /dev/null +++ b/src/Arch/Core/Variadics/World.Variadics.cs @@ -0,0 +1,43 @@ +namespace Arch.Core; +public partial class World +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [StructuralChange] + [Variadic(nameof(T0), 1, 25)] + // [Variadic: CopyParams(T0)] + public Entity Create(in T0 componentValue__T0 = default) + { + var types = Group.Types; + + // Recycle id or increase + var recycle = RecycledIds.TryDequeue(out var recycledId); + var recycled = recycle ? recycledId : new RecycledEntity(Size, 1); + + // Create new entity and put it to the back of the array + var entity = new Entity(recycled.Id, Id); + + // Add to archetype & mapping + var archetype = GetOrCreate(types); + var createdChunk = archetype.Add(entity, out var slot); + + // [Variadic: CopyArgs(componentValue)] + archetype.Set(ref slot, in componentValue__T0); + + // Resize map & Array to fit all potential new entities + if (createdChunk) + { + Capacity += archetype.EntitiesPerChunk; + EntityInfo.EnsureCapacity(Capacity); + } + + // Map + EntityInfo.Add(entity.Id, recycled.Version, archetype, slot); + + Size++; + OnEntityCreated(entity); + + // [Variadic: CopyLines] + OnComponentAdded(entity); + return entity; + } +} diff --git a/src/Arch/VariadicAttribute.cs b/src/Arch/VariadicAttribute.cs index 237e7ebc..09795275 100644 --- a/src/Arch/VariadicAttribute.cs +++ b/src/Arch/VariadicAttribute.cs @@ -3,7 +3,7 @@ /// /// Tags a method or type as being variadic; i.e. generating many generic parameters. /// -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Delegate)] +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Delegate | AttributeTargets.Interface)] internal class VariadicAttribute : Attribute { /// From 2f536455d1a4ab24633cd3581319b46bc58f6ecf Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Wed, 1 Nov 2023 02:43:50 -0700 Subject: [PATCH 06/16] convert remaining sourcegen to variadics --- src/Arch.SourceGen/QueryGenerator.cs | 4 +- src/Arch.SourceGen/VariadicGenerator.cs | 16 +- .../Core/Variadics/Interfaces.Variadics.cs | 4 +- .../Variadics/QueryDescription.Variadics.cs | 39 ++ src/Arch/Core/Variadics/World.Variadics.cs | 538 +++++++++++++++++- 5 files changed, 593 insertions(+), 8 deletions(-) create mode 100644 src/Arch/Core/Variadics/QueryDescription.Variadics.cs diff --git a/src/Arch.SourceGen/QueryGenerator.cs b/src/Arch.SourceGen/QueryGenerator.cs index 8cc285de..2e69080c 100644 --- a/src/Arch.SourceGen/QueryGenerator.cs +++ b/src/Arch.SourceGen/QueryGenerator.cs @@ -108,7 +108,6 @@ public partial class World { /* {{new StringBuilder().AppendCreates(25)}} - */ {{new StringBuilder().AppendWorldHases(25)}} {{new StringBuilder().AppendWorldGets(25)}} {{new StringBuilder().AppendWorldSets(25)}} @@ -128,14 +127,17 @@ public partial class World {{new StringBuilder().AppendSetWithQueryDescriptions(25)}} {{new StringBuilder().AppendAddWithQueryDescriptions(25)}} {{new StringBuilder().AppendRemoveWithQueryDescriptions(25)}} + */ } public partial struct QueryDescription { + /* {{new StringBuilder().AppendQueryDescriptionWithAlls(25)}} {{new StringBuilder().AppendQueryDescriptionWithAnys(25)}} {{new StringBuilder().AppendQueryDescriptionWithNones(25)}} {{new StringBuilder().AppendQueryDescriptionWithExclusives(25)}} + */ } } diff --git a/src/Arch.SourceGen/VariadicGenerator.cs b/src/Arch.SourceGen/VariadicGenerator.cs index 6403daed..5a7362e4 100644 --- a/src/Arch.SourceGen/VariadicGenerator.cs +++ b/src/Arch.SourceGen/VariadicGenerator.cs @@ -22,7 +22,6 @@ private class VariadicInfo public void Initialize(IncrementalGeneratorInitializationContext context) { - //Debugger.Launch(); var infos = context.SyntaxProvider.ForAttributeWithMetadataName("Arch.Core.VariadicAttribute", // TODO: slow, make better filter @@ -83,17 +82,26 @@ public void Initialize(IncrementalGeneratorInitializationContext context) context.RegisterSourceOutput(infos, (ctx, infos) => { + Dictionary filenames = new(); foreach (var info in infos) { var text = CSharpSyntaxTree.ParseText(MakeVariadic(info)).GetRoot().NormalizeWhitespace().ToFullString(); - if (info.EnclosingType != string.Empty) + var filename = info.EnclosingType != string.Empty ? $"{info.EnclosingTypeName}.{info.Name}.Variadic" : $"{info.Name}.Variadic"; + // if we accidentally created a duplicate filename, we need to append an integer. + int filenameIndex; + if (!filenames.ContainsKey(filename)) { - ctx.AddSource($"{info.EnclosingTypeName}.{info.Name}.Variadic.g.cs", text); + filenames[filename] = 0; + filenameIndex = 0; } else { - ctx.AddSource($"{info.Name}.Variadic.g.cs", text); + filenames[filename]++; + filenameIndex = filenames[filename]; } + + string index = filenameIndex != 0 ? $".{filenameIndex}" : string.Empty; + ctx.AddSource($"{filename}{index}.g.cs", text); } }); } diff --git a/src/Arch/Core/Variadics/Interfaces.Variadics.cs b/src/Arch/Core/Variadics/Interfaces.Variadics.cs index ccc7584d..aab54a7a 100644 --- a/src/Arch/Core/Variadics/Interfaces.Variadics.cs +++ b/src/Arch/Core/Variadics/Interfaces.Variadics.cs @@ -1,7 +1,7 @@ namespace Arch.Core; /// -[Variadic(nameof(T0), 1, 26)] // TODO change this to 25??? +[Variadic(nameof(T0), 1, 25)] public interface IForEach { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -9,7 +9,7 @@ public interface IForEach } /// -[Variadic(nameof(T0), 1, 26)] +[Variadic(nameof(T0), 1, 25)] public interface IForEachWithEntity { [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Arch/Core/Variadics/QueryDescription.Variadics.cs b/src/Arch/Core/Variadics/QueryDescription.Variadics.cs new file mode 100644 index 00000000..645a099f --- /dev/null +++ b/src/Arch/Core/Variadics/QueryDescription.Variadics.cs @@ -0,0 +1,39 @@ +namespace Arch.Core; +public partial struct QueryDescription +{ + [UnscopedRef] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T1), 2, 25)] + public ref QueryDescription WithAll() + { + All = Group.Types; + return ref this; + } + + [UnscopedRef] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T1), 2, 25)] + public ref QueryDescription WithAny() + { + Any = Group.Types; + return ref this; + } + + [UnscopedRef] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T1), 2, 25)] + public ref QueryDescription WithNone() + { + None = Group.Types; + return ref this; + } + + [UnscopedRef] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T1), 2, 25)] + public ref QueryDescription WithExclusive() + { + Exclusive = Group.Types; + return ref this; + } +} diff --git a/src/Arch/Core/Variadics/World.Variadics.cs b/src/Arch/Core/Variadics/World.Variadics.cs index ab46da6e..f34771d7 100644 --- a/src/Arch/Core/Variadics/World.Variadics.cs +++ b/src/Arch/Core/Variadics/World.Variadics.cs @@ -1,4 +1,9 @@ -namespace Arch.Core; +using System.Diagnostics.Contracts; +using Arch.Core.Extensions.Internal; +using Arch.Core.Utils; +using JobScheduler; + +namespace Arch.Core; public partial class World { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -40,4 +45,535 @@ public Entity Create(in T0 componentValue__T0 = default) OnComponentAdded(entity); return entity; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Pure] + [Variadic(nameof(T1), 2, 25)] + public bool Has(Entity entity) + { + var archetype = EntityInfo.GetArchetype(entity.Id); + return archetype.Has(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Pure] + [Variadic(nameof(T1), 2, 25)] + public Components Get(Entity entity) + { + var slot = EntityInfo.GetSlot(entity.Id); + var archetype = EntityInfo.GetArchetype(entity.Id); + return archetype.Get(ref slot); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Pure] + [Variadic(nameof(T1), 2, 25)] + public void Set(Entity entity, in T0 component__T0, in T1 component__T1) + { + var slot = EntityInfo.GetSlot(entity.Id); + var archetype = EntityInfo.GetArchetype(entity.Id); + // [Variadic: CopyArgs(component)] + archetype.Set(ref slot, in component__T0, in component__T1); + OnComponentSet(entity); + // [Variadic: CopyLines] + OnComponentSet(entity); + } + + [SkipLocalsInit] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [StructuralChange] + [Variadic(nameof(T1), 2, 25)] + // [Variadic: CopyParams(T1)] + public void Add(Entity entity, in T0 component__T0 = default, in T1 component__T1 = default) + { + var oldArchetype = EntityInfo.GetArchetype(entity.Id); + + // BitSet to stack/span bitset, size big enough to contain ALL registered components. + Span stack = stackalloc uint[BitSet.RequiredLength(ComponentRegistry.Size)]; + oldArchetype.BitSet.AsSpan(stack); + + // Create a span bitset, doing it local saves us headache and gargabe + var spanBitSet = new SpanBitSet(stack); + spanBitSet.SetBit(Component.ComponentType.Id); + // [Variadic: CopyLines] + spanBitSet.SetBit(Component.ComponentType.Id); + + if (!TryGetArchetype(spanBitSet.GetHashCode(), out var newArchetype)) + { + var type__T0 = typeof(T0); + // [Variadic: CopyLines] + var type__T1 = typeof(T1); + // [Variadic: CopyArgs(type)] + newArchetype = GetOrCreate(oldArchetype.Types.Add(type__T0, type__T1)); + } + + Move(entity, oldArchetype, newArchetype, out var newSlot); + + // [Variadic: CopyArgs(component)] + newArchetype.Set(ref newSlot, in component__T0, in component__T1); + + OnComponentAdded(entity); + // [Variadic: CopyLines] + OnComponentAdded(entity); + } + + [SkipLocalsInit] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [StructuralChange] + [Variadic(nameof(T1), 2, 25)] + public void Remove(Entity entity) + { + var oldArchetype = EntityInfo.GetArchetype(entity.Id); + + // BitSet to stack/span bitset, size big enough to contain ALL registered components. + Span stack = stackalloc uint[oldArchetype.BitSet.Length]; + oldArchetype.BitSet.AsSpan(stack); + + // Create a span bitset, doing it local saves us headache and gargabe + var spanBitSet = new SpanBitSet(stack); + spanBitSet.ClearBit(Component.ComponentType.Id); + // [Variadic: CopyLines] + spanBitSet.ClearBit(Component.ComponentType.Id); + + if (!TryGetArchetype(spanBitSet.GetHashCode(), out var newArchetype)) + { + var type__T0 = typeof(T0); + // [Variadic: CopyLines] + var type__T1 = typeof(T1); + // [Variadic: CopyArgs(type)] + newArchetype = GetOrCreate(oldArchetype.Types.Remove(type__T0, type__T1)); + } + + OnComponentRemoved(entity); + // [Variadic: CopyLines] + OnComponentRemoved(entity); + Move(entity, oldArchetype, newArchetype, out _); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T0), 1, 25)] + public void Query(in QueryDescription description, ForEach forEach) + { + var query = Query(in description); + foreach (ref var chunk in query) + { + // [Variadic: CopyLines] + ref var firstElement__T0 = ref chunk.GetFirst(); + + foreach (var entityIndex in chunk) + { + // [Variadic: CopyLines] + ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + // [Variadic: CopyArgs(component)] + forEach(ref component__T0); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T0), 1, 25)] + public void Query(in QueryDescription description, ForEachWithEntity forEach) + { + var query = Query(in description); + foreach (ref var chunk in query) + { + ref var entityFirstElement = ref chunk.Entity(0); + // [Variadic: CopyLines] + ref var firstElement__T0 = ref chunk.GetFirst(); + + foreach (var entityIndex in chunk) + { + var entity = Unsafe.Add(ref entityFirstElement, entityIndex); + // [Variadic: CopyLines] + ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + // [Variadic: CopyArgs(component)] + forEach(entity, ref component__T0); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T0), 1, 25)] + public void ParallelQuery(in QueryDescription description, ForEach forEach) + { + var innerJob = new ForEachJob(); + innerJob.ForEach = forEach; + + var pool = JobMeta>>.Pool; + var query = Query(in description); + foreach (var archetype in query.GetArchetypeIterator()) + { + + var archetypeSize = archetype.Size; + var part = new RangePartitioner(Environment.ProcessorCount, archetypeSize); + foreach (var range in part) + { + var job = pool.Get(); + job.Start = range.Start; + job.Size = range.Length; + job.Chunks = archetype.Chunks; + job.Instance = innerJob; + JobsCache.Add(job); + } + + IJob.Schedule(JobsCache, JobHandles); + JobScheduler.JobScheduler.Instance.Flush(); + JobHandle.Complete(JobHandles); + JobHandle.Return(JobHandles); + + // Return jobs to pool + for (var jobIndex = 0; jobIndex < JobsCache.Count; jobIndex++) + { + var job = Unsafe.As>>(JobsCache[jobIndex]); + pool.Return(job); + } + + JobHandles.Clear(); + JobsCache.Clear(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T0), 1, 25)] + public void ParallelQuery(in QueryDescription description, ForEachWithEntity forEach) + { + var innerJob = new ForEachWithEntityJob(); + innerJob.ForEach = forEach; + + var pool = JobMeta>>.Pool; + var query = Query(in description); + foreach (var archetype in query.GetArchetypeIterator()) + { + var archetypeSize = archetype.Size; + var part = new RangePartitioner(Environment.ProcessorCount, archetypeSize); + foreach (var range in part) + { + var job = pool.Get(); + job.Start = range.Start; + job.Size = range.Length; + job.Chunks = archetype.Chunks; + job.Instance = innerJob; + JobsCache.Add(job); + } + + IJob.Schedule(JobsCache, JobHandles); + JobScheduler.JobScheduler.Instance.Flush(); + JobHandle.Complete(JobHandles); + JobHandle.Return(JobHandles); + + // Return jobs to pool + for (var jobIndex = 0; jobIndex < JobsCache.Count; jobIndex++) + { + var job = Unsafe.As>>(JobsCache[jobIndex]); + pool.Return(job); + } + + JobHandles.Clear(); + JobsCache.Clear(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T0), 1, 25)] + public void InlineQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEach + { + var query = Query(in description); + foreach (ref var chunk in query) + { + // [Variadic: CopyLines] + ref var firstElement__T0 = ref chunk.GetFirst(); + + foreach (var entityIndex in chunk) + { + // [Variadic: CopyLines] + ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + // [Variadic: CopyArgs(component)] + iForEach.Update(ref component__T0); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T0), 1, 25)] + public void InlineQuery(in QueryDescription description) where T : struct, IForEach + { + var t = new T(); + + var query = Query(in description); + foreach (ref var chunk in query) + { + var chunkSize = chunk.Size; + // [Variadic: CopyLines] + ref var firstElement__T0 = ref chunk.GetFirst(); + + foreach (var entityIndex in chunk) + { + // [Variadic: CopyLines] + ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + // [Variadic: CopyArgs(component)] + t.Update(ref component__T0); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T0), 1, 25)] + public void InlineEntityQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEachWithEntity + { + var query = Query(in description); + foreach (ref var chunk in query) + { + var chunkSize = chunk.Size; + ref var entityFirstElement = ref chunk.Entity(0); + // [Variadic: CopyLines] + ref var firstElement__T0 = ref chunk.GetFirst(); + + foreach (var entityIndex in chunk) + { + var entity = Unsafe.Add(ref entityFirstElement, entityIndex); + // [Variadic: CopyLines] + ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + // [Variadic: CopyArgs(component)] + iForEach.Update(entity, ref component__T0); + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T0), 1, 25)] + public void InlineEntityQuery(in QueryDescription description) where T : struct, IForEachWithEntity + { + var t = new T(); + + var query = Query(in description); + foreach (ref var chunk in query) + { + var chunkSize = chunk.Size; + ref var entityFirstElement = ref chunk.Entity(0); + // [Variadic: CopyLines] + ref var firstElement__T0 = ref chunk.GetFirst(); + + foreach (var entityIndex in chunk) + { + var entity = Unsafe.Add(ref entityFirstElement, entityIndex); + // [Variadic: CopyLines] + ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + // [Variadic: CopyArgs(component)] + t.Update(entity, ref component__T0); + } + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T0), 1, 25)] + public void InlineParallelQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEach + { + var innerJob = new IForEachJob(); + innerJob.ForEach = iForEach; + + var pool = JobMeta>>.Pool; + var query = Query(in description); + foreach (var archetype in query.GetArchetypeIterator()) + { + var archetypeSize = archetype.Size; + var part = new RangePartitioner(Environment.ProcessorCount, archetypeSize); + foreach (var range in part) + { + var job = pool.Get(); + job.Start = range.Start; + job.Size = range.Length; + job.Chunks = archetype.Chunks; + job.Instance = innerJob; + JobsCache.Add(job); + } + + IJob.Schedule(JobsCache, JobHandles); + JobScheduler.JobScheduler.Instance.Flush(); + JobHandle.Complete(JobHandles); + JobHandle.Return(JobHandles); + + // Return jobs to pool + for (var jobIndex = 0; jobIndex < JobsCache.Count; jobIndex++) + { + var job = Unsafe.As>>(JobsCache[jobIndex]); + pool.Return(job); + } + + JobHandles.Clear(); + JobsCache.Clear(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T0), 1, 25)] + public void InlineParallelEntityQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEachWithEntity + { + var innerJob = new IForEachWithEntityJob(); + innerJob.ForEach = iForEach; + + var pool = JobMeta>>.Pool; + var query = Query(in description); + foreach (var archetype in query.GetArchetypeIterator()) + { + + var archetypeSize = archetype.Size; + var part = new RangePartitioner(Environment.ProcessorCount, archetypeSize); + foreach (var range in part) + { + var job = pool.Get(); + job.Start = range.Start; + job.Size = range.Length; + job.Chunks = archetype.Chunks; + job.Instance = innerJob; + JobsCache.Add(job); + } + + IJob.Schedule(JobsCache, JobHandles); + JobScheduler.JobScheduler.Instance.Flush(); + JobHandle.Complete(JobHandles); + JobHandle.Return(JobHandles); + + // Return jobs to pool + for (var jobIndex = 0; jobIndex < JobsCache.Count; jobIndex++) + { + var job = Unsafe.As>>(JobsCache[jobIndex]); + pool.Return(job); + } + + JobHandles.Clear(); + JobsCache.Clear(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Variadic(nameof(T1), 2, 25)] + // [Variadic: CopyParams(T1)] + public void Set(in QueryDescription queryDescription, in T0 componentValue__T0 = default, in T1 componentValue__T1 = default) + { + var query = Query(in queryDescription); + foreach (ref var chunk in query) + { + ref var firstElement__T0 = ref chunk.GetFirst(); + // [Variadic: CopyLines] + ref var firstElement__T1 = ref chunk.GetFirst(); + + foreach (var entityIndex in chunk) + { + ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + // [Variadic: CopyLines] + ref var component__T1 = ref Unsafe.Add(ref firstElement__T1, entityIndex); + component__T0 = componentValue__T0; + // [Variadic: CopyLines] + component__T1 = componentValue__T1; +#if EVENTS + var entity = chunk.Entity(entityIndex); + OnComponentSet(entity); + // [Variadic: CopyLines] + OnComponentSet(entity); +#endif + } + } + } + + [SkipLocalsInit] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [StructuralChange] + [Variadic(nameof(T1), 2, 25)] + // [Variadic: CopyParams(T1)] + public void Add(in QueryDescription queryDescription, in T0 component__T0 = default, in T1 component__T1 = default) + { + // BitSet to stack/span bitset, size big enough to contain ALL registered components. + Span stack = stackalloc uint[BitSet.RequiredLength(ComponentRegistry.Size)]; + + var query = Query(in queryDescription); + foreach (var archetype in query.GetArchetypeIterator()) + { + // Archetype with T shouldnt be skipped to prevent undefined behaviour. + if (archetype.Entities == 0 || archetype.Has()) + { + continue; + } + + // Create local bitset on the stack and set bits to get a new fitting bitset of the new archetype. + archetype.BitSet.AsSpan(stack); + var spanBitSet = new SpanBitSet(stack); + spanBitSet.SetBit(Component.ComponentType.Id); + // [Variadic: CopyLines] + spanBitSet.SetBit(Component.ComponentType.Id); + + // Get or create new archetype. + if (!TryGetArchetype(spanBitSet.GetHashCode(), out var newArchetype)) + { + var type__T0 = typeof(T0); + // [Variadic: CopyLines] + var type__T1 = typeof(T1); + // [Variadic: CopyArgs(type)] + newArchetype = GetOrCreate(archetype.Types.Add(type__T0, type__T1)); + } + + // Get last slots before copy, for updating entityinfo later + var archetypeSlot = archetype.LastSlot; + var newArchetypeLastSlot = newArchetype.LastSlot; + Slot.Shift(ref newArchetypeLastSlot, newArchetype.EntitiesPerChunk); + EntityInfo.Shift(archetype, archetypeSlot, newArchetype, newArchetypeLastSlot); + + // Copy, set and clear + Archetype.Copy(archetype, newArchetype); + var lastSlot = newArchetype.LastSlot; + // [Variadic: CopyArgs(component)] + newArchetype.SetRange(in lastSlot, in newArchetypeLastSlot, in component__T0, in component__T1); + // [Variadic: CopyLines] + OnComponentAdded(archetype); + archetype.Clear(); + } + } + + [SkipLocalsInit] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [StructuralChange] + [Variadic(nameof(T1), 2, 25)] + public void Remove(in QueryDescription queryDescription) + { + // BitSet to stack/span bitset, size big enough to contain ALL registered components. + Span stack = stackalloc uint[BitSet.RequiredLength(ComponentRegistry.Size)]; + + var query = Query(in queryDescription); + foreach (var archetype in query.GetArchetypeIterator()) + { + // Archetype without T shouldnt be skipped to prevent undefined behaviour. + if (archetype.Entities <= 0 || !archetype.Has()) + { + continue; + } + + // Create local bitset on the stack and set bits to get a new fitting bitset of the new archetype. + var bitSet = archetype.BitSet; + var spanBitSet = new SpanBitSet(bitSet.AsSpan(stack)); + spanBitSet.ClearBit(Component.ComponentType.Id); + // [Variadic: CopyLines] + spanBitSet.ClearBit(Component.ComponentType.Id); + + // Get or create new archetype. + if (!TryGetArchetype(spanBitSet.GetHashCode(), out var newArchetype)) + { + var type__T0 = typeof(T0); + // [Variadic: CopyLines] + var type__T1 = typeof(T1); + // [Variadic: CopyArgs(type)] + newArchetype = GetOrCreate(archetype.Types.Remove(type__T0, type__T1)); + } + + OnComponentRemoved(archetype); + // [Variadic: CopyLines] + OnComponentRemoved(archetype); + + // Get last slots before copy, for updating entityinfo later + var archetypeSlot = archetype.LastSlot; + var newArchetypeLastSlot = newArchetype.LastSlot; + Slot.Shift(ref newArchetypeLastSlot, newArchetype.EntitiesPerChunk); + EntityInfo.Shift(archetype, archetypeSlot, newArchetype, newArchetypeLastSlot); + + Archetype.Copy(archetype, newArchetype); + archetype.Clear(); + } + } } From d50d2004280b53a0ed665dd98ac28f5411856e83 Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Wed, 1 Nov 2023 02:44:46 -0700 Subject: [PATCH 07/16] remove old sourcegen --- src/Arch.SourceGen/Fundamentals/Components.cs | 131 -------- src/Arch.SourceGen/Fundamentals/Create.cs | 68 ---- src/Arch.SourceGen/Fundamentals/Get.cs | 299 ------------------ src/Arch.SourceGen/Fundamentals/Group.cs | 52 --- src/Arch.SourceGen/Fundamentals/Has.cs | 150 --------- src/Arch.SourceGen/Fundamentals/Index.cs | 46 --- src/Arch.SourceGen/Fundamentals/Set.cs | 187 ----------- .../Fundamentals/StructuralChanges.cs | 165 ---------- .../Queries/AddWithQueryDescription.cs | 93 ------ .../Queries/InlineParallelQuery.cs | 122 ------- src/Arch.SourceGen/Queries/InlineQuery.cs | 217 ------------- src/Arch.SourceGen/Queries/Job.cs | 164 ---------- src/Arch.SourceGen/Queries/ParallelQuery.cs | 124 -------- src/Arch.SourceGen/Queries/Query.cs | 134 -------- .../Queries/QueryDescription.cs | 120 ------- .../Queries/RemoveWithQueryDescription.cs | 89 ------ .../Queries/SetWithQueryDescription.cs | 68 ---- src/Arch.SourceGen/QueryGenerator.cs | 183 ----------- src/Arch.SourceGen/StringBuilderExtensions.cs | 259 --------------- 19 files changed, 2671 deletions(-) delete mode 100644 src/Arch.SourceGen/Fundamentals/Components.cs delete mode 100644 src/Arch.SourceGen/Fundamentals/Create.cs delete mode 100644 src/Arch.SourceGen/Fundamentals/Get.cs delete mode 100644 src/Arch.SourceGen/Fundamentals/Group.cs delete mode 100644 src/Arch.SourceGen/Fundamentals/Has.cs delete mode 100644 src/Arch.SourceGen/Fundamentals/Index.cs delete mode 100644 src/Arch.SourceGen/Fundamentals/Set.cs delete mode 100644 src/Arch.SourceGen/Fundamentals/StructuralChanges.cs delete mode 100644 src/Arch.SourceGen/Queries/AddWithQueryDescription.cs delete mode 100644 src/Arch.SourceGen/Queries/InlineParallelQuery.cs delete mode 100644 src/Arch.SourceGen/Queries/InlineQuery.cs delete mode 100644 src/Arch.SourceGen/Queries/Job.cs delete mode 100644 src/Arch.SourceGen/Queries/ParallelQuery.cs delete mode 100644 src/Arch.SourceGen/Queries/Query.cs delete mode 100644 src/Arch.SourceGen/Queries/QueryDescription.cs delete mode 100644 src/Arch.SourceGen/Queries/RemoveWithQueryDescription.cs delete mode 100644 src/Arch.SourceGen/Queries/SetWithQueryDescription.cs delete mode 100644 src/Arch.SourceGen/QueryGenerator.cs delete mode 100644 src/Arch.SourceGen/StringBuilderExtensions.cs diff --git a/src/Arch.SourceGen/Fundamentals/Components.cs b/src/Arch.SourceGen/Fundamentals/Components.cs deleted file mode 100644 index 17df4b90..00000000 --- a/src/Arch.SourceGen/Fundamentals/Components.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System.Text; -using Arch.SourceGen; - -namespace ArchSourceGenerator; - -public static class ReferencesExtensions -{ - public static StringBuilder AppendComponents(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - sb.AppendComponent(index); - - return sb; - } - - public static StringBuilder AppendComponent(this StringBuilder sb, int amount) - { - - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var parameters = new StringBuilder().GenericRefParams(amount); - - var refStructs = new StringBuilder(); - for (var index = 0; index <= amount; index++) - refStructs.AppendLine($"public Ref t{index};"); - - var references = new StringBuilder(); - for (var index = 0; index <= amount; index++) - references.AppendLine($"public ref T{index} t{index};"); - - var assignRefStructs = new StringBuilder(); - for (var index = 0; index <= amount; index++) - assignRefStructs.AppendLine($"t{index} = new Ref(ref t{index}Component);"); - - var assignRefs = new StringBuilder(); - for (var index = 0; index <= amount; index++) - assignRefs.AppendLine($"t{index} = ref t{index}Component;"); - - - var template = - $$""" - [SkipLocalsInit] - public ref struct Components<{{generics}}> - { - - #if NETSTANDARD2_1 || NET6_0 - {{refStructs}} - #else - {{references}} - #endif - - [SkipLocalsInit] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Components({{parameters}}){ - - #if NETSTANDARD2_1 || NET6_0 - {{assignRefStructs}} - #else - {{assignRefs}} - #endif - - } - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendEntityComponents(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - sb.AppendEntityComponent(index); - - return sb; - } - - public static StringBuilder AppendEntityComponent(this StringBuilder sb, int amount) - { - - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var parameters = new StringBuilder().GenericRefParams(amount); - - var refStructs = new StringBuilder(); - for (var index = 0; index <= amount; index++) - refStructs.AppendLine($"public Ref t{index};"); - - var references = new StringBuilder(); - for (var index = 0; index <= amount; index++) - references.AppendLine($"public ref T{index} t{index};"); - - var assignRefStructs = new StringBuilder(); - for (var index = 0; index <= amount; index++) - assignRefStructs.AppendLine($"t{index} = new Ref(ref t{index}Component);"); - - var assignRefs = new StringBuilder(); - for (var index = 0; index <= amount; index++) - assignRefs.AppendLine($"t{index} = ref t{index}Component;"); - - - var template = - $$""" - [SkipLocalsInit] - public ref struct EntityComponents<{{generics}}> - { - - #if NETSTANDARD2_1 || NET6_0 - public ReadOnlyRef Entity; - {{refStructs}} - #else - public ref readonly Entity Entity; - {{references}} - #endif - - [SkipLocalsInit] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public EntityComponents(ref Entity entity, {{parameters}}){ - - #if NETSTANDARD2_1 || NET6_0 - Entity = new ReadOnlyRef(in entity); - {{assignRefStructs}} - #else - Entity = ref entity; - {{assignRefs}} - #endif - - } - } - """; - - return sb.AppendLine(template); - } -} diff --git a/src/Arch.SourceGen/Fundamentals/Create.cs b/src/Arch.SourceGen/Fundamentals/Create.cs deleted file mode 100644 index 54198b38..00000000 --- a/src/Arch.SourceGen/Fundamentals/Create.cs +++ /dev/null @@ -1,68 +0,0 @@ -namespace Arch.SourceGen; - -public static class CreateExtensions -{ - public static StringBuilder AppendCreates(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - { - sb.AppendCreate(index); - } - - return sb; - } - - public static StringBuilder AppendCreate(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var parameters = new StringBuilder().GenericInDefaultParams(amount); - var inParameters = new StringBuilder().InsertGenericInParams(amount); - - var addEvents = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - addEvents.AppendLine($"OnComponentAdded(entity);"); - } - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [StructuralChange] - public Entity Create<{{generics}}>({{parameters}}) - { - var types = Group<{{generics}}>.Types; - - // Recycle id or increase - var recycle = RecycledIds.TryDequeue(out var recycledId); - var recycled = recycle ? recycledId : new RecycledEntity(Size, 1); - - // Create new entity and put it to the back of the array - var entity = new Entity(recycled.Id, Id); - - // Add to archetype & mapping - var archetype = GetOrCreate(types); - var createdChunk = archetype.Add(entity, out var slot); - - archetype.Set<{{generics}}>(ref slot, {{inParameters}}); - - // Resize map & Array to fit all potential new entities - if (createdChunk) - { - Capacity += archetype.EntitiesPerChunk; - EntityInfo.EnsureCapacity(Capacity); - } - - // Map - EntityInfo.Add(entity.Id, recycled.Version, archetype, slot); - - Size++; - OnEntityCreated(entity); - - {{addEvents}} - return entity; - } - """; - - return sb.AppendLine(template); - } -} diff --git a/src/Arch.SourceGen/Fundamentals/Get.cs b/src/Arch.SourceGen/Fundamentals/Get.cs deleted file mode 100644 index b5b11cf2..00000000 --- a/src/Arch.SourceGen/Fundamentals/Get.cs +++ /dev/null @@ -1,299 +0,0 @@ -namespace Arch.SourceGen; - -public static class GetExtensions -{ - - public static StringBuilder AppendChunkGetArrays(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendChunkGetArray(index); - } - - return sb; - } - - public static StringBuilder AppendChunkGetArray(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var outs = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - outs.Append($"out T{index}[] t{index}Array,"); - } - outs.Length--; - - var indexes = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - indexes.Append($"out var t{index}Index,"); - } - indexes.Length--; - - var assignComponents = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - assignComponents.AppendLine($"t{index}Array = Unsafe.As(Unsafe.Add(ref arrays, t{index}Index));"); - } - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Pure] - public void GetArray<{{generics}}>({{outs}}) - { - Index<{{generics}}>({{indexes}}); - ref var arrays = ref Components.DangerousGetReference(); - {{assignComponents}} - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendChunkGetSpans(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendChunkGetSpan(index); - } - - return sb; - } - - public static StringBuilder AppendChunkGetSpan(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var outs = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - outs.Append($"out Span t{index}Span,"); - } - outs.Length--; - - var arrays = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - arrays.Append($"out var t{index}Array,"); - } - arrays.Length--; - - var assignComponents = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - assignComponents.AppendLine($"t{index}Span = new Span(t{index}Array);"); - } - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Pure] - public void GetSpan<{{generics}}>({{outs}}) - { - GetArray<{{generics}}>({{arrays}}); - {{assignComponents}} - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendChunkGetFirsts(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendChunkGetFirst(index); - } - - return sb; - } - - public static StringBuilder AppendChunkGetFirst(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var arrays = new StringBuilder().GetChunkArrays(amount); - - var insertParams = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - insertParams.Append($"ref t{index}Array.DangerousGetReference(),"); - } - insertParams.Length--; - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Pure] - public Components<{{generics}}> GetFirst<{{generics}}>() - { - {{arrays}} - return new Components<{{generics}}>({{insertParams}}); - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendChunkIndexGets(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendChunkIndexGet(index); - } - - return sb; - } - - public static StringBuilder AppendChunkIndexGet(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var inParams = new StringBuilder().InsertGenericParams(amount); - var arrays = new StringBuilder().GetChunkArrays(amount); - - var gets = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - gets.AppendLine($"ref var t{index}Component = ref t{index}Array[index];"); - } - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Pure] - public Components<{{generics}}> Get<{{generics}}>(int index) - { - {{arrays}} - {{gets}} - - return new Components<{{generics}}>({{inParams}}); - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendChunkIndexGetRows(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendChunkIndexGetRow(index); - } - - return sb; - } - - public static StringBuilder AppendChunkIndexGetRow(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var getArrays = new StringBuilder().GetChunkArrays(amount); - var inParams = new StringBuilder().InsertGenericParams(amount); - - var gets = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - gets.AppendLine($"ref var t{index}Component = ref t{index}Array[index];"); - } - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Pure] - public EntityComponents<{{generics}}> GetRow<{{generics}}>(int index) - { - {{getArrays}} - - ref var entity = ref Entities[index]; - {{gets}} - - return new EntityComponents<{{generics}}>(ref entity, {{inParams}}); - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendArchetypeGets(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendArchetypeGet(index); - } - - return sb; - } - - public static StringBuilder AppendArchetypeGet(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal unsafe Components<{{generics}}> Get<{{generics}}>(scoped ref Slot slot) - { - ref var chunk = ref GetChunk(slot.ChunkIndex); - return chunk.Get<{{generics}}>(slot.Index); - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendWorldGets(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendWorldGet(index); - } - - return sb; - } - - public static StringBuilder AppendWorldGet(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Pure] - public Components<{{generics}}> Get<{{generics}}>(Entity entity) - { - var slot = EntityInfo.GetSlot(entity.Id); - var archetype = EntityInfo.GetArchetype(entity.Id); - return archetype.Get<{{generics}}>(ref slot); - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendEntityGets(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendEntityGet(index); - } - - return sb; - } - - public static StringBuilder AppendEntityGet(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Pure] - public static Components<{{generics}}> Get<{{generics}}>(this Entity entity) - { - var world = World.Worlds[entity.WorldId]; - return world.Get<{{generics}}>(entity); - } - """; - - return sb.AppendLine(template); - } -} diff --git a/src/Arch.SourceGen/Fundamentals/Group.cs b/src/Arch.SourceGen/Fundamentals/Group.cs deleted file mode 100644 index 52bd6e1d..00000000 --- a/src/Arch.SourceGen/Fundamentals/Group.cs +++ /dev/null @@ -1,52 +0,0 @@ -namespace Arch.SourceGen; - -public static class GroupExtensions -{ - public static StringBuilder AppendGroups(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - { - sb.AppendGroup(index); - } - - return sb; - } - - public static StringBuilder AppendGroup(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var types = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - types.Append($"Component.ComponentType,"); - } - - var template = - $$""" - /// - public static class Group<{{generics}}> - { - internal static readonly int Id; - - /// - /// The global array of for this given type group. Must not be modified in any way. - /// - public static readonly ComponentType[] Types; - - /// - /// The hash code for this given type group. - /// - public static readonly int Hash; - - static Group() - { - Id = Interlocked.Increment(ref Group.Id); - Types = new ComponentType[] { {{types}} }; - Hash = Component.GetHashCode(Types); - } - } - """; - - return sb.AppendLine(template); - } -} diff --git a/src/Arch.SourceGen/Fundamentals/Has.cs b/src/Arch.SourceGen/Fundamentals/Has.cs deleted file mode 100644 index 8f7a1327..00000000 --- a/src/Arch.SourceGen/Fundamentals/Has.cs +++ /dev/null @@ -1,150 +0,0 @@ -namespace Arch.SourceGen; - -public static class HasExtensions -{ - public static StringBuilder AppendChunkHases(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendChunkHas(index); - } - - return sb; - } - - public static StringBuilder AppendChunkHas(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var getIds = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - getIds.AppendLine($"var t{index}ComponentId = Component.ComponentType.Id;"); - } - - var boundChecks = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - boundChecks.AppendLine($"if (t{index}ComponentId >= ComponentIdToArrayIndex.Length) return false;"); - } - - var ifs = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - ifs.AppendLine($"if (ComponentIdToArrayIndex[t{index}ComponentId] == -1) return false;"); - } - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Pure] - public bool Has<{{generics}}>() - { - {{getIds}} - {{boundChecks}} - {{ifs}} - - return true; - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendArchetypeHases(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendArchetypeHas(index); - } - - return sb; - } - - public static StringBuilder AppendArchetypeHas(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var getIds = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - getIds.AppendLine($"var t{index}ComponentId = Component.ComponentType.Id;"); - } - - var isSet = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - isSet.AppendLine($"BitSet.IsSet(t{index}ComponentId) &&"); - } - - isSet.Length -= 4; - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Has<{{generics}}>() - { - {{getIds}} - return {{isSet}}; - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendWorldHases(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendWorldHas(index); - } - - return sb; - } - - public static StringBuilder AppendWorldHas(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Pure] - public bool Has<{{generics}}>(Entity entity) - { - var archetype = EntityInfo.GetArchetype(entity.Id); - return archetype.Has<{{generics}}>(); - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendEntityHases(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendEntityHas(index); - } - - return sb; - } - - public static StringBuilder AppendEntityHas(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Pure] - public static bool Has<{{generics}}>(this Entity entity) - { - var world = World.Worlds[entity.WorldId]; - return world.Has<{{generics}}>(entity); - } - """; - - return sb.AppendLine(template); - } -} diff --git a/src/Arch.SourceGen/Fundamentals/Index.cs b/src/Arch.SourceGen/Fundamentals/Index.cs deleted file mode 100644 index 3f58ebbf..00000000 --- a/src/Arch.SourceGen/Fundamentals/Index.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace Arch.SourceGen.Fundamentals; - -public static class IndexExtensions -{ - public static StringBuilder AppendChunkIndexes(this StringBuilder sb, int amount) - { - for (int index = 1; index <= amount; index++) - { - sb.AppendChunkIndex(index); - } - - return sb; - } - - public static StringBuilder AppendChunkIndex(this StringBuilder sb, int amount) - { - - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var outs = new StringBuilder(); - for (int i = 0; i <= amount; i++) - { - outs.Append($"out int t{i}Index,"); - } - outs.Length--; - - var assignIds = new StringBuilder(); - for (int i = 0; i <= amount; i++) - { - assignIds.AppendLine($"t{i}Index = Unsafe.Add(ref componentIdToArrayFirstElement, Component.ComponentType.Id);"); - } - - var template = $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Pure] - private void Index<{{generics}}>({{outs}}) - { - ref var componentIdToArrayFirstElement = ref ComponentIdToArrayIndex.DangerousGetReference(); - {{assignIds}} - } - """; - - sb.Append(template); - return sb; - } -} diff --git a/src/Arch.SourceGen/Fundamentals/Set.cs b/src/Arch.SourceGen/Fundamentals/Set.cs deleted file mode 100644 index ed480134..00000000 --- a/src/Arch.SourceGen/Fundamentals/Set.cs +++ /dev/null @@ -1,187 +0,0 @@ -namespace Arch.SourceGen; - -public static class SetExtensions -{ - public static StringBuilder AppendChunkIndexSets(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendChunkIndexSet(index); - } - - return sb; - } - - public static StringBuilder AppendChunkIndexSet(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var parameters = new StringBuilder().GenericInParams(amount); - var arrays = new StringBuilder().GetChunkArrays(amount); - - var sets = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - sets.AppendLine($"t{index}Array[index] = t{index}Component;"); - } - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set<{{generics}}>(int index, {{parameters}}) - { - {{arrays}} - {{sets}} - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendArchetypeSets(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendArchetypeSet(index); - } - - return sb; - } - - public static StringBuilder AppendArchetypeSet(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var parameters = new StringBuilder().GenericInParams(amount); - var insertParameters = new StringBuilder().InsertGenericInParams(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void Set<{{generics}}>(ref Slot slot, {{parameters}}) - { - ref var chunk = ref GetChunk(slot.ChunkIndex); - chunk.Set<{{generics}}>(slot.Index, {{insertParameters}}); - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendArchetypeSetRanges(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendArchetypeSetRange(index); - } - - return sb; - } - - public static StringBuilder AppendArchetypeSetRange(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var parameters = new StringBuilder().GenericInDefaultParams(amount,"ComponentValue"); - var getFirstElements = new StringBuilder().GetFirstGenericElements(amount); - var getComponents = new StringBuilder().GetGenericComponents(amount); - - var assignComponents = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - assignComponents.AppendLine($"t{index}Component = t{index}ComponentValue;"); - } - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void SetRange<{{generics}}>(in Slot from, in Slot to, {{parameters}}) - { - // Set the added component, start from the last slot and move down - for (var chunkIndex = from.ChunkIndex; chunkIndex >= to.ChunkIndex; --chunkIndex) - { - ref var chunk = ref GetChunk(chunkIndex); - {{getFirstElements}} - - // Only move within the range, depening on which chunk we are at. - var isStart = chunkIndex == from.ChunkIndex; - var isEnd = chunkIndex == to.ChunkIndex; - - var upper = isStart ? from.Index : chunk.Size-1; - var lower = isEnd ? to.Index : 0; - - for (var entityIndex = upper; entityIndex >= lower; --entityIndex) - { - {{getComponents}} - {{assignComponents}} - } - } - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendWorldSets(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendWorldSet(index); - } - - return sb; - } - - public static StringBuilder AppendWorldSet(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var parameters = new StringBuilder().GenericInParams(amount); - var insertParams = new StringBuilder().InsertGenericInParams(amount); - - var events = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - events.AppendLine($"OnComponentSet(entity);"); - } - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set<{{generics}}>(Entity entity, {{parameters}}) - { - var slot = EntityInfo.GetSlot(entity.Id); - var archetype = EntityInfo.GetArchetype(entity.Id); - archetype.Set<{{generics}}>(ref slot, {{insertParams}}); - {{events}} - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendEntitySets(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendEntitySet(index); - } - - return sb; - } - - public static StringBuilder AppendEntitySet(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var parameters = new StringBuilder().GenericInParams(amount); - var insertParams = new StringBuilder().InsertGenericInParams(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Set<{{generics}}>(this Entity entity, {{parameters}}) - { - var world = World.Worlds[entity.WorldId]; - world.Set<{{generics}}>(entity, {{insertParams}}); - } - """; - - return sb.AppendLine(template); - } -} diff --git a/src/Arch.SourceGen/Fundamentals/StructuralChanges.cs b/src/Arch.SourceGen/Fundamentals/StructuralChanges.cs deleted file mode 100644 index a5a5553a..00000000 --- a/src/Arch.SourceGen/Fundamentals/StructuralChanges.cs +++ /dev/null @@ -1,165 +0,0 @@ -namespace Arch.SourceGen; - -public static class StructuralChangesExtensions -{ - public static StringBuilder AppendWorldAdds(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendWorldAdd(index); - } - - return sb; - } - - public static StringBuilder AppendWorldAdd(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var parameters = new StringBuilder().GenericInDefaultParams(amount); - var inParameters = new StringBuilder().InsertGenericInParams(amount); - var types = new StringBuilder().GenericTypeParams(amount); - - var setIds = new StringBuilder(); - var addEvents = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - setIds.AppendLine($"spanBitSet.SetBit(Component.ComponentType.Id);"); - addEvents.AppendLine($"OnComponentAdded(entity);"); - } - - var template = - $$""" - [SkipLocalsInit] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [StructuralChange] - public void Add<{{generics}}>(Entity entity, {{parameters}}) - { - var oldArchetype = EntityInfo.GetArchetype(entity.Id); - - // BitSet to stack/span bitset, size big enough to contain ALL registered components. - Span stack = stackalloc uint[BitSet.RequiredLength(ComponentRegistry.Size)]; - oldArchetype.BitSet.AsSpan(stack); - - // Create a span bitset, doing it local saves us headache and gargabe - var spanBitSet = new SpanBitSet(stack); - {{setIds}} - - if (!TryGetArchetype(spanBitSet.GetHashCode(), out var newArchetype)) - newArchetype = GetOrCreate(oldArchetype.Types.Add({{types}})); - - Move(entity, oldArchetype, newArchetype, out var newSlot); - newArchetype.Set<{{generics}}>(ref newSlot, {{inParameters}}); - {{addEvents}} - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendWorldRemoves(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendWorldRemove(index); - } - - return sb; - } - - public static StringBuilder AppendWorldRemove(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var types = new StringBuilder().GenericTypeParams(amount); - - var removes = new StringBuilder(); - var events = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - removes.AppendLine($"spanBitSet.ClearBit(Component.ComponentType.Id);"); - events.AppendLine($"OnComponentRemoved(entity);"); - } - - var template = - $$""" - [SkipLocalsInit] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [StructuralChange] - public void Remove<{{generics}}>(Entity entity) - { - var oldArchetype = EntityInfo.GetArchetype(entity.Id); - - // BitSet to stack/span bitset, size big enough to contain ALL registered components. - Span stack = stackalloc uint[oldArchetype.BitSet.Length]; - oldArchetype.BitSet.AsSpan(stack); - - // Create a span bitset, doing it local saves us headache and gargabe - var spanBitSet = new SpanBitSet(stack); - {{removes}} - - if (!TryGetArchetype(spanBitSet.GetHashCode(), out var newArchetype)) - newArchetype = GetOrCreate(oldArchetype.Types.Remove({{types}})); - - {{events}} - Move(entity, oldArchetype, newArchetype, out _); - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendEntityAdds(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendEntityAdd(index); - } - - return sb; - } - - public static StringBuilder AppendEntityAdd(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var parameters = new StringBuilder().GenericInDefaultParams(amount); - var inParameters = new StringBuilder().InsertGenericInParams(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Add<{{generics}}>(this Entity entity, {{parameters}}) - { - var world = World.Worlds[entity.WorldId]; - world.Add<{{generics}}>(entity, {{inParameters}}); - } - """; - - return sb.AppendLine(template); - } - - public static StringBuilder AppendEntityRemoves(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendEntityRemove(index); - } - - return sb; - } - - public static StringBuilder AppendEntityRemove(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Remove<{{generics}}>(this Entity entity) - { - var world = World.Worlds[entity.WorldId]; - world.Remove<{{generics}}>(entity); - } - """; - - return sb.AppendLine(template); - } -} diff --git a/src/Arch.SourceGen/Queries/AddWithQueryDescription.cs b/src/Arch.SourceGen/Queries/AddWithQueryDescription.cs deleted file mode 100644 index 22f1aa18..00000000 --- a/src/Arch.SourceGen/Queries/AddWithQueryDescription.cs +++ /dev/null @@ -1,93 +0,0 @@ -namespace Arch.SourceGen; - -/// -/// Adds extension methods for generating `World.Add(in query, T0...TN);` methods. -/// -public static class AddWithQueryDescription -{ - /// - /// Appends `World.Add(in query, T0...TN)` methods. - /// - /// The instance. - /// The amount. - /// - public static StringBuilder AppendAddWithQueryDescriptions(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendAddWithQueryDescription(index); - } - - return sb; - } - - /// - /// Appends a `World.Add(in query, T0...TN)` method. - /// - /// The instance. - /// The amount of generic parameters. - public static void AppendAddWithQueryDescription(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var parameters = new StringBuilder().GenericInDefaultParams(amount); - var inParameters = new StringBuilder().InsertGenericInParams(amount); - var types = new StringBuilder().GenericTypeParams(amount); - - var setIds = new StringBuilder(); - var addEvents = new StringBuilder(); - var setEvents = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - setIds.AppendLine($"spanBitSet.SetBit(Component.ComponentType.Id);"); - addEvents.AppendLine($"OnComponentAdded(archetype);"); - } - - var template = - $$""" - [SkipLocalsInit] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [StructuralChange] - public void Add<{{generics}}>(in QueryDescription queryDescription, {{parameters}}) - { - // BitSet to stack/span bitset, size big enough to contain ALL registered components. - Span stack = stackalloc uint[BitSet.RequiredLength(ComponentRegistry.Size)]; - - var query = Query(in queryDescription); - foreach (var archetype in query.GetArchetypeIterator()) - { - // Archetype with T shouldnt be skipped to prevent undefined behaviour. - if(archetype.Entities == 0 || archetype.Has<{{generics}}>()) - { - continue; - } - - // Create local bitset on the stack and set bits to get a new fitting bitset of the new archetype. - archetype.BitSet.AsSpan(stack); - var spanBitSet = new SpanBitSet(stack); - {{setIds}} - - // Get or create new archetype. - if (!TryGetArchetype(spanBitSet.GetHashCode(), out var newArchetype)) - { - newArchetype = GetOrCreate(archetype.Types.Add({{types}})); - } - - // Get last slots before copy, for updating entityinfo later - var archetypeSlot = archetype.LastSlot; - var newArchetypeLastSlot = newArchetype.LastSlot; - Slot.Shift(ref newArchetypeLastSlot, newArchetype.EntitiesPerChunk); - EntityInfo.Shift(archetype, archetypeSlot, newArchetype, newArchetypeLastSlot); - - // Copy, set and clear - Archetype.Copy(archetype, newArchetype); - var lastSlot = newArchetype.LastSlot; - newArchetype.SetRange(in lastSlot, in newArchetypeLastSlot, {{inParameters}}); - {{addEvents}} - archetype.Clear(); - } - } - """; - - sb.AppendLine(template); - } -} diff --git a/src/Arch.SourceGen/Queries/InlineParallelQuery.cs b/src/Arch.SourceGen/Queries/InlineParallelQuery.cs deleted file mode 100644 index 6c10f567..00000000 --- a/src/Arch.SourceGen/Queries/InlineParallelQuery.cs +++ /dev/null @@ -1,122 +0,0 @@ -namespace Arch.SourceGen; - -public static class StringBuilderHpParallelQueryExtensions -{ - public static StringBuilder AppendHpParallelQuerys(this StringBuilder builder, int amount) - { - for (var index = 0; index < amount; index++) - { - builder.AppendHpParallelQuery(index); - } - - return builder; - } - - public static void AppendHpParallelQuery(this StringBuilder builder, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void InlineParallelQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEach<{{generics}}> - { - var innerJob = new IForEachJob(); - innerJob.ForEach = iForEach; - - var pool = JobMeta>>.Pool; - var query = Query(in description); - foreach (var archetype in query.GetArchetypeIterator()) - { - var archetypeSize = archetype.Size; - var part = new RangePartitioner(Environment.ProcessorCount, archetypeSize); - foreach (var range in part) - { - var job = pool.Get(); - job.Start = range.Start; - job.Size = range.Length; - job.Chunks = archetype.Chunks; - job.Instance = innerJob; - JobsCache.Add(job); - } - - IJob.Schedule(JobsCache, JobHandles); - JobScheduler.JobScheduler.Instance.Flush(); - JobHandle.Complete(JobHandles); - JobHandle.Return(JobHandles); - - // Return jobs to pool - for (var jobIndex = 0; jobIndex < JobsCache.Count; jobIndex++) - { - var job = Unsafe.As>>(JobsCache[jobIndex]); - pool.Return(job); - } - - JobHandles.Clear(); - JobsCache.Clear(); - } - } - """; - - builder.AppendLine(template); - } - - public static StringBuilder AppendHpeParallelQuerys(this StringBuilder builder, int amount) - { - for (var index = 0; index < amount; index++) - { - builder.AppendHpeParallelQuery(index); - } - - return builder; - } - - public static void AppendHpeParallelQuery(this StringBuilder builder, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void InlineParallelEntityQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEachWithEntity<{{generics}}> - { - var innerJob = new IForEachWithEntityJob(); - innerJob.ForEach = iForEach; - - var pool = JobMeta>>.Pool; - var query = Query(in description); - foreach (var archetype in query.GetArchetypeIterator()) { - - var archetypeSize = archetype.Size; - var part = new RangePartitioner(Environment.ProcessorCount, archetypeSize); - foreach (var range in part) - { - var job = pool.Get(); - job.Start = range.Start; - job.Size = range.Length; - job.Chunks = archetype.Chunks; - job.Instance = innerJob; - JobsCache.Add(job); - } - - IJob.Schedule(JobsCache, JobHandles); - JobScheduler.JobScheduler.Instance.Flush(); - JobHandle.Complete(JobHandles); - JobHandle.Return(JobHandles); - - // Return jobs to pool - for (var jobIndex = 0; jobIndex < JobsCache.Count; jobIndex++) - { - var job = Unsafe.As>>(JobsCache[jobIndex]); - pool.Return(job); - } - - JobHandles.Clear(); - JobsCache.Clear(); - } - } - """; - - builder.AppendLine(template); - } -} diff --git a/src/Arch.SourceGen/Queries/InlineQuery.cs b/src/Arch.SourceGen/Queries/InlineQuery.cs deleted file mode 100644 index 7227074c..00000000 --- a/src/Arch.SourceGen/Queries/InlineQuery.cs +++ /dev/null @@ -1,217 +0,0 @@ -namespace Arch.SourceGen; - -public struct InterfaceInfo -{ - public string Name { get; set; } - public List Generics { get; set; } - public List Params { get; set; } -} - -public static class StringBuilderHpQueryExtensions -{ - public static StringBuilder Append(this StringBuilder sb, ref InterfaceInfo interfaceInfo) - { - var genericSb = new StringBuilder(); - foreach (var generic in interfaceInfo.Generics) - { - genericSb.Append(generic).Append(","); - } - - genericSb.Length--; - - var paramSb = new StringBuilder(); - foreach (var param in interfaceInfo.Params) - { - paramSb.Append(param).Append(","); - } - - paramSb.Length--; - - var template = - $$""" - public interface {{interfaceInfo.Name}}<{{genericSb}}> - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - void Update({{paramSb}}); - } - """; - - sb.Append(template); - return sb; - } - - public static StringBuilder AppendInterfaces(this StringBuilder sb, int amount) - { - var generics = new List(); - var parameters = new List(); - - for (var index = 0; index <= amount; index++) - { - generics.Add($"T{index}"); - parameters.Add($"ref T{index} t{index}"); - var interfaceInfo = new InterfaceInfo { Name = "IForEach", Generics = generics, Params = parameters }; - sb.Append(ref interfaceInfo); - } - - return sb; - } - - public static StringBuilder AppendEntityInterfaces(this StringBuilder sb, int amount) - { - var generics = new List(); - var parameters = new List - { - "Entity entity" - }; - - for (var index = 0; index <= amount; index++) - { - generics.Add($"T{index}"); - parameters.Add($"ref T{index} t{index}"); - - var interfaceInfo = new InterfaceInfo { Name = "IForEachWithEntity", Generics = generics, Params = parameters }; - sb.Append(ref interfaceInfo); - } - - return sb; - } - - public static StringBuilder AppendQueryInterfaceMethods(this StringBuilder builder, int amount) - { - for (var index = 0; index <= amount; index++) - { - var generics = new StringBuilder().GenericWithoutBrackets(index); - var getFirstElement = new StringBuilder().GetFirstGenericElements(index); - var getComponents = new StringBuilder().GetGenericComponents(index); - var insertParams = new StringBuilder().InsertGenericParams(index); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void InlineQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEach<{{generics}}> - { - var query = Query(in description); - foreach (ref var chunk in query) - { - {{getFirstElement}} - - foreach(var entityIndex in chunk) - { - {{getComponents}} - iForEach.Update({{insertParams}}); - } - } - } - """; - - builder.AppendLine(template); - } - - // Methods with default T - for (var index = 0; index <= amount; index++) - { - var generics = new StringBuilder().GenericWithoutBrackets(index); - var getFirstElement = new StringBuilder().GetFirstGenericElements(index); - var getComponents = new StringBuilder().GetGenericComponents(index); - var insertParams = new StringBuilder().InsertGenericParams(index); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void InlineQuery(in QueryDescription description) where T : struct, IForEach<{{generics}}> - { - var t = new T(); - - var query = Query(in description); - foreach (ref var chunk in query) - { - var chunkSize = chunk.Size; - {{getFirstElement}} - - foreach(var entityIndex in chunk) - { - {{getComponents}} - t.Update({{insertParams}}); - } - } - } - """; - - builder.AppendLine(template); - } - - return builder; - } - - public static StringBuilder AppendEntityQueryInterfaceMethods(this StringBuilder builder, int amount) - { - for (var index = 0; index <= amount; index++) - { - var generics = new StringBuilder().GenericWithoutBrackets(index); - var getFirstElement = new StringBuilder().GetFirstGenericElements(index); - var getComponents = new StringBuilder().GetGenericComponents(index); - var insertParams = new StringBuilder().InsertGenericParams(index); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void InlineEntityQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEachWithEntity<{{generics}}> - { - var query = Query(in description); - foreach (ref var chunk in query) - { - var chunkSize = chunk.Size; - ref var entityFirstElement = ref chunk.Entity(0); - {{getFirstElement}} - - foreach(var entityIndex in chunk) - { - var entity = Unsafe.Add(ref entityFirstElement, entityIndex); - {{getComponents}} - iForEach.Update(entity, {{insertParams}}); - } - } - } - """; - - builder.AppendLine(template); - } - - // Methods with default T - for (var index = 0; index <= amount; index++) - { - var generics = new StringBuilder().GenericWithoutBrackets(index); - var getFirstElement = new StringBuilder().GetFirstGenericElements(index); - var getComponents = new StringBuilder().GetGenericComponents(index); - var insertParams = new StringBuilder().InsertGenericParams(index); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void InlineEntityQuery(in QueryDescription description) where T : struct, IForEachWithEntity<{{generics}}> - { - var t = new T(); - - var query = Query(in description); - foreach (ref var chunk in query) - { - var chunkSize = chunk.Size; - ref var entityFirstElement = ref chunk.Entity(0); - {{getFirstElement}} - - foreach (var entityIndex in chunk) - { - var entity = Unsafe.Add(ref entityFirstElement, entityIndex); - {{getComponents}} - t.Update(entity, {{insertParams}}); - } - } - } - """; - - builder.AppendLine(template); - } - - return builder; - } -} diff --git a/src/Arch.SourceGen/Queries/Job.cs b/src/Arch.SourceGen/Queries/Job.cs deleted file mode 100644 index 8d259711..00000000 --- a/src/Arch.SourceGen/Queries/Job.cs +++ /dev/null @@ -1,164 +0,0 @@ -namespace Arch.SourceGen; - -public static class StringBuilderChunkJobExtensions -{ - public static void AppendForEachJobs(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - { - sb.AppendForEachJob(index); - } - } - - public static void AppendForEachJob(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var getFirstElement = new StringBuilder().GetFirstGenericElements(amount); - var getComponents = new StringBuilder().GetGenericComponents(amount); - var insertParams = new StringBuilder().InsertGenericParams(amount); - - var template = - $$""" - public struct ForEachJob<{{generics}}> : IChunkJob - { - public ForEach<{{generics}}> ForEach; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Execute(int index, ref Chunk chunk) - { - var chunkSize = chunk.Size; - {{getFirstElement}} - - for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) - { - {{getComponents}} - ForEach({{insertParams}}); - } - } - } - """; - - sb.AppendLine(template); - } - - public static void AppendEntityForEachJobs(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - { - sb.AppendEntityForEachJob(index); - } - } - - public static void AppendEntityForEachJob(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var getFirstElement = new StringBuilder().GetFirstGenericElements(amount); - var getComponents = new StringBuilder().GetGenericComponents(amount); - var insertParams = new StringBuilder().InsertGenericParams(amount); - - var template = - $$""" - public struct ForEachWithEntityJob<{{generics}}> : IChunkJob - { - public ForEachWithEntity<{{generics}}> ForEach; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Execute(int index, ref Chunk chunk) - { - ref var entityFirstElement = ref chunk.Entity(0); - {{getFirstElement}} - - foreach(var entityIndex in chunk) - { - var entity = Unsafe.Add(ref entityFirstElement, entityIndex); - {{getComponents}} - - ForEach(entity, {{insertParams}}); - } - } - } - """; - - sb.AppendLine(template); - } - - public static void AppendIForEachJobs(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - { - sb.AppendIForEachJob(index); - } - } - - public static void AppendIForEachJob(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var getFirstElement = new StringBuilder().GetFirstGenericElements(amount); - var getComponents = new StringBuilder().GetGenericComponents(amount); - var insertParams = new StringBuilder().InsertGenericParams(amount); - - var template = - $$""" - public struct IForEachJob : IChunkJob where T : struct, IForEach<{{generics}}> - { - public T ForEach; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Execute(int index, ref Chunk chunk) - { - var chunkSize = chunk.Size; - {{getFirstElement}} - - for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) - { - {{getComponents}} - ForEach.Update({{insertParams}}); - } - } - } - """; - - sb.AppendLine(template); - } - - public static void AppendIForEachWithEntityJobs(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - { - sb.AppendIForEachWithEntityJob(index); - } - } - - public static void AppendIForEachWithEntityJob(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var getFirstElement = new StringBuilder().GetFirstGenericElements(amount); - var getComponents = new StringBuilder().GetGenericComponents(amount); - var insertParams = new StringBuilder().InsertGenericParams(amount); - - var template = - $$""" - public struct IForEachWithEntityJob : IChunkJob where T : struct, IForEachWithEntity<{{generics}}> - { - public T ForEach; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Execute(int index, ref Chunk chunk) - { - var chunkSize = chunk.Size; - ref var entityFirstElement = ref chunk.Entity(0); - {{getFirstElement}} - - for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) - { - var entity = Unsafe.Add(ref entityFirstElement, entityIndex); - {{getComponents}} - ForEach.Update(entity, {{insertParams}}); - } - } - } - """; - - sb.AppendLine(template); - } -} diff --git a/src/Arch.SourceGen/Queries/ParallelQuery.cs b/src/Arch.SourceGen/Queries/ParallelQuery.cs deleted file mode 100644 index df73725a..00000000 --- a/src/Arch.SourceGen/Queries/ParallelQuery.cs +++ /dev/null @@ -1,124 +0,0 @@ -namespace Arch.SourceGen; - -public static class StringBuilderParallelQueryExtensions -{ - public static StringBuilder AppendParallelQuerys(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - { - sb.AppendParallelQuery(index); - } - - return sb; - } - - public static StringBuilder AppendParallelQuery(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ParallelQuery<{{generics}}>(in QueryDescription description, ForEach<{{generics}}> forEach) - { - var innerJob = new ForEachJob<{{generics}}>(); - innerJob.ForEach = forEach; - - var pool = JobMeta>>.Pool; - var query = Query(in description); - foreach (var archetype in query.GetArchetypeIterator()) { - - var archetypeSize = archetype.Size; - var part = new RangePartitioner(Environment.ProcessorCount, archetypeSize); - foreach (var range in part) - { - var job = pool.Get(); - job.Start = range.Start; - job.Size = range.Length; - job.Chunks = archetype.Chunks; - job.Instance = innerJob; - JobsCache.Add(job); - } - - IJob.Schedule(JobsCache, JobHandles); - JobScheduler.JobScheduler.Instance.Flush(); - JobHandle.Complete(JobHandles); - JobHandle.Return(JobHandles); - - // Return jobs to pool - for (var jobIndex = 0; jobIndex < JobsCache.Count; jobIndex++) - { - var job = Unsafe.As>>(JobsCache[jobIndex]); - pool.Return(job); - } - - JobHandles.Clear(); - JobsCache.Clear(); - } - } - """; - - sb.AppendLine(template); - return sb; - } - - public static StringBuilder AppendParallelEntityQuerys(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - { - sb.AppendParallelEntityQuery(index); - } - - return sb; - } - - public static StringBuilder AppendParallelEntityQuery(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ParallelQuery<{{generics}}>(in QueryDescription description, ForEachWithEntity<{{generics}}> forEach) - { - var innerJob = new ForEachWithEntityJob<{{generics}}>(); - innerJob.ForEach = forEach; - - var pool = JobMeta>>.Pool; - var query = Query(in description); - foreach (var archetype in query.GetArchetypeIterator()) - { - var archetypeSize = archetype.Size; - var part = new RangePartitioner(Environment.ProcessorCount, archetypeSize); - foreach (var range in part) - { - var job = pool.Get(); - job.Start = range.Start; - job.Size = range.Length; - job.Chunks = archetype.Chunks; - job.Instance = innerJob; - JobsCache.Add(job); - } - - IJob.Schedule(JobsCache, JobHandles); - JobScheduler.JobScheduler.Instance.Flush(); - JobHandle.Complete(JobHandles); - JobHandle.Return(JobHandles); - - // Return jobs to pool - for (var jobIndex = 0; jobIndex < JobsCache.Count; jobIndex++) - { - var job = Unsafe.As>>(JobsCache[jobIndex]); - pool.Return(job); - } - - JobHandles.Clear(); - JobsCache.Clear(); - } - } - """; - - sb.AppendLine(template); - return sb; - } -} diff --git a/src/Arch.SourceGen/Queries/Query.cs b/src/Arch.SourceGen/Queries/Query.cs deleted file mode 100644 index d77cff0d..00000000 --- a/src/Arch.SourceGen/Queries/Query.cs +++ /dev/null @@ -1,134 +0,0 @@ -namespace Arch.SourceGen; - -public static class StringBuilderQueryExtensions -{ - public static StringBuilder AppendForEachDelegates(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - { - sb.AppendForEachDelegate(index); - } - - return sb; - } - - public static StringBuilder AppendForEachDelegate(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var parameters = new StringBuilder().GenericRefParams(amount); - - var template = - $$""" - public delegate void ForEach<{{generics}}>({{parameters}}); - """; - - sb.Append(template); - return sb; - } - - public static StringBuilder AppendForEachEntityDelegates(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - { - sb.AppendForEachEntityDelegate(index); - } - - return sb; - } - - public static StringBuilder AppendForEachEntityDelegate(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var parameters = new StringBuilder().GenericRefParams(amount); - - var template = - $$""" - public delegate void ForEachWithEntity<{{generics}}>(Entity entity, {{parameters}}); - """; - - sb.Append(template); - return sb; - } - - public static StringBuilder AppendQueryMethods(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - { - sb.AppendQueryMethod(index); - } - - return sb; - } - - public static StringBuilder AppendQueryMethod(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var getFirstElement = new StringBuilder().GetFirstGenericElements(amount); - var getComponents = new StringBuilder().GetGenericComponents(amount); - var insertParams = new StringBuilder().InsertGenericParams(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Query<{{generics}}>(in QueryDescription description, ForEach<{{generics}}> forEach) - { - var query = Query(in description); - foreach (ref var chunk in query) - { - {{getFirstElement}} - - foreach(var entityIndex in chunk) - { - {{getComponents}} - forEach({{insertParams}}); - } - } - } - """; - - sb.AppendLine(template); - return sb; - } - - public static StringBuilder AppendEntityQueryMethods(this StringBuilder sb, int amount) - { - for (var index = 0; index < amount; index++) - { - sb.AppendEntityQueryMethod(index); - } - - return sb; - } - - public static StringBuilder AppendEntityQueryMethod(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var getFirstElement = new StringBuilder().GetFirstGenericElements(amount); - var getComponents = new StringBuilder().GetGenericComponents(amount); - var insertParams = new StringBuilder().InsertGenericParams(amount); - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Query<{{generics}}>(in QueryDescription description, ForEachWithEntity<{{generics}}> forEach) - { - var query = Query(in description); - foreach (ref var chunk in query) - { - ref var entityFirstElement = ref chunk.Entity(0); - {{getFirstElement}} - - foreach(var entityIndex in chunk) - { - var entity = Unsafe.Add(ref entityFirstElement, entityIndex); - {{getComponents}} - forEach(entity, {{insertParams}}); - } - } - } - """; - - sb.AppendLine(template); - return sb; - } -} diff --git a/src/Arch.SourceGen/Queries/QueryDescription.cs b/src/Arch.SourceGen/Queries/QueryDescription.cs deleted file mode 100644 index 1a485029..00000000 --- a/src/Arch.SourceGen/Queries/QueryDescription.cs +++ /dev/null @@ -1,120 +0,0 @@ -namespace Arch.SourceGen; - -public static class QueryDescriptionExtensions -{ - public static StringBuilder AppendQueryDescriptionWithAlls(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendQueryDescriptionWithAll(index); - } - - return sb; - } - - public static StringBuilder AppendQueryDescriptionWithAll(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [UnscopedRef] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref QueryDescription WithAll<{{generics}}>() - { - All = Group<{{generics}}>.Types; - return ref this; - } - """; - - sb.AppendLine(template); - return sb; - } - - public static StringBuilder AppendQueryDescriptionWithAnys(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendQueryDescriptionWithAny(index); - } - - return sb; - } - - public static StringBuilder AppendQueryDescriptionWithAny(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [UnscopedRef] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref QueryDescription WithAny<{{generics}}>() - { - Any = Group<{{generics}}>.Types; - return ref this; - } - """; - - sb.AppendLine(template); - return sb; - } - - public static StringBuilder AppendQueryDescriptionWithNones(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendQueryDescriptionWithNone(index); - } - - return sb; - } - - public static StringBuilder AppendQueryDescriptionWithNone(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [UnscopedRef] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref QueryDescription WithNone<{{generics}}>() - { - None = Group<{{generics}}>.Types; - return ref this; - } - """; - - sb.AppendLine(template); - return sb; - } - - public static StringBuilder AppendQueryDescriptionWithExclusives(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendQueryDescriptionWithExclusive(index); - } - - return sb; - } - - public static StringBuilder AppendQueryDescriptionWithExclusive(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - - var template = - $$""" - [UnscopedRef] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref QueryDescription WithExclusive<{{generics}}>() - { - Exclusive = Group<{{generics}}>.Types; - return ref this; - } - """; - - sb.AppendLine(template); - return sb; - } -} diff --git a/src/Arch.SourceGen/Queries/RemoveWithQueryDescription.cs b/src/Arch.SourceGen/Queries/RemoveWithQueryDescription.cs deleted file mode 100644 index ea0712ec..00000000 --- a/src/Arch.SourceGen/Queries/RemoveWithQueryDescription.cs +++ /dev/null @@ -1,89 +0,0 @@ -namespace Arch.SourceGen; - -/// -/// Adds extension methods for generating `World.Remove(in query);` methods. -/// -public static class RemoveWithQueryDesription -{ - /// - /// Appends `World.Remove(in query)` methods. - /// - /// The instance. - /// The amount. - /// - public static StringBuilder AppendRemoveWithQueryDescriptions(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendRemoveWithQueryDescription(index); - } - - return sb; - } - - /// - /// Appends a `World.Remove(in query)` method. - /// - /// The instance. - /// The amount of generic parameters. - public static void AppendRemoveWithQueryDescription(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var types = new StringBuilder().GenericTypeParams(amount); - - var clearIds = new StringBuilder(); - var removeEvents = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - clearIds.AppendLine($"spanBitSet.ClearBit(Component.ComponentType.Id);"); - removeEvents.AppendLine($"OnComponentRemoved(archetype);"); - } - - var template = - $$""" - [SkipLocalsInit] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [StructuralChange] - public void Remove<{{generics}}>(in QueryDescription queryDescription) - { - // BitSet to stack/span bitset, size big enough to contain ALL registered components. - Span stack = stackalloc uint[BitSet.RequiredLength(ComponentRegistry.Size)]; - - var query = Query(in queryDescription); - foreach (var archetype in query.GetArchetypeIterator()) - { - // Archetype without T shouldnt be skipped to prevent undefined behaviour. - if(archetype.Entities <= 0 || !archetype.Has<{{generics}}>()) - { - continue; - } - - // Create local bitset on the stack and set bits to get a new fitting bitset of the new archetype. - var bitSet = archetype.BitSet; - var spanBitSet = new SpanBitSet(bitSet.AsSpan(stack)); - {{clearIds}} - - // Get or create new archetype. - if (!TryGetArchetype(spanBitSet.GetHashCode(), out var newArchetype)) - { - newArchetype = GetOrCreate(archetype.Types.Remove({{types}})); - } - - {{removeEvents}} - - // Get last slots before copy, for updating entityinfo later - var archetypeSlot = archetype.LastSlot; - var newArchetypeLastSlot = newArchetype.LastSlot; - Slot.Shift(ref newArchetypeLastSlot, newArchetype.EntitiesPerChunk); - EntityInfo.Shift(archetype, archetypeSlot, newArchetype, newArchetypeLastSlot); - - Archetype.Copy(archetype, newArchetype); - archetype.Clear(); - } - } - """; - - sb.AppendLine(template); - } -} - diff --git a/src/Arch.SourceGen/Queries/SetWithQueryDescription.cs b/src/Arch.SourceGen/Queries/SetWithQueryDescription.cs deleted file mode 100644 index c021dab2..00000000 --- a/src/Arch.SourceGen/Queries/SetWithQueryDescription.cs +++ /dev/null @@ -1,68 +0,0 @@ -namespace Arch.SourceGen; - -/// -/// Adds extension methods for generating `World.Remove(in query);` methods. -/// -public static class SetWithQueryDesription -{ - /// - /// Appends `World.Set(in query)` methods. - /// - /// The instance. - /// The amount. - /// - public static StringBuilder AppendSetWithQueryDescriptions(this StringBuilder sb, int amount) - { - for (var index = 1; index < amount; index++) - { - sb.AppendSetWithQueryDescription(index); - } - - return sb; - } - - /// - /// Appends a `World.Set(in query)` method. - /// - /// The instance. - /// The amount of generic parameters. - public static void AppendSetWithQueryDescription(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var getFirsts = new StringBuilder().GetFirstGenericElements(amount); - var getComponents = new StringBuilder().GetGenericComponents(amount); - var parameters = new StringBuilder().GenericInDefaultParams(amount,"ComponentValue"); - - var assignValues = new StringBuilder(); - var assignValuesEvents = new StringBuilder(); - for (var index = 0; index <= amount; index++) - { - assignValues.AppendLine($"t{index}Component = t{index}ComponentValue;"); - assignValuesEvents.AppendLine($"OnComponentSet(entity);"); - } - - var template = - $$""" - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set<{{generics}}>(in QueryDescription queryDescription, {{parameters}}) - { - var query = Query(in queryDescription); - foreach (ref var chunk in query) - { - {{getFirsts}} - foreach (var entityIndex in chunk) - { - {{getComponents}} - {{assignValues}} - #if EVENTS - var entity = chunk.Entity(entityIndex); - {{assignValuesEvents}} - #endif - } - } - } - """; - - sb.AppendLine(template); - } -} diff --git a/src/Arch.SourceGen/QueryGenerator.cs b/src/Arch.SourceGen/QueryGenerator.cs deleted file mode 100644 index 2e69080c..00000000 --- a/src/Arch.SourceGen/QueryGenerator.cs +++ /dev/null @@ -1,183 +0,0 @@ -using Arch.SourceGen.Fundamentals; -using ArchSourceGenerator; - -namespace Arch.SourceGen; - -[Generator] -public class QueryGenerator : IIncrementalGenerator -{ - public void Initialize(IncrementalGeneratorInitializationContext context) - { - if (!Debugger.IsAttached) - { - //Debugger.Launch(); - } - - context.RegisterPostInitializationOutput(initializationContext => - { - // DONE - var compileTimeStatics = new StringBuilder(); - compileTimeStatics.AppendLine("using System;"); - compileTimeStatics.AppendLine("using System.Threading;"); - compileTimeStatics.AppendLine("namespace Arch.Core.Utils;"); - compileTimeStatics.AppendLine("/*"); - compileTimeStatics.AppendGroups(25); - compileTimeStatics.AppendLine("*/"); - - var delegates = new StringBuilder(); - delegates.AppendLine("using System;"); - delegates.AppendLine("namespace Arch.Core;"); - delegates.AppendLine("/*"); - delegates.AppendForEachDelegates(25); - delegates.AppendForEachEntityDelegates(25); - delegates.AppendLine("*/"); - - var interfaces = new StringBuilder(); - interfaces.AppendLine("using System;"); - interfaces.AppendLine("using System.Runtime.CompilerServices;"); - interfaces.AppendLine("namespace Arch.Core;"); - interfaces.AppendLine("/*"); - interfaces.AppendInterfaces(25); - interfaces.AppendEntityInterfaces(25); - interfaces.AppendLine("*/"); - - var references = new StringBuilder(); - references.AppendLine("using System;"); - references.AppendLine("using System.Runtime.CompilerServices;"); - references.AppendLine("using CommunityToolkit.HighPerformance;"); - references.AppendLine("namespace Arch.Core;"); - references.AppendLine("/*"); - references.AppendComponents(25); - references.AppendEntityComponents(25); - references.AppendLine("*/"); - - var jobs = new StringBuilder(); - jobs.AppendLine("using System;"); - jobs.AppendLine("using System.Runtime.CompilerServices;"); - jobs.AppendLine("using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;"); - jobs.AppendLine("namespace Arch.Core;"); - jobs.AppendLine("/*"); - jobs.AppendForEachJobs(25); - jobs.AppendEntityForEachJobs(25); - jobs.AppendIForEachJobs(25); - jobs.AppendIForEachWithEntityJobs(25); - jobs.AppendLine("*/"); - - var accessors = new StringBuilder(); - accessors.AppendLine("using System;"); - accessors.AppendLine("using System.Runtime.CompilerServices;"); - accessors.AppendLine("using JobScheduler;"); - accessors.AppendLine("using Arch.Core.Utils;"); - accessors.AppendLine("using System.Diagnostics.Contracts;"); - accessors.AppendLine("using Arch.Core.Extensions;"); - accessors.AppendLine("using Arch.Core.Extensions.Internal;"); - accessors.AppendLine("using System.Diagnostics.CodeAnalysis;"); - accessors.AppendLine("using CommunityToolkit.HighPerformance;"); - accessors.AppendLine("using ArrayExtensions = CommunityToolkit.HighPerformance.ArrayExtensions;"); - accessors.AppendLine("using System.Buffers;"); - accessors.AppendLine( - $$""" - namespace Arch.Core - { - public partial struct Chunk - { - /* - {{new StringBuilder().AppendChunkIndexes(25)}} - {{new StringBuilder().AppendChunkHases(25)}} - {{new StringBuilder().AppendChunkIndexGets(25)}} - {{new StringBuilder().AppendChunkIndexGetRows(25)}} - {{new StringBuilder().AppendChunkIndexSets(25)}} - - {{new StringBuilder().AppendChunkGetArrays(25)}} - {{new StringBuilder().AppendChunkGetSpans(25)}} - {{new StringBuilder().AppendChunkGetFirsts(25)}} - */ - } - - public partial class Archetype - { - /* - {{new StringBuilder().AppendArchetypeHases(25)}} - {{new StringBuilder().AppendArchetypeGets(25)}} - {{new StringBuilder().AppendArchetypeSets(25)}} - {{new StringBuilder().AppendArchetypeSetRanges(25)}} - */ - } - - public partial class World - { - /* - {{new StringBuilder().AppendCreates(25)}} - {{new StringBuilder().AppendWorldHases(25)}} - {{new StringBuilder().AppendWorldGets(25)}} - {{new StringBuilder().AppendWorldSets(25)}} - {{new StringBuilder().AppendWorldAdds(25)}} - {{new StringBuilder().AppendWorldRemoves(25)}} - - {{new StringBuilder().AppendQueryMethods(25)}} - {{new StringBuilder().AppendEntityQueryMethods(25)}} - {{new StringBuilder().AppendParallelQuerys(25)}} - {{new StringBuilder().AppendParallelEntityQuerys(25)}} - - {{new StringBuilder().AppendQueryInterfaceMethods(25)}} - {{new StringBuilder().AppendEntityQueryInterfaceMethods(25)}} - {{new StringBuilder().AppendHpParallelQuerys(25)}} - {{new StringBuilder().AppendHpeParallelQuerys(25)}} - - {{new StringBuilder().AppendSetWithQueryDescriptions(25)}} - {{new StringBuilder().AppendAddWithQueryDescriptions(25)}} - {{new StringBuilder().AppendRemoveWithQueryDescriptions(25)}} - */ - } - - public partial struct QueryDescription - { - /* - {{new StringBuilder().AppendQueryDescriptionWithAlls(25)}} - {{new StringBuilder().AppendQueryDescriptionWithAnys(25)}} - {{new StringBuilder().AppendQueryDescriptionWithNones(25)}} - {{new StringBuilder().AppendQueryDescriptionWithExclusives(25)}} - */ - } - - } - - namespace Arch.Core.Extensions - { - /* - public static partial class EntityExtensions - { - #if !PURE_ECS - {{new StringBuilder().AppendEntityHases(25)}} - {{new StringBuilder().AppendEntitySets(25)}} - {{new StringBuilder().AppendEntityGets(25)}} - {{new StringBuilder().AppendEntityAdds(25)}} - {{new StringBuilder().AppendEntityRemoves(25)}} - #endif - } - */ - - } - """ - ); - - initializationContext.AddSource("CompileTimeStatics.g.cs", - CSharpSyntaxTree.ParseText(compileTimeStatics.ToString()).GetRoot().NormalizeWhitespace().ToFullString()); - - initializationContext.AddSource("Delegates.g.cs", - CSharpSyntaxTree.ParseText(delegates.ToString()).GetRoot().NormalizeWhitespace().ToFullString()); - - initializationContext.AddSource("Interfaces.g.cs", - CSharpSyntaxTree.ParseText(interfaces.ToString()).GetRoot().NormalizeWhitespace().ToFullString()); - - initializationContext.AddSource("References.g.cs", - CSharpSyntaxTree.ParseText(references.ToString()).GetRoot().NormalizeWhitespace().ToFullString()); - - initializationContext.AddSource("Jobs.g.cs", - CSharpSyntaxTree.ParseText(jobs.ToString()).GetRoot().NormalizeWhitespace().ToFullString()); - - initializationContext.AddSource("Accessors.g.cs", - CSharpSyntaxTree.ParseText(accessors.ToString()).GetRoot().NormalizeWhitespace().ToFullString()); - }); - } -} diff --git a/src/Arch.SourceGen/StringBuilderExtensions.cs b/src/Arch.SourceGen/StringBuilderExtensions.cs deleted file mode 100644 index fae466fd..00000000 --- a/src/Arch.SourceGen/StringBuilderExtensions.cs +++ /dev/null @@ -1,259 +0,0 @@ -namespace Arch.SourceGen; - -/// -/// The class -/// contains several static extensions for the to ease code generation. -/// -public static class StringBuilderExtensions -{ - - - /// - /// Appends a comma seperated list of generics like in between diamong operators mostly. But without the diamonds. - /// - /// - /// T0,T1,T2... - /// - /// - /// - /// - /// - /// - public static StringBuilder GenericWithoutBrackets(this StringBuilder sb, int amount) - { - for (var localIndex = 0; localIndex <= amount; localIndex++) - { - sb.Append($"T{localIndex},"); - } - - sb.Length--; - - return sb; - } - - - // Queries, set, has & get - - /// TODO : Probably use chunk.GetFirst<...>(); overloads instead? - /// - /// Gets all generic first elements from an chunk and lists them up under each other. - /// - /// - /// ref var t0FirstElement = ref chunk.GetFirst<T0>(); - /// ref var t1FirstElement = ref chunk.GetFirst<T1>(); - /// ... - /// - /// - /// - /// - /// - /// - public static StringBuilder GetFirstGenericElements(this StringBuilder sb, int amount) - { - for (var localIndex = 0; localIndex <= amount; localIndex++) - { - sb.AppendLine($"ref var t{localIndex}FirstElement = ref chunk.GetFirst();"); - } - return sb; - } - - /// - /// Gets generics components from the first element and lists them under each other. - /// - /// - /// ref var t0Component = ref Unsafe.Add(ref t0FirstElement, entityIndex); - /// ref var t1Component = ref Unsafe.Add(ref t1FirstElement, entityIndex); - /// ... - /// - /// - /// - /// - /// - /// - public static StringBuilder GetGenericComponents(this StringBuilder sb, int amount) - { - for (var localIndex = 0; localIndex <= amount; localIndex++) - { - sb.AppendLine($"ref var t{localIndex}Component = ref Unsafe.Add(ref t{localIndex}FirstElement, entityIndex);"); - } - - return sb; - } - - /// - /// Lists ref params in a row as parameters. - /// - /// - /// ref T0 t0Component, ref T1 t1Component,... - /// - /// - /// - /// - /// - /// - public static StringBuilder GenericRefParams(this StringBuilder sb, int amount) - { - for (var localIndex = 0; localIndex <= amount; localIndex++) - { - sb.Append($"ref T{localIndex} t{localIndex}Component,"); - } - - sb.Length--; - return sb; - } - - /// - /// Lists in params in a row as parameters. - /// - /// - /// in T0 t0Component, in T1 t1Component,... - /// - /// - /// - /// - /// - /// - public static StringBuilder GenericInDefaultParams(this StringBuilder sb, int amount, string name = "Component") - { - for (var localIndex = 0; localIndex <= amount; localIndex++) - { - sb.Append($"in T{localIndex} t{localIndex}{name} = default,"); - } - - sb.Length--; - return sb; - } - - /// - /// Lists ref params in a row as parameters with in. - /// - /// - /// in T0 t0Component, in T1 t1Component,... - /// - /// - /// - /// - /// - /// - public static StringBuilder GenericInParams(this StringBuilder sb, int amount) - { - for (var localIndex = 0; localIndex <= amount; localIndex++) - { - sb.Append($"in T{localIndex} t{localIndex}Component,"); - } - - sb.Length--; - return sb; - } - - /// - /// Inserts ref params in a row as parameters. - /// - /// - /// ref t0Component, ref t1Component,... - /// - /// - /// - /// - /// - /// - public static StringBuilder InsertGenericParams(this StringBuilder sb, int amount) - { - for (var localIndex = 0; localIndex <= amount; localIndex++) - { - sb.Append($"ref t{localIndex}Component,"); - } - - sb.Length--; - return sb; - } - - /// - /// Inserts ref params in a row as parameters. - /// - /// - /// in t0Component, in t1Component,... - /// - /// - /// - /// - /// - /// - public static StringBuilder InsertGenericInParams(this StringBuilder sb, int amount) - { - for (var localIndex = 0; localIndex <= amount; localIndex++) - { - sb.Append($"in t{localIndex}Component,"); - } - - sb.Length--; - return sb; - } - - - /// - /// Gets out params and appends them after each other - /// - /// - /// out var t1Array, out var t2Array - /// - /// - /// - /// The appendix. - /// - /// - /// - public static StringBuilder InsertGenericOutParams(this StringBuilder sb, string appendix, int amount) - { - var arrays = new StringBuilder(); - for (var localIndex = 0; localIndex <= amount; localIndex++) - { - arrays.Append($"out var t{localIndex}{appendix},"); - } - arrays.Length--; - - return arrays; - } - - /// - /// Lists the types of generics in a row. - /// - /// - /// typeof(T0), typeof(T1),... - /// - /// - /// - /// - /// - /// - public static StringBuilder GenericTypeParams(this StringBuilder sb, int amount) - { - for (var index = 0; index <= amount; index++) - { - sb.Append($"typeof(T{index}),"); - } - sb.Length--; - return sb; - } - - - /// - /// Gets the chunk arrays in one line and appends them. - /// - /// - /// GetArray<T, T1, ...>(out var t0Array, out var t1Array,...); - /// - /// - /// - /// - /// - /// - public static StringBuilder GetChunkArrays(this StringBuilder sb, int amount) - { - var generics = new StringBuilder().GenericWithoutBrackets(amount); - var arrays = new StringBuilder().InsertGenericOutParams("Array", amount); - - sb.Append($"GetArray<{generics}>({arrays});"); - return sb; - } -} From af7bda7b31766a8cf8918ae090e9b3d27c4ad0e5 Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Wed, 1 Nov 2023 04:45:46 -0700 Subject: [PATCH 08/16] variadic reorganization and documentation --- src/Arch.SourceGen/CopyArgsAlgorithm.cs | 69 ++++ src/Arch.SourceGen/CopyLinesAlgorithm.cs | 41 +++ src/Arch.SourceGen/CopyParamsAlgorithm.cs | 82 +++++ src/Arch.SourceGen/DefaultAlgorithm.cs | 109 ++++++ src/Arch.SourceGen/LineAlgorithm.cs | 42 +++ .../VariadicAlgorithmAttribute.cs | 6 + src/Arch.SourceGen/VariadicGenerator.cs | 323 ++++-------------- .../Core/Variadics/Archetype.Variadics.cs | 4 + src/Arch/Core/Variadics/Chunk.Variadics.cs | 12 +- .../Variadics/EntityExtensions.Variadics.cs | 8 +- src/Arch/Core/Variadics/Jobs.Variadics.cs | 11 + .../Variadics/QueryDescription.Variadics.cs | 4 + src/Arch/Core/Variadics/World.Variadics.cs | 20 ++ src/Arch/VariadicAttribute.cs | 20 +- 14 files changed, 483 insertions(+), 268 deletions(-) create mode 100644 src/Arch.SourceGen/CopyArgsAlgorithm.cs create mode 100644 src/Arch.SourceGen/CopyLinesAlgorithm.cs create mode 100644 src/Arch.SourceGen/CopyParamsAlgorithm.cs create mode 100644 src/Arch.SourceGen/DefaultAlgorithm.cs create mode 100644 src/Arch.SourceGen/LineAlgorithm.cs create mode 100644 src/Arch.SourceGen/VariadicAlgorithmAttribute.cs diff --git a/src/Arch.SourceGen/CopyArgsAlgorithm.cs b/src/Arch.SourceGen/CopyArgsAlgorithm.cs new file mode 100644 index 00000000..d7dd3172 --- /dev/null +++ b/src/Arch.SourceGen/CopyArgsAlgorithm.cs @@ -0,0 +1,69 @@ +using System.Text.RegularExpressions; + +namespace Arch.SourceGen; + +/// +/// repeats a given argument of structure {name}__{variadicType}, separated by commas. It properly copies any ref, in, out, etc modifiers. +/// It will additionally copy generic type arguments matching the variadic type, only if the variadic type is the last in the type parameter list. +/// +/// +/// With type parameter T0: +/// +/// MyMethod<T0>(in component__T0) +/// +/// ... will convert to: +/// +/// MyMethod<T0, T1>(in component__T0, in component__T1) +/// +/// +[VariadicAlgorithm] +internal class CopyArgsAlgorithm : LineAlgorithm +{ + public override string Name { get => "CopyArgs"; } + public override int ExpectedParameterCount { get => 1; } + + public override string Transform(string line, string type, int start, int variations, string[] parameters) + { + StringBuilder transformed = new(); + transformed.AppendLine(line); + StringBuilder newVariables = new(); + + // match ref, in, out + var modifiersMatch = Regex.Match(line, $@"[(,]\s*(?(ref|out ref|out var|out {type}\??|in|ref {type}\??))?\s*{parameters[0]}__{type}"); + if (!modifiersMatch.Success) + { + throw new InvalidOperationException($"Can't find variable {parameters[0]}__{type} in a parameter list."); + } + + var modifiers = modifiersMatch.Groups["Modifiers"].Value; + + newVariables.Append($"{modifiers} {parameters[0]}__{type}"); + for (int i = start; i < variations; i++) + { + var variadic = VaryType(type, i); + newVariables.Append($", {modifiers} {parameters[0]}__{variadic}"); + } + + transformed.Remove(modifiersMatch.Index + 1, modifiersMatch.Length - 1); + transformed.Insert(modifiersMatch.Index + 1, newVariables.ToString()); + + // expand any remaining generics + // note that this'll break if the user uses Span instead of var or something.... + StringBuilder variadics = new(); + for (int i = start - 1; i < variations; i++) + { + variadics.Append(VaryType(type, i)); + if (i != variations - 1) + { + variadics.Append(", "); + } + } + + variadics.Append(">"); + + // Apply generics: expand T0> -> T0, T1...> + transformed.Replace(type + ">", variadics.ToString()); + + return transformed.ToString(); + } +} diff --git a/src/Arch.SourceGen/CopyLinesAlgorithm.cs b/src/Arch.SourceGen/CopyLinesAlgorithm.cs new file mode 100644 index 00000000..17d1823b --- /dev/null +++ b/src/Arch.SourceGen/CopyLinesAlgorithm.cs @@ -0,0 +1,41 @@ +namespace Arch.SourceGen; + +/// +/// is a very simple algorithm that will simply repeat the line, replacing any occurances of the variadic type with its variant for each iteration. +/// +/// +/// With type parameter T0: +/// +/// /// [Variadic: CopyLines] +/// somethingSomething__T0 = new T0(); // look! T0! +/// +/// ... will expand to: +/// +/// somethingSomething__T0 = new T0(); // look! T0! +/// somethingSomething__T1 = new T1(); // look! T1! +/// ... +/// +/// +[VariadicAlgorithm] +internal class CopyLinesAlgorithm : LineAlgorithm +{ + public override string Name { get => "CopyLines"; } + public override int ExpectedParameterCount { get => 0; } + + public override string Transform(string line, string type, int start, int variations, string[] parameters) + { + StringBuilder transformed = new(); + transformed.AppendLine(line); + + for (int i = start; i < variations; i++) + { + StringBuilder next = new(); + next.AppendLine(line); + var variadic = VaryType(type, i); + next.Replace(type, variadic); + transformed.AppendLine(next.ToString()); + } + + return transformed.ToString(); + } +} diff --git a/src/Arch.SourceGen/CopyParamsAlgorithm.cs b/src/Arch.SourceGen/CopyParamsAlgorithm.cs new file mode 100644 index 00000000..d3dd0665 --- /dev/null +++ b/src/Arch.SourceGen/CopyParamsAlgorithm.cs @@ -0,0 +1,82 @@ +using System.Text.RegularExpressions; + +namespace Arch.SourceGen; + +/// +/// +/// The is a special algorithm for more complicated method headers that can't be handled by the basic . +/// In particular, it handles cases of a type other than directly the variadic type, that needs to be transformed and copied. It also handles variable initializers. +/// For example, it will expand ref Span<T0>? component__T0 = default to +/// ref Span<T0>? component__T0 = default, ref Span<T1>? component__T1 = default .... +/// +/// +/// Basically, use this algorithm if your method has any of these: Initializers (= default), nullables (T0?), or wrapped type arguments +/// (MyWrapper<T, T0>). +/// +/// +/// Of note, it won't expand generic parameters within arguments like the default algorithm will, which is often not desired. +/// +/// +[VariadicAlgorithm] +internal class CopyParamsAlgorithm : LineAlgorithm +{ + public override int ExpectedParameterCount { get => 1; } + public override string Name { get => "CopyParams"; } + + public override string Transform(string line, string type, int start, int variations, string[] parameters) + { + // This is a special algorithm denotion for method headers. + // This grabs the first param that matches the passed in type (in Variables[0]), like "Span? paramName__T0 = default" + // it extracts paramName, the initializer if it exists, any ref/out/in modifiers, and repeats it according to the type params. + var headerMatch = Regex.Match(line, $@"[(,]\s*(?(ref|out|ref readonly|in)\s+)?{Regex.Escape(parameters[0])}\s+(?\w+)__{type}\s*(?=\s*default)?"); + + if (!headerMatch.Success) + { + throw new InvalidOperationException($"Malformed method header for {nameof(CopyParamsAlgorithm)}."); + } + + bool hasDefault = headerMatch.Groups["Assignment"].Success; + string modifiers = headerMatch.Groups["Modifiers"].Success ? headerMatch.Groups["Modifiers"].Value : string.Empty; + string param = headerMatch.Groups["ParamName"].Value; + + List additionalParams = new(); + for (int i = start; i < variations; i++) + { + var variadic = VaryType(type, i); + // One issue with this approach... if we had a wrapper type of SomethingT1 (which is bad name but whatever) then this would break. + // but so far we don't have anything like that. + var fullType = parameters[0].Replace(type, variadic); + additionalParams.Add($"{modifiers} {fullType} {param}__{variadic} {(hasDefault ? "= default" : "")}"); + } + + StringBuilder transformed = new(); + transformed.Append(line); + + StringBuilder @params = new(); + // +1 to exclude the opening parenthesis or comma + @params.Append(line.Substring(headerMatch.Index + 1, headerMatch.Length - 1)); + foreach (var additionalParam in additionalParams) + { + @params.Append(", " + additionalParam); + } + + // For the rest of the line, we do a trick: we want to apply the regular op on the rest of the header, so we remove all args and re-add them after. + // We do this so we don't have to process constraints/generics separately. + + // Remove all the args we just added + transformed.Remove(headerMatch.Index + 1, headerMatch.Length - 1); + var lineWithoutArgs = transformed.ToString(); + var defaultAlgorithm = new DefaultAlgorithm(); + transformed.Clear(); + // Do a default transform on everything but the args + transformed.Append(defaultAlgorithm.Transform(lineWithoutArgs, type, start, variations, Array.Empty())); + + // Find where we left off; we either left a hanging comma or an () + var match = Regex.Match(transformed.ToString(), @"(,\s*\)|\(\s*\))"); + Debug.Assert(match.Success); + // Stick our params back in there + transformed.Insert(match.Index + 1, @params); + + return transformed.ToString(); + } +} diff --git a/src/Arch.SourceGen/DefaultAlgorithm.cs b/src/Arch.SourceGen/DefaultAlgorithm.cs new file mode 100644 index 00000000..f1f655b5 --- /dev/null +++ b/src/Arch.SourceGen/DefaultAlgorithm.cs @@ -0,0 +1,109 @@ +using System.Text.RegularExpressions; + +namespace Arch.SourceGen; + +/// +/// +/// The runs by default on any lines where a variadic comment like "// [Variadic: MethodName(param1...)]" is NOT present. +/// +/// +/// The behavior of the algorithm is as such: +/// +/// +/// Anywhere in the string, if there is a type sequence ending in the specified variadic type, it fills in the variadics. For example, <T, T0> will +/// expand to <T, T0, T1...>. The generic sequence must end in the specified variadic type, otherwise nothing will be changed. +/// +/// +/// If any type constraints are found with the specified variadic type, it copies the constraints to each new type. For example, with type T0, +/// where T0 : struct, new() will expand to where T0 : struct, new() where T1 : struct, new() .... Of note, nested constraints of the variadic +/// types are not currently processed correctly, i.e. where T0 : ISomething<T0>. If that behavior is needed, either edit this algorithm or introduce a new one. +/// +/// +/// For method headers, it copies simple type parameters of the given variadic type, with the form {paramName}__{type}. For example, in T0 component__T0 +/// would expand to in T0 component__T0, in T1 component__T1. Note that this algorithm isn't smart enough to recognize wrapped parameters, such as +/// in Span<T0> component__T0; it will expand it to an invalid Span<T0, T1, ...>. To use the former behavior, or if initializers like +/// component__T0 = default is needed, or nullables are needed, specify instead with an explicit type to copy. +/// +/// +/// Nothing else is changed. +/// +/// +[VariadicAlgorithm] +internal class DefaultAlgorithm : LineAlgorithm +{ + public override int ExpectedParameterCount { get => 0; } + public override string Name { get => string.Empty; } + public override string Transform(string line, string type, int start, int variations, string[] parameters) + { + StringBuilder transformed = new(); + + // copy type constraints for our selected variadic + var constraints = Regex.Match(line, @$"where\s+{type}\s*:\s*(?.*?)(?:where|{{|$)"); + if (constraints.Success) + { + // append anything prior to the original constraint + transformed.Append(line.Substring(0, constraints.Index)); + + // append extra constraints as needed + for (int i = 1; i < variations; i++) + { + transformed.Append($" where {VaryType(type, i)} : {constraints.Groups["Constraints"].Value} "); + } + + // add in the rest of the line, plus the original constraint + transformed.Append(line.Substring(constraints.Index, line.Length - constraints.Index)); + } + else + { + // no constraints, just add the line + transformed.Append(line); + } + + // build a string like "T0, T1, ...>" + StringBuilder variadics = new(); + for (int i = start - 1; i < variations; i++) + { + variadics.Append(VaryType(type, i)); + if (i != variations - 1) + { + variadics.Append(", "); + } + } + + variadics.Append(">"); + + // Apply generics: expand T0> -> T0, T1...> + // Applied everywhere, wherever generics appear! + transformed.Replace(type + ">", variadics.ToString()); + + // Expand params in header (i.e. T0 component__T0 -> T0 component__T0, T1 component__T1... + // This is the 90% case. Occasionally there needs to be special handling for a method header. + // Those cases are handled by CopyParamsAlgorithm + // Modifiers is ref, in, out etc. + // ParamName is the paramname we need to copy, + var exp = $@"[(,]\s*(?(?:in|out|ref|ref\s+readonly)\s+)?{type}\s+(?\w+)__{type}"; + var paramMatch = Regex.Match(transformed.ToString(), exp); + if (paramMatch.Success) + { + var name = paramMatch.Groups["ParamName"].Value; + var modifiers = paramMatch.Groups["Modifiers"].Value; + + StringBuilder newParams = new(); + for (int i = start - 1; i < variations; i++) + { + var varied = VaryType(type, i); + newParams.Append($"{modifiers} {varied} {name}__{varied}"); + if (i != variations - 1) + { + newParams.Append(", "); + } + } + + transformed.Remove(paramMatch.Index + 1, paramMatch.Length - 1); + transformed.Insert(paramMatch.Index + 1, newParams); + } + + return transformed.ToString(); + + } +} diff --git a/src/Arch.SourceGen/LineAlgorithm.cs b/src/Arch.SourceGen/LineAlgorithm.cs new file mode 100644 index 00000000..bdd5cd14 --- /dev/null +++ b/src/Arch.SourceGen/LineAlgorithm.cs @@ -0,0 +1,42 @@ +using System.Text.RegularExpressions; + +namespace Arch.SourceGen; + +/// +/// Base class for an algorithm that processes a given line. +/// Tag subclasses with to automatically add them to the generator. +/// +internal abstract class LineAlgorithm +{ + /// + /// The name of the algorithm, as specified in the marking comment. + /// + public abstract string Name { get; } + + /// + /// The exact count of parameters to require for . + /// + public abstract int ExpectedParameterCount { get; } + + /// + /// Transform a string based on the algorithm's behavior. + /// + /// The input line. + /// The variadic type provided in the variadic attribute, e.g. T0 + /// The first extra variadic to generate, e.g. `2` if one variadic is provided in the template method. + /// How many variadics to generate. This will be called with various numbers of variations to generate the full variadic spectrum. + /// The parameters provided to the variadic comment, if any. + /// The transformed string according to the algorithm. + public abstract string Transform(string line, string type, int start, int variations, string[] parameters); + + protected static string VaryType(string typeName, int i) + { + var match = Regex.Match(typeName, @"(?\w+)[0-9]+"); + if (!match.Success) + { + throw new InvalidOperationException("Variadic type must be of TypeName{N}"); + } + + return $"{match.Groups["PrunedName"]}{i}"; + } +} diff --git a/src/Arch.SourceGen/VariadicAlgorithmAttribute.cs b/src/Arch.SourceGen/VariadicAlgorithmAttribute.cs new file mode 100644 index 00000000..37d720d2 --- /dev/null +++ b/src/Arch.SourceGen/VariadicAlgorithmAttribute.cs @@ -0,0 +1,6 @@ +namespace Arch.SourceGen; + +/// +/// Denotes a as being an applicable algorithm, and will be applied by +/// +internal class VariadicAlgorithmAttribute : Attribute { } diff --git a/src/Arch.SourceGen/VariadicGenerator.cs b/src/Arch.SourceGen/VariadicGenerator.cs index 5a7362e4..c214e53c 100644 --- a/src/Arch.SourceGen/VariadicGenerator.cs +++ b/src/Arch.SourceGen/VariadicGenerator.cs @@ -1,12 +1,21 @@ using System.Text.RegularExpressions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using System.Linq; namespace Arch.SourceGen; +/// +/// The finds assembly members with , and generates variadic types. +/// See the attribute's documentation for information on usage. +/// [Generator] public class VariadicGenerator : IIncrementalGenerator { + // A note on implementation: + // This class is implemented on a line-by-line basis making heavy use of regular expressions to parse C# code. + // Clearly, this isn't ideal. The "correct" way of implementing something like this would be a CSharpSyntaxRewriter. + // However, CSharpSyntaxRewriter is poorly documented and can lead to a lot of very very difficult code. + // For now, since this is limited to Arch, it's enough to use this. + private class VariadicInfo { public string Type { get; set; } = string.Empty; @@ -22,15 +31,17 @@ private class VariadicInfo public void Initialize(IncrementalGeneratorInitializationContext context) { - //Debugger.Launch(); + // Uncomment to help debug with breakpoints: + // Debugger.Launch(); + var infos = context.SyntaxProvider.ForAttributeWithMetadataName("Arch.Core.VariadicAttribute", - // TODO: slow, make better filter + // We want to grab everything with the attribute, always! (node, token) => true, (ctx, token) => { VariadicInfo info = new(); - // note: doesn't support mulilevel nesting + // Note: doesn't support mulilevel type nesting, like struct Something { struct AnotherThing { struct AThirdThing {} } }. Only 1 nesting layer is supported. if (ctx.TargetSymbol.ContainingType is not null) { info.EnclosingTypeName = ctx.TargetSymbol.ContainingType.Name; @@ -106,16 +117,48 @@ public void Initialize(IncrementalGeneratorInitializationContext context) }); } + // stores the algorithms from reflection + private static Dictionary _algorithms = new(); + + // collect the algorithms available with reflection on the attribute + static VariadicGenerator() + { + foreach (var type in typeof(VariadicGenerator).Assembly.GetTypes()) + { + if (type.GetCustomAttributes(typeof(VariadicAlgorithmAttribute), true).Length > 0) + { + var algorithm = (LineAlgorithm)Activator.CreateInstance(type); + if (_algorithms.ContainsKey(algorithm.Name)) + { + throw new InvalidOperationException($"Two {nameof(LineAlgorithm)}s cannot have the same name!"); + } + _algorithms[algorithm.Name] = algorithm; + } + } + } + private string MakeVariadic(VariadicInfo info) { - var tokens = Tokenize(info).ToList(); + var lines = ProcessLines(info).ToList(); StringBuilder combined = new(); for (var i = info.Start; i < info.Count; i++) { - foreach (var token in tokens) + foreach (var line in lines) { - combined.AppendLine(token.Transform(info.Start, i + 1, info.Type)); + if (!_algorithms.ContainsKey(line.Algorithm)) + { + throw new InvalidOperationException($"Algorithm {line.Algorithm} is unknown."); + } + + var algo = _algorithms[line.Algorithm]; + if (algo.ExpectedParameterCount != line.Parameters.Length) + { + throw new InvalidOperationException($"Algorithm {line.Algorithm} supports only exactly {algo.ExpectedParameterCount} parameters, " + + $"but {line.Parameters.Length} were provided."); + } + + combined.AppendLine(algo.Transform(line.Line, info.Type, info.Start, i + 1, line.Parameters)); } } @@ -136,252 +179,17 @@ namespace {{info.Namespace}}; private struct LineInfo { - public LineInfo() { } - public enum Operation - { - None, - // [Variadic: CopyLines] - CopyLines, - // [Variadic: CopyArgs(variableName)] - CopyArgs, - // [Variadic: CopyParams(enclosingTypeName)] - // necessary for params like Span span__T0... - // or nullables, or defaults. - // But the default behavior Operation.None works for most methods. - CopyParams - } - - public Operation Op { get; set; } = Operation.None; - public string Line { get; set; } = string.Empty; - public string[] Variables { get; set; } = Array.Empty(); - - public readonly string Transform(int start, int variations, string type) - { - if (Op == Operation.None) - { - // apply type constraints - StringBuilder transformed = new(); - var constraints = Regex.Match(Line, @$"where\s+{type}\s*:\s*(?.*?)(?:where|{{|$)"); - if (constraints.Success) - { - transformed.Append(Line.Substring(0, constraints.Index)); - for (int i = 1; i < variations; i++) - { - transformed.Append($" where {VaryType(type, i)} : {constraints.Groups["Constraints"].Value} "); - } - - transformed.Append(Line.Substring(constraints.Index, Line.Length - constraints.Index)); - } - else - { - transformed.Append(Line); - } - - StringBuilder variadics = new(); - - for (int i = start - 1; i < variations; i++) - { - variadics.Append(VaryType(type, i)); - if (i != variations - 1) - { - variadics.Append(", "); - } - } - - variadics.Append(">"); - - // Apply generics: expand T0> -> T0, T1...> - transformed.Replace(type + ">", variadics.ToString()); - - // Expand params in header (i.e. T0 component__T0 -> T0 component__T0, T1 component__t1... - // This is the 90% case. Occasionally there needs to be special handling for a method header. - // Those cases are handled by Operation.CopyParams - var exp = $@"[(,]\s*(?(?:in|out|ref|ref\s+readonly)\s+)?{type}\s+(?\w+)__{type}"; - var paramMatch = Regex.Match(transformed.ToString(), exp); - if (paramMatch.Success) - { - var name = paramMatch.Groups["ParamName"].Value; - var modifiers = paramMatch.Groups["Modifiers"].Value; - - StringBuilder newParams = new(); - for (int i = start - 1; i < variations; i++) - { - var varied = VaryType(type, i); - newParams.Append($"{modifiers} {varied} {name}__{varied}"); - if (i != variations - 1) - { - newParams.Append(", "); - } - } - - transformed.Remove(paramMatch.Index + 1, paramMatch.Length - 1); - transformed.Insert(paramMatch.Index + 1, newParams); - } - - return transformed.ToString(); - } - - if (Op == Operation.CopyLines) - { - if (Variables.Length != 0) - { - throw new InvalidOperationException($"{nameof(Operation.CopyLines)} does not support variables."); - } - - StringBuilder transformed = new(); - transformed.AppendLine(Line); - - for (int i = start; i < variations; i++) - { - StringBuilder next = new(); - next.AppendLine(Line); - var variadic = VaryType(type, i); - next.Replace(type, variadic); - transformed.AppendLine(next.ToString()); - } - - return transformed.ToString(); - } - - if (Op == Operation.CopyArgs) - { - if (Variables.Length != 1) - { - throw new InvalidOperationException($"{nameof(Operation.CopyArgs)} only supports 1 variable."); - } - - StringBuilder transformed = new(); - transformed.AppendLine(Line); - StringBuilder newVariables = new(); - - // match ref, in, out - var modifiersMatch = Regex.Match(Line, $@"[(,]\s*(?(ref|out ref|out var|out {type}\??|in|ref {type}\??))?\s*{Variables[0]}__{type}"); - if (!modifiersMatch.Success) - { - throw new InvalidOperationException($"Can't find variable {Variables[0]}__{type} in a parameter list."); - } - - var modifiers = modifiersMatch.Groups["Modifiers"].Value; - - newVariables.Append($"{modifiers} {Variables[0]}__{type}"); - for (int i = start; i < variations; i++) - { - var variadic = VaryType(type, i); - newVariables.Append($", {modifiers} {Variables[0]}__{variadic}"); - } - - transformed.Remove(modifiersMatch.Index + 1, modifiersMatch.Length - 1); - transformed.Insert(modifiersMatch.Index + 1, newVariables.ToString()); - - // expand any remaining generics - // note that this'll break if the user uses Span instead of var or something. - StringBuilder variadics = new(); - for (int i = start - 1; i < variations; i++) - { - variadics.Append(VaryType(type, i)); - if (i != variations - 1) - { - variadics.Append(", "); - } - } - - variadics.Append(">"); - - // Apply generics: expand T0> -> T0, T1...> - transformed.Replace(type + ">", variadics.ToString()); - - - return transformed.ToString(); - } - - if (Op == Operation.CopyParams) - { - if (Variables.Length != 1) - { - throw new InvalidOperationException($"{nameof(Operation.CopyParams)} only supports 1 type variable."); - } - - // This is a special algorithm denotion for method headers. - // This grabs the first param that matches the passed in type (in Variables[0]), like "Span? paramName__T0 = default" - // it extracts paramName, the initializer if it exists, any ref/out/in modifiers, and repeats it according to the type params. - var headerMatch = Regex.Match(Line, $@"[(,]\s*(?(ref|out|ref readonly|in)\s+)?{Regex.Escape(Variables[0])}\s+(?\w+)__{type}\s*(?=\s*default)?"); - - if (!headerMatch.Success) - { - throw new InvalidOperationException($"Malformed method header for {nameof(Operation.CopyParams)}."); - } - - bool hasDefault = headerMatch.Groups["Assignment"].Success; - string modifiers = headerMatch.Groups["Modifiers"].Success ? headerMatch.Groups["Modifiers"].Value : string.Empty; - string param = headerMatch.Groups["ParamName"].Value; - - List additionalParams = new(); - for (int i = start; i < variations; i++) - { - var variadic = VaryType(type, i); - // One issue with this approach... if we had a wrapper type of SomethingT1 (which is bad name but whatever) then this would break. - // but so far we don't have anything like that. - var fullType = Variables[0].Replace(type, variadic); - additionalParams.Add($"{modifiers} {fullType} {param}__{variadic} {(hasDefault ? "= default" : "")}"); - } - - StringBuilder transformed = new(); - transformed.Append(Line); - - StringBuilder @params = new(); - // +1 to exclude the opening parenthesis or comma - @params.Append(Line.Substring(headerMatch.Index + 1, headerMatch.Length - 1)); - foreach (var additionalParam in additionalParams) - { - @params.Append(", " + additionalParam); - } - - // For the rest of the line, we do a trick: we want to apply the regular op on the rest of the header, so we remove all args and re-add them after. - // We do this so we don't have to process constraints separately. - transformed.Remove(headerMatch.Index + 1, headerMatch.Length - 1); - var fakeLine = new LineInfo() - { - Line = transformed.ToString(), - Op = Operation.None - }; - transformed.Clear(); - var fakeLineTf = fakeLine.Transform(start, variations, type); - transformed.Append(fakeLineTf); - - // find where we left off; we either left a hanging comma or an () - var match = Regex.Match(transformed.ToString(), @"(,\s*\)|\(\s*\))"); - Debug.Assert(match.Success); - // stick our params back in there - transformed.Insert(match.Index + 1, @params); - - return transformed.ToString(); - } - - throw new NotImplementedException(); - } - } - - private static string VaryType(string typeName, int i) - { - var match = Regex.Match(typeName, @"(?\w+)[0-9]+"); - if (!match.Success) - { - throw new InvalidOperationException("Variadic type must be of TypeName{N}"); - } - - return $"{match.Groups["PrunedName"]}{i}"; + public string Algorithm; + public string Line; + public string[] Parameters; } - private IEnumerable Tokenize(VariadicInfo info) + private IEnumerable ProcessLines(VariadicInfo info) { - // NOTE: does not support multiline operations, for example this would break: - // // [Variadic: CopyArgs(a)] - // MyMethod( - // a_T0); var lines = SplitLines(info.Code); - LineInfo.Operation nextOperation = LineInfo.Operation.None; - List nextVariables = new(); + string nextAlgorithm = string.Empty; + List nextParameters = new(); foreach (var line in lines) { if (line.StartsWith("[Variadic(")) @@ -392,25 +200,20 @@ private IEnumerable Tokenize(VariadicInfo info) if (line.StartsWith("//")) { + // match algorithm, like "// [Variadic: AlgorithmName(param1, param2...)]" var match = Regex.Match(line, @"\[Variadic:\s*(?\w+)(?:\((?:(?[?\w\[\]<>]+),?\s*)+\)\])?"); if (!match.Success) { continue; } - nextOperation = match.Groups["Operation"].Value switch - { - "CopyLines" => LineInfo.Operation.CopyLines, - "CopyArgs" => LineInfo.Operation.CopyArgs, - "CopyParams" => LineInfo.Operation.CopyParams, - _ => throw new NotImplementedException() - }; + nextAlgorithm = match.Groups["Operation"].Value; if (match.Groups["Variable"].Success) { foreach (Capture capture in match.Groups["Variable"].Captures) { - nextVariables.Add(capture.Value); + nextParameters.Add(capture.Value); } } @@ -420,11 +223,11 @@ private IEnumerable Tokenize(VariadicInfo info) var lineInfo = new LineInfo() { Line = line, - Variables = nextVariables.ToArray(), - Op = nextOperation + Algorithm = nextAlgorithm, + Parameters = nextParameters.ToArray() }; - nextVariables.Clear(); - nextOperation = LineInfo.Operation.None; + nextParameters.Clear(); + nextAlgorithm = string.Empty; yield return lineInfo; } } diff --git a/src/Arch/Core/Variadics/Archetype.Variadics.cs b/src/Arch/Core/Variadics/Archetype.Variadics.cs index c4b83cb3..8b3ddcc9 100644 --- a/src/Arch/Core/Variadics/Archetype.Variadics.cs +++ b/src/Arch/Core/Variadics/Archetype.Variadics.cs @@ -3,6 +3,7 @@ namespace Arch.Core; public partial class Archetype { + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] public bool Has() @@ -16,6 +17,7 @@ public bool Has() true; } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] internal unsafe Components Get(scoped ref Slot slot) @@ -24,6 +26,7 @@ internal unsafe Components Get(scoped ref Slot slot) return chunk.Get(slot.Index); } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] internal void Set(ref Slot slot, in T0 component__T0, in T1 component__T1) @@ -33,6 +36,7 @@ internal void Set(ref Slot slot, in T0 component__T0, in T1 component__T chunk.Set(slot.Index, in component__T0, in component__T1); } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] // [Variadic: CopyParams(T1)] diff --git a/src/Arch/Core/Variadics/Chunk.Variadics.cs b/src/Arch/Core/Variadics/Chunk.Variadics.cs index 64d7eba7..45186e20 100644 --- a/src/Arch/Core/Variadics/Chunk.Variadics.cs +++ b/src/Arch/Core/Variadics/Chunk.Variadics.cs @@ -18,7 +18,7 @@ private readonly void Index(out int index__T0, out int index__T1) index__T1 = Unsafe.Add(ref componentIdToArrayFirstElement, Component.ComponentType.Id); } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] [Variadic(nameof(T1), 2, 25)] @@ -41,7 +41,7 @@ public readonly bool Has() return true; } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] [Variadic(nameof(T1), 2, 25)] @@ -57,7 +57,7 @@ public Components Get(int index) return new Components(ref component__T0, ref component__T1); } - /// + /// [Variadic(nameof(T1), 2, 25)] [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] @@ -75,7 +75,7 @@ public EntityComponents GetRow(int index) return new EntityComponents(ref entity, ref component__T0, ref component__T1); } - /// + /// [Variadic(nameof(T1), 2, 25)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(int index, in T0 component__T0, in T1 component__T1) @@ -88,7 +88,7 @@ public void Set(int index, in T0 component__T0, in T1 component__T1) array__T1[index] = component__T1; } - /// + /// [Variadic(nameof(T1), 2, 25)] [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] @@ -104,6 +104,7 @@ public void GetArray(out T0[] array__T0, out T1[] array__T1) array__T1 = Unsafe.As(Unsafe.Add(ref arrays, index__T1)); } + /// [Variadic(nameof(T1), 2, 25)] [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] @@ -118,6 +119,7 @@ public void GetSpan(out Span span__T0, out Span span__T1) span__T1 = new Span(array__T1); } + /// [Variadic(nameof(T1), 2, 25)] [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] diff --git a/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs index f3d93616..2fb50410 100644 --- a/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs +++ b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs @@ -1,9 +1,10 @@ using System.Diagnostics.Contracts; -namespace Arch.Core; +namespace Arch.Core.Extensions; #if !PURE_ECS public static partial class EntityExtensions { + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] [Variadic(nameof(T1), 2)] @@ -13,6 +14,7 @@ public static bool Has(this Entity entity) return world.Has(entity); } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2)] public static void Set(this Entity entity, T0 component__T0, T1 component__T1) @@ -22,6 +24,7 @@ public static void Set(this Entity entity, T0 component__T0, T1 componen world.Set(entity, component__T0, component__T1); } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] [Variadic(nameof(T1), 2)] @@ -31,6 +34,7 @@ public static Components Get(this Entity entity) return world.Get(entity); } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2)] public static void Add(this Entity entity, in T0 component__T0, in T1 component__T1) @@ -40,6 +44,8 @@ public static void Add(this Entity entity, in T0 component__T0, in T1 co world.Add(entity, component__T0, component__T1); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2)] public static void Remove(this Entity entity) diff --git a/src/Arch/Core/Variadics/Jobs.Variadics.cs b/src/Arch/Core/Variadics/Jobs.Variadics.cs index f98fca9d..4366ba47 100644 --- a/src/Arch/Core/Variadics/Jobs.Variadics.cs +++ b/src/Arch/Core/Variadics/Jobs.Variadics.cs @@ -1,10 +1,13 @@ namespace Arch.Core; +/// [Variadic(nameof(T0), 1, 25)] public struct ForEachJob : IChunkJob { + /// public ForEach ForEach; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void Execute(int index, ref Chunk chunk) { @@ -22,11 +25,14 @@ public readonly void Execute(int index, ref Chunk chunk) } } +/// [Variadic(nameof(T0), 1, 25)] public struct ForEachWithEntityJob : IChunkJob { + /// public ForEachWithEntity ForEach; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void Execute(int index, ref Chunk chunk) { @@ -46,11 +52,14 @@ public readonly void Execute(int index, ref Chunk chunk) } } +/// [Variadic(nameof(T0), 1, 25)] public struct IForEachJob : IChunkJob where T : struct, IForEach { + /// public T ForEach; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Execute(int index, ref Chunk chunk) { @@ -71,8 +80,10 @@ public void Execute(int index, ref Chunk chunk) [Variadic(nameof(T0), 1, 25)] public struct IForEachWithEntityJob : IChunkJob where T : struct, IForEachWithEntity { + /// public T ForEach; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Execute(int index, ref Chunk chunk) { diff --git a/src/Arch/Core/Variadics/QueryDescription.Variadics.cs b/src/Arch/Core/Variadics/QueryDescription.Variadics.cs index 645a099f..7969cf0e 100644 --- a/src/Arch/Core/Variadics/QueryDescription.Variadics.cs +++ b/src/Arch/Core/Variadics/QueryDescription.Variadics.cs @@ -1,6 +1,7 @@ namespace Arch.Core; public partial struct QueryDescription { + /// [UnscopedRef] [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] @@ -10,6 +11,7 @@ public ref QueryDescription WithAll() return ref this; } + /// [UnscopedRef] [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] @@ -19,6 +21,7 @@ public ref QueryDescription WithAny() return ref this; } + /// [UnscopedRef] [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] @@ -28,6 +31,7 @@ public ref QueryDescription WithNone() return ref this; } + /// [UnscopedRef] [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] diff --git a/src/Arch/Core/Variadics/World.Variadics.cs b/src/Arch/Core/Variadics/World.Variadics.cs index f34771d7..7d33fbf9 100644 --- a/src/Arch/Core/Variadics/World.Variadics.cs +++ b/src/Arch/Core/Variadics/World.Variadics.cs @@ -6,6 +6,7 @@ namespace Arch.Core; public partial class World { + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [StructuralChange] [Variadic(nameof(T0), 1, 25)] @@ -46,6 +47,7 @@ public Entity Create(in T0 componentValue__T0 = default) return entity; } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] [Variadic(nameof(T1), 2, 25)] @@ -55,6 +57,7 @@ public bool Has(Entity entity) return archetype.Has(); } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] [Variadic(nameof(T1), 2, 25)] @@ -65,6 +68,7 @@ public Components Get(Entity entity) return archetype.Get(ref slot); } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] [Variadic(nameof(T1), 2, 25)] @@ -79,6 +83,7 @@ public void Set(Entity entity, in T0 component__T0, in T1 component__T1) OnComponentSet(entity); } + /// [SkipLocalsInit] [MethodImpl(MethodImplOptions.AggressiveInlining)] [StructuralChange] @@ -117,6 +122,7 @@ public void Add(Entity entity, in T0 component__T0 = default, in T1 comp OnComponentAdded(entity); } + /// [SkipLocalsInit] [MethodImpl(MethodImplOptions.AggressiveInlining)] [StructuralChange] @@ -150,6 +156,7 @@ public void Remove(Entity entity) Move(entity, oldArchetype, newArchetype, out _); } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T0), 1, 25)] public void Query(in QueryDescription description, ForEach forEach) @@ -170,6 +177,7 @@ public void Query(in QueryDescription description, ForEach forEach) } } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T0), 1, 25)] public void Query(in QueryDescription description, ForEachWithEntity forEach) @@ -192,6 +200,7 @@ public void Query(in QueryDescription description, ForEachWithEntity for } } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T0), 1, 25)] public void ParallelQuery(in QueryDescription description, ForEach forEach) @@ -233,6 +242,7 @@ public void ParallelQuery(in QueryDescription description, ForEach forEa } } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T0), 1, 25)] public void ParallelQuery(in QueryDescription description, ForEachWithEntity forEach) @@ -273,6 +283,7 @@ public void ParallelQuery(in QueryDescription description, ForEachWithEntity } } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T0), 1, 25)] public void InlineQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEach @@ -293,6 +304,7 @@ public void InlineQuery(in QueryDescription description, ref T iForEach) } } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T0), 1, 25)] public void InlineQuery(in QueryDescription description) where T : struct, IForEach @@ -316,6 +328,7 @@ public void InlineQuery(in QueryDescription description) where T : struct } } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T0), 1, 25)] public void InlineEntityQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEachWithEntity @@ -339,6 +352,7 @@ public void InlineEntityQuery(in QueryDescription description, ref T iFor } } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T0), 1, 25)] public void InlineEntityQuery(in QueryDescription description) where T : struct, IForEachWithEntity @@ -363,6 +377,8 @@ public void InlineEntityQuery(in QueryDescription description) where T : } } } + + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T0), 1, 25)] public void InlineParallelQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEach @@ -403,6 +419,7 @@ public void InlineParallelQuery(in QueryDescription description, ref T iF } } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T0), 1, 25)] public void InlineParallelEntityQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEachWithEntity @@ -444,6 +461,7 @@ public void InlineParallelEntityQuery(in QueryDescription description, re } } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] // [Variadic: CopyParams(T1)] @@ -474,6 +492,7 @@ public void Set(in QueryDescription queryDescription, in T0 componentVal } } + /// [SkipLocalsInit] [MethodImpl(MethodImplOptions.AggressiveInlining)] [StructuralChange] @@ -527,6 +546,7 @@ public void Add(in QueryDescription queryDescription, in T0 component__T } } + /// [SkipLocalsInit] [MethodImpl(MethodImplOptions.AggressiveInlining)] [StructuralChange] diff --git a/src/Arch/VariadicAttribute.cs b/src/Arch/VariadicAttribute.cs index 09795275..b6a722af 100644 --- a/src/Arch/VariadicAttribute.cs +++ b/src/Arch/VariadicAttribute.cs @@ -1,13 +1,29 @@ namespace Arch.Core; +#pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved /// -/// Tags a method or type as being variadic; i.e. generating many generic parameters. +/// Tags a method or type as being variadic; i.e. generating many versions with any number of generic parameters. /// +/// +/// +/// See for the default behavior. +/// +/// +/// Frequently, the default behavior of the generator will be inadequate. In those cases, you can precede an offending line with +/// "// [Variadic: AlgorithmName(...algorithmParams)]". Currently, the available algorithms are (for SOME method headers +/// with special params), (to simply copy a line for as many variadics are generating), and +/// (to insert a variable into a method call's arguments.). See their respective documentation for their usage information. +/// +/// +/// For examples, look at the existing implementations. +/// +/// [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Delegate | AttributeTargets.Interface)] +#pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved internal class VariadicAttribute : Attribute { /// - /// Tag a method or type as being variadic; i.e. generating many generic parameters. + /// Tag a method or type as being variadic; i.e. generating many generic parameters. /// /// /// The name of the type to begin. For example, if your method is Add<T0, T1>, it would be nameof(T1). From e66f22bcea88ba6d6f01a5bd7328de6a69ea2567 Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Wed, 1 Nov 2023 05:34:08 -0700 Subject: [PATCH 09/16] fix variadic oversights --- src/Arch/Core/Variadics/EntityExtensions.Variadics.cs | 6 +++--- src/Arch/Core/Variadics/Jobs.Variadics.cs | 3 +-- src/Arch/Core/Variadics/World.Variadics.cs | 5 +++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs index 2fb50410..bb294ff3 100644 --- a/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs +++ b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs @@ -17,11 +17,11 @@ public static bool Has(this Entity entity) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2)] - public static void Set(this Entity entity, T0 component__T0, T1 component__T1) + public static void Set(this Entity entity, in T0 component__T0, in T1 component__T1) { var world = World.Worlds[entity.WorldId]; // [Variadic: CopyArgs(component)] - world.Set(entity, component__T0, component__T1); + world.Set(entity, in component__T0, in component__T1); } /// @@ -41,7 +41,7 @@ public static void Add(this Entity entity, in T0 component__T0, in T1 co { var world = World.Worlds[entity.WorldId]; // [Variadic: CopyArgs(component)] - world.Add(entity, component__T0, component__T1); + world.Add(entity, in component__T0, in component__T1); } /// diff --git a/src/Arch/Core/Variadics/Jobs.Variadics.cs b/src/Arch/Core/Variadics/Jobs.Variadics.cs index 4366ba47..065f2ea9 100644 --- a/src/Arch/Core/Variadics/Jobs.Variadics.cs +++ b/src/Arch/Core/Variadics/Jobs.Variadics.cs @@ -37,11 +37,10 @@ public struct ForEachWithEntityJob : IChunkJob public readonly void Execute(int index, ref Chunk chunk) { ref var entityFirstElement = ref chunk.Entity(0); - var chunkSize = chunk.Size; // [Variadic: CopyLines] ref var firstElement__T0 = ref chunk.GetFirst(); - for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) + foreach (var entityIndex in chunk) { var entity = Unsafe.Add(ref entityFirstElement, entityIndex); // [Variadic: CopyLines] diff --git a/src/Arch/Core/Variadics/World.Variadics.cs b/src/Arch/Core/Variadics/World.Variadics.cs index 7d33fbf9..e8d88d9f 100644 --- a/src/Arch/Core/Variadics/World.Variadics.cs +++ b/src/Arch/Core/Variadics/World.Variadics.cs @@ -540,8 +540,9 @@ public void Add(in QueryDescription queryDescription, in T0 component__T var lastSlot = newArchetype.LastSlot; // [Variadic: CopyArgs(component)] newArchetype.SetRange(in lastSlot, in newArchetypeLastSlot, in component__T0, in component__T1); - // [Variadic: CopyLines] OnComponentAdded(archetype); + // [Variadic: CopyLines] + OnComponentAdded(archetype); archetype.Clear(); } } @@ -570,7 +571,7 @@ public void Remove(in QueryDescription queryDescription) var spanBitSet = new SpanBitSet(bitSet.AsSpan(stack)); spanBitSet.ClearBit(Component.ComponentType.Id); // [Variadic: CopyLines] - spanBitSet.ClearBit(Component.ComponentType.Id); + spanBitSet.ClearBit(Component.ComponentType.Id); // Get or create new archetype. if (!TryGetArchetype(spanBitSet.GetHashCode(), out var newArchetype)) From c0a00dfe6ac8a48a316d91569cbb83de40a3d784 Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Wed, 1 Nov 2023 05:43:16 -0700 Subject: [PATCH 10/16] allow comments in generated variadics --- src/Arch.SourceGen/IgnoreAlgorithm.cs | 16 ++++++++++++++++ src/Arch.SourceGen/VariadicGenerator.cs | 22 ++++++++++++++++------ 2 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 src/Arch.SourceGen/IgnoreAlgorithm.cs diff --git a/src/Arch.SourceGen/IgnoreAlgorithm.cs b/src/Arch.SourceGen/IgnoreAlgorithm.cs new file mode 100644 index 00000000..a9a01836 --- /dev/null +++ b/src/Arch.SourceGen/IgnoreAlgorithm.cs @@ -0,0 +1,16 @@ +namespace Arch.SourceGen; + +/// +/// Processes nothing on a line. +/// +[VariadicAlgorithm] +internal class IgnoreAlgorithm : LineAlgorithm +{ + public override string Name { get => "Ignore"; } + public override int ExpectedParameterCount { get => 0; } + + public override string Transform(string line, string type, int start, int variations, string[] parameters) + { + return line; + } +} diff --git a/src/Arch.SourceGen/VariadicGenerator.cs b/src/Arch.SourceGen/VariadicGenerator.cs index c214e53c..2456ba93 100644 --- a/src/Arch.SourceGen/VariadicGenerator.cs +++ b/src/Arch.SourceGen/VariadicGenerator.cs @@ -66,7 +66,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) info.Namespace = ns; info.Name = ctx.TargetSymbol.Name; - info.Code = ctx.TargetNode.ToString(); + info.Code = ctx.TargetNode.GetLeadingTrivia().ToString() + ctx.TargetNode.ToString(); foreach (var use in (ctx.TargetNode.SyntaxTree.GetRoot() as CompilationUnitSyntax)!.Usings) { info.Usings += use.ToString() + "\n"; @@ -198,7 +198,14 @@ private IEnumerable ProcessLines(VariadicInfo info) continue; } - if (line.StartsWith("//")) + bool isDocumentation = false; + // never process documentation + if (line.StartsWith("///")) + { + isDocumentation = true; + } + + else if (line.StartsWith("//")) { // match algorithm, like "// [Variadic: AlgorithmName(param1, param2...)]" var match = Regex.Match(line, @"\[Variadic:\s*(?\w+)(?:\((?:(?[?\w\[\]<>]+),?\s*)+\)\])?"); @@ -223,11 +230,14 @@ private IEnumerable ProcessLines(VariadicInfo info) var lineInfo = new LineInfo() { Line = line, - Algorithm = nextAlgorithm, - Parameters = nextParameters.ToArray() + Algorithm = !isDocumentation ? nextAlgorithm : "Ignore", + Parameters = !isDocumentation ? nextParameters.ToArray() : Array.Empty() }; - nextParameters.Clear(); - nextAlgorithm = string.Empty; + if (!isDocumentation) + { + nextAlgorithm = string.Empty; + nextParameters.Clear(); + } yield return lineInfo; } } From 2752daaa016b58e407e5cf2d08f0e7210010d6a9 Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Wed, 1 Nov 2023 05:54:30 -0700 Subject: [PATCH 11/16] fix variadic compiler warns --- src/Arch.SourceGen/VariadicGenerator.cs | 5 +- .../Core/Variadics/Archetype.Variadics.cs | 7 +-- src/Arch/Core/Variadics/Chunk.Variadics.cs | 8 ++-- src/Arch/Core/Variadics/World.Variadics.cs | 46 +++++++++++-------- 4 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/Arch.SourceGen/VariadicGenerator.cs b/src/Arch.SourceGen/VariadicGenerator.cs index 2456ba93..9cc2a910 100644 --- a/src/Arch.SourceGen/VariadicGenerator.cs +++ b/src/Arch.SourceGen/VariadicGenerator.cs @@ -118,7 +118,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) } // stores the algorithms from reflection - private static Dictionary _algorithms = new(); + private readonly static Dictionary _algorithms = new(); // collect the algorithms available with reflection on the attribute static VariadicGenerator() @@ -132,6 +132,7 @@ static VariadicGenerator() { throw new InvalidOperationException($"Two {nameof(LineAlgorithm)}s cannot have the same name!"); } + _algorithms[algorithm.Name] = algorithm; } } @@ -169,6 +170,7 @@ private string MakeVariadic(VariadicInfo info) } return $$""" + #nullable enable {{info.Usings}} namespace {{info.Namespace}}; @@ -238,6 +240,7 @@ private IEnumerable ProcessLines(VariadicInfo info) nextAlgorithm = string.Empty; nextParameters.Clear(); } + yield return lineInfo; } } diff --git a/src/Arch/Core/Variadics/Archetype.Variadics.cs b/src/Arch/Core/Variadics/Archetype.Variadics.cs index 8b3ddcc9..7c40df86 100644 --- a/src/Arch/Core/Variadics/Archetype.Variadics.cs +++ b/src/Arch/Core/Variadics/Archetype.Variadics.cs @@ -29,7 +29,8 @@ internal unsafe Components Get(scoped ref Slot slot) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] - internal void Set(ref Slot slot, in T0 component__T0, in T1 component__T1) + // [Variadic: CopyParams(T1?)] + internal void Set(ref Slot slot, in T0? component__T0, in T1? component__T1) { ref var chunk = ref GetChunk(slot.ChunkIndex); // [Variadic: CopyArgs(component)] @@ -39,8 +40,8 @@ internal void Set(ref Slot slot, in T0 component__T0, in T1 component__T /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] - // [Variadic: CopyParams(T1)] - internal void SetRange(in Slot from, in Slot to, in T0 componentValue__T0 = default, in T1 componentValue__T1 = default) + // [Variadic: CopyParams(T1?)] + internal void SetRange(in Slot from, in Slot to, in T0? componentValue__T0 = default, in T1? componentValue__T1 = default) { // Set the added component, start from the last slot and move down for (var chunkIndex = from.ChunkIndex; chunkIndex >= to.ChunkIndex; --chunkIndex) diff --git a/src/Arch/Core/Variadics/Chunk.Variadics.cs b/src/Arch/Core/Variadics/Chunk.Variadics.cs index 45186e20..9606e52f 100644 --- a/src/Arch/Core/Variadics/Chunk.Variadics.cs +++ b/src/Arch/Core/Variadics/Chunk.Variadics.cs @@ -78,20 +78,22 @@ public EntityComponents GetRow(int index) /// [Variadic(nameof(T1), 2, 25)] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set(int index, in T0 component__T0, in T1 component__T1) + // [Variadic: CopyParams(T1?)] + public void Set(int index, in T0? component__T0, in T1? component__T1) { // [Variadic: CopyArgs(array)] GetArray(out var array__T0, out var array__T1); - array__T0[index] = component__T0; + array__T0[index] = component__T0!; // [Variadic: CopyLines] - array__T1[index] = component__T1; + array__T1[index] = component__T1!; } /// [Variadic(nameof(T1), 2, 25)] [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] + [SuppressMessage("Style", "IDE0251:Make member 'readonly'", Justification = "Not actually readonly due to unsafe get")] // [Variadic: CopyParams(T1[])] public void GetArray(out T0[] array__T0, out T1[] array__T1) { diff --git a/src/Arch/Core/Variadics/World.Variadics.cs b/src/Arch/Core/Variadics/World.Variadics.cs index e8d88d9f..2619fbfa 100644 --- a/src/Arch/Core/Variadics/World.Variadics.cs +++ b/src/Arch/Core/Variadics/World.Variadics.cs @@ -10,8 +10,8 @@ public partial class World [MethodImpl(MethodImplOptions.AggressiveInlining)] [StructuralChange] [Variadic(nameof(T0), 1, 25)] - // [Variadic: CopyParams(T0)] - public Entity Create(in T0 componentValue__T0 = default) + // [Variadic: CopyParams(T0?)] + public Entity Create(in T0? componentValue__T0 = default) { var types = Group.Types; @@ -68,7 +68,7 @@ public Components Get(Entity entity) return archetype.Get(ref slot); } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] [Variadic(nameof(T1), 2, 25)] @@ -88,8 +88,8 @@ public void Set(Entity entity, in T0 component__T0, in T1 component__T1) [MethodImpl(MethodImplOptions.AggressiveInlining)] [StructuralChange] [Variadic(nameof(T1), 2, 25)] - // [Variadic: CopyParams(T1)] - public void Add(Entity entity, in T0 component__T0 = default, in T1 component__T1 = default) + // [Variadic: CopyParams(T1?)] + public void Add(Entity entity, in T0? component__T0 = default, in T1? component__T1 = default) { var oldArchetype = EntityInfo.GetArchetype(entity.Id); @@ -205,8 +205,10 @@ public void Query(in QueryDescription description, ForEachWithEntity for [Variadic(nameof(T0), 1, 25)] public void ParallelQuery(in QueryDescription description, ForEach forEach) { - var innerJob = new ForEachJob(); - innerJob.ForEach = forEach; + var innerJob = new ForEachJob + { + ForEach = forEach + }; var pool = JobMeta>>.Pool; var query = Query(in description); @@ -247,8 +249,10 @@ public void ParallelQuery(in QueryDescription description, ForEach forEa [Variadic(nameof(T0), 1, 25)] public void ParallelQuery(in QueryDescription description, ForEachWithEntity forEach) { - var innerJob = new ForEachWithEntityJob(); - innerJob.ForEach = forEach; + var innerJob = new ForEachWithEntityJob + { + ForEach = forEach + }; var pool = JobMeta>>.Pool; var query = Query(in description); @@ -383,8 +387,10 @@ public void InlineEntityQuery(in QueryDescription description) where T : [Variadic(nameof(T0), 1, 25)] public void InlineParallelQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEach { - var innerJob = new IForEachJob(); - innerJob.ForEach = iForEach; + var innerJob = new IForEachJob + { + ForEach = iForEach + }; var pool = JobMeta>>.Pool; var query = Query(in description); @@ -424,8 +430,10 @@ public void InlineParallelQuery(in QueryDescription description, ref T iF [Variadic(nameof(T0), 1, 25)] public void InlineParallelEntityQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEachWithEntity { - var innerJob = new IForEachWithEntityJob(); - innerJob.ForEach = iForEach; + var innerJob = new IForEachWithEntityJob + { + ForEach = iForEach + }; var pool = JobMeta>>.Pool; var query = Query(in description); @@ -461,11 +469,11 @@ public void InlineParallelEntityQuery(in QueryDescription description, re } } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] - // [Variadic: CopyParams(T1)] - public void Set(in QueryDescription queryDescription, in T0 componentValue__T0 = default, in T1 componentValue__T1 = default) + // [Variadic: CopyParams(T1?)] + public void Set(in QueryDescription queryDescription, in T0? componentValue__T0 = default, in T1? componentValue__T1 = default) { var query = Query(in queryDescription); foreach (ref var chunk in query) @@ -492,13 +500,13 @@ public void Set(in QueryDescription queryDescription, in T0 componentVal } } - /// + /// [SkipLocalsInit] [MethodImpl(MethodImplOptions.AggressiveInlining)] [StructuralChange] [Variadic(nameof(T1), 2, 25)] - // [Variadic: CopyParams(T1)] - public void Add(in QueryDescription queryDescription, in T0 component__T0 = default, in T1 component__T1 = default) + // [Variadic: CopyParams(T1?)] + public void Add(in QueryDescription queryDescription, in T0? component__T0 = default, in T1? component__T1 = default) { // BitSet to stack/span bitset, size big enough to contain ALL registered components. Span stack = stackalloc uint[BitSet.RequiredLength(ComponentRegistry.Size)]; From 38a356903e5bba4936da8ae9b82d416639db2e75 Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Tue, 7 Nov 2023 01:56:58 -0800 Subject: [PATCH 12/16] change __ to _ --- src/Arch.Benchmarks/QueryBenchmark.cs | 12 +-- src/Arch.SourceGen/CopyArgsAlgorithm.cs | 14 +-- src/Arch.SourceGen/CopyLinesAlgorithm.cs | 6 +- src/Arch.SourceGen/CopyParamsAlgorithm.cs | 10 +-- src/Arch.SourceGen/DefaultAlgorithm.cs | 14 +-- src/Arch.Tests/EntityTest.cs | 8 +- src/Arch.Tests/WorldTest.cs | 8 +- .../Core/Variadics/Archetype.Variadics.cs | 26 +++--- src/Arch/Core/Variadics/Chunk.Variadics.cs | 66 +++++++------- .../Core/Variadics/Components.Variadics.cs | 20 ++--- .../Variadics/EntityExtensions.Variadics.cs | 8 +- src/Arch/Core/Variadics/ForEach.Variadics.cs | 4 +- .../Core/Variadics/Interfaces.Variadics.cs | 4 +- src/Arch/Core/Variadics/Jobs.Variadics.cs | 24 ++--- src/Arch/Core/Variadics/World.Variadics.cs | 90 +++++++++---------- 15 files changed, 157 insertions(+), 157 deletions(-) diff --git a/src/Arch.Benchmarks/QueryBenchmark.cs b/src/Arch.Benchmarks/QueryBenchmark.cs index 3908c044..eb9a588c 100644 --- a/src/Arch.Benchmarks/QueryBenchmark.cs +++ b/src/Arch.Benchmarks/QueryBenchmark.cs @@ -37,8 +37,8 @@ public void WorldEntityQuery() { var refs = _world.Get(entity); - refs.Component__T0.X += refs.Component__T1.X; - refs.Component__T0.Y += refs.Component__T1.Y; + refs.Component_T0.X += refs.Component_T1.X; + refs.Component_T0.Y += refs.Component_T1.Y; }); } @@ -49,8 +49,8 @@ public void EntityExtensionQuery() _world.Query(in _queryDescription, (Entity entity) => { var refs = entity.Get(); - refs.Component__T0.X += refs.Component__T1.X; - refs.Component__T0.Y += refs.Component__T1.Y; + refs.Component_T0.X += refs.Component_T1.X; + refs.Component_T0.Y += refs.Component_T1.Y; }); } #endif @@ -84,8 +84,8 @@ public void Iterator() var refs = chunk.GetFirst(); foreach (var entity in chunk) { - ref var pos = ref Unsafe.Add(ref refs.Component__T0, entity); - ref var vel = ref Unsafe.Add(ref refs.Component__T1, entity); + ref var pos = ref Unsafe.Add(ref refs.Component_T0, entity); + ref var vel = ref Unsafe.Add(ref refs.Component_T1, entity); pos.X += vel.X; pos.Y += vel.Y; diff --git a/src/Arch.SourceGen/CopyArgsAlgorithm.cs b/src/Arch.SourceGen/CopyArgsAlgorithm.cs index d7dd3172..856a31de 100644 --- a/src/Arch.SourceGen/CopyArgsAlgorithm.cs +++ b/src/Arch.SourceGen/CopyArgsAlgorithm.cs @@ -3,17 +3,17 @@ namespace Arch.SourceGen; /// -/// repeats a given argument of structure {name}__{variadicType}, separated by commas. It properly copies any ref, in, out, etc modifiers. +/// repeats a given argument of structure {name}_{variadicType}, separated by commas. It properly copies any ref, in, out, etc modifiers. /// It will additionally copy generic type arguments matching the variadic type, only if the variadic type is the last in the type parameter list. /// /// /// With type parameter T0: /// -/// MyMethod<T0>(in component__T0) +/// MyMethod<T0>(in component_T0) /// /// ... will convert to: /// -/// MyMethod<T0, T1>(in component__T0, in component__T1) +/// MyMethod<T0, T1>(in component_T0, in component_T1) /// /// [VariadicAlgorithm] @@ -29,19 +29,19 @@ public override string Transform(string line, string type, int start, int variat StringBuilder newVariables = new(); // match ref, in, out - var modifiersMatch = Regex.Match(line, $@"[(,]\s*(?(ref|out ref|out var|out {type}\??|in|ref {type}\??))?\s*{parameters[0]}__{type}"); + var modifiersMatch = Regex.Match(line, $@"[(,]\s*(?(ref|out ref|out var|out {type}\??|in|ref {type}\??))?\s*{parameters[0]}_{type}"); if (!modifiersMatch.Success) { - throw new InvalidOperationException($"Can't find variable {parameters[0]}__{type} in a parameter list."); + throw new InvalidOperationException($"Can't find variable {parameters[0]}_{type} in a parameter list."); } var modifiers = modifiersMatch.Groups["Modifiers"].Value; - newVariables.Append($"{modifiers} {parameters[0]}__{type}"); + newVariables.Append($"{modifiers} {parameters[0]}_{type}"); for (int i = start; i < variations; i++) { var variadic = VaryType(type, i); - newVariables.Append($", {modifiers} {parameters[0]}__{variadic}"); + newVariables.Append($", {modifiers} {parameters[0]}_{variadic}"); } transformed.Remove(modifiersMatch.Index + 1, modifiersMatch.Length - 1); diff --git a/src/Arch.SourceGen/CopyLinesAlgorithm.cs b/src/Arch.SourceGen/CopyLinesAlgorithm.cs index 17d1823b..d50f4e6b 100644 --- a/src/Arch.SourceGen/CopyLinesAlgorithm.cs +++ b/src/Arch.SourceGen/CopyLinesAlgorithm.cs @@ -7,12 +7,12 @@ /// With type parameter T0: /// /// /// [Variadic: CopyLines] -/// somethingSomething__T0 = new T0(); // look! T0! +/// somethingSomething_T0 = new T0(); // look! T0! /// /// ... will expand to: /// -/// somethingSomething__T0 = new T0(); // look! T0! -/// somethingSomething__T1 = new T1(); // look! T1! +/// somethingSomething_T0 = new T0(); // look! T0! +/// somethingSomething_T1 = new T1(); // look! T1! /// ... /// /// diff --git a/src/Arch.SourceGen/CopyParamsAlgorithm.cs b/src/Arch.SourceGen/CopyParamsAlgorithm.cs index d3dd0665..3424e003 100644 --- a/src/Arch.SourceGen/CopyParamsAlgorithm.cs +++ b/src/Arch.SourceGen/CopyParamsAlgorithm.cs @@ -6,8 +6,8 @@ namespace Arch.SourceGen; /// /// The is a special algorithm for more complicated method headers that can't be handled by the basic . /// In particular, it handles cases of a type other than directly the variadic type, that needs to be transformed and copied. It also handles variable initializers. -/// For example, it will expand ref Span<T0>? component__T0 = default to -/// ref Span<T0>? component__T0 = default, ref Span<T1>? component__T1 = default .... +/// For example, it will expand ref Span<T0>? component_T0 = default to +/// ref Span<T0>? component_T0 = default, ref Span<T1>? component_T1 = default .... /// /// /// Basically, use this algorithm if your method has any of these: Initializers (= default), nullables (T0?), or wrapped type arguments @@ -26,9 +26,9 @@ internal class CopyParamsAlgorithm : LineAlgorithm public override string Transform(string line, string type, int start, int variations, string[] parameters) { // This is a special algorithm denotion for method headers. - // This grabs the first param that matches the passed in type (in Variables[0]), like "Span? paramName__T0 = default" + // This grabs the first param that matches the passed in type (in Variables[0]), like "Span? paramName_T0 = default" // it extracts paramName, the initializer if it exists, any ref/out/in modifiers, and repeats it according to the type params. - var headerMatch = Regex.Match(line, $@"[(,]\s*(?(ref|out|ref readonly|in)\s+)?{Regex.Escape(parameters[0])}\s+(?\w+)__{type}\s*(?=\s*default)?"); + var headerMatch = Regex.Match(line, $@"[(,]\s*(?(ref|out|ref readonly|in)\s+)?{Regex.Escape(parameters[0])}\s+(?\w+)_{type}\s*(?=\s*default)?"); if (!headerMatch.Success) { @@ -46,7 +46,7 @@ public override string Transform(string line, string type, int start, int variat // One issue with this approach... if we had a wrapper type of SomethingT1 (which is bad name but whatever) then this would break. // but so far we don't have anything like that. var fullType = parameters[0].Replace(type, variadic); - additionalParams.Add($"{modifiers} {fullType} {param}__{variadic} {(hasDefault ? "= default" : "")}"); + additionalParams.Add($"{modifiers} {fullType} {param}_{variadic} {(hasDefault ? "= default" : "")}"); } StringBuilder transformed = new(); diff --git a/src/Arch.SourceGen/DefaultAlgorithm.cs b/src/Arch.SourceGen/DefaultAlgorithm.cs index f1f655b5..cff84495 100644 --- a/src/Arch.SourceGen/DefaultAlgorithm.cs +++ b/src/Arch.SourceGen/DefaultAlgorithm.cs @@ -19,10 +19,10 @@ namespace Arch.SourceGen; /// types are not currently processed correctly, i.e. where T0 : ISomething<T0>. If that behavior is needed, either edit this algorithm or introduce a new one. /// /// -/// For method headers, it copies simple type parameters of the given variadic type, with the form {paramName}__{type}. For example, in T0 component__T0 -/// would expand to in T0 component__T0, in T1 component__T1. Note that this algorithm isn't smart enough to recognize wrapped parameters, such as -/// in Span<T0> component__T0; it will expand it to an invalid Span<T0, T1, ...>. To use the former behavior, or if initializers like -/// component__T0 = default is needed, or nullables are needed, specify instead with an explicit type to copy. +/// For method headers, it copies simple type parameters of the given variadic type, with the form {paramName}_{type}. For example, in T0 component_T0 +/// would expand to in T0 component_T0, in T1 component_T1. Note that this algorithm isn't smart enough to recognize wrapped parameters, such as +/// in Span<T0> component_T0; it will expand it to an invalid Span<T0, T1, ...>. To use the former behavior, or if initializers like +/// component_T0 = default is needed, or nullables are needed, specify instead with an explicit type to copy. /// /// /// Nothing else is changed. @@ -76,12 +76,12 @@ public override string Transform(string line, string type, int start, int variat // Applied everywhere, wherever generics appear! transformed.Replace(type + ">", variadics.ToString()); - // Expand params in header (i.e. T0 component__T0 -> T0 component__T0, T1 component__T1... + // Expand params in header (i.e. T0 component_T0 -> T0 component_T0, T1 component_T1... // This is the 90% case. Occasionally there needs to be special handling for a method header. // Those cases are handled by CopyParamsAlgorithm // Modifiers is ref, in, out etc. // ParamName is the paramname we need to copy, - var exp = $@"[(,]\s*(?(?:in|out|ref|ref\s+readonly)\s+)?{type}\s+(?\w+)__{type}"; + var exp = $@"[(,]\s*(?(?:in|out|ref|ref\s+readonly)\s+)?{type}\s+(?\w+)_{type}"; var paramMatch = Regex.Match(transformed.ToString(), exp); if (paramMatch.Success) { @@ -92,7 +92,7 @@ public override string Transform(string line, string type, int start, int variat for (int i = start - 1; i < variations; i++) { var varied = VaryType(type, i); - newParams.Append($"{modifiers} {varied} {name}__{varied}"); + newParams.Append($"{modifiers} {varied} {name}_{varied}"); if (i != variations - 1) { newParams.Append(", "); diff --git a/src/Arch.Tests/EntityTest.cs b/src/Arch.Tests/EntityTest.cs index de28c2ba..f629d2a9 100644 --- a/src/Arch.Tests/EntityTest.cs +++ b/src/Arch.Tests/EntityTest.cs @@ -155,10 +155,10 @@ public void GeneratedSetAndGet() _entity.Set(new Transform { X = 10, Y = 10 }, new Rotation { X = 10, Y = 10 }); var refs = _entity.Get(); - AreEqual(10, refs.Component__T0.X); - AreEqual(10, refs.Component__T0.Y); - AreEqual(10, refs.Component__T1.X); - AreEqual(10, refs.Component__T1.Y); + AreEqual(10, refs.Component_T0.X); + AreEqual(10, refs.Component_T0.Y); + AreEqual(10, refs.Component_T1.X); + AreEqual(10, refs.Component_T1.Y); } /// diff --git a/src/Arch.Tests/WorldTest.cs b/src/Arch.Tests/WorldTest.cs index 91376f2c..f2dfa425 100644 --- a/src/Arch.Tests/WorldTest.cs +++ b/src/Arch.Tests/WorldTest.cs @@ -622,10 +622,10 @@ public void GeneratedSetGetAndHas() _world.Set(entity, new Transform { X = 20, Y = 20 }, new Rotation { X = 20, Y = 20 }); var references = _world.Get(entity); - That(references.Component__T0.X, Is.EqualTo(20)); - That(references.Component__T0.Y, Is.EqualTo(20)); - That(references.Component__T1.X, Is.EqualTo(20)); - That(references.Component__T1.Y, Is.EqualTo(20)); + That(references.Component_T0.X, Is.EqualTo(20)); + That(references.Component_T0.Y, Is.EqualTo(20)); + That(references.Component_T1.X, Is.EqualTo(20)); + That(references.Component_T1.Y, Is.EqualTo(20)); } /// diff --git a/src/Arch/Core/Variadics/Archetype.Variadics.cs b/src/Arch/Core/Variadics/Archetype.Variadics.cs index 7c40df86..85e01ab8 100644 --- a/src/Arch/Core/Variadics/Archetype.Variadics.cs +++ b/src/Arch/Core/Variadics/Archetype.Variadics.cs @@ -8,12 +8,12 @@ public partial class Archetype [Variadic(nameof(T1), 2, 25)] public bool Has() { - var componentId__T0 = Component.ComponentType.Id; + var componentId_T0 = Component.ComponentType.Id; // [Variadic: CopyLines] - var componentId__T1 = Component.ComponentType.Id; - return BitSet.IsSet(componentId__T0) && + var componentId_T1 = Component.ComponentType.Id; + return BitSet.IsSet(componentId_T0) && // [Variadic: CopyLines] - BitSet.IsSet(componentId__T1) && + BitSet.IsSet(componentId_T1) && true; } @@ -30,26 +30,26 @@ internal unsafe Components Get(scoped ref Slot slot) [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] // [Variadic: CopyParams(T1?)] - internal void Set(ref Slot slot, in T0? component__T0, in T1? component__T1) + internal void Set(ref Slot slot, in T0? component_T0, in T1? component_T1) { ref var chunk = ref GetChunk(slot.ChunkIndex); // [Variadic: CopyArgs(component)] - chunk.Set(slot.Index, in component__T0, in component__T1); + chunk.Set(slot.Index, in component_T0, in component_T1); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] // [Variadic: CopyParams(T1?)] - internal void SetRange(in Slot from, in Slot to, in T0? componentValue__T0 = default, in T1? componentValue__T1 = default) + internal void SetRange(in Slot from, in Slot to, in T0? componentValue_T0 = default, in T1? componentValue_T1 = default) { // Set the added component, start from the last slot and move down for (var chunkIndex = from.ChunkIndex; chunkIndex >= to.ChunkIndex; --chunkIndex) { ref var chunk = ref GetChunk(chunkIndex); - ref var firstElement__T0 = ref chunk.GetFirst(); + ref var firstElement_T0 = ref chunk.GetFirst(); // [Variadic: CopyLines] - ref var firstElement__T1 = ref chunk.GetFirst(); + ref var firstElement_T1 = ref chunk.GetFirst(); // Only move within the range, depening on which chunk we are at. var isStart = chunkIndex == from.ChunkIndex; @@ -60,12 +60,12 @@ internal void SetRange(in Slot from, in Slot to, in T0? componentValue__ for (var entityIndex = upper; entityIndex >= lower; --entityIndex) { - ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + ref var component_T0 = ref Unsafe.Add(ref firstElement_T0, entityIndex); // [Variadic: CopyLines] - ref var component__T1 = ref Unsafe.Add(ref firstElement__T1, entityIndex); - component__T0 = componentValue__T0; + ref var component_T1 = ref Unsafe.Add(ref firstElement_T1, entityIndex); + component_T0 = componentValue_T0; // [Variadic: CopyLines] - component__T1 = componentValue__T1; + component_T1 = componentValue_T1; } } } diff --git a/src/Arch/Core/Variadics/Chunk.Variadics.cs b/src/Arch/Core/Variadics/Chunk.Variadics.cs index 9606e52f..efa4a5d9 100644 --- a/src/Arch/Core/Variadics/Chunk.Variadics.cs +++ b/src/Arch/Core/Variadics/Chunk.Variadics.cs @@ -10,12 +10,12 @@ public partial struct Chunk [Variadic(nameof(T1), 2, 25)] [Pure] // [Variadic: CopyParams(int)] - private readonly void Index(out int index__T0, out int index__T1) + private readonly void Index(out int index_T0, out int index_T1) { ref var componentIdToArrayFirstElement = ref ComponentIdToArrayIndex.DangerousGetReference(); - index__T0 = Unsafe.Add(ref componentIdToArrayFirstElement, Component.ComponentType.Id); + index_T0 = Unsafe.Add(ref componentIdToArrayFirstElement, Component.ComponentType.Id); // [Variadic: CopyLines] - index__T1 = Unsafe.Add(ref componentIdToArrayFirstElement, Component.ComponentType.Id); + index_T1 = Unsafe.Add(ref componentIdToArrayFirstElement, Component.ComponentType.Id); } /// @@ -26,17 +26,17 @@ private readonly void Index(out int index__T0, out int index__T1) [SuppressMessage("Style", "IDE2001:Embedded statements must be on their own line", Justification = "Enables single-line statements")] public readonly bool Has() { - var componentId__T0 = Component.ComponentType.Id; + var componentId_T0 = Component.ComponentType.Id; // [Variadic: CopyLines] - var componentId__T1 = Component.ComponentType.Id; + var componentId_T1 = Component.ComponentType.Id; - if (componentId__T0 >= ComponentIdToArrayIndex.Length) return false; + if (componentId_T0 >= ComponentIdToArrayIndex.Length) return false; // [Variadic: CopyLines] - if (componentId__T1 >= ComponentIdToArrayIndex.Length) return false; + if (componentId_T1 >= ComponentIdToArrayIndex.Length) return false; - if (ComponentIdToArrayIndex[componentId__T0] == -1) return false; + if (ComponentIdToArrayIndex[componentId_T0] == -1) return false; // [Variadic: CopyLines] - if (ComponentIdToArrayIndex[componentId__T1] == -1) return false; + if (ComponentIdToArrayIndex[componentId_T1] == -1) return false; return true; } @@ -48,13 +48,13 @@ public readonly bool Has() public Components Get(int index) { // [Variadic: CopyArgs(array)] - GetArray(out var array__T0, out var array__T1); - ref var component__T0 = ref array__T0[index]; + GetArray(out var array_T0, out var array_T1); + ref var component_T0 = ref array_T0[index]; // [Variadic: CopyLines] - ref var component__T1 = ref array__T1[index]; + ref var component_T1 = ref array_T1[index]; // [Variadic: CopyArgs(component)] - return new Components(ref component__T0, ref component__T1); + return new Components(ref component_T0, ref component_T1); } /// @@ -64,29 +64,29 @@ public Components Get(int index) public EntityComponents GetRow(int index) { // [Variadic: CopyArgs(array)] - GetArray(out var array__T0, out var array__T1); + GetArray(out var array_T0, out var array_T1); ref var entity = ref Entities[index]; - ref var component__T0 = ref array__T0[index]; + ref var component_T0 = ref array_T0[index]; // [Variadic: CopyLines] - ref var component__T1 = ref array__T1[index]; + ref var component_T1 = ref array_T1[index]; // [Variadic: CopyArgs(component)] - return new EntityComponents(ref entity, ref component__T0, ref component__T1); + return new EntityComponents(ref entity, ref component_T0, ref component_T1); } /// [Variadic(nameof(T1), 2, 25)] [MethodImpl(MethodImplOptions.AggressiveInlining)] // [Variadic: CopyParams(T1?)] - public void Set(int index, in T0? component__T0, in T1? component__T1) + public void Set(int index, in T0? component_T0, in T1? component_T1) { // [Variadic: CopyArgs(array)] - GetArray(out var array__T0, out var array__T1); + GetArray(out var array_T0, out var array_T1); - array__T0[index] = component__T0!; + array_T0[index] = component_T0!; // [Variadic: CopyLines] - array__T1[index] = component__T1!; + array_T1[index] = component_T1!; } /// @@ -95,15 +95,15 @@ public void Set(int index, in T0? component__T0, in T1? component__T1) [Pure] [SuppressMessage("Style", "IDE0251:Make member 'readonly'", Justification = "Not actually readonly due to unsafe get")] // [Variadic: CopyParams(T1[])] - public void GetArray(out T0[] array__T0, out T1[] array__T1) + public void GetArray(out T0[] array_T0, out T1[] array_T1) { // [Variadic: CopyArgs(index)] - Index(out var index__T0, out var index__T1); + Index(out var index_T0, out var index_T1); ref var arrays = ref Components.DangerousGetReference(); - array__T0 = Unsafe.As(Unsafe.Add(ref arrays, index__T0)); + array_T0 = Unsafe.As(Unsafe.Add(ref arrays, index_T0)); // [Variadic: CopyLines] - array__T1 = Unsafe.As(Unsafe.Add(ref arrays, index__T1)); + array_T1 = Unsafe.As(Unsafe.Add(ref arrays, index_T1)); } /// @@ -111,14 +111,14 @@ public void GetArray(out T0[] array__T0, out T1[] array__T1) [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] // [Variadic: CopyParams(Span)] - public void GetSpan(out Span span__T0, out Span span__T1) + public void GetSpan(out Span span_T0, out Span span_T1) { // [Variadic: CopyArgs(array)] - GetArray(out var array__T0, out var array__T1); - span__T0 = new Span(array__T0); + GetArray(out var array_T0, out var array_T1); + span_T0 = new Span(array_T0); // [Variadic: CopyLines] - span__T1 = new Span(array__T1); + span_T1 = new Span(array_T1); } /// @@ -128,13 +128,13 @@ public void GetSpan(out Span span__T0, out Span span__T1) public Components GetFirst() { // [Variadic: CopyArgs(array)] - GetArray(out var array__T0, out var array__T1); + GetArray(out var array_T0, out var array_T1); - ref var arrayRef__T0 = ref array__T0.DangerousGetReference(); + ref var arrayRef_T0 = ref array_T0.DangerousGetReference(); // [Variadic: CopyLines]; - ref var arrayRef__T1 = ref array__T1.DangerousGetReference(); + ref var arrayRef_T1 = ref array_T1.DangerousGetReference(); // [Variadic: CopyArgs(arrayRef)] - return new Components(ref arrayRef__T0, ref arrayRef__T1); + return new Components(ref arrayRef_T0, ref arrayRef_T1); } } diff --git a/src/Arch/Core/Variadics/Components.Variadics.cs b/src/Arch/Core/Variadics/Components.Variadics.cs index 88a63259..3ba3ef43 100644 --- a/src/Arch/Core/Variadics/Components.Variadics.cs +++ b/src/Arch/Core/Variadics/Components.Variadics.cs @@ -14,10 +14,10 @@ public ref struct Components /// #if NETSTANDARD2_1 || NET6_0 // [Variadic: CopyLines] - public Ref Component__T0; + public Ref Component_T0; #else // [Variadic: CopyLines] - public ref T0 Component__T0; + public ref T0 Component_T0; #endif /// @@ -25,14 +25,14 @@ public ref struct Components /// [SkipLocalsInit] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Components(ref T0 component__T0) + public Components(ref T0 component_T0) { #if NETSTANDARD2_1 || NET6_0 // [Variadic: CopyLines] - Component__T0 = new Ref(ref component__T0); + Component_T0 = new Ref(ref component_T0); #else // [Variadic: CopyLines] - Component__T0 = ref component__T0; + Component_T0 = ref component_T0; #endif } } @@ -48,11 +48,11 @@ public ref struct EntityComponents #if NETSTANDARD2_1 || NET6_0 public ReadOnlyRef Entity; // [Variadic: CopyLines] - public Ref Component__T0; + public Ref Component_T0; #else public ref readonly Entity Entity; // [Variadic: CopyLines] - public ref T0 Component__T0; + public ref T0 Component_T0; #endif /// @@ -60,16 +60,16 @@ public ref struct EntityComponents /// [SkipLocalsInit] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public EntityComponents(ref Entity entity, ref T0 component__T0) + public EntityComponents(ref Entity entity, ref T0 component_T0) { #if NETSTANDARD2_1 || NET6_0 Entity = new ReadOnlyRef(in entity); // [Variadic: CopyLines] - Component__T0 = new Ref(ref component__T0); + Component_T0 = new Ref(ref component_T0); #else Entity = ref entity; // [Variadic: CopyLines] - Component__T0 = ref component__T0; + Component_T0 = ref component_T0; #endif } } diff --git a/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs index bb294ff3..a86f69cb 100644 --- a/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs +++ b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs @@ -17,11 +17,11 @@ public static bool Has(this Entity entity) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2)] - public static void Set(this Entity entity, in T0 component__T0, in T1 component__T1) + public static void Set(this Entity entity, in T0 component_T0, in T1 component_T1) { var world = World.Worlds[entity.WorldId]; // [Variadic: CopyArgs(component)] - world.Set(entity, in component__T0, in component__T1); + world.Set(entity, in component_T0, in component_T1); } /// @@ -37,11 +37,11 @@ public static Components Get(this Entity entity) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2)] - public static void Add(this Entity entity, in T0 component__T0, in T1 component__T1) + public static void Add(this Entity entity, in T0 component_T0, in T1 component_T1) { var world = World.Worlds[entity.WorldId]; // [Variadic: CopyArgs(component)] - world.Add(entity, in component__T0, in component__T1); + world.Add(entity, in component_T0, in component_T1); } /// diff --git a/src/Arch/Core/Variadics/ForEach.Variadics.cs b/src/Arch/Core/Variadics/ForEach.Variadics.cs index 64db8c7c..81e1bb4c 100644 --- a/src/Arch/Core/Variadics/ForEach.Variadics.cs +++ b/src/Arch/Core/Variadics/ForEach.Variadics.cs @@ -5,11 +5,11 @@ /// provides a callback to execute logic on up to 25 component types. /// [Variadic(nameof(T0), 1, 25)] -public delegate void ForEach(ref T0 component__T0); +public delegate void ForEach(ref T0 component_T0); /// /// The delegate /// provides a callback to execute logic on an and up to 25 component types. /// [Variadic(nameof(T0), 1, 25)] -public delegate void ForEachWithEntity(Entity entity, ref T0 component__T0); +public delegate void ForEachWithEntity(Entity entity, ref T0 component_T0); diff --git a/src/Arch/Core/Variadics/Interfaces.Variadics.cs b/src/Arch/Core/Variadics/Interfaces.Variadics.cs index aab54a7a..51367a1a 100644 --- a/src/Arch/Core/Variadics/Interfaces.Variadics.cs +++ b/src/Arch/Core/Variadics/Interfaces.Variadics.cs @@ -5,7 +5,7 @@ public interface IForEach { [MethodImpl(MethodImplOptions.AggressiveInlining)] - void Update(ref T0 component__T0); + void Update(ref T0 component_T0); } /// @@ -13,5 +13,5 @@ public interface IForEach public interface IForEachWithEntity { [MethodImpl(MethodImplOptions.AggressiveInlining)] - void Update(Entity entity, ref T0 component__T0); + void Update(Entity entity, ref T0 component_T0); } diff --git a/src/Arch/Core/Variadics/Jobs.Variadics.cs b/src/Arch/Core/Variadics/Jobs.Variadics.cs index 065f2ea9..45a2a8e4 100644 --- a/src/Arch/Core/Variadics/Jobs.Variadics.cs +++ b/src/Arch/Core/Variadics/Jobs.Variadics.cs @@ -13,14 +13,14 @@ public readonly void Execute(int index, ref Chunk chunk) { var chunkSize = chunk.Size; // [Variadic: CopyLines] - ref var firstElement__T0 = ref chunk.GetFirst(); + ref var firstElement_T0 = ref chunk.GetFirst(); for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) { // [Variadic: CopyLines] - ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + ref var component_T0 = ref Unsafe.Add(ref firstElement_T0, entityIndex); // [Variadic: CopyArgs(component)] - ForEach(ref component__T0); + ForEach(ref component_T0); } } } @@ -38,15 +38,15 @@ public readonly void Execute(int index, ref Chunk chunk) { ref var entityFirstElement = ref chunk.Entity(0); // [Variadic: CopyLines] - ref var firstElement__T0 = ref chunk.GetFirst(); + ref var firstElement_T0 = ref chunk.GetFirst(); foreach (var entityIndex in chunk) { var entity = Unsafe.Add(ref entityFirstElement, entityIndex); // [Variadic: CopyLines] - ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + ref var component_T0 = ref Unsafe.Add(ref firstElement_T0, entityIndex); // [Variadic: CopyArgs(component)] - ForEach(entity, ref component__T0); + ForEach(entity, ref component_T0); } } } @@ -64,14 +64,14 @@ public void Execute(int index, ref Chunk chunk) { var chunkSize = chunk.Size; // [Variadic: CopyLines] - ref var firstElement__T0 = ref chunk.GetFirst(); + ref var firstElement_T0 = ref chunk.GetFirst(); for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) { // [Variadic: CopyLines] - ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + ref var component_T0 = ref Unsafe.Add(ref firstElement_T0, entityIndex); // [Variadic: CopyArgs(component)] - ForEach.Update(ref component__T0); + ForEach.Update(ref component_T0); } } } @@ -89,15 +89,15 @@ public void Execute(int index, ref Chunk chunk) var chunkSize = chunk.Size; ref var entityFirstElement = ref chunk.Entity(0); // [Variadic: CopyLines] - ref var firstElement__T0 = ref chunk.GetFirst(); + ref var firstElement_T0 = ref chunk.GetFirst(); for (var entityIndex = chunkSize - 1; entityIndex >= 0; --entityIndex) { var entity = Unsafe.Add(ref entityFirstElement, entityIndex); // [Variadic: CopyLines] - ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + ref var component_T0 = ref Unsafe.Add(ref firstElement_T0, entityIndex); // [Variadic: CopyArgs(component)] - ForEach.Update(entity, ref component__T0); + ForEach.Update(entity, ref component_T0); } } } diff --git a/src/Arch/Core/Variadics/World.Variadics.cs b/src/Arch/Core/Variadics/World.Variadics.cs index 2619fbfa..4d2a40a5 100644 --- a/src/Arch/Core/Variadics/World.Variadics.cs +++ b/src/Arch/Core/Variadics/World.Variadics.cs @@ -11,7 +11,7 @@ public partial class World [StructuralChange] [Variadic(nameof(T0), 1, 25)] // [Variadic: CopyParams(T0?)] - public Entity Create(in T0? componentValue__T0 = default) + public Entity Create(in T0? componentValue_T0 = default) { var types = Group.Types; @@ -27,7 +27,7 @@ public Entity Create(in T0? componentValue__T0 = default) var createdChunk = archetype.Add(entity, out var slot); // [Variadic: CopyArgs(componentValue)] - archetype.Set(ref slot, in componentValue__T0); + archetype.Set(ref slot, in componentValue_T0); // Resize map & Array to fit all potential new entities if (createdChunk) @@ -72,12 +72,12 @@ public Components Get(Entity entity) [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] [Variadic(nameof(T1), 2, 25)] - public void Set(Entity entity, in T0 component__T0, in T1 component__T1) + public void Set(Entity entity, in T0 component_T0, in T1 component_T1) { var slot = EntityInfo.GetSlot(entity.Id); var archetype = EntityInfo.GetArchetype(entity.Id); // [Variadic: CopyArgs(component)] - archetype.Set(ref slot, in component__T0, in component__T1); + archetype.Set(ref slot, in component_T0, in component_T1); OnComponentSet(entity); // [Variadic: CopyLines] OnComponentSet(entity); @@ -89,7 +89,7 @@ public void Set(Entity entity, in T0 component__T0, in T1 component__T1) [StructuralChange] [Variadic(nameof(T1), 2, 25)] // [Variadic: CopyParams(T1?)] - public void Add(Entity entity, in T0? component__T0 = default, in T1? component__T1 = default) + public void Add(Entity entity, in T0? component_T0 = default, in T1? component_T1 = default) { var oldArchetype = EntityInfo.GetArchetype(entity.Id); @@ -105,17 +105,17 @@ public void Add(Entity entity, in T0? component__T0 = default, in T1? co if (!TryGetArchetype(spanBitSet.GetHashCode(), out var newArchetype)) { - var type__T0 = typeof(T0); + var type_T0 = typeof(T0); // [Variadic: CopyLines] - var type__T1 = typeof(T1); + var type_T1 = typeof(T1); // [Variadic: CopyArgs(type)] - newArchetype = GetOrCreate(oldArchetype.Types.Add(type__T0, type__T1)); + newArchetype = GetOrCreate(oldArchetype.Types.Add(type_T0, type_T1)); } Move(entity, oldArchetype, newArchetype, out var newSlot); // [Variadic: CopyArgs(component)] - newArchetype.Set(ref newSlot, in component__T0, in component__T1); + newArchetype.Set(ref newSlot, in component_T0, in component_T1); OnComponentAdded(entity); // [Variadic: CopyLines] @@ -143,11 +143,11 @@ public void Remove(Entity entity) if (!TryGetArchetype(spanBitSet.GetHashCode(), out var newArchetype)) { - var type__T0 = typeof(T0); + var type_T0 = typeof(T0); // [Variadic: CopyLines] - var type__T1 = typeof(T1); + var type_T1 = typeof(T1); // [Variadic: CopyArgs(type)] - newArchetype = GetOrCreate(oldArchetype.Types.Remove(type__T0, type__T1)); + newArchetype = GetOrCreate(oldArchetype.Types.Remove(type_T0, type_T1)); } OnComponentRemoved(entity); @@ -165,14 +165,14 @@ public void Query(in QueryDescription description, ForEach forEach) foreach (ref var chunk in query) { // [Variadic: CopyLines] - ref var firstElement__T0 = ref chunk.GetFirst(); + ref var firstElement_T0 = ref chunk.GetFirst(); foreach (var entityIndex in chunk) { // [Variadic: CopyLines] - ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + ref var component_T0 = ref Unsafe.Add(ref firstElement_T0, entityIndex); // [Variadic: CopyArgs(component)] - forEach(ref component__T0); + forEach(ref component_T0); } } } @@ -187,15 +187,15 @@ public void Query(in QueryDescription description, ForEachWithEntity for { ref var entityFirstElement = ref chunk.Entity(0); // [Variadic: CopyLines] - ref var firstElement__T0 = ref chunk.GetFirst(); + ref var firstElement_T0 = ref chunk.GetFirst(); foreach (var entityIndex in chunk) { var entity = Unsafe.Add(ref entityFirstElement, entityIndex); // [Variadic: CopyLines] - ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + ref var component_T0 = ref Unsafe.Add(ref firstElement_T0, entityIndex); // [Variadic: CopyArgs(component)] - forEach(entity, ref component__T0); + forEach(entity, ref component_T0); } } } @@ -296,14 +296,14 @@ public void InlineQuery(in QueryDescription description, ref T iForEach) foreach (ref var chunk in query) { // [Variadic: CopyLines] - ref var firstElement__T0 = ref chunk.GetFirst(); + ref var firstElement_T0 = ref chunk.GetFirst(); foreach (var entityIndex in chunk) { // [Variadic: CopyLines] - ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + ref var component_T0 = ref Unsafe.Add(ref firstElement_T0, entityIndex); // [Variadic: CopyArgs(component)] - iForEach.Update(ref component__T0); + iForEach.Update(ref component_T0); } } } @@ -320,14 +320,14 @@ public void InlineQuery(in QueryDescription description) where T : struct { var chunkSize = chunk.Size; // [Variadic: CopyLines] - ref var firstElement__T0 = ref chunk.GetFirst(); + ref var firstElement_T0 = ref chunk.GetFirst(); foreach (var entityIndex in chunk) { // [Variadic: CopyLines] - ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + ref var component_T0 = ref Unsafe.Add(ref firstElement_T0, entityIndex); // [Variadic: CopyArgs(component)] - t.Update(ref component__T0); + t.Update(ref component_T0); } } } @@ -343,15 +343,15 @@ public void InlineEntityQuery(in QueryDescription description, ref T iFor var chunkSize = chunk.Size; ref var entityFirstElement = ref chunk.Entity(0); // [Variadic: CopyLines] - ref var firstElement__T0 = ref chunk.GetFirst(); + ref var firstElement_T0 = ref chunk.GetFirst(); foreach (var entityIndex in chunk) { var entity = Unsafe.Add(ref entityFirstElement, entityIndex); // [Variadic: CopyLines] - ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + ref var component_T0 = ref Unsafe.Add(ref firstElement_T0, entityIndex); // [Variadic: CopyArgs(component)] - iForEach.Update(entity, ref component__T0); + iForEach.Update(entity, ref component_T0); } } } @@ -369,15 +369,15 @@ public void InlineEntityQuery(in QueryDescription description) where T : var chunkSize = chunk.Size; ref var entityFirstElement = ref chunk.Entity(0); // [Variadic: CopyLines] - ref var firstElement__T0 = ref chunk.GetFirst(); + ref var firstElement_T0 = ref chunk.GetFirst(); foreach (var entityIndex in chunk) { var entity = Unsafe.Add(ref entityFirstElement, entityIndex); // [Variadic: CopyLines] - ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + ref var component_T0 = ref Unsafe.Add(ref firstElement_T0, entityIndex); // [Variadic: CopyArgs(component)] - t.Update(entity, ref component__T0); + t.Update(entity, ref component_T0); } } } @@ -473,23 +473,23 @@ public void InlineParallelEntityQuery(in QueryDescription description, re [MethodImpl(MethodImplOptions.AggressiveInlining)] [Variadic(nameof(T1), 2, 25)] // [Variadic: CopyParams(T1?)] - public void Set(in QueryDescription queryDescription, in T0? componentValue__T0 = default, in T1? componentValue__T1 = default) + public void Set(in QueryDescription queryDescription, in T0? componentValue_T0 = default, in T1? componentValue_T1 = default) { var query = Query(in queryDescription); foreach (ref var chunk in query) { - ref var firstElement__T0 = ref chunk.GetFirst(); + ref var firstElement_T0 = ref chunk.GetFirst(); // [Variadic: CopyLines] - ref var firstElement__T1 = ref chunk.GetFirst(); + ref var firstElement_T1 = ref chunk.GetFirst(); foreach (var entityIndex in chunk) { - ref var component__T0 = ref Unsafe.Add(ref firstElement__T0, entityIndex); + ref var component_T0 = ref Unsafe.Add(ref firstElement_T0, entityIndex); // [Variadic: CopyLines] - ref var component__T1 = ref Unsafe.Add(ref firstElement__T1, entityIndex); - component__T0 = componentValue__T0; + ref var component_T1 = ref Unsafe.Add(ref firstElement_T1, entityIndex); + component_T0 = componentValue_T0; // [Variadic: CopyLines] - component__T1 = componentValue__T1; + component_T1 = componentValue_T1; #if EVENTS var entity = chunk.Entity(entityIndex); OnComponentSet(entity); @@ -506,7 +506,7 @@ public void Set(in QueryDescription queryDescription, in T0? componentVa [StructuralChange] [Variadic(nameof(T1), 2, 25)] // [Variadic: CopyParams(T1?)] - public void Add(in QueryDescription queryDescription, in T0? component__T0 = default, in T1? component__T1 = default) + public void Add(in QueryDescription queryDescription, in T0? component_T0 = default, in T1? component_T1 = default) { // BitSet to stack/span bitset, size big enough to contain ALL registered components. Span stack = stackalloc uint[BitSet.RequiredLength(ComponentRegistry.Size)]; @@ -530,11 +530,11 @@ public void Add(in QueryDescription queryDescription, in T0? component__ // Get or create new archetype. if (!TryGetArchetype(spanBitSet.GetHashCode(), out var newArchetype)) { - var type__T0 = typeof(T0); + var type_T0 = typeof(T0); // [Variadic: CopyLines] - var type__T1 = typeof(T1); + var type_T1 = typeof(T1); // [Variadic: CopyArgs(type)] - newArchetype = GetOrCreate(archetype.Types.Add(type__T0, type__T1)); + newArchetype = GetOrCreate(archetype.Types.Add(type_T0, type_T1)); } // Get last slots before copy, for updating entityinfo later @@ -547,7 +547,7 @@ public void Add(in QueryDescription queryDescription, in T0? component__ Archetype.Copy(archetype, newArchetype); var lastSlot = newArchetype.LastSlot; // [Variadic: CopyArgs(component)] - newArchetype.SetRange(in lastSlot, in newArchetypeLastSlot, in component__T0, in component__T1); + newArchetype.SetRange(in lastSlot, in newArchetypeLastSlot, in component_T0, in component_T1); OnComponentAdded(archetype); // [Variadic: CopyLines] OnComponentAdded(archetype); @@ -584,11 +584,11 @@ public void Remove(in QueryDescription queryDescription) // Get or create new archetype. if (!TryGetArchetype(spanBitSet.GetHashCode(), out var newArchetype)) { - var type__T0 = typeof(T0); + var type_T0 = typeof(T0); // [Variadic: CopyLines] - var type__T1 = typeof(T1); + var type_T1 = typeof(T1); // [Variadic: CopyArgs(type)] - newArchetype = GetOrCreate(archetype.Types.Remove(type__T0, type__T1)); + newArchetype = GetOrCreate(archetype.Types.Remove(type_T0, type_T1)); } OnComponentRemoved(archetype); From 4df660ca6f82460a744d23fb643dfced23c0577a Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Tue, 7 Nov 2023 01:59:35 -0800 Subject: [PATCH 13/16] change stringbuilder to var --- src/Arch.SourceGen/CopyArgsAlgorithm.cs | 6 +++--- src/Arch.SourceGen/CopyLinesAlgorithm.cs | 4 ++-- src/Arch.SourceGen/CopyParamsAlgorithm.cs | 4 ++-- src/Arch.SourceGen/DefaultAlgorithm.cs | 6 +++--- src/Arch.SourceGen/VariadicGenerator.cs | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Arch.SourceGen/CopyArgsAlgorithm.cs b/src/Arch.SourceGen/CopyArgsAlgorithm.cs index 856a31de..51854894 100644 --- a/src/Arch.SourceGen/CopyArgsAlgorithm.cs +++ b/src/Arch.SourceGen/CopyArgsAlgorithm.cs @@ -24,9 +24,9 @@ internal class CopyArgsAlgorithm : LineAlgorithm public override string Transform(string line, string type, int start, int variations, string[] parameters) { - StringBuilder transformed = new(); + var transformed = new StringBuilder(); transformed.AppendLine(line); - StringBuilder newVariables = new(); + var newVariables = new StringBuilder(); // match ref, in, out var modifiersMatch = Regex.Match(line, $@"[(,]\s*(?(ref|out ref|out var|out {type}\??|in|ref {type}\??))?\s*{parameters[0]}_{type}"); @@ -49,7 +49,7 @@ public override string Transform(string line, string type, int start, int variat // expand any remaining generics // note that this'll break if the user uses Span instead of var or something.... - StringBuilder variadics = new(); + var variadics = new StringBuilder(); for (int i = start - 1; i < variations; i++) { variadics.Append(VaryType(type, i)); diff --git a/src/Arch.SourceGen/CopyLinesAlgorithm.cs b/src/Arch.SourceGen/CopyLinesAlgorithm.cs index d50f4e6b..3b8a50e9 100644 --- a/src/Arch.SourceGen/CopyLinesAlgorithm.cs +++ b/src/Arch.SourceGen/CopyLinesAlgorithm.cs @@ -24,12 +24,12 @@ internal class CopyLinesAlgorithm : LineAlgorithm public override string Transform(string line, string type, int start, int variations, string[] parameters) { - StringBuilder transformed = new(); + var transformed = new StringBuilder(); transformed.AppendLine(line); for (int i = start; i < variations; i++) { - StringBuilder next = new(); + var next = new StringBuilder(); next.AppendLine(line); var variadic = VaryType(type, i); next.Replace(type, variadic); diff --git a/src/Arch.SourceGen/CopyParamsAlgorithm.cs b/src/Arch.SourceGen/CopyParamsAlgorithm.cs index 3424e003..9d88abee 100644 --- a/src/Arch.SourceGen/CopyParamsAlgorithm.cs +++ b/src/Arch.SourceGen/CopyParamsAlgorithm.cs @@ -49,10 +49,10 @@ public override string Transform(string line, string type, int start, int variat additionalParams.Add($"{modifiers} {fullType} {param}_{variadic} {(hasDefault ? "= default" : "")}"); } - StringBuilder transformed = new(); + var transformed = new StringBuilder(); transformed.Append(line); - StringBuilder @params = new(); + var @params = new StringBuilder(); // +1 to exclude the opening parenthesis or comma @params.Append(line.Substring(headerMatch.Index + 1, headerMatch.Length - 1)); foreach (var additionalParam in additionalParams) diff --git a/src/Arch.SourceGen/DefaultAlgorithm.cs b/src/Arch.SourceGen/DefaultAlgorithm.cs index cff84495..8bd7f2e9 100644 --- a/src/Arch.SourceGen/DefaultAlgorithm.cs +++ b/src/Arch.SourceGen/DefaultAlgorithm.cs @@ -35,7 +35,7 @@ internal class DefaultAlgorithm : LineAlgorithm public override string Name { get => string.Empty; } public override string Transform(string line, string type, int start, int variations, string[] parameters) { - StringBuilder transformed = new(); + var transformed = new StringBuilder(); // copy type constraints for our selected variadic var constraints = Regex.Match(line, @$"where\s+{type}\s*:\s*(?.*?)(?:where|{{|$)"); @@ -60,7 +60,7 @@ public override string Transform(string line, string type, int start, int variat } // build a string like "T0, T1, ...>" - StringBuilder variadics = new(); + var variadics = new StringBuilder(); for (int i = start - 1; i < variations; i++) { variadics.Append(VaryType(type, i)); @@ -88,7 +88,7 @@ public override string Transform(string line, string type, int start, int variat var name = paramMatch.Groups["ParamName"].Value; var modifiers = paramMatch.Groups["Modifiers"].Value; - StringBuilder newParams = new(); + var newParams = new StringBuilder(); for (int i = start - 1; i < variations; i++) { var varied = VaryType(type, i); diff --git a/src/Arch.SourceGen/VariadicGenerator.cs b/src/Arch.SourceGen/VariadicGenerator.cs index 9cc2a910..edf19537 100644 --- a/src/Arch.SourceGen/VariadicGenerator.cs +++ b/src/Arch.SourceGen/VariadicGenerator.cs @@ -141,7 +141,7 @@ static VariadicGenerator() private string MakeVariadic(VariadicInfo info) { var lines = ProcessLines(info).ToList(); - StringBuilder combined = new(); + var combined = new StringBuilder(); for (var i = info.Start; i < info.Count; i++) { From e4e6476ae2c447e75dd3e41d4149e208efc7441b Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Tue, 7 Nov 2023 02:29:37 -0800 Subject: [PATCH 14/16] VariadicGenerator documentation pass --- src/Arch.SourceGen/VariadicGenerator.cs | 291 +++++++++++++++++------- 1 file changed, 204 insertions(+), 87 deletions(-) diff --git a/src/Arch.SourceGen/VariadicGenerator.cs b/src/Arch.SourceGen/VariadicGenerator.cs index edf19537..2efe96ad 100644 --- a/src/Arch.SourceGen/VariadicGenerator.cs +++ b/src/Arch.SourceGen/VariadicGenerator.cs @@ -1,4 +1,5 @@ -using System.Text.RegularExpressions; +using System.Collections.Immutable; +using System.Text.RegularExpressions; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Arch.SourceGen; @@ -16,19 +17,61 @@ public class VariadicGenerator : IIncrementalGenerator // However, CSharpSyntaxRewriter is poorly documented and can lead to a lot of very very difficult code. // For now, since this is limited to Arch, it's enough to use this. + /// + /// Stores useful info about a member marked with . + /// private class VariadicInfo { + /// + /// The generic type to look for, as passed to . For example, T0. + /// public string Type { get; set; } = string.Empty; + + /// + /// The amount of total variadics that should be generated, as passed to . + /// + public int Count { get; set; } = 0; + + /// + /// How many variadics have already been specified and should be skipped during generation, as passed to . + /// + public int Start { get; internal set; } + + /// + /// The full code of the member the attribute is on, including any preceding documentation and attributes. + /// public string Code { get; set; } = string.Empty; + + /// + /// The name of the member the attribute is on. + /// public string Name { get; set; } = string.Empty; + + /// + /// The type declaration that the member is nested in, or an empty string if not nested. For example, public partial class MyClass + /// public string EnclosingType { get; set; } = string.Empty; + + /// + /// The name of the type declaration that the member is nested in, or an empty string if not nested. For example, MyClass + /// public string EnclosingTypeName { get; set; } = string.Empty; + + /// + /// The namespace the type is in. + /// public string Namespace { get; set; } = string.Empty; + + /// + /// Any usings from the file of the attribute definition. + /// public string Usings { get; set; } = string.Empty; - public int Count { get; set; } = 0; - public int Start { get; internal set; } } + /// + /// Initialize the incremental generator. + /// + /// public void Initialize(IncrementalGeneratorInitializationContext context) { // Uncomment to help debug with breakpoints: @@ -37,90 +80,126 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var infos = context.SyntaxProvider.ForAttributeWithMetadataName("Arch.Core.VariadicAttribute", // We want to grab everything with the attribute, always! (node, token) => true, - (ctx, token) => - { - VariadicInfo info = new(); + // Convert into an array of VariadicInfo objects, for each attribute + (ctx, token) => ParseVariadicInfo(ctx)) + // Collect into a single array so we can process the whole thing in one go + .Collect(); - // Note: doesn't support mulilevel type nesting, like struct Something { struct AnotherThing { struct AThirdThing {} } }. Only 1 nesting layer is supported. - if (ctx.TargetSymbol.ContainingType is not null) - { - info.EnclosingTypeName = ctx.TargetSymbol.ContainingType.Name; - var accessibility = ctx.TargetSymbol.ContainingType.DeclaredAccessibility switch - { - Accessibility.Public => "public", - _ => "internal", - }; + context.RegisterSourceOutput(infos, GenerateVariadics); + } - var reference = ctx.TargetSymbol.ContainingType.IsReferenceType ? "class" : "struct"; + /// + /// Generate all of the files from a of . + /// + /// + /// + private void GenerateVariadics(SourceProductionContext ctx, ImmutableArray infos) + { + Dictionary filenames = new(); + foreach (var info in infos) + { + // Generate the code + var convertedCode = MakeVariadic(info); - info.EnclosingType = $"{accessibility} partial {reference} {ctx.TargetSymbol.ContainingType.Name}"; - } + // Format properly + var text = CSharpSyntaxTree.ParseText(convertedCode).GetRoot().NormalizeWhitespace().ToFullString(); - string ns = string.Empty; - var containingNamespace = ctx.TargetSymbol.ContainingNamespace; - while (containingNamespace is not null && !string.IsNullOrEmpty(containingNamespace.Name)) - { - ns = ns != string.Empty ? containingNamespace.Name + "." + ns : containingNamespace.Name; - containingNamespace = containingNamespace.ContainingNamespace; - } + // Calculate the filename + var filename = info.EnclosingType != string.Empty ? $"{info.EnclosingTypeName}.{info.Name}.Variadic" : $"{info.Name}.Variadic"; - info.Namespace = ns; - info.Name = ctx.TargetSymbol.Name; - info.Code = ctx.TargetNode.GetLeadingTrivia().ToString() + ctx.TargetNode.ToString(); - foreach (var use in (ctx.TargetNode.SyntaxTree.GetRoot() as CompilationUnitSyntax)!.Usings) - { - info.Usings += use.ToString() + "\n"; - } + // If we accidentally created a duplicate filename, we need to append an integer. + int filenameIndex; + if (!filenames.ContainsKey(filename)) + { + filenames[filename] = 0; + filenameIndex = 0; + } + else + { + filenames[filename]++; + filenameIndex = filenames[filename]; + } - foreach (var attr in ctx.TargetSymbol.GetAttributes()) - { - if (attr.AttributeClass?.Name == "VariadicAttribute") - { - info.Type = attr.ConstructorArguments[0].Value as string ?? throw new InvalidOperationException(); - info.Start = Convert.ToInt32(attr.ConstructorArguments[1].Value); - info.Count = Convert.ToInt32(attr.ConstructorArguments[2].Value); - break; - } - } + // We add a .1, .2 etc to repeat filenames, but leave .0 off. + string index = filenameIndex != 0 ? $".{filenameIndex}" : string.Empty; - if (info.Type == string.Empty) - { - throw new InvalidOperationException(); - } + // Finally, add the source as well as the index + ctx.AddSource($"{filename}{index}.g.cs", text); + } + } - return info; - }).Collect(); + /// + /// Given a , produces a object describing the method to be generated. + /// + /// The context. + /// A new instance. + private VariadicInfo ParseVariadicInfo(GeneratorAttributeSyntaxContext ctx) + { + var info = new VariadicInfo(); - context.RegisterSourceOutput(infos, (ctx, infos) => + // Note: doesn't support mulilevel type nesting, like struct Something { struct AnotherThing { struct AThirdThing {} } }. Only 1 nesting layer is supported. + if (ctx.TargetSymbol.ContainingType is not null) { - Dictionary filenames = new(); - foreach (var info in infos) + info.EnclosingTypeName = ctx.TargetSymbol.ContainingType.Name; + var accessibility = ctx.TargetSymbol.ContainingType.DeclaredAccessibility switch { - var text = CSharpSyntaxTree.ParseText(MakeVariadic(info)).GetRoot().NormalizeWhitespace().ToFullString(); - var filename = info.EnclosingType != string.Empty ? $"{info.EnclosingTypeName}.{info.Name}.Variadic" : $"{info.Name}.Variadic"; - // if we accidentally created a duplicate filename, we need to append an integer. - int filenameIndex; - if (!filenames.ContainsKey(filename)) - { - filenames[filename] = 0; - filenameIndex = 0; - } - else - { - filenames[filename]++; - filenameIndex = filenames[filename]; - } + Accessibility.Public => "public", + _ => "internal", + }; + + var reference = ctx.TargetSymbol.ContainingType.IsReferenceType ? "class" : "struct"; + + var record = ctx.TargetSymbol.ContainingType.IsRecord ? "record" : ""; + + info.EnclosingType = $"{accessibility} partial {record} {reference} {ctx.TargetSymbol.ContainingType.Name}"; + } - string index = filenameIndex != 0 ? $".{filenameIndex}" : string.Empty; - ctx.AddSource($"{filename}{index}.g.cs", text); + // Loop through the namespaces to get the full namespace path + string ns = string.Empty; + var containingNamespace = ctx.TargetSymbol.ContainingNamespace; + while (containingNamespace is not null && !string.IsNullOrEmpty(containingNamespace.Name)) + { + ns = ns != string.Empty ? containingNamespace.Name + "." + ns : containingNamespace.Name; + containingNamespace = containingNamespace.ContainingNamespace; + } + + info.Namespace = ns; + info.Name = ctx.TargetSymbol.Name; + + // Leading documentation (trivia) + code + info.Code = ctx.TargetNode.GetLeadingTrivia().ToString() + ctx.TargetNode.ToString(); + foreach (var use in (ctx.TargetNode.SyntaxTree.GetRoot() as CompilationUnitSyntax)!.Usings) + { + info.Usings += use.ToString() + "\n"; + } + + // Grab the arguments of the variadic attribute + foreach (var attr in ctx.TargetSymbol.GetAttributes()) + { + if (attr.AttributeClass?.Name == "VariadicAttribute") + { + info.Type = attr.ConstructorArguments[0].Value as string ?? throw new InvalidOperationException(); + info.Start = Convert.ToInt32(attr.ConstructorArguments[1].Value); + info.Count = Convert.ToInt32(attr.ConstructorArguments[2].Value); + break; } - }); + } + + if (info.Type == string.Empty) + { + throw new InvalidOperationException(); + } + + return info; } // stores the algorithms from reflection private readonly static Dictionary _algorithms = new(); - // collect the algorithms available with reflection on the attribute + /// + /// Collect any methods tagged with to register them as potential algorithms for the generation. + /// process. + /// static VariadicGenerator() { foreach (var type in typeof(VariadicGenerator).Assembly.GetTypes()) @@ -138,13 +217,23 @@ static VariadicGenerator() } } + /// + /// Generate a full string of generated variadic methods given a . + /// + /// The instance with information on how to generate the code. + /// A C# string containing all the generated methods. private string MakeVariadic(VariadicInfo info) { - var lines = ProcessLines(info).ToList(); + // Grab a list of code tokens to help us generate + var lines = ProcessLines(info.Code).ToList(); + var combined = new StringBuilder(); + // Run for each variadic requested, starting after Start (so if start is 1, it means we already defined 1 variadic , + // and must start by generating ). for (var i = info.Start; i < info.Count; i++) { + // Process line by line, and run the algorithm on each foreach (var line in lines) { if (!_algorithms.ContainsKey(line.Algorithm)) @@ -152,17 +241,22 @@ private string MakeVariadic(VariadicInfo info) throw new InvalidOperationException($"Algorithm {line.Algorithm} is unknown."); } + // Grab our algorithm class from the reflection dictionary. If line.Algorithm is empty, it gets the default algorithm. var algo = _algorithms[line.Algorithm]; + + // Validate algorithm params if (algo.ExpectedParameterCount != line.Parameters.Length) { throw new InvalidOperationException($"Algorithm {line.Algorithm} supports only exactly {algo.ExpectedParameterCount} parameters, " + $"but {line.Parameters.Length} were provided."); } + // Run the transformation algorithm on the line combined.AppendLine(algo.Transform(line.Line, info.Type, info.Start, i + 1, line.Parameters)); } } + // If we're inside a type (like a method, for example, or an inner class), we have to put it in its parent. if (info.EnclosingType != string.Empty) { combined.Insert(0, info.EnclosingType + "{"); @@ -179,16 +273,38 @@ namespace {{info.Namespace}}; """; } + /// + /// Represents a line "token" from the original code, + /// private struct LineInfo { + /// + /// The user-specified algorithm to use. For example, [Variadic: CopyLines] would use . + /// If blank, is assumed. + /// public string Algorithm; - public string Line; + + /// + /// The parameters passed into the algorrithm. For example, [Variadic: CopyArgs(component)] would pass in component as + /// a singular param to . + /// public string[] Parameters; + + /// + /// The unprocessed C# line, ready to go into an algorithm. + /// + public string Line; } - private IEnumerable ProcessLines(VariadicInfo info) + /// + /// "Tokenize" the input code into a series of lines, assigning them processing algorithms where necessary. + /// Processing algorithms are determined by a comment on the preceding lines, like // [Variadic: MyAlgorithm(param1...)] + /// + /// The info to process the code of + /// + private IEnumerable ProcessLines(string code) { - var lines = SplitLines(info.Code); + var lines = code.Split('\n').Select(line => line.Trim()); string nextAlgorithm = string.Empty; List nextParameters = new(); @@ -196,28 +312,29 @@ private IEnumerable ProcessLines(VariadicInfo info) { if (line.StartsWith("[Variadic(")) { - // don't include variadic attrs + // Don't include variadic attributes; skip over them continue; } - bool isDocumentation = false; - // never process documentation - if (line.StartsWith("///")) - { - isDocumentation = true; - } + // Never process documentation, just leave it as-is + bool isDocumentation = line.StartsWith("///"); - else if (line.StartsWith("//")) + // If it's a normal comment, check for variadic. + // If not, discard it. If so, include it in the line token. + if (!isDocumentation && line.StartsWith("//")) { - // match algorithm, like "// [Variadic: AlgorithmName(param1, param2...)]" + // Match an algorithm specifier, like "// [Variadic: AlgorithmName(param1, param2...)]" var match = Regex.Match(line, @"\[Variadic:\s*(?\w+)(?:\((?:(?[?\w\[\]<>]+),?\s*)+\)\])?"); if (!match.Success) { + // discard the comment continue; } + // The next line will have this algorithm! nextAlgorithm = match.Groups["Operation"].Value; + // Add parameters as specified if (match.Groups["Variable"].Success) { foreach (Capture capture in match.Groups["Variable"].Captures) @@ -226,15 +343,20 @@ private IEnumerable ProcessLines(VariadicInfo info) } } + // Since it's a comment, we want to discard anyways. continue; } + // At this point, we know that the line is a meaningful line, either documentation or code. var lineInfo = new LineInfo() { Line = line, + // The algorithm, as previously specified, or if it's documentation a directive to completely ignore it! Algorithm = !isDocumentation ? nextAlgorithm : "Ignore", Parameters = !isDocumentation ? nextParameters.ToArray() : Array.Empty() }; + + // If this was meaningful code, we used up the algorithm and reset to default. if (!isDocumentation) { nextAlgorithm = string.Empty; @@ -244,9 +366,4 @@ private IEnumerable ProcessLines(VariadicInfo info) yield return lineInfo; } } - - private IEnumerable SplitLines(string code) - { - return code.Split('\n').Select(line => line.Trim()); - } } From 5dc266703ae814b60e119df61c7ca0fbb84ef9ad Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Tue, 7 Nov 2023 02:39:52 -0800 Subject: [PATCH 15/16] fix typename for generic containers --- src/Arch.SourceGen/VariadicGenerator.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Arch.SourceGen/VariadicGenerator.cs b/src/Arch.SourceGen/VariadicGenerator.cs index 2efe96ad..f7e5a583 100644 --- a/src/Arch.SourceGen/VariadicGenerator.cs +++ b/src/Arch.SourceGen/VariadicGenerator.cs @@ -151,7 +151,9 @@ private VariadicInfo ParseVariadicInfo(GeneratorAttributeSyntaxContext ctx) var record = ctx.TargetSymbol.ContainingType.IsRecord ? "record" : ""; - info.EnclosingType = $"{accessibility} partial {record} {reference} {ctx.TargetSymbol.ContainingType.Name}"; + var typeName = ctx.TargetSymbol.ContainingType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); + + info.EnclosingType = $"{accessibility} partial {record} {reference} {typeName}"; } // Loop through the namespaces to get the full namespace path From 77113c9de418fa972fa3adf98bcd5ed7943ee95f Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6U9TBJ\\Lilith" Date: Thu, 9 Nov 2023 04:54:11 -0800 Subject: [PATCH 16/16] improve readability of variadic sourcegen --- src/Arch.SourceGen/CopyArgsAlgorithm.cs | 47 +---- src/Arch.SourceGen/CopyLinesAlgorithm.cs | 12 +- src/Arch.SourceGen/CopyParamsAlgorithm.cs | 64 ++---- src/Arch.SourceGen/DefaultAlgorithm.cs | 76 +------ src/Arch.SourceGen/IgnoreAlgorithm.cs | 2 +- src/Arch.SourceGen/LineAlgorithm.cs | 16 +- src/Arch.SourceGen/Utils.cs | 194 ++++++++++++++++++ src/Arch.SourceGen/VariadicGenerator.cs | 19 +- .../Core/Variadics/Archetype.Variadics.cs | 8 +- src/Arch/Core/Variadics/Chunk.Variadics.cs | 16 +- .../Core/Variadics/Components.Variadics.cs | 4 +- .../Variadics/EntityExtensions.Variadics.cs | 10 +- src/Arch/Core/Variadics/ForEach.Variadics.cs | 4 +- src/Arch/Core/Variadics/Group.Variadics.cs | 2 +- .../Core/Variadics/Interfaces.Variadics.cs | 4 +- src/Arch/Core/Variadics/Jobs.Variadics.cs | 8 +- .../Variadics/QueryDescription.Variadics.cs | 8 +- src/Arch/Core/Variadics/World.Variadics.cs | 38 ++-- src/Arch/VariadicAttribute.cs | 13 +- 19 files changed, 294 insertions(+), 251 deletions(-) create mode 100644 src/Arch.SourceGen/Utils.cs diff --git a/src/Arch.SourceGen/CopyArgsAlgorithm.cs b/src/Arch.SourceGen/CopyArgsAlgorithm.cs index 51854894..65b0fb51 100644 --- a/src/Arch.SourceGen/CopyArgsAlgorithm.cs +++ b/src/Arch.SourceGen/CopyArgsAlgorithm.cs @@ -22,48 +22,15 @@ internal class CopyArgsAlgorithm : LineAlgorithm public override string Name { get => "CopyArgs"; } public override int ExpectedParameterCount { get => 1; } - public override string Transform(string line, string type, int start, int variations, string[] parameters) + public override string Transform(string line, string type, int lastVariadic, string[] parameters) { - var transformed = new StringBuilder(); - transformed.AppendLine(line); - var newVariables = new StringBuilder(); + // Expand the args + line = Utils.ExpandUntypedArguments(line, type, lastVariadic, parameters[0]); - // match ref, in, out - var modifiersMatch = Regex.Match(line, $@"[(,]\s*(?(ref|out ref|out var|out {type}\??|in|ref {type}\??))?\s*{parameters[0]}_{type}"); - if (!modifiersMatch.Success) - { - throw new InvalidOperationException($"Can't find variable {parameters[0]}_{type} in a parameter list."); - } + // Expand any remaining generics + // Note that this'll break if the user uses Span instead of var or something.... + line = Utils.ExpandGenericTypes(line, type, lastVariadic); - var modifiers = modifiersMatch.Groups["Modifiers"].Value; - - newVariables.Append($"{modifiers} {parameters[0]}_{type}"); - for (int i = start; i < variations; i++) - { - var variadic = VaryType(type, i); - newVariables.Append($", {modifiers} {parameters[0]}_{variadic}"); - } - - transformed.Remove(modifiersMatch.Index + 1, modifiersMatch.Length - 1); - transformed.Insert(modifiersMatch.Index + 1, newVariables.ToString()); - - // expand any remaining generics - // note that this'll break if the user uses Span instead of var or something.... - var variadics = new StringBuilder(); - for (int i = start - 1; i < variations; i++) - { - variadics.Append(VaryType(type, i)); - if (i != variations - 1) - { - variadics.Append(", "); - } - } - - variadics.Append(">"); - - // Apply generics: expand T0> -> T0, T1...> - transformed.Replace(type + ">", variadics.ToString()); - - return transformed.ToString(); + return line; } } diff --git a/src/Arch.SourceGen/CopyLinesAlgorithm.cs b/src/Arch.SourceGen/CopyLinesAlgorithm.cs index 3b8a50e9..da3a02df 100644 --- a/src/Arch.SourceGen/CopyLinesAlgorithm.cs +++ b/src/Arch.SourceGen/CopyLinesAlgorithm.cs @@ -22,18 +22,16 @@ internal class CopyLinesAlgorithm : LineAlgorithm public override string Name { get => "CopyLines"; } public override int ExpectedParameterCount { get => 0; } - public override string Transform(string line, string type, int start, int variations, string[] parameters) + public override string Transform(string line, string type, int lastVariadic, string[] parameters) { + var (typeName, typeNum) = Utils.ExtractTypeInfo(type); + var transformed = new StringBuilder(); transformed.AppendLine(line); - for (int i = start; i < variations; i++) + for (int i = typeNum + 1; i <= lastVariadic; i++) { - var next = new StringBuilder(); - next.AppendLine(line); - var variadic = VaryType(type, i); - next.Replace(type, variadic); - transformed.AppendLine(next.ToString()); + transformed.AppendLine(Utils.ReplaceType(line, type, i)); } return transformed.ToString(); diff --git a/src/Arch.SourceGen/CopyParamsAlgorithm.cs b/src/Arch.SourceGen/CopyParamsAlgorithm.cs index 9d88abee..8bda8961 100644 --- a/src/Arch.SourceGen/CopyParamsAlgorithm.cs +++ b/src/Arch.SourceGen/CopyParamsAlgorithm.cs @@ -23,60 +23,24 @@ internal class CopyParamsAlgorithm : LineAlgorithm public override int ExpectedParameterCount { get => 1; } public override string Name { get => "CopyParams"; } - public override string Transform(string line, string type, int start, int variations, string[] parameters) + public override string Transform(string line, string type, int lastVariadic, string[] parameters) { - // This is a special algorithm denotion for method headers. - // This grabs the first param that matches the passed in type (in Variables[0]), like "Span? paramName_T0 = default" - // it extracts paramName, the initializer if it exists, any ref/out/in modifiers, and repeats it according to the type params. - var headerMatch = Regex.Match(line, $@"[(,]\s*(?(ref|out|ref readonly|in)\s+)?{Regex.Escape(parameters[0])}\s+(?\w+)_{type}\s*(?=\s*default)?"); + // Expand the "where" constraints (like where T0 : ISomething) + line = Utils.ExpandConstraints(line, type, lastVariadic); - if (!headerMatch.Success) - { - throw new InvalidOperationException($"Malformed method header for {nameof(CopyParamsAlgorithm)}."); - } + // Expand params in header (i.e. Span component_T0 -> Span component_T0, Span component_T1... + line = Utils.ExpandTypedParameters(line, type, parameters[0], lastVariadic, out int transformedStart, out int transformedEnd); - bool hasDefault = headerMatch.Groups["Assignment"].Success; - string modifiers = headerMatch.Groups["Modifiers"].Success ? headerMatch.Groups["Modifiers"].Value : string.Empty; - string param = headerMatch.Groups["ParamName"].Value; + // Expand any generic type groups (like ). We need to explicitly ONLY do this on the part of the header outside of the params, or Span + // will turn into Span which we don't want. + // So, we exclude the transformed range from the typed parameter extension. - List additionalParams = new(); - for (int i = start; i < variations; i++) - { - var variadic = VaryType(type, i); - // One issue with this approach... if we had a wrapper type of SomethingT1 (which is bad name but whatever) then this would break. - // but so far we don't have anything like that. - var fullType = parameters[0].Replace(type, variadic); - additionalParams.Add($"{modifiers} {fullType} {param}_{variadic} {(hasDefault ? "= default" : "")}"); - } + var beforeParams = line.Substring(0, transformedStart); + var @params = line.Substring(transformedStart, transformedEnd - transformedStart); + var afterParams = line.Substring(transformedEnd, line.Length - transformedEnd); - var transformed = new StringBuilder(); - transformed.Append(line); - - var @params = new StringBuilder(); - // +1 to exclude the opening parenthesis or comma - @params.Append(line.Substring(headerMatch.Index + 1, headerMatch.Length - 1)); - foreach (var additionalParam in additionalParams) - { - @params.Append(", " + additionalParam); - } - - // For the rest of the line, we do a trick: we want to apply the regular op on the rest of the header, so we remove all args and re-add them after. - // We do this so we don't have to process constraints/generics separately. - - // Remove all the args we just added - transformed.Remove(headerMatch.Index + 1, headerMatch.Length - 1); - var lineWithoutArgs = transformed.ToString(); - var defaultAlgorithm = new DefaultAlgorithm(); - transformed.Clear(); - // Do a default transform on everything but the args - transformed.Append(defaultAlgorithm.Transform(lineWithoutArgs, type, start, variations, Array.Empty())); - - // Find where we left off; we either left a hanging comma or an () - var match = Regex.Match(transformed.ToString(), @"(,\s*\)|\(\s*\))"); - Debug.Assert(match.Success); - // Stick our params back in there - transformed.Insert(match.Index + 1, @params); - - return transformed.ToString(); + // Composite the parts back together + return Utils.ExpandGenericTypes(beforeParams, type, lastVariadic) + @params + + Utils.ExpandGenericTypes(afterParams, type, lastVariadic); } } diff --git a/src/Arch.SourceGen/DefaultAlgorithm.cs b/src/Arch.SourceGen/DefaultAlgorithm.cs index 8bd7f2e9..ed739ada 100644 --- a/src/Arch.SourceGen/DefaultAlgorithm.cs +++ b/src/Arch.SourceGen/DefaultAlgorithm.cs @@ -33,77 +33,19 @@ internal class DefaultAlgorithm : LineAlgorithm { public override int ExpectedParameterCount { get => 0; } public override string Name { get => string.Empty; } - public override string Transform(string line, string type, int start, int variations, string[] parameters) + public override string Transform(string line, string type, int lastVariadic, string[] parameters) { - var transformed = new StringBuilder(); + // Expand the "where" constraints (like where T0 : ISomething) + line = Utils.ExpandConstraints(line, type, lastVariadic); - // copy type constraints for our selected variadic - var constraints = Regex.Match(line, @$"where\s+{type}\s*:\s*(?.*?)(?:where|{{|$)"); - if (constraints.Success) - { - // append anything prior to the original constraint - transformed.Append(line.Substring(0, constraints.Index)); - - // append extra constraints as needed - for (int i = 1; i < variations; i++) - { - transformed.Append($" where {VaryType(type, i)} : {constraints.Groups["Constraints"].Value} "); - } - - // add in the rest of the line, plus the original constraint - transformed.Append(line.Substring(constraints.Index, line.Length - constraints.Index)); - } - else - { - // no constraints, just add the line - transformed.Append(line); - } - - // build a string like "T0, T1, ...>" - var variadics = new StringBuilder(); - for (int i = start - 1; i < variations; i++) - { - variadics.Append(VaryType(type, i)); - if (i != variations - 1) - { - variadics.Append(", "); - } - } - - variadics.Append(">"); - - // Apply generics: expand T0> -> T0, T1...> - // Applied everywhere, wherever generics appear! - transformed.Replace(type + ">", variadics.ToString()); + // Expand any generic type groups (like ) + line = Utils.ExpandGenericTypes(line, type, lastVariadic); // Expand params in header (i.e. T0 component_T0 -> T0 component_T0, T1 component_T1... - // This is the 90% case. Occasionally there needs to be special handling for a method header. - // Those cases are handled by CopyParamsAlgorithm - // Modifiers is ref, in, out etc. - // ParamName is the paramname we need to copy, - var exp = $@"[(,]\s*(?(?:in|out|ref|ref\s+readonly)\s+)?{type}\s+(?\w+)_{type}"; - var paramMatch = Regex.Match(transformed.ToString(), exp); - if (paramMatch.Success) - { - var name = paramMatch.Groups["ParamName"].Value; - var modifiers = paramMatch.Groups["Modifiers"].Value; - - var newParams = new StringBuilder(); - for (int i = start - 1; i < variations; i++) - { - var varied = VaryType(type, i); - newParams.Append($"{modifiers} {varied} {name}_{varied}"); - if (i != variations - 1) - { - newParams.Append(", "); - } - } - - transformed.Remove(paramMatch.Index + 1, paramMatch.Length - 1); - transformed.Insert(paramMatch.Index + 1, newParams); - } - - return transformed.ToString(); + // This is the 90% case. Occasionally there needs to be special handling for a method header with wrapped types, like Span. + // Those cases are handled by CopyParamsAlgorithm; this algorithm incorrectly produces Span instead of copying the typed params. + line = Utils.ExpandTypedParameters(line, type, type, lastVariadic, out var _, out var _); + return line; } } diff --git a/src/Arch.SourceGen/IgnoreAlgorithm.cs b/src/Arch.SourceGen/IgnoreAlgorithm.cs index a9a01836..c7e96e66 100644 --- a/src/Arch.SourceGen/IgnoreAlgorithm.cs +++ b/src/Arch.SourceGen/IgnoreAlgorithm.cs @@ -9,7 +9,7 @@ internal class IgnoreAlgorithm : LineAlgorithm public override string Name { get => "Ignore"; } public override int ExpectedParameterCount { get => 0; } - public override string Transform(string line, string type, int start, int variations, string[] parameters) + public override string Transform(string line, string type, int lastVariadic, string[] parameters) { return line; } diff --git a/src/Arch.SourceGen/LineAlgorithm.cs b/src/Arch.SourceGen/LineAlgorithm.cs index bdd5cd14..631d975f 100644 --- a/src/Arch.SourceGen/LineAlgorithm.cs +++ b/src/Arch.SourceGen/LineAlgorithm.cs @@ -23,20 +23,8 @@ internal abstract class LineAlgorithm /// /// The input line. /// The variadic type provided in the variadic attribute, e.g. T0 - /// The first extra variadic to generate, e.g. `2` if one variadic is provided in the template method. - /// How many variadics to generate. This will be called with various numbers of variations to generate the full variadic spectrum. + /// The last variadic to generate. If 1, for example, would generate T0, T1. /// The parameters provided to the variadic comment, if any. /// The transformed string according to the algorithm. - public abstract string Transform(string line, string type, int start, int variations, string[] parameters); - - protected static string VaryType(string typeName, int i) - { - var match = Regex.Match(typeName, @"(?\w+)[0-9]+"); - if (!match.Success) - { - throw new InvalidOperationException("Variadic type must be of TypeName{N}"); - } - - return $"{match.Groups["PrunedName"]}{i}"; - } + public abstract string Transform(string line, string type, int lastVariadic, string[] parameters); } diff --git a/src/Arch.SourceGen/Utils.cs b/src/Arch.SourceGen/Utils.cs new file mode 100644 index 00000000..d1940707 --- /dev/null +++ b/src/Arch.SourceGen/Utils.cs @@ -0,0 +1,194 @@ +using System.Text.RegularExpressions; + +namespace Arch.SourceGen; +internal static class Utils +{ + /// + /// Within a method call, expand untyped arguments into their generic version. For example, MyMethod(foo, out T0 component_T0) + /// would expand to MyMethod(foo, out T0 component_T0, out T1 component_T1) given a of T0, + /// a of 1, and a of "component". + /// + /// The line to transform. + /// The basic type to expand, for example T0. + /// The last variadic to generate, incremented from the number of . + /// The variable to expand, with a _0 suffix. For example, "component" would expand "component_T0" into its types. + /// The transformed line. + public static string ExpandUntypedArguments(string line, string type, int endIndex, string variable) + { + var (typeName, typeNumber) = ExtractTypeInfo(type); + + // Modifiers capture group contains ref out, out var, etc + var modifiersMatch = Regex.Match(line, $@"[(,]\s*(?(ref|out ref|out var|out {type}\??|in|ref {type}\??))?\s*{variable}_{type}"); + if (!modifiersMatch.Success) + { + throw new InvalidOperationException($"Can't find variable {variable}_{type} in a parameter list."); + } + + var modifiers = modifiersMatch.Groups["Modifiers"].Value; + + // Collect the new arguments + var arguments = new List(); + for (int i = typeNumber; i <= endIndex; i++) + { + arguments.Add($"{modifiers} {variable}_{typeName}{i}"); + } + + // Remove the original arguments, and replace them with our variadic version. + // +1 to remove the preceding , or ( + var transformed = new StringBuilder(); + transformed.AppendLine(line); + transformed.Remove(modifiersMatch.Index + 1, modifiersMatch.Length - 1); + transformed.Insert(modifiersMatch.Index + 1, string.Join(", ", arguments)); + + return transformed.ToString(); + } + + /// The method header line. + /// The basic type to expand, for example T0. + /// The full type to copy, for example Span. + /// The last variadic to generate, incremented from the number of . + /// The inclusive start index of the transformed region of the original string. + /// The exclusive end index of the transformed region of the original string. + /// + public static string ExpandTypedParameters(string line, string type, string fullType, int endIndex, out int transformedStart, out int transformedEnd) + { + var (typeName, typeNumber) = ExtractTypeInfo(type); + + // This matches, specifically, a method header. + // This grabs the first param that matches the passed in type (in Variables[0]), like "Span? paramName_T0 = default" + // it extracts paramName, the initializer if it exists, any ref/out/in modifiers, and repeats it according to the type params. + // Captured groups: + // - Modifiers: holds ref, out, ref readonly, etc + // - ParamName: holds the parameter name that matches fullType and type. For example, if fullType is Span and type is T0, and the parameters includes + // "component_T0", this will match "component". + // - Assignment: holds the = assignment if present. Currently only supports default assignment. + var headerMatch = Regex.Match(line, $@"[(,]\s*(?(ref|out|ref readonly|in)\s+)?{Regex.Escape(fullType)}\s+(?\w+)_{type}\s*(?=\s*default)?"); + + // If we didn't find anything to transform, we give up. + if (!headerMatch.Success) + { + transformedStart = 0; + transformedEnd = 0; + return line; + } + + bool hasDefault = headerMatch.Groups["Assignment"].Success; + string modifiers = headerMatch.Groups["Modifiers"].Success ? headerMatch.Groups["Modifiers"].Value : string.Empty; + string param = headerMatch.Groups["ParamName"].Value; + + // Here, we build up the parameter string. So T0 component_T0 would become "T0 component_T0, T1 component_T1..." + var @params = new List(); + for (int i = typeNumber; i <= endIndex; i++) + { + // One issue with this approach... if we had a wrapper type of SomethingT1 (which is bad name but whatever) then this would break. + // but so far we don't have anything like that. + var variedFullType = fullType.Replace(type, $"{typeName}{i}"); + @params.Add($"{modifiers} {variedFullType} {param}_{typeName}{i} {(hasDefault ? "= default" : "")}"); + } + + var transformed = new StringBuilder(); + transformed.Append(line); + + // Remove the parameters we found + transformed.Remove(headerMatch.Index + 1, headerMatch.Length - 1); + + // Add in our newly constructed params + var paramsString = string.Join(", ", @params); + transformed.Insert(headerMatch.Index + 1, string.Join(", ", paramsString)); + + transformedStart = headerMatch.Index + 1; + transformedEnd = headerMatch.Index + 1 + paramsString.Length; + return transformed.ToString(); + } + + /// + /// Given a line and a type string, convert all instances of type constraints to the variadic version. + /// + /// The line of code to transform. + /// The type to expand, in format TypeName{N}. For example, T0. + /// The last type to generate. For example, to expand T2 to T2, T3, T4, this parameter should be 4. + /// The transformed line. + public static string ExpandConstraints(string line, string type, int endIndex) + { + var (typeName, typeNumber) = ExtractTypeInfo(type); + + // copy type constraints for our selected type + var transformed = new StringBuilder(); + var constraints = Regex.Match(line, $@"where\s+{type}\s*:\s*(?.*?)(?:where|{{|$)"); + if (!constraints.Success) + { + // no constraints, just return the line + return line; + } + + // append anything prior to the original constraint + transformed.Append(line.Substring(0, constraints.Index)); + + // append extra constraints as needed + for (int i = typeNumber; i <= endIndex; i++) + { + transformed.Append($" where {typeName}{i} : {constraints.Groups["Constraints"].Value} "); + } + + // add in the rest of the line, including the original constraint + transformed.Append(line.Substring(constraints.Index, line.Length - constraints.Index)); + return transformed.ToString(); + } + + /// + /// Given a line and a type string, convert all instances of angle brackets in the line to variadic version, + /// where the last type is the given type. + /// For example, <A, T0> would expand to <A, T0, T1, T2>. + /// + /// The line of code to transform. + /// The type to expand, in format TypeName{N}. For example, T0. + /// The last type to generate. For example, to expand T2 to T2, T3, T4, this parameter should be 4. + /// The transformed line. + public static string ExpandGenericTypes(string line, string type, int endIndex) + { + var (typeName, typeNumber) = ExtractTypeInfo(type); + + // build a string like "T0, T1, ...>" + var variadics = new List(); + for (int i = typeNumber; i <= endIndex; i++) + { + variadics.Add($"{typeName}{i}"); + } + + // Replace any occurances of T0> with our generated T0, ...> + return line.Replace($"{type}>", $"{string.Join(", ", variadics)}>"); + } + + /// + /// Replace a type with one of its variadics in a line. + /// + /// The line to transform + /// A type. For example, T0. + /// The variadic to replace the type with. For example, 1 for T1. + /// The transformed line + public static string ReplaceType(string line, string type, int variadic) + { + var (typeName, _) = ExtractTypeInfo(type); + + var transformed = new StringBuilder(); + transformed.AppendLine(line); + transformed.Replace(type, $"{typeName}{variadic}"); + return transformed.ToString(); + } + + /// + /// Given a type string, extracts the type name and number. For example, T0 would return ("T", 0). + /// + /// The type string. + /// A tuple with the type name and number + public static (string TypeName, int TypeNumber) ExtractTypeInfo(string type) + { + var match = Regex.Match(type, @"(?\w+?)(?[0-9]+)"); + if (!match.Success) + { + throw new InvalidOperationException($"{type} doesn't match format TypeName{{N}} (for example T0)"); + } + + return (match.Groups["Name"].Value, int.Parse(match.Groups["Number"].Value)); + } +} diff --git a/src/Arch.SourceGen/VariadicGenerator.cs b/src/Arch.SourceGen/VariadicGenerator.cs index f7e5a583..60df390a 100644 --- a/src/Arch.SourceGen/VariadicGenerator.cs +++ b/src/Arch.SourceGen/VariadicGenerator.cs @@ -28,14 +28,9 @@ private class VariadicInfo public string Type { get; set; } = string.Empty; /// - /// The amount of total variadics that should be generated, as passed to . + /// The last variadic index to generate, passed into . /// - public int Count { get; set; } = 0; - - /// - /// How many variadics have already been specified and should be skipped during generation, as passed to . - /// - public int Start { get; internal set; } + public int LastVariadic { get; set; } = 0; /// /// The full code of the member the attribute is on, including any preceding documentation and attributes. @@ -181,8 +176,7 @@ private VariadicInfo ParseVariadicInfo(GeneratorAttributeSyntaxContext ctx) if (attr.AttributeClass?.Name == "VariadicAttribute") { info.Type = attr.ConstructorArguments[0].Value as string ?? throw new InvalidOperationException(); - info.Start = Convert.ToInt32(attr.ConstructorArguments[1].Value); - info.Count = Convert.ToInt32(attr.ConstructorArguments[2].Value); + info.LastVariadic = Convert.ToInt32(attr.ConstructorArguments[1].Value); break; } } @@ -231,9 +225,10 @@ private string MakeVariadic(VariadicInfo info) var combined = new StringBuilder(); - // Run for each variadic requested, starting after Start (so if start is 1, it means we already defined 1 variadic , + // Run for each variadic requested, starting after typeNum (so if the type passed is T0, it means we already defined 1 variadic , // and must start by generating ). - for (var i = info.Start; i < info.Count; i++) + var (_, typeNum) = Utils.ExtractTypeInfo(info.Type); + for (var i = typeNum + 1; i <= info.LastVariadic; i++) { // Process line by line, and run the algorithm on each foreach (var line in lines) @@ -254,7 +249,7 @@ private string MakeVariadic(VariadicInfo info) } // Run the transformation algorithm on the line - combined.AppendLine(algo.Transform(line.Line, info.Type, info.Start, i + 1, line.Parameters)); + combined.AppendLine(algo.Transform(line.Line, info.Type, i, line.Parameters)); } } diff --git a/src/Arch/Core/Variadics/Archetype.Variadics.cs b/src/Arch/Core/Variadics/Archetype.Variadics.cs index 85e01ab8..f352665c 100644 --- a/src/Arch/Core/Variadics/Archetype.Variadics.cs +++ b/src/Arch/Core/Variadics/Archetype.Variadics.cs @@ -5,7 +5,7 @@ public partial class Archetype { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] public bool Has() { var componentId_T0 = Component.ComponentType.Id; @@ -19,7 +19,7 @@ public bool Has() /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] internal unsafe Components Get(scoped ref Slot slot) { ref var chunk = ref GetChunk(slot.ChunkIndex); @@ -28,7 +28,7 @@ internal unsafe Components Get(scoped ref Slot slot) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] // [Variadic: CopyParams(T1?)] internal void Set(ref Slot slot, in T0? component_T0, in T1? component_T1) { @@ -39,7 +39,7 @@ internal void Set(ref Slot slot, in T0? component_T0, in T1? component_T /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] // [Variadic: CopyParams(T1?)] internal void SetRange(in Slot from, in Slot to, in T0? componentValue_T0 = default, in T1? componentValue_T1 = default) { diff --git a/src/Arch/Core/Variadics/Chunk.Variadics.cs b/src/Arch/Core/Variadics/Chunk.Variadics.cs index efa4a5d9..f967f8ec 100644 --- a/src/Arch/Core/Variadics/Chunk.Variadics.cs +++ b/src/Arch/Core/Variadics/Chunk.Variadics.cs @@ -7,7 +7,7 @@ namespace Arch.Core; public partial struct Chunk { [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] [Pure] // [Variadic: CopyParams(int)] private readonly void Index(out int index_T0, out int index_T1) @@ -21,7 +21,7 @@ private readonly void Index(out int index_T0, out int index_T1) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] [SuppressMessage("Style", "IDE0011:Add braces", Justification = "Enables single-line statements")] [SuppressMessage("Style", "IDE2001:Embedded statements must be on their own line", Justification = "Enables single-line statements")] public readonly bool Has() @@ -44,7 +44,7 @@ public readonly bool Has() /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] public Components Get(int index) { // [Variadic: CopyArgs(array)] @@ -58,7 +58,7 @@ public Components Get(int index) } /// - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] public EntityComponents GetRow(int index) @@ -76,7 +76,7 @@ public EntityComponents GetRow(int index) } /// - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] [MethodImpl(MethodImplOptions.AggressiveInlining)] // [Variadic: CopyParams(T1?)] public void Set(int index, in T0? component_T0, in T1? component_T1) @@ -90,7 +90,7 @@ public void Set(int index, in T0? component_T0, in T1? component_T1) } /// - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] [SuppressMessage("Style", "IDE0251:Make member 'readonly'", Justification = "Not actually readonly due to unsafe get")] @@ -107,7 +107,7 @@ public void GetArray(out T0[] array_T0, out T1[] array_T1) } /// - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] // [Variadic: CopyParams(Span)] @@ -122,7 +122,7 @@ public void GetSpan(out Span span_T0, out Span span_T1) } /// - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] public Components GetFirst() diff --git a/src/Arch/Core/Variadics/Components.Variadics.cs b/src/Arch/Core/Variadics/Components.Variadics.cs index 3ba3ef43..e2c47d9e 100644 --- a/src/Arch/Core/Variadics/Components.Variadics.cs +++ b/src/Arch/Core/Variadics/Components.Variadics.cs @@ -6,7 +6,7 @@ namespace Arch.Core; /// Stores a reference group of up to 25 components. /// [SkipLocalsInit] -[Variadic(nameof(T0), 1, 25)] +[Variadic(nameof(T0), 24)] public ref struct Components { /// @@ -41,7 +41,7 @@ public Components(ref T0 component_T0) /// Stores a reference group of up to 25 components, as well as an entity. /// [SkipLocalsInit] -[Variadic(nameof(T0), 1, 25)] +[Variadic(nameof(T0), 24)] public ref struct EntityComponents { diff --git a/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs index a86f69cb..6aa76ff7 100644 --- a/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs +++ b/src/Arch/Core/Variadics/EntityExtensions.Variadics.cs @@ -7,7 +7,7 @@ public static partial class EntityExtensions /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] - [Variadic(nameof(T1), 2)] + [Variadic(nameof(T1), 24)] public static bool Has(this Entity entity) { var world = World.Worlds[entity.WorldId]; @@ -16,7 +16,7 @@ public static bool Has(this Entity entity) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T1), 2)] + [Variadic(nameof(T1), 24)] public static void Set(this Entity entity, in T0 component_T0, in T1 component_T1) { var world = World.Worlds[entity.WorldId]; @@ -27,7 +27,7 @@ public static void Set(this Entity entity, in T0 component_T0, in T1 com /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] - [Variadic(nameof(T1), 2)] + [Variadic(nameof(T1), 24)] public static Components Get(this Entity entity) { var world = World.Worlds[entity.WorldId]; @@ -36,7 +36,7 @@ public static Components Get(this Entity entity) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T1), 2)] + [Variadic(nameof(T1), 24)] public static void Add(this Entity entity, in T0 component_T0, in T1 component_T1) { var world = World.Worlds[entity.WorldId]; @@ -47,7 +47,7 @@ public static void Add(this Entity entity, in T0 component_T0, in T1 com /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T1), 2)] + [Variadic(nameof(T1), 24)] public static void Remove(this Entity entity) { var world = World.Worlds[entity.WorldId]; diff --git a/src/Arch/Core/Variadics/ForEach.Variadics.cs b/src/Arch/Core/Variadics/ForEach.Variadics.cs index 81e1bb4c..4120e3a1 100644 --- a/src/Arch/Core/Variadics/ForEach.Variadics.cs +++ b/src/Arch/Core/Variadics/ForEach.Variadics.cs @@ -4,12 +4,12 @@ /// The delegate /// provides a callback to execute logic on up to 25 component types. /// -[Variadic(nameof(T0), 1, 25)] +[Variadic(nameof(T0), 24)] public delegate void ForEach(ref T0 component_T0); /// /// The delegate /// provides a callback to execute logic on an and up to 25 component types. /// -[Variadic(nameof(T0), 1, 25)] +[Variadic(nameof(T0), 24)] public delegate void ForEachWithEntity(Entity entity, ref T0 component_T0); diff --git a/src/Arch/Core/Variadics/Group.Variadics.cs b/src/Arch/Core/Variadics/Group.Variadics.cs index 2a8a3403..3766a76a 100644 --- a/src/Arch/Core/Variadics/Group.Variadics.cs +++ b/src/Arch/Core/Variadics/Group.Variadics.cs @@ -4,7 +4,7 @@ namespace Arch.Core; /// -[Variadic(nameof(T0), 1, 25)] +[Variadic(nameof(T0), 24)] public static class Group { internal static readonly int Id; diff --git a/src/Arch/Core/Variadics/Interfaces.Variadics.cs b/src/Arch/Core/Variadics/Interfaces.Variadics.cs index 51367a1a..18f444b4 100644 --- a/src/Arch/Core/Variadics/Interfaces.Variadics.cs +++ b/src/Arch/Core/Variadics/Interfaces.Variadics.cs @@ -1,7 +1,7 @@ namespace Arch.Core; /// -[Variadic(nameof(T0), 1, 25)] +[Variadic(nameof(T0), 24)] public interface IForEach { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -9,7 +9,7 @@ public interface IForEach } /// -[Variadic(nameof(T0), 1, 25)] +[Variadic(nameof(T0), 24)] public interface IForEachWithEntity { [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Arch/Core/Variadics/Jobs.Variadics.cs b/src/Arch/Core/Variadics/Jobs.Variadics.cs index 45a2a8e4..45317976 100644 --- a/src/Arch/Core/Variadics/Jobs.Variadics.cs +++ b/src/Arch/Core/Variadics/Jobs.Variadics.cs @@ -1,7 +1,7 @@ namespace Arch.Core; /// -[Variadic(nameof(T0), 1, 25)] +[Variadic(nameof(T0), 24)] public struct ForEachJob : IChunkJob { /// @@ -26,7 +26,7 @@ public readonly void Execute(int index, ref Chunk chunk) } /// -[Variadic(nameof(T0), 1, 25)] +[Variadic(nameof(T0), 24)] public struct ForEachWithEntityJob : IChunkJob { /// @@ -52,7 +52,7 @@ public readonly void Execute(int index, ref Chunk chunk) } /// -[Variadic(nameof(T0), 1, 25)] +[Variadic(nameof(T0), 24)] public struct IForEachJob : IChunkJob where T : struct, IForEach { /// @@ -76,7 +76,7 @@ public void Execute(int index, ref Chunk chunk) } } -[Variadic(nameof(T0), 1, 25)] +[Variadic(nameof(T0), 24)] public struct IForEachWithEntityJob : IChunkJob where T : struct, IForEachWithEntity { /// diff --git a/src/Arch/Core/Variadics/QueryDescription.Variadics.cs b/src/Arch/Core/Variadics/QueryDescription.Variadics.cs index 7969cf0e..1506c17a 100644 --- a/src/Arch/Core/Variadics/QueryDescription.Variadics.cs +++ b/src/Arch/Core/Variadics/QueryDescription.Variadics.cs @@ -4,7 +4,7 @@ public partial struct QueryDescription /// [UnscopedRef] [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] public ref QueryDescription WithAll() { All = Group.Types; @@ -14,7 +14,7 @@ public ref QueryDescription WithAll() /// [UnscopedRef] [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] public ref QueryDescription WithAny() { Any = Group.Types; @@ -24,7 +24,7 @@ public ref QueryDescription WithAny() /// [UnscopedRef] [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] public ref QueryDescription WithNone() { None = Group.Types; @@ -34,7 +34,7 @@ public ref QueryDescription WithNone() /// [UnscopedRef] [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] public ref QueryDescription WithExclusive() { Exclusive = Group.Types; diff --git a/src/Arch/Core/Variadics/World.Variadics.cs b/src/Arch/Core/Variadics/World.Variadics.cs index 4d2a40a5..7fad4b87 100644 --- a/src/Arch/Core/Variadics/World.Variadics.cs +++ b/src/Arch/Core/Variadics/World.Variadics.cs @@ -9,7 +9,7 @@ public partial class World /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [StructuralChange] - [Variadic(nameof(T0), 1, 25)] + [Variadic(nameof(T0), 24)] // [Variadic: CopyParams(T0?)] public Entity Create(in T0? componentValue_T0 = default) { @@ -50,7 +50,7 @@ public Entity Create(in T0? componentValue_T0 = default) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] public bool Has(Entity entity) { var archetype = EntityInfo.GetArchetype(entity.Id); @@ -60,7 +60,7 @@ public bool Has(Entity entity) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] public Components Get(Entity entity) { var slot = EntityInfo.GetSlot(entity.Id); @@ -71,7 +71,7 @@ public Components Get(Entity entity) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] [Pure] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] public void Set(Entity entity, in T0 component_T0, in T1 component_T1) { var slot = EntityInfo.GetSlot(entity.Id); @@ -87,7 +87,7 @@ public void Set(Entity entity, in T0 component_T0, in T1 component_T1) [SkipLocalsInit] [MethodImpl(MethodImplOptions.AggressiveInlining)] [StructuralChange] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] // [Variadic: CopyParams(T1?)] public void Add(Entity entity, in T0? component_T0 = default, in T1? component_T1 = default) { @@ -126,7 +126,7 @@ public void Add(Entity entity, in T0? component_T0 = default, in T1? com [SkipLocalsInit] [MethodImpl(MethodImplOptions.AggressiveInlining)] [StructuralChange] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] public void Remove(Entity entity) { var oldArchetype = EntityInfo.GetArchetype(entity.Id); @@ -158,7 +158,7 @@ public void Remove(Entity entity) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T0), 1, 25)] + [Variadic(nameof(T0), 24)] public void Query(in QueryDescription description, ForEach forEach) { var query = Query(in description); @@ -179,7 +179,7 @@ public void Query(in QueryDescription description, ForEach forEach) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T0), 1, 25)] + [Variadic(nameof(T0), 24)] public void Query(in QueryDescription description, ForEachWithEntity forEach) { var query = Query(in description); @@ -202,7 +202,7 @@ public void Query(in QueryDescription description, ForEachWithEntity for /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T0), 1, 25)] + [Variadic(nameof(T0), 24)] public void ParallelQuery(in QueryDescription description, ForEach forEach) { var innerJob = new ForEachJob @@ -246,7 +246,7 @@ public void ParallelQuery(in QueryDescription description, ForEach forEa /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T0), 1, 25)] + [Variadic(nameof(T0), 24)] public void ParallelQuery(in QueryDescription description, ForEachWithEntity forEach) { var innerJob = new ForEachWithEntityJob @@ -289,7 +289,7 @@ public void ParallelQuery(in QueryDescription description, ForEachWithEntity /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T0), 1, 25)] + [Variadic(nameof(T0), 24)] public void InlineQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEach { var query = Query(in description); @@ -310,7 +310,7 @@ public void InlineQuery(in QueryDescription description, ref T iForEach) /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T0), 1, 25)] + [Variadic(nameof(T0), 24)] public void InlineQuery(in QueryDescription description) where T : struct, IForEach { var t = new T(); @@ -334,7 +334,7 @@ public void InlineQuery(in QueryDescription description) where T : struct /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T0), 1, 25)] + [Variadic(nameof(T0), 24)] public void InlineEntityQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEachWithEntity { var query = Query(in description); @@ -358,7 +358,7 @@ public void InlineEntityQuery(in QueryDescription description, ref T iFor /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T0), 1, 25)] + [Variadic(nameof(T0), 24)] public void InlineEntityQuery(in QueryDescription description) where T : struct, IForEachWithEntity { var t = new T(); @@ -384,7 +384,7 @@ public void InlineEntityQuery(in QueryDescription description) where T : /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T0), 1, 25)] + [Variadic(nameof(T0), 24)] public void InlineParallelQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEach { var innerJob = new IForEachJob @@ -427,7 +427,7 @@ public void InlineParallelQuery(in QueryDescription description, ref T iF /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T0), 1, 25)] + [Variadic(nameof(T0), 24)] public void InlineParallelEntityQuery(in QueryDescription description, ref T iForEach) where T : struct, IForEachWithEntity { var innerJob = new IForEachWithEntityJob @@ -471,7 +471,7 @@ public void InlineParallelEntityQuery(in QueryDescription description, re /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] // [Variadic: CopyParams(T1?)] public void Set(in QueryDescription queryDescription, in T0? componentValue_T0 = default, in T1? componentValue_T1 = default) { @@ -504,7 +504,7 @@ public void Set(in QueryDescription queryDescription, in T0? componentVa [SkipLocalsInit] [MethodImpl(MethodImplOptions.AggressiveInlining)] [StructuralChange] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] // [Variadic: CopyParams(T1?)] public void Add(in QueryDescription queryDescription, in T0? component_T0 = default, in T1? component_T1 = default) { @@ -559,7 +559,7 @@ public void Add(in QueryDescription queryDescription, in T0? component_T [SkipLocalsInit] [MethodImpl(MethodImplOptions.AggressiveInlining)] [StructuralChange] - [Variadic(nameof(T1), 2, 25)] + [Variadic(nameof(T1), 24)] public void Remove(in QueryDescription queryDescription) { // BitSet to stack/span bitset, size big enough to contain ALL registered components. diff --git a/src/Arch/VariadicAttribute.cs b/src/Arch/VariadicAttribute.cs index b6a722af..6d154de5 100644 --- a/src/Arch/VariadicAttribute.cs +++ b/src/Arch/VariadicAttribute.cs @@ -26,16 +26,11 @@ internal class VariadicAttribute : Attribute /// Tag a method or type as being variadic; i.e. generating many generic parameters. /// /// - /// The name of the type to begin. For example, if your method is Add<T0, T1>, it would be nameof(T1). + /// The name of the type to expand. For example, if your method is Add<T0, T1>, it would be nameof(T1). /// - /// - /// The current template after which to begin generating. - /// For example, if you've already defined signatures T0 and T0, T1, and have the latter annotated as [Variadic], - /// mark the current template as start = 2. - /// - /// - /// The end template to generate. For example, if there should be up to T0, ... T24 variadics, would be 25. + /// + /// The last variadic to generate. If your type is T0, use 24 to get 25 total methods (T0 to T24). /// [SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Instance params not necessary for sourcegen.")] - public VariadicAttribute(string name, int start = 1, int count = 25) { } + public VariadicAttribute(string name, int lastVariadic) { } }