Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions include/util/DigitCounter.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,31 @@ namespace OpenShock::Util {
template<typename T>
constexpr std::size_t Digits10Count(T val)
{
static_assert(std::is_integral_v<T>);
using Decayed = std::remove_cv_t<std::remove_reference_t<T>>;
static_assert(std::is_integral_v<Decayed>);

using U = std::make_unsigned_t<Decayed>;

std::size_t digits = 1;
U u;

if constexpr (std::is_signed_v<T> && val < 0) {
digits++;
val = -val;
if constexpr (std::is_signed_v<Decayed>) {
if (val < 0) {
// Account for the sign
digits++;

// Safe magnitude via unsigned modular negation
u = U(0) - static_cast<U>(val);
} else {
u = static_cast<U>(val);
}
} else {
u = static_cast<U>(val);
}

while (val >= 10) {
val /= 10;
// Now count digits of u (magnitude), base-10
while (u >= 10) {
u /= 10;
digits++;
}

Expand Down
32 changes: 24 additions & 8 deletions src/Convert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,38 @@ void fromNonZeroT(T val, std::string& out)
{
// Ensure the template type T is an integral type
static_assert(std::is_integral_v<T>, "T must be an integral type");
using U = std::make_unsigned_t<T>;

constexpr std::size_t MaxDigits = OpenShock::Util::Digits10CountMax<T>;

char buf[MaxDigits];

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

bool negative = val < 0;
if (negative) {
val = -val; // Make the value positive for digit extraction
U u;
bool negative = false;

if constexpr (std::is_signed_v<T>) {
if (val < 0) {
negative = true;

// Convert to unsigned, then take the modular negation.
// This is well-defined and yields the magnitude of val.
u = U(0) - U(val);
} else {
u = U(val);
}
} else {
// Unsigned types: just use the value as-is.
u = U(val);
}

// Extract digits and store them in reverse order in the buffer
while (val > 0) {
*--ptr = '0' + (val % 10);
val /= 10;
while (u > 0) {
*--ptr = char('0' + (u % 10));
u /= 10;
}

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

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

// Base converter
Expand Down