When handling the Nodes collection in MiniYaml, individual nodes are located via one of two methods:
// Lookup a single key with linear search.
var node = yaml.Nodes.FirstOrDefault(n => n.Key == "SomeKey");
// Convert to dictionary, expecting many key lookups.
var dict = nodes.ToDictionary();
// Lookup a single key in the dictionary.
var node = dict["SomeKey"];
To simplify lookup of individual keys via linear search, provide helper methods NodeWithKeyOrDefault and NodeWithKey. These helpers do the equivalent of Single{OrDefault} searches. Whilst this requires checking the whole list, it provides a useful correctness check. Two duplicated keys in TS yaml are fixed as a result. We can also optimize the helpers to not use LINQ, avoiding allocation of the delegate to search for a key.
Adjust existing code to use either lnear searches or dictionary lookups based on whether it will be resolving many keys. Resolving few keys can be done with linear searches to avoid building a dictionary. Resolving many keys should be done with a dictionary to avoid quaradtic runtime from repeated linear searches.
113 lines
2.8 KiB
C#
113 lines
2.8 KiB
C#
#region Copyright & License Information
|
|
/*
|
|
* Copyright (c) The OpenRA Developers and Contributors
|
|
* This file is part of OpenRA, which is free software. It is made
|
|
* available to you under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation, either version 3 of
|
|
* the License, or (at your option) any later version. For more
|
|
* information, see COPYING.
|
|
*/
|
|
#endregion
|
|
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Linguini.Shared.Types.Bundle;
|
|
|
|
namespace OpenRA.Network
|
|
{
|
|
public class FluentArgument
|
|
{
|
|
public enum FluentArgumentType
|
|
{
|
|
String = 0,
|
|
Number = 1,
|
|
}
|
|
|
|
public readonly string Key;
|
|
public readonly string Value;
|
|
public readonly FluentArgumentType Type;
|
|
|
|
public FluentArgument() { }
|
|
|
|
public FluentArgument(string key, object value)
|
|
{
|
|
Key = key;
|
|
Value = value.ToString();
|
|
Type = GetFluentArgumentType(value);
|
|
}
|
|
|
|
static FluentArgumentType GetFluentArgumentType(object value)
|
|
{
|
|
switch (value.ToFluentType())
|
|
{
|
|
case FluentNumber:
|
|
return FluentArgumentType.Number;
|
|
default:
|
|
return FluentArgumentType.String;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class LocalizedMessage
|
|
{
|
|
public const int ProtocolVersion = 1;
|
|
|
|
public readonly string Key = string.Empty;
|
|
|
|
[FieldLoader.LoadUsing(nameof(LoadArguments))]
|
|
public readonly Dictionary<string, object> Arguments;
|
|
|
|
static object LoadArguments(MiniYaml yaml)
|
|
{
|
|
var arguments = new Dictionary<string, object>();
|
|
var argumentsNode = yaml.NodeWithKeyOrDefault("Arguments");
|
|
if (argumentsNode != null)
|
|
{
|
|
foreach (var argumentNode in argumentsNode.Value.Nodes)
|
|
{
|
|
var argument = FieldLoader.Load<FluentArgument>(argumentNode.Value);
|
|
if (argument.Type == FluentArgument.FluentArgumentType.Number)
|
|
{
|
|
if (!double.TryParse(argument.Value, out var number))
|
|
Log.Write("debug", $"Failed to parse {argument.Value}");
|
|
|
|
arguments.Add(argument.Key, number);
|
|
}
|
|
else
|
|
arguments.Add(argument.Key, argument.Value);
|
|
}
|
|
}
|
|
|
|
return arguments;
|
|
}
|
|
|
|
public LocalizedMessage(MiniYaml yaml)
|
|
{
|
|
// Let the FieldLoader do the dirty work of loading the public fields.
|
|
FieldLoader.Load(this, yaml);
|
|
}
|
|
|
|
public static string Serialize(string key, Dictionary<string, object> arguments = null)
|
|
{
|
|
var root = new List<MiniYamlNode>
|
|
{
|
|
new MiniYamlNode("Protocol", ProtocolVersion.ToStringInvariant()),
|
|
new MiniYamlNode("Key", key)
|
|
};
|
|
|
|
if (arguments != null)
|
|
{
|
|
var argumentsNode = new MiniYaml("", arguments
|
|
.Select(a => new FluentArgument(a.Key, a.Value))
|
|
.Select((argument, i) => new MiniYamlNode("Argument@" + i, FieldSaver.Save(argument))));
|
|
|
|
root.Add(new MiniYamlNode("Arguments", argumentsNode));
|
|
}
|
|
|
|
return new MiniYaml("", root)
|
|
.ToLines("LocalizedMessage")
|
|
.JoinWith("\n");
|
|
}
|
|
}
|
|
}
|