diff --git a/src/util/format/builder.cpp b/src/util/format/builder.cpp index 5b31f7e..5bff2ab 100644 --- a/src/util/format/builder.cpp +++ b/src/util/format/builder.cpp @@ -6,6 +6,7 @@ #include // min #include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t #include // setprecision #include // defaultfloat, fixed #include // numeric_limits @@ -28,9 +29,42 @@ void Builder::putLiteral(std::string_view literal) } } -void Builder::putU64(size_t value, char fill, Align align, Sign sign, bool zeroPadding, size_t width, bool isNegative) const +static constexpr std::string numberToString(size_t value, uint8_t base, bool uppercase) { - std::string string = (std::stringstream {} << value).str(); + std::string result; + + if (value > std::numeric_limits::max()) { + result.reserve(64); + } + else if (value > std::numeric_limits::max()) { + result.reserve(32); + } + + constexpr const auto& lookupLowercase = "0123456789abcdef"; + constexpr const auto& lookupUppercase = "0123456789ABCDEF"; + + if (value == 0) { + result = '0'; + } + else if (uppercase) { + while (value > 0) { + result.insert(0, 1, lookupUppercase[value % base]); + value /= base; + } + } + else { + while (value > 0) { + result.insert(0, 1, lookupLowercase[value % base]); + value /= base; + } + } + + return result; +} + +void Builder::putU64(size_t value, uint8_t base, bool uppercase, char fill, Align align, Sign sign, bool zeroPadding, size_t width, bool isNegative) const +{ + std::string string = numberToString(value, base, uppercase); // Sign std::string signCharacter = ""; @@ -96,11 +130,11 @@ void Builder::putU64(size_t value, char fill, Align align, Sign sign, bool zeroP }; } -void Builder::putI64(int64_t value, char fill, Align align, Sign sign, bool zeroPadding, size_t width) const +void Builder::putI64(int64_t value, uint8_t base, bool uppercase, char fill, Align align, Sign sign, bool zeroPadding, size_t width) const { bool isNegative = value < 0; value = isNegative ? -value : value; - putU64(static_cast(value), fill, align, sign, zeroPadding, width, isNegative); + putU64(static_cast(value), base, uppercase, fill, align, sign, zeroPadding, width, isNegative); } void Builder::putF64(double number, uint8_t precision) const diff --git a/src/util/format/builder.h b/src/util/format/builder.h index 5e3745b..c03afc6 100644 --- a/src/util/format/builder.h +++ b/src/util/format/builder.h @@ -36,8 +36,8 @@ public: void putLiteral(std::string_view literal); - void putU64(size_t value, char fill = ' ', Align align = Align::Right, Sign sign = Sign::Negative, bool zeroPadding = false, size_t width = 0, bool isNegative = false) const; - void putI64(int64_t value, char fill = ' ', Align align = Align::Right, Sign sign = Sign::Negative, bool zeroPadding = false, size_t width = 0) const; + void putU64(size_t value, uint8_t base = 10, bool uppercase = false, char fill = ' ', Align align = Align::Right, Sign sign = Sign::Negative, bool zeroPadding = false, size_t width = 0, bool isNegative = false) const; + void putI64(int64_t value, uint8_t base = 10, bool uppercase = false, char fill = ' ', Align align = Align::Right, Sign sign = Sign::Negative, bool zeroPadding = false, size_t width = 0) const; void putF64(double number, uint8_t precision = 6) const; void putCharacter(char character) const { m_builder.write(&character, 1); } void putString(std::string_view string, char fill = ' ', Align align = Align::Left, size_t width = 0) const; diff --git a/src/util/format/formatter.h b/src/util/format/formatter.h index 6b8bc75..f30702a 100644 --- a/src/util/format/formatter.h +++ b/src/util/format/formatter.h @@ -6,6 +6,7 @@ #pragma once +#include #include // size_t #include // int8_t, int32_t, int64_t, uint8_t, uint32_t #include @@ -91,14 +92,38 @@ struct Formatter { void format(Builder& builder, T value) const { - if (std::is_signed_v) { - builder.putI64( - value, specifier.fill, specifier.align, specifier.sign, + uint8_t base = 0; + bool uppercase = false; + switch (specifier.type) { + case PresentationType::BinaryUppercase: + uppercase = true; + case PresentationType::Binary: + base = 2; + break; + case PresentationType::Octal: + base = 8; + break; + case PresentationType::None: + case PresentationType::Decimal: + base = 10; + break; + case PresentationType::HexUppercase: + uppercase = true; + case PresentationType::Hex: + base = 16; + break; + default: + assert(false); + }; + + if constexpr (std::is_unsigned_v) { + builder.putU64( + value, base, uppercase, specifier.fill, specifier.align, specifier.sign, specifier.zeroPadding, specifier.width); } - if (std::is_unsigned_v) { - builder.putU64( - value, specifier.fill, specifier.align, specifier.sign, + else { + builder.putI64( + value, base, uppercase, specifier.fill, specifier.align, specifier.sign, specifier.zeroPadding, specifier.width); } }