diff --git a/Hexa.NET.Utilities.Tests/Utf8FormatterTests.cs b/Hexa.NET.Utilities.Tests/Utf8FormatterTests.cs new file mode 100644 index 0000000..e7d282a --- /dev/null +++ b/Hexa.NET.Utilities.Tests/Utf8FormatterTests.cs @@ -0,0 +1,100 @@ +using System.Globalization; +using System.Text; +using Hexa.NET.Utilities.Text; + +namespace Hexa.NET.Utilities.Tests; + +public class Utf8FormatterTests +{ + [TestCase(1f, 0, "1")] + [TestCase(10f, 0, "10")] + [TestCase(0.5f, 1, "0.5")] + [TestCase(0.75f, 2, "0.75")] + [TestCase(0.125f, 3, "0.125")] + [TestCase(0.0625f, 4, "0.0625")] + [TestCase(0.03125f, 5, "0.03125")] + [TestCase(0.015625f, 6, "0.015625")] + [TestCase(0.0078125f, 7, "0.0078125")] + public unsafe void FormatFloatTest(float value, int digit, string expected) + { + // Arrange + byte* buffer = stackalloc byte[128]; + + // Act + int len = Utf8Formatter.Format(value, buffer, 128, CultureInfo.InvariantCulture, digit); + ReadOnlySpan utf8Span = new ReadOnlySpan(buffer, len); + + // Assert + Assert.That(Encoding.UTF8.GetString(utf8Span), Is.EqualTo(expected)); + } + + [TestCase(1, 0, "1")] + [TestCase(10, 0, "10")] + [TestCase(0.5, 1, "0.5")] + [TestCase(0.75, 2, "0.75")] + [TestCase(0.125, 3, "0.125")] + [TestCase(0.0625, 4, "0.0625")] + [TestCase(0.03125, 5, "0.03125")] + [TestCase(0.015625, 6, "0.015625")] + [TestCase(0.0078125, 7, "0.0078125")] + public unsafe void FormatDoubleTest(double value, int digit, string expected) + { + // Arrange + byte* buffer = stackalloc byte[128]; + + // Act + int len = Utf8Formatter.Format(value, buffer, 128, CultureInfo.InvariantCulture, digit); + ReadOnlySpan utf8Span = new ReadOnlySpan(buffer, len); + + // Assert + Assert.That(Encoding.UTF8.GetString(utf8Span), Is.EqualTo(expected)); + } + + [TestCase(10, 0, ".","10")] + [TestCase(10, 0, "\uFF0C","10")] + [TestCase(0.75f, 2, ".","0.75")] + [TestCase(0.75f, 2, "\uFF0C","0\uFF0C75")] + public unsafe void FormatFloatCultureTest(float value, int digit, string separator, string expected) + { + // Arrange + byte* buffer = stackalloc byte[128]; + var culture = new CultureInfo( "", false ) + { + NumberFormat = + { + CurrencyDecimalSeparator = separator + } + }; + + // Act + int len = Utf8Formatter.Format(value, buffer, 128, culture, digit); + ReadOnlySpan utf8Span = new ReadOnlySpan(buffer, len); + + // Assert + Assert.That(Encoding.UTF8.GetString(utf8Span), Is.EqualTo(expected)); + } + + [TestCase(10, 0, ".","10")] + [TestCase(10, 0, "\uFF0C","10")] + [TestCase(0.75, 2, ".","0.75")] + [TestCase(0.75, 2, "\uFF0C","0\uFF0C75")] + public unsafe void FormatDoubleCultureTest(double value, int digit, string separator, string expected) + { + // Arrange + byte* buffer = stackalloc byte[128]; + var culture = new CultureInfo( "", false ) + { + NumberFormat = + { + CurrencyDecimalSeparator = separator + } + }; + + // Act + int len = Utf8Formatter.Format(value, buffer, 128, culture, digit); + var utf8Span = new ReadOnlySpan(buffer, len); + + // Assert + Assert.That(Encoding.UTF8.GetString(utf8Span), Is.EqualTo(expected)); + } +} \ No newline at end of file diff --git a/Hexa.NET.Utilities/Text/Utf8Formatter.cs b/Hexa.NET.Utilities/Text/Utf8Formatter.cs index fc771c0..192afc3 100644 --- a/Hexa.NET.Utilities/Text/Utf8Formatter.cs +++ b/Hexa.NET.Utilities/Text/Utf8Formatter.cs @@ -326,7 +326,9 @@ public static unsafe int Format(float value, byte* buffer, int bufSize, CultureI return (int)(buffer - start); } + byte* beforeSeparator = buffer; buffer += ConvertUtf16ToUtf8(format.CurrencyDecimalSeparator, buffer, (int)(end - buffer)); + byte* afterSeparator = buffer; digits = digits >= 0 ? digits : 7; @@ -340,11 +342,16 @@ public static unsafe int Format(float value, byte* buffer, int bufSize, CultureI if (fraction < 1e-14) break; } - while (*(buffer - 1) == '0' || *(buffer - 1) == '.') + while (buffer != afterSeparator && *(buffer - 1) == '0') { buffer--; } + if (buffer == afterSeparator) + { + buffer = beforeSeparator; + } + end: *buffer = 0; return (int)(buffer - start); @@ -404,7 +411,9 @@ public static unsafe int Format(double value, byte* buffer, int bufSize, Culture return (int)(buffer - start); } + byte* beforeSeparator = buffer; buffer += ConvertUtf16ToUtf8(format.CurrencyDecimalSeparator, buffer, (int)(end - buffer)); + byte* afterSeparator = buffer; digits = digits >= 0 ? digits : 7; @@ -418,11 +427,16 @@ public static unsafe int Format(double value, byte* buffer, int bufSize, Culture if (fraction < 1e-14) break; } - while (*(buffer - 1) == '0' || *(buffer - 1) == '.') + while (buffer != afterSeparator && *(buffer - 1) == '0') { buffer--; } + if (buffer == afterSeparator) + { + buffer = beforeSeparator; + } + end: *buffer = 0; return (int)(buffer - start);