@@ -12,13 +12,20 @@ internal class ExpressionState
1212 public string WorkingText { get ; set ; } = string . Empty ;
1313 public readonly StringBuilder Buffer ;
1414
15+ private int _nextComputedStepSlot = 0 ;
16+ private int _consumedComputedStepSlots = 0 ;
17+ private ComputedStepItem [ ] _computedStep = [ ] ;
18+ private bool _isTemplateCacheHydrated = false ;
19+
20+ private int _nextScanStepSlot = 0 ;
21+ private int _consumedScanStepSlots = 0 ;
22+ private ScanStepItem [ ] _scanStep = [ ] ;
23+ private bool _isScanStepHydrated = false ;
24+
25+ private PlaceholderCacheItem [ ] _placeholderCache = [ ] ;
1526 private int _nextPlaceholderCacheSlot = 0 ;
16- private PreComputedCacheItem [ ] _preComputedCache = [ ] ;
17- private int _nextPreComputedCacheSlot = 0 ;
1827 private int _operationCount = 0 ;
19- private PlaceholderCacheItem ? [ ] _placeholderCache = [ ] ;
2028 private readonly ExpressionOptions _options ;
21- private bool _isPlaceholderCacheHydrated = false ;
2229
2330 public ExpressionState ( Sanitized sanitized , ExpressionOptions options )
2431 {
@@ -27,14 +34,17 @@ public ExpressionState(Sanitized sanitized, ExpressionOptions options)
2734
2835 WorkingText = sanitized . Text ;
2936 _operationCount = sanitized . OperationCount ;
30- _nextPreComputedCacheSlot = sanitized . ConsumedPreComputedCacheSlots ;
31- _preComputedCache = new PreComputedCacheItem [ sanitized . OperationCount ] ;
32- _placeholderCache = new PlaceholderCacheItem ? [ _operationCount ] ;
33- _nextPlaceholderCacheSlot = 0 ;
37+ _nextPlaceholderCacheSlot = sanitized . ConsumedPlaceholderCacheSlots ;
38+ _placeholderCache = new PlaceholderCacheItem [ sanitized . OperationCount ] ;
39+ _computedStep = new ComputedStepItem [ _operationCount ] ;
40+ _nextComputedStepSlot = 0 ;
41+
42+ _scanStep = new ScanStepItem [ _operationCount ] ;
43+ _nextScanStepSlot = 0 ;
3444
35- for ( int i = 0 ; i < sanitized . ConsumedPreComputedCacheSlots ; i ++ )
45+ for ( int i = 0 ; i < sanitized . ConsumedPlaceholderCacheSlots ; i ++ )
3646 {
37- _preComputedCache [ i ] = new PreComputedCacheItem ( )
47+ _placeholderCache [ i ] = new PlaceholderCacheItem ( )
3848 {
3949 ComputedValue = options . DefaultNullValue ,
4050 IsVariable = false ,
@@ -50,60 +60,103 @@ public ExpressionState(ExpressionOptions options, int preAllocation)
5060 _options = options ;
5161 }
5262
53- #region Pre-Parsed Cache Management.
63+ #region Scan Step Cache Management.
5464
55- public int ConsumeNextPlaceholderCacheSlot ( )
65+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
66+ public bool TryGetScanStep ( [ NotNullWhen ( true ) ] out ScanStepItem value )
5667 {
57- return _nextPlaceholderCacheSlot ++ ;
68+ if ( _nextScanStepSlot < _consumedScanStepSlots )
69+ {
70+ value = _scanStep [ _nextScanStepSlot ] ;
71+ _nextScanStepSlot ++ ;
72+ return value . IsValid ;
73+ }
74+ _nextScanStepSlot ++ ;
75+ value = default ;
76+ return false ;
5877 }
5978
6079 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
61- public bool TryGetPlaceholderCache ( int slot , [ NotNullWhen ( true ) ] out PlaceholderCacheItem value )
80+ public void StoreScanStep ( ScanStepItem value )
6281 {
63- if ( slot < _placeholderCache . Length )
82+ if ( _consumedScanStepSlots >= _scanStep . Length ) //Resize the cache if needed.
6483 {
65- var cached = _placeholderCache [ slot ] ;
66- if ( cached != null )
67- {
68- value = cached . Value ;
69- return true ;
70- }
84+ Array . Resize ( ref _scanStep , ( _scanStep . Length + 1 ) * 2 ) ;
85+ }
86+ value . IsValid = true ;
87+ _scanStep [ _consumedScanStepSlots ++ ] = value ;
88+ }
89+
90+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
91+ public void IncrementScanStep ( )
92+ {
93+ if ( _consumedScanStepSlots >= _scanStep . Length ) //Resize the cache if needed.
94+ {
95+ Array . Resize ( ref _scanStep , ( _scanStep . Length + 1 ) * 2 ) ;
96+ }
97+ _scanStep [ _consumedScanStepSlots ++ ] = new ScanStepItem ( ) { IsValid = false } ;
98+ }
99+
100+ #endregion
101+
102+ #region Computed Step Cache Management.
103+
104+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
105+ public bool TryGetComputedStep ( [ NotNullWhen ( true ) ] out ComputedStepItem value )
106+ {
107+ if ( _nextComputedStepSlot < _consumedComputedStepSlots )
108+ {
109+ value = _computedStep [ _nextComputedStepSlot ] ;
110+ _nextComputedStepSlot ++ ;
111+ return value . IsValid ;
71112 }
113+ _nextComputedStepSlot ++ ;
72114 value = default ;
73115 return false ;
74116 }
75117
76118 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
77- public void StorePlaceholderCache ( int slot , PlaceholderCacheItem value )
119+ public void StoreComputedStep ( ComputedStepItem value )
78120 {
79- if ( slot >= _placeholderCache . Length ) //Resize the cache if needed.
121+ if ( _consumedComputedStepSlots >= _computedStep . Length ) //Resize the cache if needed.
80122 {
81- Array . Resize ( ref _placeholderCache , ( _placeholderCache . Length + 1 ) * 2 ) ;
123+ Array . Resize ( ref _computedStep , ( _computedStep . Length + 1 ) * 2 ) ;
124+ }
125+ value . IsValid = true ;
126+ _computedStep [ _consumedComputedStepSlots ++ ] = value ;
127+ }
128+
129+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
130+ public void IncrementComputedStep ( )
131+ {
132+ if ( _consumedComputedStepSlots >= _computedStep . Length ) //Resize the cache if needed.
133+ {
134+ Array . Resize ( ref _computedStep , ( _computedStep . Length + 1 ) * 2 ) ;
82135 }
83- _placeholderCache [ slot ] = value ;
136+ _computedStep [ _consumedComputedStepSlots ++ ] = new ComputedStepItem ( ) { IsValid = false } ;
84137 }
85138
86139 #endregion
87140
88141 #region Pre-Computed Cache Management.
89142
90- public int ConsumeNextPreComputedCacheSlot ( out string cacheKey )
143+ public int ConsumeNextPlaceholderCacheSlot ( out string cacheKey )
91144 {
92- int cacheSlot = _nextPreComputedCacheSlot ++ ;
145+ int cacheSlot = _nextPlaceholderCacheSlot ++ ;
93146 cacheKey = $ "${ cacheSlot } $";
94147 return cacheSlot ;
95148 }
96149
97- public string StorePreComputedCacheItem ( double ? value , bool isVariable = false )
150+ public string StorePlaceholderCacheItem ( double ? value , bool isVariable = false )
98151 {
99- var cacheSlot = ConsumeNextPreComputedCacheSlot ( out var cacheKey ) ;
152+ var cacheSlot = ConsumeNextPlaceholderCacheSlot ( out var cacheKey ) ;
100153
101- if ( cacheSlot >= _preComputedCache . Length ) //Resize the cache if needed.
154+ if ( cacheSlot >= _placeholderCache . Length ) //Resize the cache if needed.
102155 {
103- Array . Resize ( ref _preComputedCache , ( _preComputedCache . Length + 1 ) * 2 ) ;
156+ Array . Resize ( ref _placeholderCache , ( _placeholderCache . Length + 1 ) * 2 ) ;
104157 }
105158
106- _preComputedCache [ cacheSlot ] = new PreComputedCacheItem ( )
159+ _placeholderCache [ cacheSlot ] = new PlaceholderCacheItem ( )
107160 {
108161 IsVariable = isVariable ,
109162 ComputedValue = value
@@ -112,67 +165,88 @@ public string StorePreComputedCacheItem(double? value, bool isVariable = false)
112165 return cacheKey ;
113166 }
114167
115- public PreComputedCacheItem GetPreComputedCacheItem ( ReadOnlySpan < char > span )
168+ public PlaceholderCacheItem GetPlaceholderCacheItem ( ReadOnlySpan < char > span )
116169 {
117170 switch ( span . Length )
118171 {
119172 case 1 :
120- return _preComputedCache [ span [ 0 ] - '0' ] ;
173+ return _placeholderCache [ span [ 0 ] - '0' ] ;
121174 default :
122175 int index = 0 ;
123176 for ( int i = 0 ; i < span . Length ; i ++ )
124177 index = index * 10 + ( span [ i ] - '0' ) ;
125- return _preComputedCache [ index ] ;
178+ return _placeholderCache [ index ] ;
126179 }
127180 }
128181
129182 #endregion
130183
131- public void HydrateTemplateParsedCache ( int expressionHash )
184+ public void HydrateTemplateCache ( int expressionHash )
132185 {
133- if ( ! _isPlaceholderCacheHydrated )
186+ if ( ! _isTemplateCacheHydrated )
134187 {
135188 lock ( this )
136189 {
137- if ( ! _isPlaceholderCacheHydrated )
190+ if ( ! _isTemplateCacheHydrated )
138191 {
139192 if ( Utility . PersistentCaches . TryGetValue ( expressionHash , out CachedState ? entry ) && entry != null )
140193 {
141- entry . State . HydratePlaceholderCache ( _placeholderCache ) ;
194+ entry . State . HydrateComputedStepCache ( _computedStep , _consumedComputedStepSlots ) ;
195+ entry . State . HydrateScanStepCache ( _scanStep , _consumedScanStepSlots ) ;
142196 }
143- _isPlaceholderCacheHydrated = true ;
197+ _isTemplateCacheHydrated = true ;
144198 }
145199 }
146200 }
147201 }
148202
149- private void HydratePlaceholderCache ( PlaceholderCacheItem ? [ ] populatedCache )
203+ private void HydrateScanStepCache ( ScanStepItem [ ] populatedCache , int consumedScanStepSlots )
150204 {
151- Interlocked . Exchange ( ref _placeholderCache , populatedCache ) ;
205+ _consumedScanStepSlots = consumedScanStepSlots ;
206+ Interlocked . Exchange ( ref _scanStep , populatedCache ) ;
207+ }
208+
209+ private void HydrateComputedStepCache ( ComputedStepItem [ ] populatedCache , int consumedComputedStepSlots )
210+ {
211+ _consumedComputedStepSlots = consumedComputedStepSlots ;
212+ Interlocked . Exchange ( ref _computedStep , populatedCache ) ;
152213 }
153214
154215 public void Reset ( Sanitized sanitized )
155216 {
156217 WorkingText = sanitized . Text ;
157- _nextPreComputedCacheSlot = sanitized . ConsumedPreComputedCacheSlots ;
158- _nextPlaceholderCacheSlot = 0 ;
218+ _nextPlaceholderCacheSlot = sanitized . ConsumedPlaceholderCacheSlots ;
219+ _nextComputedStepSlot = 0 ;
159220 }
160221
161- public ExpressionState Clone ( )
222+ public ExpressionState Clone ( Sanitized sanitized )
162223 {
163224 var clone = new ExpressionState ( _options , WorkingText . Length * 2 )
164225 {
165226 WorkingText = WorkingText ,
166227 _operationCount = _operationCount ,
167- _nextPreComputedCacheSlot = _nextPreComputedCacheSlot ,
168- _preComputedCache = new PreComputedCacheItem [ _preComputedCache . Length ] ,
169- _placeholderCache = new PlaceholderCacheItem ? [ _placeholderCache . Length ] ,
170- _nextPlaceholderCacheSlot = 0 ,
171- _isPlaceholderCacheHydrated = _isPlaceholderCacheHydrated
228+ _nextPlaceholderCacheSlot = _nextPlaceholderCacheSlot ,
229+ _placeholderCache = new PlaceholderCacheItem [ _placeholderCache . Length ] ,
230+ _isTemplateCacheHydrated = _isTemplateCacheHydrated ,
231+
232+ _computedStep = new ComputedStepItem [ _computedStep . Length ] ,
233+ _nextComputedStepSlot = 0 ,
234+ _consumedComputedStepSlots = _consumedComputedStepSlots ,
235+
236+ _scanStep = new ScanStepItem [ _scanStep . Length ] ,
237+ _nextScanStepSlot = 0 ,
238+ _consumedScanStepSlots = _consumedScanStepSlots
239+
172240 } ;
173241
174- Array . Copy ( _preComputedCache , clone . _preComputedCache , _preComputedCache . Length ) ; //Copy any pre-computed NULLs.
175- Array . Copy ( _placeholderCache , clone . _placeholderCache , _placeholderCache . Length ) ;
242+ for ( int i = 0 ; i < sanitized . ConsumedPlaceholderCacheSlots ; i ++ )
243+ {
244+ clone . _placeholderCache [ i ] = _placeholderCache [ i ] ; //Copy any pre-defined NULLs.
245+ }
246+
247+ //Array.Copy(_placeholderCache, clone._placeholderCache, _placeholderCache.Length); //Copy any pre-computed NULLs.
248+ Array . Copy ( _computedStep , clone . _computedStep , _computedStep . Length ) ;
249+ Array . Copy ( _scanStep , clone . _scanStep , _scanStep . Length ) ;
176250
177251 return clone ;
178252 }
@@ -184,8 +258,8 @@ public void ApplyParameters(Sanitized sanitized, Dictionary<string, double?> def
184258 {
185259 if ( definedParameters . TryGetValue ( variable , out var value ) )
186260 {
187- var cacheSlot = ConsumeNextPreComputedCacheSlot ( out var cacheKey ) ;
188- _preComputedCache [ cacheSlot ] = new PreComputedCacheItem ( )
261+ var cacheSlot = ConsumeNextPlaceholderCacheSlot ( out var cacheKey ) ;
262+ _placeholderCache [ cacheSlot ] = new PlaceholderCacheItem ( )
189263 {
190264 ComputedValue = value ?? _options . DefaultNullValue ,
191265 IsVariable = true
0 commit comments