Improve performance of MiniYaml inheritance tree tracking.
Use an ImmutableDictionary to avoid having to clone the inheritance tree in ResolveInherits. This avoids a lot of dictionary clones.
This commit is contained in:
committed by
Matthias Mailänder
parent
58e8b123db
commit
30b1f926f2
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRA.FileSystem;
|
using OpenRA.FileSystem;
|
||||||
@@ -324,22 +325,19 @@ namespace OpenRA
|
|||||||
var resolved = new Dictionary<string, MiniYaml>(tree.Count);
|
var resolved = new Dictionary<string, MiniYaml>(tree.Count);
|
||||||
foreach (var kv in tree)
|
foreach (var kv in tree)
|
||||||
{
|
{
|
||||||
var inherited = new Dictionary<string, MiniYamlNode.SourceLocation>
|
// Inheritance is tracked from parent->child, but not from child->parentsiblings.
|
||||||
{
|
var inherited = ImmutableDictionary<string, MiniYamlNode.SourceLocation>.Empty.Add(kv.Key, default);
|
||||||
{ kv.Key, default }
|
|
||||||
};
|
|
||||||
|
|
||||||
var children = ResolveInherits(kv.Value, tree, inherited);
|
var children = ResolveInherits(kv.Value, tree, inherited);
|
||||||
resolved.Add(kv.Key, new MiniYaml(kv.Value.Value, children));
|
resolved.Add(kv.Key, new MiniYaml(kv.Value.Value, children));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve any top-level removals (e.g. removing whole actor blocks)
|
// Resolve any top-level removals (e.g. removing whole actor blocks)
|
||||||
var nodes = new MiniYaml("", resolved.Select(kv => new MiniYamlNode(kv.Key, kv.Value)).ToList());
|
var nodes = new MiniYaml("", resolved.Select(kv => new MiniYamlNode(kv.Key, kv.Value)).ToList());
|
||||||
return ResolveInherits(nodes, tree, new Dictionary<string, MiniYamlNode.SourceLocation>());
|
return ResolveInherits(nodes, tree, ImmutableDictionary<string, MiniYamlNode.SourceLocation>.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MergeIntoResolved(MiniYamlNode overrideNode, List<MiniYamlNode> existingNodes, HashSet<string> existingNodeKeys,
|
static void MergeIntoResolved(MiniYamlNode overrideNode, List<MiniYamlNode> existingNodes, HashSet<string> existingNodeKeys,
|
||||||
Dictionary<string, MiniYaml> tree, Dictionary<string, MiniYamlNode.SourceLocation> inherited)
|
Dictionary<string, MiniYaml> tree, ImmutableDictionary<string, MiniYamlNode.SourceLocation> inherited)
|
||||||
{
|
{
|
||||||
if (existingNodeKeys.Add(overrideNode.Key))
|
if (existingNodeKeys.Add(overrideNode.Key))
|
||||||
{
|
{
|
||||||
@@ -352,14 +350,11 @@ namespace OpenRA
|
|||||||
existingNode.Value.Nodes = ResolveInherits(existingNode.Value, tree, inherited);
|
existingNode.Value.Nodes = ResolveInherits(existingNode.Value, tree, inherited);
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<MiniYamlNode> ResolveInherits(MiniYaml node, Dictionary<string, MiniYaml> tree, Dictionary<string, MiniYamlNode.SourceLocation> inherited)
|
static List<MiniYamlNode> ResolveInherits(MiniYaml node, Dictionary<string, MiniYaml> tree, ImmutableDictionary<string, MiniYamlNode.SourceLocation> inherited)
|
||||||
{
|
{
|
||||||
var resolved = new List<MiniYamlNode>(node.Nodes.Count);
|
var resolved = new List<MiniYamlNode>(node.Nodes.Count);
|
||||||
var resolvedKeys = new HashSet<string>(node.Nodes.Count);
|
var resolvedKeys = new HashSet<string>(node.Nodes.Count);
|
||||||
|
|
||||||
// Inheritance is tracked from parent->child, but not from child->parentsiblings.
|
|
||||||
inherited = new Dictionary<string, MiniYamlNode.SourceLocation>(inherited);
|
|
||||||
|
|
||||||
foreach (var n in node.Nodes)
|
foreach (var n in node.Nodes)
|
||||||
{
|
{
|
||||||
if (n.Key == "Inherits" || n.Key.StartsWith("Inherits@", StringComparison.Ordinal))
|
if (n.Key == "Inherits" || n.Key.StartsWith("Inherits@", StringComparison.Ordinal))
|
||||||
@@ -368,10 +363,15 @@ namespace OpenRA
|
|||||||
throw new YamlException(
|
throw new YamlException(
|
||||||
$"{n.Location}: Parent type `{n.Value.Value}` not found");
|
$"{n.Location}: Parent type `{n.Value.Value}` not found");
|
||||||
|
|
||||||
if (inherited.TryGetValue(n.Value.Value, out var location))
|
try
|
||||||
throw new YamlException($"{n.Location}: Parent type `{n.Value.Value}` was already inherited by this yaml tree at {location} (note: may be from a derived tree)");
|
{
|
||||||
|
inherited = inherited.Add(n.Value.Value, n.Location);
|
||||||
|
}
|
||||||
|
catch (ArgumentException)
|
||||||
|
{
|
||||||
|
throw new YamlException($"{n.Location}: Parent type `{n.Value.Value}` was already inherited by this yaml tree at {inherited[n.Value.Value]} (note: may be from a derived tree)");
|
||||||
|
}
|
||||||
|
|
||||||
inherited.Add(n.Value.Value, n.Location);
|
|
||||||
foreach (var r in ResolveInherits(parent, tree, inherited))
|
foreach (var r in ResolveInherits(parent, tree, inherited))
|
||||||
MergeIntoResolved(r, resolved, resolvedKeys, tree, inherited);
|
MergeIntoResolved(r, resolved, resolvedKeys, tree, inherited);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="6.0.0" />
|
||||||
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup Condition="'$(MSBuildRuntimeType)'=='Mono'">
|
||||||
|
<PackageReference Include="System.Collections.Immutable" Version="6.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Linguini.Bundle" Version="0.5.0" />
|
<PackageReference Include="Linguini.Bundle" Version="0.5.0" />
|
||||||
<PackageReference Include="OpenRA-Eluant" Version="1.0.21" />
|
<PackageReference Include="OpenRA-Eluant" Version="1.0.21" />
|
||||||
|
|||||||
Reference in New Issue
Block a user