Skip to content

Commit 2cd8dd4

Browse files
PhenXcodingseb
authored andcommitted
Optimize memory use by not instantiating new Regex instances on each constructor call (#23)
1 parent bcc6a53 commit 2cd8dd4

File tree

1 file changed

+24
-29
lines changed

1 file changed

+24
-29
lines changed

CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ public class ExpressionEvaluator
2828
{
2929
#region Regex declarations
3030

31-
private static readonly string diactitics = "áàâãåǎăāąæéèêëěēĕėęěìíîïīĭįijóôõöōŏőøðœùúûüǔũūŭůűųýþÿŷıćĉċčçďđĝğġģĥħĵķĺļľŀłńņňŋñŕŗřśŝşšţťŧŵźżžÁÀÂÃÅǍĂĀĄÆÉÈÊËĚĒĔĖĘĚÌÍÎÏĪĬĮIJÓÔÕÖŌŎŐØÐŒÙÚÛÜǓŨŪŬŮŰŲÝÞŸŶIĆĈĊČÇĎĐĜĞĠĢĤĦĴĶĹĻĽĿŁŃŅŇŊÑŔŖŘŚŜŞŠŢŤŦŴŹŻŽß";
32-
private static readonly string diactiticsKeywordsRegexPattern = "a-zA-Z_" + diactitics;
31+
private const string diactitics = "áàâãåǎăāąæéèêëěēĕėęěìíîïīĭįijóôõöōŏőøðœùúûüǔũūŭůűųýþÿŷıćĉċčçďđĝğġģĥħĵķĺļľŀłńņňŋñŕŗřśŝşšţťŧŵźżžÁÀÂÃÅǍĂĀĄÆÉÈÊËĚĒĔĖĘĚÌÍÎÏĪĬĮIJÓÔÕÖŌŎŐØÐŒÙÚÛÜǓŨŪŬŮŰŲÝÞŸŶIĆĈĊČÇĎĐĜĞĠĢĤĦĴĶĹĻĽĿŁŃŅŇŊÑŔŖŘŚŜŞŠŢŤŦŴŹŻŽß";
32+
private const string diactiticsKeywordsRegexPattern = "a-zA-Z_" + diactitics;
3333

3434
private static readonly Regex varOrFunctionRegEx = new Regex($@"^((?<sign>[+-])|(?<prefixOperator>[+][+]|--)|(?<inObject>(?<nullConditional>[?])?\.)?)(?<name>[{ diactiticsKeywordsRegexPattern }][{ diactiticsKeywordsRegexPattern }0-9]*)\s*((?<assignationOperator>(?<assignmentPrefix>[+\-*/%&|^]|<<|>>)?=(?![=>]))|(?<postfixOperator>([+][+]|--)(?![{ diactiticsKeywordsRegexPattern}0-9]))|((?<isgeneric>[<](?>[^<>]+|(?<gentag>[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?(?<isfunction>[(])?))", RegexOptions.IgnoreCase | RegexOptions.Compiled);
3535

36-
private readonly string numberRegexPattern = @"^(?<sign>[+-])?([0-9][0-9_{1}]*[0-9]|\d)(?<hasdecimal>{0}?([0-9][0-9_]*[0-9]|\d)(e[+-]?([0-9][0-9_]*[0-9]|\d))?)?(?<type>ul|[fdulm])?";
37-
private Regex numberRegex = null;
36+
private const string numberRegexOrigPattern = @"^(?<sign>[+-])?([0-9][0-9_{1}]*[0-9]|\d)(?<hasdecimal>{0}?([0-9][0-9_]*[0-9]|\d)(e[+-]?([0-9][0-9_]*[0-9]|\d))?)?(?<type>ul|[fdulm])?";
37+
private string numberRegexPattern = null;
3838

3939
private static readonly Regex otherBasesNumberRegex = new Regex(@"^(?<sign>[+-])?(?<value>0(?<type>x)([0-9a-f][0-9a-f_]*[0-9a-f]|[0-9a-f])|0(?<type>b)([01][01_]*[01]|[01]))", RegexOptions.IgnoreCase);
4040
private static readonly Regex stringBeginningRegex = new Regex("^(?<interpolated>[$])?(?<escaped>[@])?[\"]");
@@ -57,18 +57,15 @@ public class ExpressionEvaluator
5757

5858
// Depending on OptionInlineNamespacesEvaluationActive. Initialized in constructor
5959
private string InstanceCreationWithNewKeywordRegexPattern { get { return $@"^new\s+(?<name>[{ diactiticsKeywordsRegexPattern }][{ diactiticsKeywordsRegexPattern}0-9{ (OptionInlineNamespacesEvaluationActive ? @"\." : string.Empty) }]*)\s*(?<isgeneric>[<](?>[^<>]+|(?<gentag>[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?\s*((?<isfunction>[(])|(?<isArray>\[)|(?<isInit>[{{]))?"; } }
60-
private Regex instanceCreationWithNewKeywordRegex = null;
6160
private string CastRegexPattern { get { return $@"^\(\s*(?<typeName>[{ diactiticsKeywordsRegexPattern }][{ diactiticsKeywordsRegexPattern }0-9{ (OptionInlineNamespacesEvaluationActive ? @"\." : string.Empty) }\[\]<>]*[?]?)\s*\)"; } }
62-
private Regex castRegex = null;
6361

64-
private static readonly string primaryTypesRegexPattern = @"(?<=^|[^" + diactiticsKeywordsRegexPattern + @"])(?<primaryType>object|string|bool[?]?|byte[?]?|char[?]?|decimal[?]?|double[?]?|short[?]?|int[?]?|long[?]?|sbyte[?]?|float[?]?|ushort[?]?|uint[?]?|ulong[?]?|void)(?=[^a-zA-Z_]|$)";
65-
private Regex primaryTypesRegex = new Regex(primaryTypesRegexPattern);
62+
private const string primaryTypesRegexPattern = @"(?<=^|[^" + diactiticsKeywordsRegexPattern + @"])(?<primaryType>object|string|bool[?]?|byte[?]?|char[?]?|decimal[?]?|double[?]?|short[?]?|int[?]?|long[?]?|sbyte[?]?|float[?]?|ushort[?]?|uint[?]?|ulong[?]?|void)(?=[^a-zA-Z_]|$)";
6663

6764
// To remove comments in scripts based on https://stackoverflow.com/questions/3524317/regex-to-strip-line-comments-from-c-sharp/3524689#3524689
68-
private static readonly string blockComments = @"/\*(.*?)\*/";
69-
private static readonly string lineComments = @"//[^\r\n]*";
70-
private static readonly string stringsIgnore = @"""((\\[^\n]|[^""\n])*)""";
71-
private static readonly string verbatimStringsIgnore = @"@(""[^""]*"")+";
65+
private const string blockComments = @"/\*(.*?)\*/";
66+
private const string lineComments = @"//[^\r\n]*";
67+
private const string stringsIgnore = @"""((\\[^\n]|[^""\n])*)""";
68+
private const string verbatimStringsIgnore = @"@(""[^""]*"")+";
7269
private static readonly Regex removeCommentsRegex = new Regex($"{blockComments}|{lineComments}|{stringsIgnore}|{verbatimStringsIgnore}", RegexOptions.Singleline);
7370
private static readonly Regex newLineCharsRegex = new Regex(@"\r\n|\r|\n");
7471

@@ -519,8 +516,6 @@ public bool OptionCaseSensitiveEvaluationActive
519516
simpleDoubleMathFuncsDictionary = new Dictionary<string, Func<double, double>>(simpleDoubleMathFuncsDictionary, StringComparerForCasing);
520517
doubleDoubleMathFuncsDictionary = new Dictionary<string, Func<double, double, double>>(doubleDoubleMathFuncsDictionary, StringComparerForCasing);
521518
complexStandardFuncsDictionary = new Dictionary<string, Func<ExpressionEvaluator, List<string>, object>>(complexStandardFuncsDictionary, StringComparerForCasing);
522-
instanceCreationWithNewKeywordRegex = new Regex(InstanceCreationWithNewKeywordRegexPattern, (optionCaseSensitiveEvaluationActive ? RegexOptions.None : RegexOptions.IgnoreCase));
523-
primaryTypesRegex = new Regex(primaryTypesRegexPattern, (optionCaseSensitiveEvaluationActive ? RegexOptions.None : RegexOptions.IgnoreCase));
524519
}
525520
}
526521

@@ -577,7 +572,9 @@ public string OptionNumberParsingDecimalSeparator
577572
optionNumberParsingDecimalSeparator = value ?? ".";
578573
CultureInfoForNumberParsing.NumberFormat.NumberDecimalSeparator = optionNumberParsingDecimalSeparator;
579574

580-
numberRegex = new Regex(string.Format(numberRegexPattern, Regex.Escape(optionNumberParsingDecimalSeparator), Regex.Escape(optionNumberParsingThousandSeparator)), RegexOptions.IgnoreCase);
575+
numberRegexPattern = string.Format(numberRegexOrigPattern,
576+
optionNumberParsingDecimalSeparator != null ? Regex.Escape(optionNumberParsingDecimalSeparator) : ".",
577+
optionNumberParsingThousandSeparator != null ? Regex.Escape(optionNumberParsingThousandSeparator) : "");
581578
}
582579
}
583580

@@ -600,9 +597,10 @@ public string OptionNumberParsingThousandSeparator
600597
{
601598
optionNumberParsingThousandSeparator = value ?? string.Empty;
602599
CultureInfoForNumberParsing.NumberFormat.NumberGroupSeparator = value;
603-
604-
numberRegex = new Regex(string.Format(numberRegexPattern, Regex.Escape(optionNumberParsingDecimalSeparator), Regex.Escape(optionNumberParsingThousandSeparator)), RegexOptions.IgnoreCase);
605-
600+
601+
numberRegexPattern = string.Format(numberRegexOrigPattern,
602+
optionNumberParsingDecimalSeparator != null ? Regex.Escape(optionNumberParsingDecimalSeparator) : ".",
603+
optionNumberParsingThousandSeparator != null ? Regex.Escape(optionNumberParsingThousandSeparator) : "");
606604
}
607605
}
608606

@@ -640,8 +638,6 @@ public bool OptionInlineNamespacesEvaluationActive
640638
set
641639
{
642640
optionInlineNamespacesEvaluationActive = value;
643-
instanceCreationWithNewKeywordRegex = new Regex(InstanceCreationWithNewKeywordRegexPattern, (optionCaseSensitiveEvaluationActive ? RegexOptions.None : RegexOptions.IgnoreCase));
644-
castRegex = new Regex(CastRegexPattern, (optionCaseSensitiveEvaluationActive ? RegexOptions.None : RegexOptions.IgnoreCase));
645641
}
646642
}
647643

@@ -836,10 +832,10 @@ public Dictionary<string, object> Variables
836832
public ExpressionEvaluator()
837833
{
838834
Assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies());
839-
instanceCreationWithNewKeywordRegex = new Regex(InstanceCreationWithNewKeywordRegexPattern);
840-
numberRegex = new Regex(string.Format(numberRegexPattern, @"\.", string.Empty), RegexOptions.IgnoreCase);
835+
836+
numberRegexPattern = string.Format(numberRegexPattern, @"\.", string.Empty);
837+
841838
CultureInfoForNumberParsing.NumberFormat.NumberDecimalSeparator = ".";
842-
castRegex = new Regex(CastRegexPattern);
843839
}
844840

845841
/// <summary>
@@ -915,7 +911,6 @@ private object ScriptEvaluate(string script, ref bool valueReturned, ref bool br
915911

916912
object ManageJumpStatementsOrExpressionEval(string expression)
917913
{
918-
string baseExpression = expression;
919914
object result = null;
920915

921916
expression = expression.Trim();
@@ -1454,7 +1449,7 @@ public object Evaluate(string expression)
14541449

14551450
private bool EvaluateCast(string restOfExpression, Stack<object> stack, ref int i)
14561451
{
1457-
Match castMatch = castRegex.Match(restOfExpression);
1452+
Match castMatch = Regex.Match(restOfExpression, CastRegexPattern, optionCaseSensitiveEvaluationActive ? RegexOptions.None : RegexOptions.IgnoreCase);
14581453

14591454
if (castMatch.Success)
14601455
{
@@ -1476,7 +1471,7 @@ private bool EvaluateCast(string restOfExpression, Stack<object> stack, ref int
14761471

14771472
private bool EvaluateNumber(string restOfExpression, Stack<object> stack, ref int i)
14781473
{
1479-
Match numberMatch = numberRegex.Match(restOfExpression);
1474+
Match numberMatch = Regex.Match(restOfExpression, numberRegexPattern, RegexOptions.IgnoreCase);
14801475
Match otherBaseMatch = otherBasesNumberRegex.Match(restOfExpression);
14811476

14821477
if (otherBaseMatch.Success
@@ -1542,7 +1537,7 @@ private bool EvaluateInstanceCreationWithNewKeyword(string expr, string restOfEx
15421537
if (!OptionNewKeywordEvaluationActive)
15431538
return false;
15441539

1545-
Match instanceCreationMatch = instanceCreationWithNewKeywordRegex.Match(restOfExpression);
1540+
Match instanceCreationMatch = Regex.Match(restOfExpression, InstanceCreationWithNewKeywordRegexPattern, optionCaseSensitiveEvaluationActive ? RegexOptions.None : RegexOptions.IgnoreCase);
15461541

15471542
if (instanceCreationMatch.Success &&
15481543
(stack.Count == 0
@@ -2890,10 +2885,10 @@ private Type GetTypeByFriendlyName(string typeName, string genericTypes = "", bo
28902885

28912886
if (result == null)
28922887
{
2893-
typeName = primaryTypesRegex.Replace(typeName, delegate (Match match)
2888+
typeName = Regex.Replace(typeName, primaryTypesRegexPattern, delegate (Match match)
28942889
{
28952890
return primaryTypesDict[match.Value.ManageCasing(OptionCaseSensitiveEvaluationActive)].ToString();
2896-
});
2891+
}, (optionCaseSensitiveEvaluationActive ? RegexOptions.None : RegexOptions.IgnoreCase));
28972892

28982893
result = Type.GetType(typeName, false, !OptionCaseSensitiveEvaluationActive);
28992894
}

0 commit comments

Comments
 (0)