Skip to content

Commit ecb9f4e

Browse files
committed
Promoting reuse and avoiding memory leak
1 parent 88b9292 commit ecb9f4e

File tree

4 files changed

+182
-144
lines changed

4 files changed

+182
-144
lines changed

Source/ModuleManager/MMPatchLoader.cs

Lines changed: 29 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Diagnostics.CodeAnalysis;
43
using System.Globalization;
54
using System.IO;
65
using System.Linq;
76
using System.Reflection;
87
using System.Text;
98
using System.Text.RegularExpressions;
109

11-
using ModuleManager.Collections;
1210
using ModuleManager.Logging;
1311
using ModuleManager.Extensions;
14-
using ModuleManager.Threading;
1512
using ModuleManager.Tags;
1613
using ModuleManager.Patches;
1714
using NodeStack = ModuleManager.Collections.ImmutableStack<ConfigNode>;
1815

1916
using static ModuleManager.FilePathRepository;
17+
using ModuleManager.Utils;
2018

2119
namespace ModuleManager
2220
{
@@ -30,8 +28,6 @@ public class MMPatchLoader : LoadingSystem
3028

3129
public static bool keepPartDB = false;
3230

33-
private static readonly KeyValueCache<string, Regex> regexCache = new KeyValueCache<string, Regex>();
34-
3531
private string configSha;
3632
private int totalConfigFilesSize;
3733
private readonly Dictionary<string, string> filesShaMap = new Dictionary<string, string>();
@@ -57,6 +53,12 @@ public MMPatchLoader(IEnumerable<ModListGenerator.ModAddedByAssembly> modsAddedB
5753
this.timings = timings;
5854
}
5955

56+
~MMPatchLoader()
57+
{ // Being paranoid on memory cleaning...
58+
this.CleanUpCaches();
59+
ConfigNodeEditUtils.Instance.Destroy();
60+
}
61+
6062
public IEnumerable<IProtoUrlConfig> Run()
6163
{
6264
this.timings.Patching.Start();
@@ -226,6 +228,10 @@ public IEnumerable<IProtoUrlConfig> Run()
226228

227229
logger.Info(status + "\n" + errors);
228230

231+
// Cleaning some memory
232+
ConfigNodeEditUtils.Instance.Destroy();
233+
this.CleanUpCaches();
234+
229235
this.timings.Patching.Stop();
230236
logger.Info("Ran in " + this.timings.Patching);
231237

@@ -266,6 +272,12 @@ private void SaveModdedPhysics(IEnumerable<IProtoUrlConfig> databaseConfigs)
266272
PHYSICS_CONFIG.Save(configs.First().Node);
267273
}
268274

275+
private void CleanUpCaches()
276+
{
277+
this.filesShaMap.Clear();
278+
this.filesSizeMap.Clear();
279+
}
280+
269281
private bool IsCacheUpToDate()
270282
{
271283
this.timings.ShaCalc.Start();
@@ -275,8 +287,7 @@ private bool IsCacheUpToDate()
275287
UrlDir.UrlFile[] files = GameDatabase.Instance.root.AllConfigFiles.ToArray();
276288
this.totalConfigFilesSize = 0;
277289

278-
this.filesShaMap.Clear();
279-
this.filesSizeMap.Clear();
290+
this.CleanUpCaches();
280291

281292
for (int i = 0; i < files.Length; i++)
282293
{
@@ -451,6 +462,7 @@ private void CreateCache(IEnumerable<IProtoUrlConfig> databaseConfigs, int patch
451462
shaNode.AddValue("SHA", filesShaMap[url]);
452463
shaNode.AddValue("SIZE", this.filesSizeMap[url]);
453464
filesShaMap.Remove(url);
465+
filesSizeMap.Remove(url);
454466
}
455467
}
456468

@@ -753,7 +765,7 @@ public static ConfigNode ModifyNode(NodeStack original, ConfigNode mod, PatchCon
753765

754766
if (varValue != null)
755767
{
756-
string value = FindAndReplaceValue(
768+
string value = ConfigNodeEditUtils.Instance.FindAndReplaceValue(
757769
mod,
758770
ref valName,
759771
varValue, newNode,
@@ -800,7 +812,7 @@ public static ConfigNode ModifyNode(NodeStack original, ConfigNode mod, PatchCon
800812
while (index < valCount)
801813
{
802814
// If there is an index, use it.
803-
ConfigNode.Value v = FindValueIn(newNode, valName, index);
815+
ConfigNode.Value v = ConfigNodeEditUtils.Instance.FindValueIn(newNode, valName, index);
804816
if (v != null)
805817
newNode.values.Remove(v);
806818
if (isStar) index++;
@@ -813,7 +825,7 @@ public static ConfigNode ModifyNode(NodeStack original, ConfigNode mod, PatchCon
813825
ConfigNode.Value last = null;
814826
while (true)
815827
{
816-
ConfigNode.Value v = FindValueIn(newNode, valName, index++);
828+
ConfigNode.Value v = ConfigNodeEditUtils.Instance.FindValueIn(newNode, valName, index++);
817829
if (v == last)
818830
break;
819831
last = v;
@@ -1171,7 +1183,7 @@ private static ConfigNode RecurseNodeSearch(string path, NodeStack nodeStack, Pa
11711183

11721184
foundNodeType = true;
11731185

1174-
if (nodeName == null || (node.GetValue("name") is string testNodeName && WildcardMatch(testNodeName, nodeName)))
1186+
if (nodeName == null || (node.GetValue("name") is string testNodeName && ConfigNodeEditUtils.Instance.WildcardMatch(testNodeName, nodeName)))
11751187
{
11761188
nodeStack = new NodeStack(node);
11771189
break;
@@ -1267,7 +1279,7 @@ private static ConfigNode.Value RecurseVariableSearch(string path, NodeStack nod
12671279

12681280
foundNodeType = true;
12691281

1270-
if (nodeName == null || (node.GetValue("name") is string testNodeName && WildcardMatch(testNodeName, nodeName)))
1282+
if (nodeName == null || (node.GetValue("name") is string testNodeName && ConfigNodeEditUtils.Instance.WildcardMatch(testNodeName, nodeName)))
12711283
{
12721284
return RecurseVariableSearch(path.Substring(nextSep + 1), new NodeStack(node), context);
12731285
}
@@ -1361,7 +1373,7 @@ private static ConfigNode.Value RecurseVariableSearch(string path, NodeStack nod
13611373
if (match.Groups[2].Success)
13621374
int.TryParse(match.Groups[2].Value, out idx);
13631375

1364-
ConfigNode.Value cVal = FindValueIn(nodeStack.value, valName, idx);
1376+
ConfigNode.Value cVal = ConfigNodeEditUtils.Instance.FindValueIn(nodeStack.value, valName, idx);
13651377
if (cVal == null)
13661378
{
13671379
context.logger.Warning("Cannot find key " + valName + " in " + nodeStack.value.name);
@@ -1415,104 +1427,6 @@ private static string ProcessVariableSearch(string value, NodeStack nodeStack, P
14151427
return value;
14161428
}
14171429

1418-
private static string FindAndReplaceValue(
1419-
ConfigNode mod,
1420-
ref string valName,
1421-
string value,
1422-
ConfigNode newNode,
1423-
Operator op,
1424-
int index,
1425-
out ConfigNode.Value origVal,
1426-
PatchContext context,
1427-
bool hasPosIndex = false,
1428-
int posIndex = 0,
1429-
bool hasPosStar = false,
1430-
char seperator = ',')
1431-
{
1432-
origVal = FindValueIn(newNode, valName, index);
1433-
if (origVal == null)
1434-
return null;
1435-
string oValue = origVal.value;
1436-
1437-
string[] strArray = new string[] { oValue };
1438-
if (hasPosIndex)
1439-
{
1440-
strArray = oValue.Split(new char[] { seperator }, StringSplitOptions.RemoveEmptyEntries);
1441-
if (posIndex >= strArray.Length)
1442-
{
1443-
context.progress.Error(context.patchUrl, "Invalid Vector Index!");
1444-
return null;
1445-
}
1446-
}
1447-
string backupValue = value;
1448-
while (posIndex < strArray.Length)
1449-
{
1450-
value = backupValue;
1451-
oValue = strArray[posIndex];
1452-
if (op != Operator.Assign)
1453-
{
1454-
if (op == Operator.RegexReplace)
1455-
{
1456-
try
1457-
{
1458-
string[] split = value.Split(value[0]);
1459-
1460-
Regex replace = regexCache.Fetch(split[1], delegate
1461-
{
1462-
return new Regex(split[1]);
1463-
});
1464-
1465-
value = replace.Replace(oValue, split[2]);
1466-
}
1467-
catch (Exception ex)
1468-
{
1469-
context.progress.Exception(context.patchUrl, "Error - Failed to do a regexp replacement: " + mod.name + " : original value=\"" + oValue +
1470-
"\" regexp=\"" + value +
1471-
"\" \nNote - to use regexp, the first char is used to subdivide the string (much like sed)", ex);
1472-
return null;
1473-
}
1474-
}
1475-
else if (double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out double s)
1476-
&& double.TryParse(oValue, NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out double os))
1477-
{
1478-
switch (op)
1479-
{
1480-
case Operator.Multiply:
1481-
value = (os * s).ToString(CultureInfo.InvariantCulture);
1482-
break;
1483-
1484-
case Operator.Divide:
1485-
value = (os / s).ToString(CultureInfo.InvariantCulture);
1486-
break;
1487-
1488-
case Operator.Add:
1489-
value = (os + s).ToString(CultureInfo.InvariantCulture);
1490-
break;
1491-
1492-
case Operator.Subtract:
1493-
value = (os - s).ToString(CultureInfo.InvariantCulture);
1494-
break;
1495-
1496-
case Operator.Exponentiate:
1497-
value = Math.Pow(os, s).ToString(CultureInfo.InvariantCulture);
1498-
break;
1499-
}
1500-
}
1501-
else
1502-
{
1503-
context.progress.Error(context.patchUrl, "Error - Failed to do a maths replacement: " + mod.name + " : original value=\"" + oValue +
1504-
"\" operator=" + op + " mod value=\"" + value + "\"");
1505-
return null;
1506-
}
1507-
}
1508-
strArray[posIndex] = value;
1509-
if (hasPosStar) posIndex++;
1510-
else break;
1511-
}
1512-
value = String.Join(new string(seperator, 1), strArray);
1513-
return value;
1514-
}
1515-
15161430
#endregion Applying Patches
15171431

15181432
#region Condition checking
@@ -1665,7 +1579,7 @@ public static bool WildcardMatchValues(ConfigNode node, string type, string valu
16651579
string[] values = node.GetValues(type);
16661580
for (int i = 0; i < values.Length; i++)
16671581
{
1668-
if (!compare && WildcardMatch(values[i], value))
1582+
if (!compare && ConfigNodeEditUtils.Instance.WildcardMatch(values[i], value))
16691583
return true;
16701584

16711585
if (compare && double.TryParse(values[i], NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out double val2)
@@ -1677,19 +1591,6 @@ public static bool WildcardMatchValues(ConfigNode node, string type, string valu
16771591
return false;
16781592
}
16791593

1680-
public static bool WildcardMatch(string s, string wildcard)
1681-
{
1682-
if (wildcard == null)
1683-
return true;
1684-
string pattern = "^" + Regex.Escape(wildcard).Replace(@"\*", ".*").Replace(@"\?", ".") + "$";
1685-
1686-
Regex regex = regexCache.Fetch(pattern, delegate
1687-
{
1688-
return new Regex(pattern);
1689-
});
1690-
return regex.IsMatch(s);
1691-
}
1692-
16931594
#endregion Condition checking
16941595

16951596
#region Config Node Utilities
@@ -1743,7 +1644,7 @@ public static ConfigNode FindConfigNodeIn(
17431644
int c = src.nodes.Count;
17441645
for(int i = 0; i < c; ++i)
17451646
{
1746-
if (WildcardMatch(src.nodes[i].name, nodeType))
1647+
if (ConfigNodeEditUtils.Instance.WildcardMatch(src.nodes[i].name, nodeType))
17471648
nodes.Add(src.nodes[i]);
17481649
}
17491650
int nodeCount = nodes.Count;
@@ -1760,7 +1661,7 @@ public static ConfigNode FindConfigNodeIn(
17601661
{
17611662
for (int i = 0; i < nodeCount; ++i)
17621663
{
1763-
if (nodes[i].HasValue("name") && WildcardMatch(nodes[i].GetValue("name"), nodeName))
1664+
if (nodes[i].HasValue("name") && ConfigNodeEditUtils.Instance.WildcardMatch(nodes[i].GetValue("name"), nodeName))
17641665
{
17651666
last = nodes[i];
17661667
if (--index < 0)
@@ -1771,7 +1672,7 @@ public static ConfigNode FindConfigNodeIn(
17711672
}
17721673
for (int i = nodeCount - 1; i >= 0; --i)
17731674
{
1774-
if (nodes[i].HasValue("name") && WildcardMatch(nodes[i].GetValue("name"), nodeName))
1675+
if (nodes[i].HasValue("name") && ConfigNodeEditUtils.Instance.WildcardMatch(nodes[i].GetValue("name"), nodeName))
17751676
{
17761677
last = nodes[i];
17771678
if (++index >= 0)
@@ -1781,21 +1682,6 @@ public static ConfigNode FindConfigNodeIn(
17811682
return last;
17821683
}
17831684

1784-
private static ConfigNode.Value FindValueIn(ConfigNode newNode, string valName, int index)
1785-
{
1786-
ConfigNode.Value v = null;
1787-
for (int i = 0; i < newNode.values.Count; ++i)
1788-
{
1789-
if (WildcardMatch(newNode.values[i].name, valName))
1790-
{
1791-
v = newNode.values[i];
1792-
if (--index < 0)
1793-
return v;
1794-
}
1795-
}
1796-
return v;
1797-
}
1798-
17991685
#endregion Config Node Utilities
18001686
}
18011687
}

Source/ModuleManager/ModuleManager.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
<Compile Include="Properties\LegalMamboJambo.cs" />
140140
<Compile Include="Progress\Timings.cs" />
141141
<Compile Include="Utils\Stopwatch.cs" />
142+
<Compile Include="Utils\ConfigNodeEditUtils.cs" />
142143
</ItemGroup>
143144
<ItemGroup>
144145
<Reference Include="System" />

Source/ModuleManager/NodeMatcher.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using ModuleManager.Extensions;
3+
using ModuleManager.Utils;
34

45
namespace ModuleManager
56
{
@@ -42,7 +43,7 @@ public bool IsMatch(ConfigNode node)
4243
bool match = false;
4344
foreach (string pattern in namePatterns)
4445
{
45-
if (MMPatchLoader.WildcardMatch(name, pattern))
46+
if (ConfigNodeEditUtils.Instance.WildcardMatch(name, pattern))
4647
{
4748
match = true;
4849
break;

0 commit comments

Comments
 (0)