From aae20662e29654f9a83a14932c6ba604955a119a Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Thu, 25 Feb 2021 19:16:51 +0100 Subject: [PATCH] Add option to extract constant tables, fix string.start --- .../IO/LuaSkeleton/LuaSkeleton.Expressions.cs | 15 ++++- AspectedRouting/IO/LuaSkeleton/LuaSkeleton.cs | 63 +++++++++++-------- AspectedRouting/IO/itinero1/LuaPrinter1.cs | 2 +- AspectedRouting/IO/itinero2/LuaPrinter2.cs | 53 ++++++++-------- .../IO/lua/remove_relation_prefix.lua | 4 +- 5 files changed, 78 insertions(+), 59 deletions(-) diff --git a/AspectedRouting/IO/LuaSkeleton/LuaSkeleton.Expressions.cs b/AspectedRouting/IO/LuaSkeleton/LuaSkeleton.Expressions.cs index 52f20c1..54b57ee 100644 --- a/AspectedRouting/IO/LuaSkeleton/LuaSkeleton.Expressions.cs +++ b/AspectedRouting/IO/LuaSkeleton/LuaSkeleton.Expressions.cs @@ -218,6 +218,7 @@ namespace AspectedRouting.IO.LuaSkeleton public string MappingToLua(Mapping m) { + var isConstant = true; var contents = m.StringToResultFunctions.Select(kv => { var (key, expr) = kv; @@ -228,13 +229,23 @@ namespace AspectedRouting.IO.LuaSkeleton left = key; } - return left + " = " + ToLua(expr, key); + var luaExpr = ToLua(expr, key); + if (luaExpr.Contains("tags")) { + isConstant = false; + } + return left + " = " + luaExpr ; } ); - return + var mapping = "{\n " + string.Join(",\n ", contents) + "\n}"; + if (_staticTables && isConstant) { + return AddConstant(mapping); + } + + return mapping; + } /// diff --git a/AspectedRouting/IO/LuaSkeleton/LuaSkeleton.cs b/AspectedRouting/IO/LuaSkeleton/LuaSkeleton.cs index dcdbf17..ab76101 100644 --- a/AspectedRouting/IO/LuaSkeleton/LuaSkeleton.cs +++ b/AspectedRouting/IO/LuaSkeleton/LuaSkeleton.cs @@ -1,30 +1,38 @@ using System.Collections.Generic; using System.IO; +using System.Linq; using AspectedRouting.Language; namespace AspectedRouting.IO.LuaSkeleton { - /// - /// The 'LuaSkeleton' is a class which is used in Lua generation of profiles. - /// - /// The lua skeleton basically keeps track of dependencies, and added functions. - /// Once done, all these can be retrieved as code. - /// - /// E.g. if an expression is turned into lua with 'ToExpression', then the dependencies will be automatically added. - /// + /// The 'LuaSkeleton' is a class which is used in Lua generation of profiles. + /// The lua skeleton basically keeps track of dependencies, and added functions. + /// Once done, all these can be retrieved as code. + /// E.g. if an expression is turned into lua with 'ToExpression', then the dependencies will be automatically added. /// public partial class LuaSkeleton { + private readonly HashSet _alreadyAddedFunctions = new HashSet(); + + private readonly List _constants = new List(); private readonly Context _context; private readonly HashSet _dependencies = new HashSet(); private readonly List _functionImplementations = new List(); - private readonly HashSet _alreadyAddedFunctions = new HashSet(); - public LuaSkeleton(Context context) + /// + /// It turns out that creating lua tables is a huge performance overhead. + /// Lots of functions however need a constant table to be invoked. Creating this table over and over is performance + /// issue. + /// If this flag is set, those constant tables are exported so they are created only once + /// + private readonly bool _staticTables; + + public LuaSkeleton(Context context, bool staticTables = false) { _context = context; + _staticTables = staticTables; } internal void AddDep(string name) @@ -41,19 +49,15 @@ namespace AspectedRouting.IO.LuaSkeleton { return _alreadyAddedFunctions.Contains(name); } - + public void AddDependenciesFor(IExpression e) { var (_, functionNames) = e.InList().DirectlyAndInderectlyCalled(_context); - foreach (var functionName in functionNames) - { - - if (_context.DefinedFunctions.TryGetValue(functionName, out var aspectemeta)) - { - AddFunction(aspectemeta); + foreach (var functionName in functionNames) { + if (_context.DefinedFunctions.TryGetValue(functionName, out var aspectMeta)) { + AddFunction(aspectMeta); } - else - { + else { AddDep(functionName); } } @@ -63,21 +67,28 @@ namespace AspectedRouting.IO.LuaSkeleton { var imps = new List(); - foreach (var name in _dependencies) - { + foreach (var name in _dependencies) { var path = $"IO/lua/{name}.lua"; - if (File.Exists(path)) - { + if (File.Exists(path)) { imps.Add(File.ReadAllText(path)); } - else - { + else { throw new FileNotFoundException(path); } } return imps; } - + + public string AddConstant(string luaExpression) + { + _constants.Add(luaExpression); + return "c" + (_constants.Count - 1); + } + + public IEnumerable GenerateConstants() + { + return _constants.Select((c, i) => $"c{i} = {c}"); + } } } \ No newline at end of file diff --git a/AspectedRouting/IO/itinero1/LuaPrinter1.cs b/AspectedRouting/IO/itinero1/LuaPrinter1.cs index dab9e3f..fb2a378 100644 --- a/AspectedRouting/IO/itinero1/LuaPrinter1.cs +++ b/AspectedRouting/IO/itinero1/LuaPrinter1.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Linq; using AspectedRouting.Language; @@ -88,6 +87,7 @@ namespace AspectedRouting.IO.itinero1 functions, "---------------------- UTILS ------------------------".InList(), dependencies, + _skeleton.GenerateConstants().ToList(), "----------------------- TESTS ------------------------".InList(), tests.InList(), GenerateLegacyTail().InList() diff --git a/AspectedRouting/IO/itinero2/LuaPrinter2.cs b/AspectedRouting/IO/itinero2/LuaPrinter2.cs index a5b9a7e..ef7495e 100644 --- a/AspectedRouting/IO/itinero2/LuaPrinter2.cs +++ b/AspectedRouting/IO/itinero2/LuaPrinter2.cs @@ -9,33 +9,30 @@ using AspectedRouting.Tests; namespace AspectedRouting.IO.itinero2 { /// - /// Lua printer for itinero2-lua format - /// - /// The itinero 2.0 lua profile is a whole lot simpler then the 1.0 format, - /// as a single profile there only describes a single behaviour of a vehicle: - /// - /// It has: - /// - name: string, e.g. 'bicycle.fastest' - /// - factor(attributes, result): void, where 'attributes' are all the tags of the way, - /// and result must contain (after calling): - /// - 'forward_speed', a double describing the forward speed (in km/h) - /// - 'backward_speed', the speed when travelling in the opposite direction (0 if not possible) - /// - 'forward', a double describing the forwardfactor - /// - 'backward', the backward factor - /// - 'canstop', a boolean indicating if stopping along the road is possible - /// + /// Lua printer for itinero2-lua format + /// The itinero 2.0 lua profile is a whole lot simpler then the 1.0 format, + /// as a single profile there only describes a single behaviour of a vehicle: + /// It has: + /// - name: string, e.g. 'bicycle.fastest' + /// - factor(attributes, result): void, where 'attributes' are all the tags of the way, + /// and result must contain (after calling): + /// - 'forward_speed', a double describing the forward speed (in km/h) + /// - 'backward_speed', the speed when travelling in the opposite direction (0 if not possible) + /// - 'forward', a double describing the forwardfactor + /// - 'backward', the backward factor + /// - 'canstop', a boolean indicating if stopping along the road is possible /// public partial class LuaPrinter2 { - private readonly ProfileMetaData _profile; - private readonly string _behaviourName; - private readonly Context _context; private readonly List _aspectTests; + private readonly string _behaviourName; private readonly IEnumerable _behaviourTestSuite; + private readonly Context _context; private readonly DateTime _lastChangeTime; + private readonly LuaParameterPrinter _parameterPrinter; + private readonly ProfileMetaData _profile; private readonly LuaSkeleton.LuaSkeleton _skeleton; - private readonly LuaParameterPrinter _parameterPrinter; public LuaPrinter2(ProfileMetaData profile, string behaviourName, @@ -43,7 +40,7 @@ namespace AspectedRouting.IO.itinero2 List aspectTests, IEnumerable behaviourTestSuite, DateTime lastChangeTime) { - _skeleton = new LuaSkeleton.LuaSkeleton(context); + _skeleton = new LuaSkeleton.LuaSkeleton(context, false); _profile = profile; _behaviourName = behaviourName; _context = context; @@ -55,23 +52,21 @@ namespace AspectedRouting.IO.itinero2 public string ToLua() { - var profileDescr = _profile.Behaviours[_behaviourName]["description"].Evaluate(_context).ToString(); + var profileDescr = _profile.Behaviours[_behaviourName]["description"].Evaluate(_context).ToString(); var header = - new List - { + new List { $"name = \"{_profile.Name}.{_behaviourName}\"", $"generationDate = \"{_lastChangeTime:s}\"", $"description = \"{profileDescr} ({_profile.Description})\"" }; var testPrinter = new LuaTestPrinter(_skeleton, - new List() {"unitTestProfile2"}); + new List {"unitTestProfile2"}); var tests = testPrinter.GenerateFullTestSuite( - _behaviourTestSuite.ToList(), + _behaviourTestSuite.ToList(), new List(), true); - var all = new List - { + var all = new List { header.Lined(), "", GenerateMainFunction(), @@ -85,9 +80,11 @@ namespace AspectedRouting.IO.itinero2 "", string.Join("\n\n", _skeleton.GenerateDependencies()), // Should be AFTER generating the main function! "", + string.Join("\n\n", _skeleton.GenerateConstants()), + "", tests, "", - + "if (itinero == nil) then", " itinero = {}", " itinero.log = print", diff --git a/AspectedRouting/IO/lua/remove_relation_prefix.lua b/AspectedRouting/IO/lua/remove_relation_prefix.lua index 781ba98..2cf8415 100644 --- a/AspectedRouting/IO/lua/remove_relation_prefix.lua +++ b/AspectedRouting/IO/lua/remove_relation_prefix.lua @@ -1,4 +1,4 @@ -function string.start(strt, s) +function string_start(strt, s) return string.sub(s, 1, string.len(strt)) == strt end @@ -9,7 +9,7 @@ function remove_relation_prefix(tags, name) local new_tags = {} for k, v in pairs(tags) do local prefix = "_relation:" .. name .. ":"; - if (string.start(prefix, k)) then + if (string_start(prefix, k)) then local new_key = "_relation:" .. string.sub(k, string.len(prefix) + 1) -- plus 1: sub uses one-based indexing to select the start new_tags[new_key] = v else