diff --git a/au/code/au/magnitude.hh b/au/code/au/magnitude.hh index 3a4daf35..4e811df2 100644 --- a/au/code/au/magnitude.hh +++ b/au/code/au/magnitude.hh @@ -604,7 +604,7 @@ constexpr const bool MagnitudeLabelImplementation::has_exposed_s template struct MagnitudeLabelImplementation - : detail::IToA(MagT{})> { + : detail::UIToA(MagT{})> { static constexpr const bool has_exposed_slash = false; }; template diff --git a/au/code/au/utility/string_constant.hh b/au/code/au/utility/string_constant.hh index 451444ac..b1b9e211 100644 --- a/au/code/au/utility/string_constant.hh +++ b/au/code/au/utility/string_constant.hh @@ -87,12 +87,8 @@ struct IToA; // Implementation details below. //////////////////////////////////////////////////////////////////////////////////////////////////// -// The string-length needed to hold a representation of this integer. -constexpr std::size_t string_size(int64_t x) { - if (x < 0) { - return string_size(-x) + 1; - } - +// The string-length needed to hold a representation of this unsigned integer. +constexpr std::size_t string_size_unsigned(uint64_t x) { std::size_t digits = 1; while (x > 9) { x /= 10; @@ -101,6 +97,16 @@ constexpr std::size_t string_size(int64_t x) { return digits; } +// The string-length needed to hold a representation of this integer. +constexpr std::size_t string_size(int64_t x) { + std::size_t sign_length = 0u; + if (x < 0) { + x = -x; + ++sign_length; + } + return string_size_unsigned(static_cast(x)) + sign_length; +} + // The sum of the template parameters. template constexpr std::size_t sum() { @@ -201,33 +207,52 @@ constexpr auto join_by(const SepT &sep, const StringTs &...ts) { return as_string_constant(sep).join(as_string_constant(ts)...); } -template -struct IToA { +template +struct UIToA { private: static constexpr auto print_to_array() { - char data[length + 1] = {'\0'}; - - int num = N; - if (num < 0) { - data[0] = '-'; - num = -num; - } + char data[length + 1u] = {'\0'}; + uint64_t num = N; std::size_t i = length - 1; do { - data[i--] = '0' + static_cast(num % 10); - num /= 10; - } while (num > 0); + data[i--] = '0' + static_cast(num % 10u); + num /= 10u; + } while (num > 0u); return StringConstant{data}; } public: - static constexpr std::size_t length = string_size(N); + static constexpr std::size_t length = string_size_unsigned(N); static constexpr StringConstant value = print_to_array(); }; +// Definitions for UIToA::value. (Needed to prevent linker errors.) +template +constexpr std::size_t UIToA::length; +template +constexpr StringConstant::length> UIToA::value; + +template +struct SignIfPositiveIs { + static constexpr StringConstant<0> value() { return ""; } +}; +template <> +struct SignIfPositiveIs { + static constexpr StringConstant<1> value() { return "-"; } +}; + +template +struct IToA { + static constexpr std::size_t length = string_size(N); + + static constexpr StringConstant value = + concatenate(SignIfPositiveIs<(N >= 0)>::value(), + UIToA((N) >= 0) ? N : -N>::value); +}; + // Definitions for IToA::value. (Needed to prevent linker errors.) template constexpr std::size_t IToA::length; diff --git a/au/code/au/utility/test/string_constant_test.cc b/au/code/au/utility/test/string_constant_test.cc index eee992c3..d9983f62 100644 --- a/au/code/au/utility/test/string_constant_test.cc +++ b/au/code/au/utility/test/string_constant_test.cc @@ -66,6 +66,10 @@ TEST(IToA, HasLengthMember) { EXPECT_EQ(IToA<-12345>::length, 6); } +TEST(UIToA, CanHandleNumbersBiggerThanIntmaxButWithinUintmax) { + EXPECT_STREQ(UIToA<10000000000000000000u>::value.c_str(), "10000000000000000000"); +} + TEST(join, EmptyStringForNoArguments) { constexpr auto x = as_string_constant("sep").join(); EXPECT_STREQ(x.c_str(), "");