From 9e13c405f376db2d45ab25aa24dc9b4b9ea17647 Mon Sep 17 00:00:00 2001 From: anmo Date: Thu, 10 Apr 2025 16:04:40 +0200 Subject: [PATCH 1/4] added some type caching and use TryGetValue --- MN.L10n/L10n.cs | 43 +++++++++++++++++++++++------------------- MN.L10n/MN.L10n.csproj | 4 ++-- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/MN.L10n/L10n.cs b/MN.L10n/L10n.cs index ef585d5..d6c405a 100644 --- a/MN.L10n/L10n.cs +++ b/MN.L10n/L10n.cs @@ -5,6 +5,9 @@ using System.Threading; using System.Threading.Tasks; using MN.L10n.PhraseMetadata; +using System.Reflection; +using System.Text; +using System.Xml; namespace MN.L10n { @@ -140,9 +143,11 @@ internal L10nTranslatedString __getPhrase(string phrase, object args = null) { if (lang.Phrases.TryGetValue(cleanedPhrase, out var phr)) { - if (phr.r.ContainsKey("0")) + string getVal; + + if (phr.r.TryGetValue("0", out getVal)) { - cleanedPhrase = phr.r["0"]; + cleanedPhrase = getVal; } if (isPluralized && lang.AstPluralRule != null) @@ -150,9 +155,9 @@ internal L10nTranslatedString __getPhrase(string phrase, object args = null) // Here there be dragons // Dynamic evaluation to get the phrase to use, based on the pluralization rule specified var phraseIndex = lang.AstPluralRule.Evaluate(GetCount(args)).ToString(); - if (phr.r.ContainsKey(phraseIndex)) + if (phr.r.TryGetValue(phraseIndex, out getVal)) { - cleanedPhrase = phr.r[phraseIndex]; + cleanedPhrase = getVal; } } } @@ -182,41 +187,41 @@ internal L10nTranslatedString __getPhrase(string phrase, object args = null) return FormatNamed(withoutMetadata, args); } + private static ConcurrentDictionary IsPluralizedCache = new ConcurrentDictionary(); + public static bool IsPluralized(object args = null) { if (args == null) return false; - var t = args.GetType(); - foreach (var p in t.GetProperties()) - { - if (p.Name == "__count") return true; - } - return false; + var t = args.GetType(); + return IsPluralizedCache.GetOrAdd(t, t.GetProperty("__count")) is not null; } public static long GetCount(object args = null) { - if (args == null) return 0; - var t = args.GetType(); - foreach (var p in t.GetProperties()) + IsPluralizedCache.TryGetValue(args.GetType(), out var p); + + if(p is not null) { - if (p.Name == "__count") - { - long.TryParse(p.GetValue(args).ToString(), out long __count); - return __count; - } + return Convert.ToInt64(p.GetValue(args)); + } return 0; } + private static ConcurrentDictionary propCache = new ConcurrentDictionary(); + public static L10nTranslatedString FormatNamed(string formatString, object args = null) { if (args == null) return new L10nTranslatedString(formatString); var t = args.GetType(); var tmpVal = formatString; - foreach (var p in t.GetProperties()) + + var props = propCache.GetOrAdd(t, tp => tp.GetProperties()); + + foreach (var p in props) { tmpVal = tmpVal.Replace("$" + p.Name + "$", p.GetValue(args)?.ToString()); } diff --git a/MN.L10n/MN.L10n.csproj b/MN.L10n/MN.L10n.csproj index fcafe24..c50c1b0 100644 --- a/MN.L10n/MN.L10n.csproj +++ b/MN.L10n/MN.L10n.csproj @@ -1,7 +1,7 @@  - net472;netstandard2.0;net8.0;net9.0 + net48;netstandard2.0;net8.0;net9.0 True MultiNet Interactive AB Chris Gårdenberg @@ -29,7 +29,7 @@ Translation package AnyCPU - + From b7892be679ecf9942f7717869988b059d9f63140 Mon Sep 17 00:00:00 2001 From: anmo Date: Fri, 11 Apr 2025 10:58:23 +0200 Subject: [PATCH 2/4] changed InvocationCount --- MN.L10n.Benchmark/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MN.L10n.Benchmark/Program.cs b/MN.L10n.Benchmark/Program.cs index 7d2a769..51a7067 100644 --- a/MN.L10n.Benchmark/Program.cs +++ b/MN.L10n.Benchmark/Program.cs @@ -55,7 +55,7 @@ public class Foo } [MemoryDiagnoser(true)] -[InvocationCount(100000)] +[InvocationCount(1_000_000)] public class SpanTest { [Params("$data$", "Hej $data$ $count$ $many$", "$den här texten inleds med $data$$data2$")] From efd920525b666b719be4f60ec79a5ec56ab6fa1b Mon Sep 17 00:00:00 2001 From: anmo Date: Fri, 11 Apr 2025 11:58:06 +0200 Subject: [PATCH 3/4] more examples --- MN.L10n.Benchmark/Program.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/MN.L10n.Benchmark/Program.cs b/MN.L10n.Benchmark/Program.cs index 5b3239b..f811a61 100644 --- a/MN.L10n.Benchmark/Program.cs +++ b/MN.L10n.Benchmark/Program.cs @@ -19,7 +19,7 @@ public class BenchmarkL10nLanguageProvider : IL10nLanguageProvider { public string GetLanguage() { - return "0"; + return "1"; } } @@ -58,7 +58,7 @@ public class Foo [InvocationCount(1_000_000)] public class SpanTest { - [Params("$data$", "Hej $data$ $count$ $many$", "$den här texten inleds med $data$$data2$")] + [Params("$data$", "Hej $data$ $count$ $many$", "$den här texten inleds med $data$$data2$", "Här har vi en längre förklarande text utan dollartecken. Den här skulle t.ex. kunna finnas i ")] public string formatString { get; set; } = ""; public static Foo args = new Foo { data = "Anders" }; @@ -68,7 +68,7 @@ public void GlobalSetup() var dataProvider = new BenchmarkL10nDataProvider(); var stack = new Stack(); - stack.Push("0"); + stack.Push("1"); var items = new Dictionary() { { "___l10nlang", stack } }; var l10n = L10n.CreateInstance(new BenchmarkL10nLanguageProvider(), dataProvider, () => items); dataProvider.SaveL10n(l10n); @@ -80,6 +80,12 @@ public void GetPhase() L10n._s(formatString, args); } + [Benchmark] + public void GetPhaseWithoutArgs() + { + L10n._s(formatString); + } + [Benchmark] public void FormatNamed() { From 012420df1fe7f52080aad504f69bdeba2ef59805 Mon Sep 17 00:00:00 2001 From: anmo Date: Fri, 11 Apr 2025 14:52:27 +0200 Subject: [PATCH 4/4] added phrasedata --- MN.L10n.Benchmark/MN.L10n.Benchmark.csproj | 21 +++++++++++++++++++++ MN.L10n.Benchmark/Program.cs | 9 +++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/MN.L10n.Benchmark/MN.L10n.Benchmark.csproj b/MN.L10n.Benchmark/MN.L10n.Benchmark.csproj index 471543e..643647c 100644 --- a/MN.L10n.Benchmark/MN.L10n.Benchmark.csproj +++ b/MN.L10n.Benchmark/MN.L10n.Benchmark.csproj @@ -15,4 +15,25 @@ + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + diff --git a/MN.L10n.Benchmark/Program.cs b/MN.L10n.Benchmark/Program.cs index f811a61..dfbfee3 100644 --- a/MN.L10n.Benchmark/Program.cs +++ b/MN.L10n.Benchmark/Program.cs @@ -2,6 +2,7 @@ using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Running; using MN.L10n; +using MN.L10n.FileProviders; using System.Collections.Concurrent; using System.Reflection; using System.Text; @@ -10,7 +11,7 @@ -BenchmarkRunner.Run(); +BenchmarkRunner.Run(); @@ -55,8 +56,8 @@ public class Foo } [MemoryDiagnoser(true)] -[InvocationCount(1_000_000)] -public class SpanTest +[InvocationCount(100_000)] +public class Benchmarks { [Params("$data$", "Hej $data$ $count$ $many$", "$den här texten inleds med $data$$data2$", "Här har vi en längre förklarande text utan dollartecken. Den här skulle t.ex. kunna finnas i ")] public string formatString { get; set; } = ""; @@ -70,7 +71,7 @@ public void GlobalSetup() var stack = new Stack(); stack.Push("1"); var items = new Dictionary() { { "___l10nlang", stack } }; - var l10n = L10n.CreateInstance(new BenchmarkL10nLanguageProvider(), dataProvider, () => items); + var l10n = L10n.CreateInstance(new BenchmarkL10nLanguageProvider(), new FileDataProvider(AppDomain.CurrentDomain.BaseDirectory), () => items); dataProvider.SaveL10n(l10n); }