From 47da218cc33c631326b9d77194a6853ea9d568b0 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 18 Feb 2022 07:03:33 -0800 Subject: [PATCH] Remove uintptr_fallback --- include/fmt/format-inl.h | 8 ---- include/fmt/format.h | 91 ++++++++++++++++------------------------ test/format-impl-test.cc | 6 ++- 3 files changed, 40 insertions(+), 65 deletions(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index c4340cf4..ed87209e 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -141,14 +141,6 @@ FMT_FUNC std::system_error vsystem_error(int error_code, string_view format_str, namespace detail { -template <> FMT_FUNC int count_digits<4>(detail::uintptr_fallback n) { - // uintptr_fallback is always stored in little endian. - int i = static_cast(sizeof(void*)) - 1; - while (i > 0 && n.value[i] == 0) --i; - auto char_digits = std::numeric_limits::digits / 4; - return i >= 0 ? i * char_digits + count_digits<4, unsigned>(n.value[i]) : 1; -} - template struct basic_impl_data { // Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. // These are generated by support/compute-powers.py. diff --git a/include/fmt/format.h b/include/fmt/format.h index 2ac466ff..c57d9fff 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -314,31 +314,6 @@ inline auto is_big_endian() -> bool { #endif } -// A fallback implementation of uintptr_t for systems that lack it. -struct uintptr_fallback { - unsigned char value[sizeof(void*)]; - - uintptr_fallback() = default; - explicit uintptr_fallback(const void* p) { - *this = bit_cast(p); - if (const_check(is_big_endian())) { - for (size_t i = 0, j = sizeof(void*) - 1; i < j; ++i, --j) - std::swap(value[i], value[j]); - } - } -}; -#ifdef UINTPTR_MAX -using uintptr_t = ::uintptr_t; -inline auto to_uintptr(const void* p) -> uintptr_t { - return bit_cast(p); -} -#else -using uintptr_t = uintptr_fallback; -inline auto to_uintptr(const void* p) -> uintptr_fallback { - return uintptr_fallback(p); -} -#endif - class uint128_fallback { private: uint64_t lo_, hi_; @@ -356,6 +331,14 @@ class uint128_fallback { const uint128_fallback& rhs) -> bool { return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_; } + friend auto operator!=(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return !(lhs == rhs); + } + friend auto operator|(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> uint128_fallback { + return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_}; + } friend auto operator&(const uint128_fallback& lhs, const uint128_fallback& rhs) -> uint128_fallback { return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_}; @@ -373,7 +356,9 @@ class uint128_fallback { if (shift == 64) return {lo_, 0}; return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)}; } - FMT_CONSTEXPR void operator>>=(int shift) { *this = *this >> shift; } + FMT_CONSTEXPR auto operator>>=(int shift) -> uint128_fallback& { + return *this = *this >> shift; + } FMT_CONSTEXPR void operator+=(uint64_t n) { lo_ += n; if (lo_ < n) ++hi_; @@ -382,6 +367,30 @@ class uint128_fallback { using uint128_t = conditional_t; +#ifdef UINTPTR_MAX +using uintptr_t = ::uintptr_t; +inline auto to_uintptr(const void* p) -> uintptr_t { + return bit_cast(p); +} +#else +using uintptr_t = uint128_t; +#endif + +// A fallback for systems that lack uintptr_t. +template inline auto to_uintptr(const void* p) -> T { + constexpr auto size = static_cast(sizeof(void*)); + struct data_t { + unsigned char value[size]; + } data = bit_cast(p); + auto result = T(); + if (const_check(is_big_endian())) { + for (int i = 0; i < size; ++i) result = (result << 8) | data.value[i]; + } else { + for (int i = size - 1; i >= 0; --i) result = (result << 8) | data.value[i]; + } + return result; +} + // Returns the largest possible value for type T. Same as // std::numeric_limits::max() but shorter and not affected by the max macro. template constexpr auto max_value() -> T { @@ -393,10 +402,6 @@ template constexpr auto num_bits() -> int { // std::numeric_limits::digits may return 0 for 128-bit ints. template <> constexpr auto num_bits() -> int { return 128; } template <> constexpr auto num_bits() -> int { return 128; } -template <> constexpr auto num_bits() -> int { - return static_cast(sizeof(void*) * - std::numeric_limits::digits); -} FMT_INLINE void assume(bool condition) { (void)condition; @@ -1048,8 +1053,6 @@ FMT_CONSTEXPR auto count_digits(UInt n) -> int { }(n); } -template <> auto count_digits<4>(detail::uintptr_fallback n) -> int; - #ifdef FMT_BUILTIN_CLZ // It is a separate function rather than a part of count_digits to workaround // the lack of static constexpr in constexpr functions. @@ -1184,35 +1187,13 @@ FMT_CONSTEXPR auto format_uint(Char* buffer, UInt value, int num_digits, Char* end = buffer; do { const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; - unsigned digit = (value & ((1 << BASE_BITS) - 1)); + unsigned digit = static_cast(value & ((1 << BASE_BITS) - 1)); *--buffer = static_cast(BASE_BITS < 4 ? static_cast('0' + digit) : digits[digit]); } while ((value >>= BASE_BITS) != 0); return end; } -template -auto format_uint(Char* buffer, detail::uintptr_fallback n, int num_digits, - bool = false) -> Char* { - auto char_digits = std::numeric_limits::digits / 4; - int start = (num_digits + char_digits - 1) / char_digits - 1; - if (int start_digits = num_digits % char_digits) { - unsigned value = n.value[start--]; - buffer = format_uint(buffer, value, start_digits); - } - for (; start >= 0; --start) { - unsigned value = n.value[start]; - buffer += char_digits; - auto p = buffer; - for (int i = 0; i < char_digits; ++i) { - unsigned digit = (value & ((1 << BASE_BITS) - 1)); - *--p = static_cast("0123456789abcdef"[digit]); - value >>= BASE_BITS; - } - } - return buffer; -} - template inline auto format_uint(It out, UInt value, int num_digits, bool upper = false) -> It { diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 194cfa92..2cdc2899 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -340,11 +340,13 @@ TEST(format_impl_test, count_digits) { test_count_digits(); } -TEST(format_impl_test, write_fallback_uintptr) { +TEST(format_impl_test, write_uintptr_fallback) { std::string s; fmt::detail::write_ptr( std::back_inserter(s), - fmt::detail::uintptr_fallback(reinterpret_cast(0xface)), nullptr); + fmt::detail::to_uintptr( + reinterpret_cast(0xface)), + nullptr); EXPECT_EQ(s, "0xface"); }