From a92628555f946078f7587d31a6c8574c72d73f15 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Wed, 9 Oct 2024 08:24:45 +0900 Subject: [PATCH 1/3] perf: Optimize regular numbers parse logics --- .../Serialization/DeserializerTest.cs | 38 +++++++++++++++++++ .../ScalarNodeDeserializer.cs | 31 +++++++++++---- 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/YamlDotNet.Test/Serialization/DeserializerTest.cs b/YamlDotNet.Test/Serialization/DeserializerTest.cs index fc49ae52..f0fd5c01 100644 --- a/YamlDotNet.Test/Serialization/DeserializerTest.cs +++ b/YamlDotNet.Test/Serialization/DeserializerTest.cs @@ -220,6 +220,44 @@ public void NewLinesInKeys() Assert.Equal($"value\na\nb", dictionary.First().Value); } + [Theory] + [InlineData(System.Byte.MinValue)] + [InlineData(System.Byte.MaxValue)] + [InlineData(System.Int16.MinValue)] + [InlineData(System.Int16.MaxValue)] + [InlineData(System.Int32.MinValue)] + [InlineData(System.Int32.MaxValue)] + [InlineData(System.Int64.MinValue)] + [InlineData(System.Int64.MaxValue)] + [InlineData(System.UInt64.MaxValue)] + [InlineData(System.Single.MinValue)] + [InlineData(System.Single.MaxValue)] + [InlineData(System.Double.MinValue)] + [InlineData(System.Double.MaxValue)] + public void UnquotedStringTypeDeserialization_RegularNumbers(object expected) + { + var deserializer = new DeserializerBuilder() + .WithAttemptingUnquotedStringTypeDeserialization().Build(); + + var yaml = $"Value: {expected}"; + +#if NETFRAMEWORK + // It needs explicitly specifying maximum precision for value roundtrip. + if (expected is float floatValue) + { + yaml = $"Value: {floatValue:G9}"; + } + if (expected is double doubleValue) + { + yaml = $"Value: {doubleValue:G17}"; + } +#endif + + var resultDict = deserializer.Deserialize>(yaml); + Assert.True(resultDict.ContainsKey("Value")); + Assert.Equal(expected, resultDict["Value"]); + } + [Theory] [InlineData(".nan", System.Single.NaN)] [InlineData(".NaN", System.Single.NaN)] diff --git a/YamlDotNet/Serialization/NodeDeserializers/ScalarNodeDeserializer.cs b/YamlDotNet/Serialization/NodeDeserializers/ScalarNodeDeserializer.cs index 95ff8f5f..7146c83a 100644 --- a/YamlDotNet/Serialization/NodeDeserializers/ScalarNodeDeserializer.cs +++ b/YamlDotNet/Serialization/NodeDeserializers/ScalarNodeDeserializer.cs @@ -382,13 +382,30 @@ private static object CastInteger(ulong number, TypeCode typeCode) } else if (Regex.IsMatch(v, @"[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?")) //regular number { - if (TryAndSwallow(() => byte.Parse(v, formatter.NumberFormat), out result)) { } - else if (TryAndSwallow(() => short.Parse(v, formatter.NumberFormat), out result)) { } - else if (TryAndSwallow(() => int.Parse(v, formatter.NumberFormat), out result)) { } - else if (TryAndSwallow(() => long.Parse(v, formatter.NumberFormat), out result)) { } - else if (TryAndSwallow(() => ulong.Parse(v, formatter.NumberFormat), out result)) { } - else if (TryAndSwallow(() => float.Parse(v, formatter.NumberFormat), out result)) { } - else if (TryAndSwallow(() => double.Parse(v, formatter.NumberFormat), out result)) { } +#pragma warning disable format + if ( byte.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var byteValue )) { result = byteValue; } + else if (short.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var shortValue )) { result = shortValue; } + else if ( int.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var intValue )) { result = intValue; } + else if ( long.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var longValue )) { result = longValue; } + else if (ulong.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var ulongValue )) { result = ulongValue; } +#if NETFRAMEWORK + else if ( float.TryParse(v, NumberStyles.Float | NumberStyles.AllowThousands, formatter.NumberFormat, out var floatValue)) { result = floatValue; } + else if (double.TryParse(v, NumberStyles.Float | NumberStyles.AllowThousands, formatter.NumberFormat, out var doubleValue)) { result = doubleValue; } +#else + else if (double.TryParse(v, NumberStyles.Float | NumberStyles.AllowThousands, formatter.NumberFormat, out var doubleValue)) + { + var floatValue = (float)doubleValue; + if (!float.IsNaN(floatValue) && !float.IsInfinity(floatValue)) // .NET 6 or later support float.IsNormal + { + result = floatValue; + } + else + { + result = doubleValue; + } + } +#endif +#pragma warning restore format else { //we couldn't parse it, default to string, It's probably too big From 2d369d59b660449eaf38e00f34fd8abdbb5a5673 Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Thu, 10 Oct 2024 06:45:18 +0900 Subject: [PATCH 2/3] chore: modify code that is pointed out in the code review --- .../ScalarNodeDeserializer.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/YamlDotNet/Serialization/NodeDeserializers/ScalarNodeDeserializer.cs b/YamlDotNet/Serialization/NodeDeserializers/ScalarNodeDeserializer.cs index 7146c83a..c0d5b9c0 100644 --- a/YamlDotNet/Serialization/NodeDeserializers/ScalarNodeDeserializer.cs +++ b/YamlDotNet/Serialization/NodeDeserializers/ScalarNodeDeserializer.cs @@ -382,17 +382,16 @@ private static object CastInteger(ulong number, TypeCode typeCode) } else if (Regex.IsMatch(v, @"[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?")) //regular number { -#pragma warning disable format - if ( byte.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var byteValue )) { result = byteValue; } - else if (short.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var shortValue )) { result = shortValue; } - else if ( int.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var intValue )) { result = intValue; } - else if ( long.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var longValue )) { result = longValue; } - else if (ulong.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var ulongValue )) { result = ulongValue; } + if (byte.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var byteValue)) { result = byteValue; } + else if (short.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var shortValue)) { result = shortValue; } + else if (int.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var intValue)) { result = intValue; } + else if (long.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var longValue)) { result = longValue; } + else if (ulong.TryParse(v, NumberStyles.Integer, formatter.NumberFormat, out var ulongValue)) { result = ulongValue; } #if NETFRAMEWORK - else if ( float.TryParse(v, NumberStyles.Float | NumberStyles.AllowThousands, formatter.NumberFormat, out var floatValue)) { result = floatValue; } - else if (double.TryParse(v, NumberStyles.Float | NumberStyles.AllowThousands, formatter.NumberFormat, out var doubleValue)) { result = doubleValue; } + else if (float.TryParse(v, NumberStyles.Float, formatter.NumberFormat, out var floatValue)) { result = floatValue; } + else if (double.TryParse(v, NumberStyles.Float, formatter.NumberFormat, out var doubleValue)) { result = doubleValue; } #else - else if (double.TryParse(v, NumberStyles.Float | NumberStyles.AllowThousands, formatter.NumberFormat, out var doubleValue)) + else if (double.TryParse(v, NumberStyles.Float, formatter.NumberFormat, out var doubleValue)) { var floatValue = (float)doubleValue; if (!float.IsNaN(floatValue) && !float.IsInfinity(floatValue)) // .NET 6 or later support float.IsNormal @@ -405,7 +404,6 @@ private static object CastInteger(ulong number, TypeCode typeCode) } } #endif -#pragma warning restore format else { //we couldn't parse it, default to string, It's probably too big From 9f39f5736ee11d4923071a73bd992c158cfe8a7d Mon Sep 17 00:00:00 2001 From: filzrev <103790468+filzrev@users.noreply.github.com> Date: Sat, 26 Oct 2024 10:32:04 +0900 Subject: [PATCH 3/3] chore: remove incorrect comment --- .../Serialization/NodeDeserializers/ScalarNodeDeserializer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YamlDotNet/Serialization/NodeDeserializers/ScalarNodeDeserializer.cs b/YamlDotNet/Serialization/NodeDeserializers/ScalarNodeDeserializer.cs index c0d5b9c0..fd7bcf19 100644 --- a/YamlDotNet/Serialization/NodeDeserializers/ScalarNodeDeserializer.cs +++ b/YamlDotNet/Serialization/NodeDeserializers/ScalarNodeDeserializer.cs @@ -394,7 +394,7 @@ private static object CastInteger(ulong number, TypeCode typeCode) else if (double.TryParse(v, NumberStyles.Float, formatter.NumberFormat, out var doubleValue)) { var floatValue = (float)doubleValue; - if (!float.IsNaN(floatValue) && !float.IsInfinity(floatValue)) // .NET 6 or later support float.IsNormal + if (!float.IsNaN(floatValue) && !float.IsInfinity(floatValue)) { result = floatValue; }