From 432f8281d2a1b7721405dc88683e252a353b8044 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] 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..b7a7c9e8 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 NET47 + 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