1+ using System . Collections ;
2+ using System . Linq ;
3+ using Genbox . FastData . Generator . CPlusPlus . Internal ;
14using Genbox . FastData . Generator . CPlusPlus . Internal . Framework ;
25using Genbox . FastData . Generator . CPlusPlus . Internal . Generators ;
6+ using Genbox . FastData . Generator . CPlusPlus . Internal . TemplateData ;
7+ using Genbox . FastData . Generator . Enums ;
38using Genbox . FastData . Generator . Framework ;
49using Genbox . FastData . Generator . Framework . Interfaces ;
10+ using Genbox . FastData . Generator . Helpers ;
511using Genbox . FastData . Generators ;
612using Genbox . FastData . Generators . Abstracts ;
713using Genbox . FastData . Generators . Contexts ;
14+ using Microsoft . VisualStudio . TextTemplating ;
15+ using Mono . TextTemplating ;
816
917namespace 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