Skip to content

Commit b3a3a3e

Browse files
authored
Merge pull request #3 from adienakhmad/fix/ut8format-float
fix Ut8Formatter when formatting floating-point whole number
2 parents fbd0ac2 + 7fc5a2e commit b3a3a3e

File tree

2 files changed

+116
-2
lines changed

2 files changed

+116
-2
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using System.Globalization;
2+
using System.Text;
3+
using Hexa.NET.Utilities.Text;
4+
5+
namespace Hexa.NET.Utilities.Tests;
6+
7+
public class Utf8FormatterTests
8+
{
9+
[TestCase(1f, 0, "1")]
10+
[TestCase(10f, 0, "10")]
11+
[TestCase(0.5f, 1, "0.5")]
12+
[TestCase(0.75f, 2, "0.75")]
13+
[TestCase(0.125f, 3, "0.125")]
14+
[TestCase(0.0625f, 4, "0.0625")]
15+
[TestCase(0.03125f, 5, "0.03125")]
16+
[TestCase(0.015625f, 6, "0.015625")]
17+
[TestCase(0.0078125f, 7, "0.0078125")]
18+
public unsafe void FormatFloatTest(float value, int digit, string expected)
19+
{
20+
// Arrange
21+
byte* buffer = stackalloc byte[128];
22+
23+
// Act
24+
int len = Utf8Formatter.Format(value, buffer, 128, CultureInfo.InvariantCulture, digit);
25+
ReadOnlySpan<byte> utf8Span = new ReadOnlySpan<byte>(buffer, len);
26+
27+
// Assert
28+
Assert.That(Encoding.UTF8.GetString(utf8Span), Is.EqualTo(expected));
29+
}
30+
31+
[TestCase(1, 0, "1")]
32+
[TestCase(10, 0, "10")]
33+
[TestCase(0.5, 1, "0.5")]
34+
[TestCase(0.75, 2, "0.75")]
35+
[TestCase(0.125, 3, "0.125")]
36+
[TestCase(0.0625, 4, "0.0625")]
37+
[TestCase(0.03125, 5, "0.03125")]
38+
[TestCase(0.015625, 6, "0.015625")]
39+
[TestCase(0.0078125, 7, "0.0078125")]
40+
public unsafe void FormatDoubleTest(double value, int digit, string expected)
41+
{
42+
// Arrange
43+
byte* buffer = stackalloc byte[128];
44+
45+
// Act
46+
int len = Utf8Formatter.Format(value, buffer, 128, CultureInfo.InvariantCulture, digit);
47+
ReadOnlySpan<byte> utf8Span = new ReadOnlySpan<byte>(buffer, len);
48+
49+
// Assert
50+
Assert.That(Encoding.UTF8.GetString(utf8Span), Is.EqualTo(expected));
51+
}
52+
53+
[TestCase(10, 0, ".","10")]
54+
[TestCase(10, 0, "\uFF0C","10")]
55+
[TestCase(0.75f, 2, ".","0.75")]
56+
[TestCase(0.75f, 2, "\uFF0C","0\uFF0C75")]
57+
public unsafe void FormatFloatCultureTest(float value, int digit, string separator, string expected)
58+
{
59+
// Arrange
60+
byte* buffer = stackalloc byte[128];
61+
var culture = new CultureInfo( "", false )
62+
{
63+
NumberFormat =
64+
{
65+
CurrencyDecimalSeparator = separator
66+
}
67+
};
68+
69+
// Act
70+
int len = Utf8Formatter.Format(value, buffer, 128, culture, digit);
71+
ReadOnlySpan<byte> utf8Span = new ReadOnlySpan<byte>(buffer, len);
72+
73+
// Assert
74+
Assert.That(Encoding.UTF8.GetString(utf8Span), Is.EqualTo(expected));
75+
}
76+
77+
[TestCase(10, 0, ".","10")]
78+
[TestCase(10, 0, "\uFF0C","10")]
79+
[TestCase(0.75, 2, ".","0.75")]
80+
[TestCase(0.75, 2, "\uFF0C","0\uFF0C75")]
81+
public unsafe void FormatDoubleCultureTest(double value, int digit, string separator, string expected)
82+
{
83+
// Arrange
84+
byte* buffer = stackalloc byte[128];
85+
var culture = new CultureInfo( "", false )
86+
{
87+
NumberFormat =
88+
{
89+
CurrencyDecimalSeparator = separator
90+
}
91+
};
92+
93+
// Act
94+
int len = Utf8Formatter.Format(value, buffer, 128, culture, digit);
95+
var utf8Span = new ReadOnlySpan<byte>(buffer, len);
96+
97+
// Assert
98+
Assert.That(Encoding.UTF8.GetString(utf8Span), Is.EqualTo(expected));
99+
}
100+
}

Hexa.NET.Utilities/Text/Utf8Formatter.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,9 @@ public static unsafe int Format(float value, byte* buffer, int bufSize, CultureI
328328
return (int)(buffer - start);
329329
}
330330

331+
byte* beforeSeparator = buffer;
331332
buffer += ConvertUtf16ToUtf8(format.CurrencyDecimalSeparator, buffer, (int)(end - buffer));
333+
byte* afterSeparator = buffer;
332334

333335
digits = digits >= 0 ? digits : 7;
334336

@@ -342,11 +344,16 @@ public static unsafe int Format(float value, byte* buffer, int bufSize, CultureI
342344
if (fraction < 1e-14) break;
343345
}
344346

345-
while (*(buffer - 1) == '0' || *(buffer - 1) == '.')
347+
while (buffer != afterSeparator && *(buffer - 1) == '0')
346348
{
347349
buffer--;
348350
}
349351

352+
if (buffer == afterSeparator)
353+
{
354+
buffer = beforeSeparator;
355+
}
356+
350357
end:
351358
*buffer = 0;
352359
return (int)(buffer - start);
@@ -406,7 +413,9 @@ public static unsafe int Format(double value, byte* buffer, int bufSize, Culture
406413
return (int)(buffer - start);
407414
}
408415

416+
byte* beforeSeparator = buffer;
409417
buffer += ConvertUtf16ToUtf8(format.CurrencyDecimalSeparator, buffer, (int)(end - buffer));
418+
byte* afterSeparator = buffer;
410419

411420
digits = digits >= 0 ? digits : 7;
412421

@@ -420,11 +429,16 @@ public static unsafe int Format(double value, byte* buffer, int bufSize, Culture
420429
if (fraction < 1e-14) break;
421430
}
422431

423-
while (*(buffer - 1) == '0' || *(buffer - 1) == '.')
432+
while (buffer != afterSeparator && *(buffer - 1) == '0')
424433
{
425434
buffer--;
426435
}
427436

437+
if (buffer == afterSeparator)
438+
{
439+
buffer = beforeSeparator;
440+
}
441+
428442
end:
429443
*buffer = 0;
430444
return (int)(buffer - start);

0 commit comments

Comments
 (0)