Skip to content

Commit a32c18f

Browse files
committed
wip: caching
1 parent d63a4d4 commit a32c18f

4 files changed

Lines changed: 47 additions & 118 deletions

File tree

NTDLS.ExpressionParser/Expression.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using Microsoft.Extensions.Caching.Memory;
2-
using System.Diagnostics;
32
using System.Globalization;
43
using System.Runtime.CompilerServices;
54
using System.Text;

NTDLS.ExpressionParser/ExpressionState.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,17 @@ public void IncrementComputedStep()
136136

137137
#endregion
138138

139-
#region Pre-Computed Cache Management.
139+
#region Placeholder Cache Management.
140140

141+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
141142
public int ConsumeNextPlaceholderCacheSlot(out string cacheKey)
142143
{
143144
int cacheSlot = _nextPlaceholderCacheSlot++;
144145
cacheKey = $"${cacheSlot}$";
145146
return cacheSlot;
146147
}
147148

149+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
148150
public string StorePlaceholderCacheItem(double? value, bool isVariable = false)
149151
{
150152
var cacheSlot = ConsumeNextPlaceholderCacheSlot(out var cacheKey);
@@ -163,6 +165,8 @@ public string StorePlaceholderCacheItem(double? value, bool isVariable = false)
163165
return cacheKey;
164166
}
165167

168+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
169+
166170
public PlaceholderCacheItem GetPlaceholderCacheItem(ReadOnlySpan<char> span)
167171
{
168172
switch (span.Length)

NTDLS.ExpressionParser/SubExpression.cs

Lines changed: 41 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -105,20 +105,20 @@ private bool ProcessFunctionCall()
105105

106106
if (foundNull)
107107
{
108-
StorePreComputed(functionStartIndex, functionEndIndex, null);
108+
StorePlaceholder(functionStartIndex, functionEndIndex, null);
109109
return true;
110110
}
111111
else if (Utility.IsNativeFunction(foundFunction))
112112
{
113113
double functionResult = Utility.ComputeNativeFunction(foundFunction, parameters.ToArray());
114-
StorePreComputed(functionStartIndex, functionEndIndex, functionResult);
114+
StorePlaceholder(functionStartIndex, functionEndIndex, functionResult);
115115
}
116116
else
117117
{
118118
if (_parentExpression.ExpressionFunctions.TryGetValue(foundFunction, out var customFunction))
119119
{
120120
var functionResult = customFunction.Invoke(parameters.ToArray()) ?? _parentExpression.Options.DefaultNullValue;
121-
StorePreComputed(functionStartIndex, functionEndIndex, functionResult);
121+
StorePlaceholder(functionStartIndex, functionEndIndex, functionResult);
122122
}
123123
else
124124
{
@@ -156,124 +156,33 @@ internal string Compute(bool isCacheable)
156156
//Pre-first-order:
157157
while ((operatorIndex = GetFreestandingNotOperation(out _)) != -1)
158158
{
159-
if (_parentExpression.State.TryGetComputedStep(out ComputedStepItem cachedObj))
160-
{
161-
StorePreComputed(cachedObj.BeginPosition, cachedObj.EndPosition, cachedObj.ParsedValue);
162-
}
163-
else
164-
{
165-
var rightValue = GetRightValue(operatorIndex + 1, out int outParsedLength, out bool isOperationCacheable);
166-
int? calculatedResult = rightValue == null ? null : (rightValue == 0) ? 1 : 0;
167-
StorePreComputed(operatorIndex, operatorIndex + outParsedLength, calculatedResult);
159+
var rightValue = GetRightValue(operatorIndex + 1, out int outParsedLength, out bool isOperationCacheable);
160+
int? calculatedResult = rightValue == null ? null : (rightValue == 0) ? 1 : 0;
168161

169-
if (isCacheable && isOperationCacheable)
170-
{
171-
var parsedNumber = new ComputedStepItem
172-
{
173-
ParsedValue = calculatedResult,
174-
BeginPosition = operatorIndex,
175-
EndPosition = operatorIndex + outParsedLength
176-
};
177-
_parentExpression.State.StoreComputedStep(parsedNumber);
178-
}
179-
else
180-
{
181-
_parentExpression.State.IncrementComputedStep();
182-
}
183-
}
162+
StorePlaceholder(operatorIndex, operatorIndex + outParsedLength, calculatedResult);
184163
}
185164

186165
//First order operations:
187166
operatorIndex = GetIndexOfOperation(Utility.FirstOrderOperations, out string operation);
188167
if (operatorIndex > 0)
189168
{
190-
var calculatedResult = GetLeftAndRightValues(operation, operatorIndex, out double leftValue, out double rightValue, out int beginPosition, out int endPosition, out bool isOperationCacheable);
191-
192-
if (_parentExpression.State.TryGetComputedStep(out ComputedStepItem cachedObj))
193-
{
194-
StorePreComputed(cachedObj.BeginPosition, cachedObj.EndPosition, cachedObj.ParsedValue);
195-
}
196-
else
197-
{
198-
StorePreComputed(beginPosition, endPosition, calculatedResult);
199-
if (isCacheable && isOperationCacheable)
200-
{
201-
var parsedNumber = new ComputedStepItem
202-
{
203-
ParsedValue = calculatedResult,
204-
BeginPosition = beginPosition,
205-
EndPosition = endPosition
206-
};
207-
_parentExpression.State.StoreComputedStep(parsedNumber);
208-
}
209-
else
210-
{
211-
_parentExpression.State.IncrementComputedStep();
212-
}
213-
}
214-
169+
CollapseRightAndLeft(operation, operatorIndex);
215170
continue;
216171
}
217172

218173
//Second order operations:
219174
operatorIndex = GetIndexOfOperation(Utility.SecondOrderOperations, out operation);
220175
if (operatorIndex > 0)
221176
{
222-
var calculatedResult = GetLeftAndRightValues(operation, operatorIndex, out double leftValue, out double rightValue, out int beginPosition, out int endPosition, out bool isOperationCacheable);
223-
224-
if (_parentExpression.State.TryGetComputedStep(out ComputedStepItem cachedObj))
225-
{
226-
StorePreComputed(cachedObj.BeginPosition, cachedObj.EndPosition, cachedObj.ParsedValue);
227-
}
228-
else
229-
{
230-
StorePreComputed(beginPosition, endPosition, calculatedResult);
231-
if (isCacheable && isOperationCacheable)
232-
{
233-
var parsedNumber = new ComputedStepItem
234-
{
235-
ParsedValue = calculatedResult,
236-
BeginPosition = beginPosition,
237-
EndPosition = endPosition
238-
};
239-
_parentExpression.State.StoreComputedStep(parsedNumber);
240-
}
241-
else
242-
{
243-
_parentExpression.State.IncrementComputedStep();
244-
}
245-
}
177+
CollapseRightAndLeft(operation, operatorIndex);
246178
continue;
247179
}
248180

249181
//Third order operations:
250182
operatorIndex = GetIndexOfOperation(Utility.ThirdOrderOperations, out operation);
251183
if (operatorIndex > 0)
252184
{
253-
var calculatedResult = GetLeftAndRightValues(operation, operatorIndex, out double leftValue, out double rightValue, out int beginPosition, out int endPosition, out bool isOperationCacheable);
254-
255-
if (_parentExpression.State.TryGetComputedStep(out ComputedStepItem cachedObj))
256-
{
257-
StorePreComputed(cachedObj.BeginPosition, cachedObj.EndPosition, cachedObj.ParsedValue);
258-
}
259-
else
260-
{
261-
StorePreComputed(beginPosition, endPosition, calculatedResult);
262-
if (isCacheable && isOperationCacheable)
263-
{
264-
var parsedNumber = new ComputedStepItem
265-
{
266-
ParsedValue = calculatedResult,
267-
BeginPosition = beginPosition,
268-
EndPosition = endPosition
269-
};
270-
_parentExpression.State.StoreComputedStep(parsedNumber);
271-
}
272-
else
273-
{
274-
_parentExpression.State.IncrementComputedStep();
275-
}
276-
}
185+
CollapseRightAndLeft(operation, operatorIndex);
277186
continue;
278187
}
279188

@@ -289,7 +198,7 @@ internal string Compute(bool isCacheable)
289198
return _parentExpression.State.StorePlaceholderCacheItem(_parentExpression.StringToDouble(Text));
290199
}
291200

292-
internal void StorePreComputed(int startIndex, int endIndex, double? value)
201+
internal void StorePlaceholder(int startIndex, int endIndex, double? value)
293202
{
294203
var cacheKey = _parentExpression.State.StorePlaceholderCacheItem(value);
295204
Text = _parentExpression.ReplaceRange(Text, startIndex, endIndex, cacheKey);
@@ -310,26 +219,43 @@ internal void TruncateParenthesizes()
310219
/// Gets the numbers to the left and right of an operator.
311220
/// Returns FALSE when NULL is found for either value.
312221
/// </summary>
313-
private double? GetLeftAndRightValues(string operation,
314-
int operationBeginIndex, out double leftValue, out double rightValue, out int beginPosition, out int endPosition, out bool isCacheable)
222+
private void CollapseRightAndLeft(string operation, int operationBeginIndex)
315223
{
316224
var left = GetLeftValue(operationBeginIndex, out int leftParsedLength, out bool isLeftCacheable);
317225
var right = GetRightValue(operationBeginIndex + operation.Length, out int rightParsedLength, out bool isRightCacheable);
318226

319-
leftValue = left ?? 0;
320-
rightValue = right ?? 0;
321-
322-
beginPosition = operationBeginIndex - leftParsedLength;
323-
endPosition = operationBeginIndex + rightParsedLength + (operation.Length - 1);
324-
325-
isCacheable = isLeftCacheable && isRightCacheable;
227+
var beginPosition = operationBeginIndex - leftParsedLength;
228+
var endPosition = operationBeginIndex + rightParsedLength + (operation.Length - 1);
326229

327-
if (left != null && right != null)
230+
if (_parentExpression.State.TryGetComputedStep(out ComputedStepItem cachedObj))
328231
{
329-
return Utility.ComputePrivative(leftValue, operation, rightValue);
232+
StorePlaceholder(cachedObj.BeginPosition, cachedObj.EndPosition, cachedObj.ParsedValue);
330233
}
234+
else
235+
{
236+
double? result = null;
331237

332-
return null;
238+
if (left != null && right != null)
239+
{
240+
result = Utility.ComputePrivative(left ?? 0, operation, right ?? 0);
241+
}
242+
243+
StorePlaceholder(beginPosition, endPosition, result);
244+
if (isLeftCacheable && isRightCacheable)
245+
{
246+
var parsedNumber = new ComputedStepItem
247+
{
248+
ParsedValue = result,
249+
BeginPosition = beginPosition,
250+
EndPosition = endPosition
251+
};
252+
_parentExpression.State.StoreComputedStep(parsedNumber);
253+
}
254+
else
255+
{
256+
_parentExpression.State.IncrementComputedStep();
257+
}
258+
}
333259
}
334260

335261
private double? GetLeftValue(int operationIndex, out int outParsedLength, out bool isCacheable)
@@ -357,7 +283,7 @@ internal void TruncateParenthesizes()
357283
outParsedLength = (operationIndex - i) - 1;
358284
var cacheKey = span.Slice(operationIndex - outParsedLength + 1, outParsedLength - 2);
359285
var cachedItem = _parentExpression.State.GetPlaceholderCacheItem(cacheKey);
360-
isCacheable = false;
286+
isCacheable = !cachedItem.IsVariable;
361287
_parentExpression.State.IncrementScanStep();
362288
return cachedItem.ComputedValue;
363289
}
@@ -419,7 +345,7 @@ internal void TruncateParenthesizes()
419345
i++;
420346
outParsedLength = i;
421347
var cachedItem = _parentExpression.State.GetPlaceholderCacheItem(span.Slice(1, i - 2));
422-
isCacheable = false;
348+
isCacheable = !cachedItem.IsVariable;
423349
_parentExpression.State.IncrementScanStep();
424350
return cachedItem.ComputedValue;
425351
}

TestHarness/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ static void Baseline()
2929

3030
static void Main()
3131
{
32-
var expression = new Expression("1+2+3");
32+
var expression = new Expression("10 * ((5 + 1000 + ( 10 )) * 60.5) * 10");
3333
Console.WriteLine("---FIRST---");
3434
Console.WriteLine(expression.Evaluate()); //20
3535
Console.WriteLine("---SECOND---");

0 commit comments

Comments
 (0)