Skip to content

Commit e3a8a75

Browse files
authored
fix: Integer conversion logic (#394)
1 parent 9bebff8 commit e3a8a75

File tree

2 files changed

+44
-14
lines changed

2 files changed

+44
-14
lines changed

include/util/DigitCounter.h

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,31 @@ namespace OpenShock::Util {
1111
template<typename T>
1212
constexpr std::size_t Digits10Count(T val)
1313
{
14-
static_assert(std::is_integral_v<T>);
14+
using Decayed = std::remove_cv_t<std::remove_reference_t<T>>;
15+
static_assert(std::is_integral_v<Decayed>);
16+
17+
using U = std::make_unsigned_t<Decayed>;
1518

1619
std::size_t digits = 1;
20+
U u;
1721

18-
if constexpr (std::is_signed_v<T> && val < 0) {
19-
digits++;
20-
val = -val;
22+
if constexpr (std::is_signed_v<Decayed>) {
23+
if (val < 0) {
24+
// Account for the sign
25+
digits++;
26+
27+
// Safe magnitude via unsigned modular negation
28+
u = U(0) - static_cast<U>(val);
29+
} else {
30+
u = static_cast<U>(val);
31+
}
32+
} else {
33+
u = static_cast<U>(val);
2134
}
2235

23-
while (val >= 10) {
24-
val /= 10;
36+
// Now count digits of u (magnitude), base-10
37+
while (u >= 10) {
38+
u /= 10;
2539
digits++;
2640
}
2741

src/Convert.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,38 @@ void fromNonZeroT(T val, std::string& out)
1717
{
1818
// Ensure the template type T is an integral type
1919
static_assert(std::is_integral_v<T>, "T must be an integral type");
20+
using U = std::make_unsigned_t<T>;
21+
2022
constexpr std::size_t MaxDigits = OpenShock::Util::Digits10CountMax<T>;
2123

2224
char buf[MaxDigits];
2325

2426
// Start from the end of the buffer to construct the number in reverse (from least to most significant digit)
25-
char* ptr = buf + MaxDigits;
27+
char* const end = buf + MaxDigits;
28+
char* ptr = end;
2629

27-
bool negative = val < 0;
28-
if (negative) {
29-
val = -val; // Make the value positive for digit extraction
30+
U u;
31+
bool negative = false;
32+
33+
if constexpr (std::is_signed_v<T>) {
34+
if (val < 0) {
35+
negative = true;
36+
37+
// Convert to unsigned, then take the modular negation.
38+
// This is well-defined and yields the magnitude of val.
39+
u = U(0) - U(val);
40+
} else {
41+
u = U(val);
42+
}
43+
} else {
44+
// Unsigned types: just use the value as-is.
45+
u = U(val);
3046
}
3147

3248
// Extract digits and store them in reverse order in the buffer
33-
while (val > 0) {
34-
*--ptr = '0' + (val % 10);
35-
val /= 10;
49+
while (u > 0) {
50+
*--ptr = char('0' + (u % 10));
51+
u /= 10;
3652
}
3753

3854
// If the number was negative, add the negative sign
@@ -41,7 +57,7 @@ void fromNonZeroT(T val, std::string& out)
4157
}
4258

4359
// Append the resulting string to the output
44-
out.append(ptr, buf + MaxDigits);
60+
out.append(ptr, end - ptr);
4561
}
4662

4763
// Base converter

0 commit comments

Comments
 (0)