diff --git a/include/fmt/core.h b/include/fmt/core.h index d8baed9e..db6cf669 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -390,7 +390,35 @@ template inline auto convert_for_visit(T value) -> T { #endif #if !FMT_USE_INT128 enum class int128_t {}; -enum class uint128_t {}; +class uint128_t { + private: + uint64_t lo_, hi_; + constexpr uint128_t(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {} + + public: + constexpr uint128_t(uint64_t value = 0) : hi_(0), lo_(value) {} + explicit operator int() const { return lo_; } + explicit operator uint64_t() const { return lo_; } + friend auto operator==(const uint128_t& lhs, const uint128_t& rhs) -> bool { + return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_; + } + friend auto operator&(const uint128_t& lhs, const uint128_t& rhs) + -> uint128_t { + return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_}; + } + friend auto operator-(const uint128_t& lhs, uint64_t rhs) -> uint128_t { + FMT_ASSERT(lhs.lo_ >= rhs, ""); + return {lhs.hi_, lhs.lo_ - rhs}; + } + auto operator>>(int shift) const -> uint128_t { + if (shift == 64) return {0, hi_}; + return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)}; + } + auto operator<<(int shift) const -> uint128_t { + if (shift == 64) return {lo_, 0}; + return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)}; + } +}; // Reduce template instantiations. template inline auto convert_for_visit(T) -> monostate { return {}; @@ -1431,7 +1459,8 @@ template struct arg_mapper { !std::is_const>::value || has_fallback_formatter::value> {}; -#if (FMT_MSC_VER != 0 && FMT_MSC_VER < 1910) || FMT_ICC_VERSION != 0 || FMT_NVCC != 0 +#if (FMT_MSC_VER != 0 && FMT_MSC_VER < 1910) || FMT_ICC_VERSION != 0 || \ + FMT_NVCC != 0 // Workaround a bug in MSVC and Intel (Issue 2746). template FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& { return val; diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index b2e6a14a..87663901 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -259,7 +259,7 @@ struct fp { using carrier_uint = typename dragonbox::float_info::carrier_uint; const carrier_uint significand_mask = implicit_bit - 1; auto u = bit_cast(n); - f = u & significand_mask; + f = static_cast(u & significand_mask); int biased_e = static_cast((u & exponent_mask()) >> dragonbox::float_info::significand_bits); diff --git a/test/core-test.cc b/test/core-test.cc index a040d241..fcc988b1 100644 --- a/test/core-test.cc +++ b/test/core-test.cc @@ -33,6 +33,33 @@ using testing::Return; # error core-test includes format.h #endif +TEST(uint128_test, ctor) { + using fmt::detail::uint128_t; + auto n = uint128_t(); + EXPECT_EQ(n, 0); + n = uint128_t(42); + EXPECT_EQ(n, 42); + EXPECT_EQ(static_cast(n), 42); +} + +TEST(uint128_test, shift) { + auto n = fmt::detail::uint128_t(42); + n = n << 64; + EXPECT_EQ(static_cast(n), 0); + n = n >> 64; + EXPECT_EQ(static_cast(n), 42); + n = n << 62; + EXPECT_EQ(static_cast(n >> 64), 0xa); + EXPECT_EQ(static_cast(n), 0x8000000000000000); + n = n >> 62; + EXPECT_EQ(static_cast(n), 42); +} + +TEST(uint128_test, minus) { + auto n = fmt::detail::uint128_t(42); + EXPECT_EQ(n - 2, 40); +} + TEST(string_view_test, value_type) { static_assert(std::is_same::value, ""); }