Skip to content

Commit 4454693

Browse files
committed
Add rust and C++ template support
1 parent 85aa9e7 commit 4454693

77 files changed

Lines changed: 2957 additions & 41 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@
2929
# Verify
3030
*.received.*
3131
*.received/
32-
Src/FastData.Generator.CSharp/Templates/*.cs
32+
**/Templates/*.cs

Src/FastData.Generator.CSharp/Compat/CallContext.cs renamed to Misc/Compat/CallContext.cs

File renamed without changes.

Src/FastData.Generator.CSharp/Compat/CompilerFeatureRequiredAttribute.cs renamed to Misc/Compat/CompilerFeatureRequiredAttribute.cs

File renamed without changes.

Src/FastData.Generator.CSharp/Compat/IsExternalInit.cs renamed to Misc/Compat/IsExternalInit.cs

File renamed without changes.

Src/FastData.Generator.CSharp/Compat/RequiredMemberAttribute.cs renamed to Misc/Compat/RequiredMemberAttribute.cs

File renamed without changes.

Src/FastData.Cli.Tests/packages.lock.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,8 @@
252252
"Genbox.FastData.Generator.CPlusPlus": {
253253
"type": "Project",
254254
"dependencies": {
255-
"Genbox.FastData.Generator": "[1.0.0, )"
255+
"Genbox.FastData.Generator": "[1.0.0, )",
256+
"Mono.TextTemplating": "[3.0.0, )"
256257
}
257258
},
258259
"Genbox.FastData.Generator.CSharp": {
@@ -265,7 +266,8 @@
265266
"Genbox.FastData.Generator.Rust": {
266267
"type": "Project",
267268
"dependencies": {
268-
"Genbox.FastData.Generator": "[1.0.0, )"
269+
"Genbox.FastData.Generator": "[1.0.0, )",
270+
"Mono.TextTemplating": "[3.0.0, )"
269271
}
270272
},
271273
"Genbox.FastData.InternalShared": {

Src/FastData.Cli/packages.lock.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@
163163
"Genbox.FastData.Generator.CPlusPlus": {
164164
"type": "Project",
165165
"dependencies": {
166-
"Genbox.FastData.Generator": "[1.0.0, )"
166+
"Genbox.FastData.Generator": "[1.0.0, )",
167+
"Mono.TextTemplating": "[3.0.0, )"
167168
}
168169
},
169170
"Genbox.FastData.Generator.CSharp": {
@@ -176,7 +177,8 @@
176177
"Genbox.FastData.Generator.Rust": {
177178
"type": "Project",
178179
"dependencies": {
179-
"Genbox.FastData.Generator": "[1.0.0, )"
180+
"Genbox.FastData.Generator": "[1.0.0, )",
181+
"Mono.TextTemplating": "[3.0.0, )"
180182
}
181183
},
182184
"Microsoft.Extensions.Logging.Abstractions": {

Src/FastData.Generator.CPlusPlus.Benchmarks/packages.lock.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
"resolved": "10.0.1",
2626
"contentHash": "oIy8fQxxbUsSrrOvgBqlVgOeCtDmrcynnTG+FQufcUWBrwyPfwlUkCDB2vaiBeYPyT+20u9/HeuHeBf+H4F/8g=="
2727
},
28+
"System.CodeDom": {
29+
"type": "Transitive",
30+
"resolved": "6.0.0",
31+
"contentHash": "CPc6tWO1LAer3IzfZufDBRL+UZQcj5uS207NHALQzP84Vp/z6wF0Aa0YZImOQY8iStY0A2zI/e3ihKNPfUm8XA=="
32+
},
2833
"xunit.v3.common": {
2934
"type": "Transitive",
3035
"resolved": "3.2.1",
@@ -48,7 +53,8 @@
4853
"Genbox.FastData.Generator.CPlusPlus": {
4954
"type": "Project",
5055
"dependencies": {
51-
"Genbox.FastData.Generator": "[1.0.0, )"
56+
"Genbox.FastData.Generator": "[1.0.0, )",
57+
"Mono.TextTemplating": "[3.0.0, )"
5258
}
5359
},
5460
"Genbox.FastData.Generator.CPlusPlus.TestHarness": {
@@ -85,6 +91,15 @@
8591
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.1"
8692
}
8793
},
94+
"Mono.TextTemplating": {
95+
"type": "CentralTransitive",
96+
"requested": "[3.0.0, )",
97+
"resolved": "3.0.0",
98+
"contentHash": "YqueG52R/Xej4VVbKuRIodjiAhV0HR/XVbLbNrJhCZnzjnSjgMJ/dCdV0akQQxavX6hp/LC6rqLGLcXeQYU7XA==",
99+
"dependencies": {
100+
"System.CodeDom": "6.0.0"
101+
}
102+
},
88103
"Newtonsoft.Json": {
89104
"type": "CentralTransitive",
90105
"requested": "[13.0.4, )",

Src/FastData.Generator.CPlusPlus.TestHarness/packages.lock.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@
135135
"resolved": "8.0.0",
136136
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
137137
},
138+
"System.CodeDom": {
139+
"type": "Transitive",
140+
"resolved": "6.0.0",
141+
"contentHash": "CPc6tWO1LAer3IzfZufDBRL+UZQcj5uS207NHALQzP84Vp/z6wF0Aa0YZImOQY8iStY0A2zI/e3ihKNPfUm8XA=="
142+
},
138143
"xunit.v3.common": {
139144
"type": "Transitive",
140145
"resolved": "3.2.1",
@@ -158,7 +163,8 @@
158163
"Genbox.FastData.Generator.CPlusPlus": {
159164
"type": "Project",
160165
"dependencies": {
161-
"Genbox.FastData.Generator": "[1.0.0, )"
166+
"Genbox.FastData.Generator": "[1.0.0, )",
167+
"Mono.TextTemplating": "[3.0.0, )"
162168
}
163169
},
164170
"Genbox.FastData.InternalShared": {
@@ -188,6 +194,15 @@
188194
"Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.1"
189195
}
190196
},
197+
"Mono.TextTemplating": {
198+
"type": "CentralTransitive",
199+
"requested": "[3.0.0, )",
200+
"resolved": "3.0.0",
201+
"contentHash": "YqueG52R/Xej4VVbKuRIodjiAhV0HR/XVbLbNrJhCZnzjnSjgMJ/dCdV0akQQxavX6hp/LC6rqLGLcXeQYU7XA==",
202+
"dependencies": {
203+
"System.CodeDom": "6.0.0"
204+
}
205+
},
191206
"Newtonsoft.Json": {
192207
"type": "CentralTransitive",
193208
"requested": "[13.0.4, )",

Src/FastData.Generator.CPlusPlus/CPlusPlusCodeGenerator.cs

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1+
using System.Collections;
2+
using System.Linq;
3+
using Genbox.FastData.Generator.CPlusPlus.Internal;
14
using Genbox.FastData.Generator.CPlusPlus.Internal.Framework;
25
using Genbox.FastData.Generator.CPlusPlus.Internal.Generators;
6+
using Genbox.FastData.Generator.CPlusPlus.Internal.TemplateData;
7+
using Genbox.FastData.Generator.Enums;
38
using Genbox.FastData.Generator.Framework;
49
using Genbox.FastData.Generator.Framework.Interfaces;
10+
using Genbox.FastData.Generator.Helpers;
511
using Genbox.FastData.Generators;
612
using Genbox.FastData.Generators.Abstracts;
713
using Genbox.FastData.Generators.Contexts;
14+
using Microsoft.VisualStudio.TextTemplating;
15+
using Mono.TextTemplating;
816

917
namespace Genbox.FastData.Generator.CPlusPlus;
1018

@@ -81,4 +89,248 @@ protected override void AppendFooter<T>(StringBuilder sb, GeneratorConfig<T> gen
8189
RrrBitVectorContext x => new RrrBitVectorCode<TKey>(x),
8290
_ => null
8391
};
92+
93+
private sealed class TemplateBasedOutputWriter<TKey, TValue>(IContext context) : CPlusPlusOutputWriter<TKey>
94+
{
95+
public override string Generate()
96+
{
97+
ITemplateData? dataModel = CreateContextModel();
98+
99+
CommonDataModel common = new CommonDataModel
100+
{
101+
MethodAttribute = MethodAttribute,
102+
PostMethodModifier = PostMethodModifier,
103+
KeyTypeName = KeyTypeName,
104+
ValueTypeName = ValueTypeName,
105+
InputKeyName = InputKeyName,
106+
LookupKeyName = LookupKeyName,
107+
ArraySizeType = ArraySizeType,
108+
HashSizeType = HashSizeType,
109+
IsPrimitive = typeof(TValue).IsPrimitive
110+
};
111+
112+
TemplateModel model = new TemplateModel
113+
{
114+
KeyType = KeyType,
115+
HashSource = HashSource,
116+
GetMethodHeader = GetMethodHeader,
117+
GetEqualFunction = (a, b) => GetEqualFunction(a, b),
118+
GetEqualFunctionByType = GetEqualFunction,
119+
GetCompareFunction = GetCompareFunction,
120+
GetModFunction = GetModFunction,
121+
GetSmallestSignedType = GetSmallestSignedType,
122+
GetSmallestUnsignedType = GetSmallestUnsignedType,
123+
ToValueLabel = ToValueLabel,
124+
ValueObjectDeclarations = GetObjectDeclarations<TValue>(),
125+
GetMethodModifier = GetMethodModifier,
126+
GetFieldModifier = GetFieldModifier,
127+
GetValueTypeName = GetValueTypeName
128+
};
129+
130+
string raw = context.GetType().Name;
131+
int idx = raw.IndexOf("Context", StringComparison.Ordinal);
132+
string name = raw.Substring(0, idx) + "Code.t4";
133+
string text = File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "Templates", name));
134+
135+
TemplateGenerator generator = new TemplateGenerator();
136+
AddTemplateReference(generator, typeof(TemplateModel));
137+
AddTemplateReference(generator, typeof(CommonDataModel));
138+
AddTemplateReference(generator, typeof(SharedCode));
139+
AddTemplateReference(generator, typeof(MethodType));
140+
AddTemplateReference(generator, typeof(KeyType));
141+
AddTemplateReference(generator, typeof(FormatHelper));
142+
AddTemplateReference(generator, typeof(CPlusPlusCodeGeneratorConfig));
143+
144+
ITextTemplatingSession session = generator.GetOrCreateSession();
145+
session["Model"] = model;
146+
session["Context"] = context;
147+
session["Common"] = common;
148+
session["Shared"] = Shared;
149+
if (dataModel != null)
150+
session["Data"] = dataModel;
151+
152+
ParsedTemplate parsed = generator.ParseTemplate(name, text);
153+
TemplateSettings settings = TemplatingEngine.GetSettings(generator, parsed);
154+
ValueTuple<string, string> result = generator.ProcessTemplateAsync(parsed, name, text, name, settings).GetAwaiter().GetResult();
155+
156+
if (generator.Errors.HasErrors)
157+
{
158+
string errors = string.Join("\n", generator.Errors.Cast<object>().Select(x => x.ToString()));
159+
throw new InvalidOperationException("Failed to process template '" + name + "':\n" + errors);
160+
}
161+
162+
return result.Item2;
163+
}
164+
165+
private ITemplateData? CreateContextModel()
166+
{
167+
switch (context)
168+
{
169+
case ArrayContext<TKey, TValue> arrayCtx:
170+
return new ArrayTemplateData
171+
{
172+
Keys = ToObjects(arrayCtx.Keys),
173+
KeyCount = arrayCtx.Keys.Length,
174+
Values = ToObjects(arrayCtx.Values),
175+
ValueCount = arrayCtx.Values.Length
176+
};
177+
178+
case BinarySearchContext<TKey, TValue> bsCtx:
179+
return new BinarySearchTemplateData
180+
{
181+
Keys = ToObjects(bsCtx.Keys),
182+
KeyCount = bsCtx.Keys.Length,
183+
Values = ToObjects(bsCtx.Values),
184+
ValueCount = bsCtx.Values.Length
185+
};
186+
187+
case ConditionalContext<TKey, TValue> conCtx:
188+
return new ArrayTemplateData
189+
{
190+
Keys = ToObjects(conCtx.Keys),
191+
KeyCount = conCtx.Keys.Length,
192+
Values = ToObjects(conCtx.Values),
193+
ValueCount = conCtx.Values.Length
194+
};
195+
196+
case SingleValueContext<TKey, TValue> singleCtx:
197+
return new SingleValueTemplateData
198+
{
199+
Item = singleCtx.Key,
200+
Value = singleCtx.Values.IsEmpty ? null : singleCtx.Values.Span[0]
201+
};
202+
203+
case RangeContext<TKey> rangeCtx:
204+
return new RangeTemplateData
205+
{
206+
Min = rangeCtx.Min,
207+
Max = rangeCtx.Max
208+
};
209+
210+
case KeyLengthContext<TValue> klCtx:
211+
return new KeyLengthTemplateData
212+
{
213+
Keys = klCtx.Lengths,
214+
KeyCount = klCtx.Lengths.Length,
215+
Values = ToObjects(klCtx.Values),
216+
ValueCount = klCtx.Values.Length
217+
};
218+
219+
case BloomFilterContext:
220+
return null;
221+
222+
case BitSetContext<TValue> bsCtx:
223+
return new BitSetTemplateData
224+
{
225+
Values = ToObjects(bsCtx.Values),
226+
ValueCount = bsCtx.Values.Length
227+
};
228+
229+
case HashTableContext<TKey, TValue> hashCtx:
230+
HashTableEntryTemplateData[] hashEntries = new HashTableEntryTemplateData[hashCtx.Entries.Length];
231+
232+
for (int i = 0; i < hashCtx.Entries.Length; i++)
233+
{
234+
hashEntries[i] = new HashTableEntryTemplateData
235+
{
236+
Key = hashCtx.Entries[i].Key,
237+
Hash = hashCtx.Entries[i].Hash,
238+
Next = hashCtx.Entries[i].Next
239+
};
240+
}
241+
242+
return new HashTableTemplateData
243+
{
244+
Entries = hashEntries,
245+
Values = ToObjects(hashCtx.Values),
246+
ValueCount = hashCtx.Values.Length
247+
};
248+
249+
case HashTableCompactContext<TKey, TValue> compactCtx:
250+
HashTableCompactEntryTemplateData[] compactEntries = new HashTableCompactEntryTemplateData[compactCtx.Entries.Length];
251+
252+
for (int i = 0; i < compactCtx.Entries.Length; i++)
253+
{
254+
compactEntries[i] = new HashTableCompactEntryTemplateData
255+
{
256+
Key = compactCtx.Entries[i].Key,
257+
Hash = compactCtx.Entries[i].Hash
258+
};
259+
}
260+
261+
return new HashTableCompactTemplateData
262+
{
263+
Entries = compactEntries,
264+
Values = ToObjects(compactCtx.Values),
265+
ValueCount = compactCtx.Values.Length
266+
};
267+
268+
case HashTablePerfectContext<TKey, TValue> perfectCtx:
269+
HashTablePerfectEntryTemplateData[] perfectEntries = new HashTablePerfectEntryTemplateData[perfectCtx.Data.Length];
270+
271+
for (int i = 0; i < perfectCtx.Data.Length; i++)
272+
{
273+
perfectEntries[i] = new HashTablePerfectEntryTemplateData
274+
{
275+
Key = perfectCtx.Data[i].Key,
276+
Hash = perfectCtx.Data[i].Value
277+
};
278+
}
279+
280+
return new HashTablePerfectTemplateData
281+
{
282+
Entries = perfectEntries,
283+
Values = ToObjects(perfectCtx.Values),
284+
ValueCount = perfectCtx.Values.Length
285+
};
286+
287+
case RrrBitVectorContext:
288+
return null;
289+
290+
case EliasFanoContext<TKey>:
291+
return null;
292+
293+
default:
294+
throw new InvalidOperationException("No template mapping found for context type: " + context.GetType().FullName);
295+
}
296+
}
297+
298+
private static IEnumerable<object> ToObjects(ReadOnlyMemory<TKey> keys) => new MemoryObjectEnumerable<TKey>(keys);
299+
300+
private static IEnumerable<object> ToObjects(ReadOnlyMemory<TValue> values) => new MemoryObjectEnumerable<TValue>(values);
301+
302+
private sealed class MemoryObjectEnumerable<T>(ReadOnlyMemory<T> memory) : IEnumerable<object>
303+
{
304+
public IEnumerator<object> GetEnumerator() => new Enumerator(memory);
305+
306+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
307+
308+
private sealed class Enumerator(ReadOnlyMemory<T> memory) : IEnumerator<object>
309+
{
310+
private int _index = -1;
311+
312+
public object Current => memory.Span[_index];
313+
314+
object IEnumerator.Current => Current;
315+
316+
public bool MoveNext()
317+
{
318+
_index++;
319+
return _index < memory.Length;
320+
}
321+
322+
public void Dispose() {}
323+
324+
public void Reset() => throw new NotSupportedException("not supported");
325+
}
326+
}
327+
328+
private static void AddTemplateReference(TemplateGenerator generator, Type type)
329+
{
330+
string location = type.Assembly.Location;
331+
332+
if (!string.IsNullOrEmpty(location) && !generator.Refs.Exists(x => string.Equals(x, location, StringComparison.OrdinalIgnoreCase)))
333+
generator.Refs.Add(location);
334+
}
335+
}
84336
}

0 commit comments

Comments
 (0)