mirror of
https://github.com/fmtlib/fmt.git
synced 2026-02-06 01:39:55 +08:00
uint128_fallback -> uint128
This commit is contained in:
parent
6322cf0520
commit
b98926b73b
@ -404,9 +404,9 @@ inline auto map(native_uint128 x) -> native_uint128 { return x; }
|
||||
# define FMT_USE_INT128 0
|
||||
#endif
|
||||
#if !FMT_USE_INT128
|
||||
enum class native_int128 {}; // A fallback to reduce conditional compilation.
|
||||
// Fallbacks to reduce conditional compilation and SFINAE.
|
||||
enum class native_int128 {};
|
||||
enum class native_uint128 {};
|
||||
// Reduce template instantiations.
|
||||
inline auto map(native_int128) -> monostate { return {}; }
|
||||
inline auto map(native_uint128) -> monostate { return {}; }
|
||||
#endif
|
||||
|
||||
@ -209,10 +209,9 @@ inline auto umul96_upper64(uint32_t x, uint64_t y) noexcept -> uint64_t {
|
||||
|
||||
// Computes lower 128 bits of multiplication of a 64-bit unsigned integer and a
|
||||
// 128-bit unsigned integer.
|
||||
inline auto umul192_lower128(uint64_t x, uint128_fallback y) noexcept
|
||||
-> uint128_fallback {
|
||||
inline auto umul192_lower128(uint64_t x, uint128 y) noexcept -> uint128 {
|
||||
uint64_t high = x * y.high();
|
||||
uint128_fallback high_low = umul128(x, y.low());
|
||||
uint128 high_low = umul128(x, y.low());
|
||||
return {high + high_low.high(), high_low.low()};
|
||||
}
|
||||
|
||||
@ -380,13 +379,13 @@ template <> struct cache_accessor<float> {
|
||||
|
||||
template <> struct cache_accessor<double> {
|
||||
using carrier_uint = float_info<double>::carrier_uint;
|
||||
using cache_entry_type = uint128_fallback;
|
||||
using cache_entry_type = uint128;
|
||||
|
||||
static auto get_cached_power(int k) noexcept -> uint128_fallback {
|
||||
static auto get_cached_power(int k) noexcept -> uint128 {
|
||||
FMT_ASSERT(k >= float_info<double>::min_k && k <= float_info<double>::max_k,
|
||||
"k is out of range");
|
||||
|
||||
static constexpr uint128_fallback pow10_significands[] = {
|
||||
static constexpr uint128 pow10_significands[] = {
|
||||
#if FMT_USE_FULL_CACHE_DRAGONBOX
|
||||
{0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b},
|
||||
{0x9faacf3df73609b1, 0x77b191618c54e9ad},
|
||||
@ -1072,7 +1071,7 @@ template <> struct cache_accessor<double> {
|
||||
int offset = k - kb;
|
||||
|
||||
// Get base cache.
|
||||
uint128_fallback base_cache = pow10_significands[cache_index];
|
||||
uint128 base_cache = pow10_significands[cache_index];
|
||||
if (offset == 0) return base_cache;
|
||||
|
||||
// Compute the required amount of bit-shift.
|
||||
@ -1081,17 +1080,16 @@ template <> struct cache_accessor<double> {
|
||||
|
||||
// Try to recover the real cache.
|
||||
uint64_t pow5 = powers_of_5_64[offset];
|
||||
uint128_fallback recovered_cache = umul128(base_cache.high(), pow5);
|
||||
uint128_fallback middle_low = umul128(base_cache.low(), pow5);
|
||||
uint128 recovered_cache = umul128(base_cache.high(), pow5);
|
||||
uint128 middle_low = umul128(base_cache.low(), pow5);
|
||||
|
||||
recovered_cache += middle_low.high();
|
||||
|
||||
uint64_t high_to_middle = recovered_cache.high() << (64 - alpha);
|
||||
uint64_t middle_to_low = recovered_cache.low() << (64 - alpha);
|
||||
|
||||
recovered_cache =
|
||||
uint128_fallback{(recovered_cache.low() >> alpha) | high_to_middle,
|
||||
((middle_low.low() >> alpha) | middle_to_low)};
|
||||
recovered_cache = uint128{(recovered_cache.low() >> alpha) | high_to_middle,
|
||||
((middle_low.low() >> alpha) | middle_to_low)};
|
||||
FMT_ASSERT(recovered_cache.low() + 1 != 0, "");
|
||||
return {recovered_cache.high(), recovered_cache.low() + 1};
|
||||
#endif
|
||||
@ -1152,7 +1150,7 @@ template <> struct cache_accessor<double> {
|
||||
}
|
||||
};
|
||||
|
||||
FMT_FUNC auto get_cached_power(int k) noexcept -> uint128_fallback {
|
||||
FMT_FUNC auto get_cached_power(int k) noexcept -> uint128 {
|
||||
return cache_accessor<double>::get_cached_power(k);
|
||||
}
|
||||
|
||||
|
||||
@ -291,13 +291,13 @@ inline auto is_big_endian() -> bool {
|
||||
#endif
|
||||
}
|
||||
|
||||
class uint128_fallback {
|
||||
class uint128 {
|
||||
private:
|
||||
uint64_t lo_, hi_;
|
||||
|
||||
public:
|
||||
constexpr uint128_fallback(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {}
|
||||
constexpr uint128_fallback(uint64_t value = 0) : lo_(value), hi_(0) {}
|
||||
constexpr uint128(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {}
|
||||
constexpr uint128(uint64_t value = 0) : lo_(value), hi_(0) {}
|
||||
|
||||
constexpr auto high() const noexcept -> uint64_t { return hi_; }
|
||||
constexpr auto low() const noexcept -> uint64_t { return lo_; }
|
||||
@ -307,77 +307,69 @@ class uint128_fallback {
|
||||
return static_cast<T>(lo_);
|
||||
}
|
||||
|
||||
friend constexpr auto operator==(const uint128_fallback& lhs,
|
||||
const uint128_fallback& rhs) -> bool {
|
||||
friend constexpr auto operator==(const uint128& lhs, const uint128& rhs)
|
||||
-> bool {
|
||||
return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_;
|
||||
}
|
||||
friend constexpr auto operator!=(const uint128_fallback& lhs,
|
||||
const uint128_fallback& rhs) -> bool {
|
||||
friend constexpr auto operator!=(const uint128& lhs, const uint128& rhs)
|
||||
-> bool {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
friend constexpr auto operator>(const uint128_fallback& lhs,
|
||||
const uint128_fallback& rhs) -> bool {
|
||||
friend constexpr auto operator>(const uint128& lhs, const uint128& rhs)
|
||||
-> bool {
|
||||
return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_;
|
||||
}
|
||||
friend constexpr auto operator|(const uint128_fallback& lhs,
|
||||
const uint128_fallback& rhs)
|
||||
-> uint128_fallback {
|
||||
friend constexpr auto operator|(const uint128& lhs, const uint128& rhs)
|
||||
-> uint128 {
|
||||
return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_};
|
||||
}
|
||||
friend constexpr auto operator&(const uint128_fallback& lhs,
|
||||
const uint128_fallback& rhs)
|
||||
-> uint128_fallback {
|
||||
friend constexpr auto operator&(const uint128& lhs, const uint128& rhs)
|
||||
-> uint128 {
|
||||
return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_};
|
||||
}
|
||||
friend constexpr auto operator~(const uint128_fallback& n)
|
||||
-> uint128_fallback {
|
||||
return {~n.hi_, ~n.lo_};
|
||||
}
|
||||
friend FMT_CONSTEXPR auto operator+(const uint128_fallback& lhs,
|
||||
const uint128_fallback& rhs)
|
||||
-> uint128_fallback {
|
||||
auto result = uint128_fallback(lhs);
|
||||
friend FMT_CONSTEXPR auto operator+(const uint128& lhs, const uint128& rhs)
|
||||
-> uint128 {
|
||||
auto result = uint128(lhs);
|
||||
result += rhs;
|
||||
return result;
|
||||
}
|
||||
friend FMT_CONSTEXPR auto operator*(const uint128_fallback& lhs, uint32_t rhs)
|
||||
-> uint128_fallback {
|
||||
friend FMT_CONSTEXPR auto operator*(const uint128& lhs, uint32_t rhs)
|
||||
-> uint128 {
|
||||
FMT_ASSERT(lhs.hi_ == 0, "");
|
||||
uint64_t hi = (lhs.lo_ >> 32) * rhs;
|
||||
uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs;
|
||||
uint64_t new_lo = (hi << 32) + lo;
|
||||
return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo};
|
||||
}
|
||||
friend constexpr auto operator-(const uint128_fallback& lhs, uint64_t rhs)
|
||||
-> uint128_fallback {
|
||||
friend constexpr auto operator-(const uint128& lhs, uint64_t rhs) -> uint128 {
|
||||
return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs};
|
||||
}
|
||||
FMT_CONSTEXPR auto operator>>(int shift) const -> uint128_fallback {
|
||||
FMT_CONSTEXPR auto operator>>(int shift) const -> uint128 {
|
||||
if (shift == 64) return {0, hi_};
|
||||
if (shift > 64) return uint128_fallback(0, hi_) >> (shift - 64);
|
||||
if (shift > 64) return uint128(0, hi_) >> (shift - 64);
|
||||
return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)};
|
||||
}
|
||||
FMT_CONSTEXPR auto operator<<(int shift) const -> uint128_fallback {
|
||||
FMT_CONSTEXPR auto operator<<(int shift) const -> uint128 {
|
||||
if (shift == 64) return {lo_, 0};
|
||||
if (shift > 64) return uint128_fallback(lo_, 0) << (shift - 64);
|
||||
if (shift > 64) return uint128(lo_, 0) << (shift - 64);
|
||||
return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)};
|
||||
}
|
||||
FMT_CONSTEXPR auto operator>>=(int shift) -> uint128_fallback& {
|
||||
FMT_CONSTEXPR auto operator>>=(int shift) -> uint128& {
|
||||
return *this = *this >> shift;
|
||||
}
|
||||
FMT_CONSTEXPR void operator+=(uint128_fallback n) {
|
||||
FMT_CONSTEXPR void operator+=(uint128 n) {
|
||||
uint64_t new_lo = lo_ + n.lo_;
|
||||
uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0);
|
||||
FMT_ASSERT(new_hi >= hi_, "");
|
||||
lo_ = new_lo;
|
||||
hi_ = new_hi;
|
||||
}
|
||||
FMT_CONSTEXPR void operator&=(uint128_fallback n) {
|
||||
FMT_CONSTEXPR void operator&=(uint128 n) {
|
||||
lo_ &= n.lo_;
|
||||
hi_ &= n.hi_;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR20 auto operator+=(uint64_t n) noexcept -> uint128_fallback& {
|
||||
FMT_CONSTEXPR20 auto operator+=(uint64_t n) noexcept -> uint128& {
|
||||
if (is_constant_evaluated()) {
|
||||
lo_ += n;
|
||||
hi_ += (lo_ < n ? 1 : 0);
|
||||
@ -403,8 +395,7 @@ class uint128_fallback {
|
||||
}
|
||||
};
|
||||
|
||||
using uint128_t =
|
||||
conditional_t<FMT_USE_INT128, native_uint128, uint128_fallback>;
|
||||
using uint128_t = conditional_t<FMT_USE_INT128, native_uint128, uint128>;
|
||||
|
||||
#ifdef UINTPTR_MAX
|
||||
using uintptr_t = ::uintptr_t;
|
||||
@ -423,10 +414,10 @@ template <typename T> constexpr auto num_bits() -> int {
|
||||
// std::numeric_limits<T>::digits may return 0 for 128-bit ints.
|
||||
template <> constexpr auto num_bits<native_int128>() -> int { return 128; }
|
||||
template <> constexpr auto num_bits<native_uint128>() -> int { return 128; }
|
||||
template <> constexpr auto num_bits<uint128_fallback>() -> int { return 128; }
|
||||
template <> constexpr auto num_bits<uint128>() -> int { return 128; }
|
||||
|
||||
// A heterogeneous bit_cast used for converting 96-bit long double to uint128_t
|
||||
// and 128-bit pointers to uint128_fallback.
|
||||
// and 128-bit pointers to uint128.
|
||||
template <typename To, typename From, FMT_ENABLE_IF(sizeof(To) > sizeof(From))>
|
||||
inline auto bit_cast(const From& from) -> To {
|
||||
constexpr auto size = static_cast<int>(sizeof(From) / sizeof(unsigned short));
|
||||
@ -1472,7 +1463,7 @@ template <typename WChar, typename Buffer = memory_buffer> class to_utf8 {
|
||||
};
|
||||
|
||||
// Computes 128-bit result of multiplication of two 64-bit unsigned integers.
|
||||
FMT_INLINE auto umul128(uint64_t x, uint64_t y) noexcept -> uint128_fallback {
|
||||
FMT_INLINE auto umul128(uint64_t x, uint64_t y) noexcept -> uint128 {
|
||||
#if FMT_USE_INT128
|
||||
auto p = static_cast<native_uint128>(x) * static_cast<native_uint128>(y);
|
||||
return {static_cast<uint64_t>(p >> 64), static_cast<uint64_t>(p)};
|
||||
@ -1528,14 +1519,13 @@ inline auto umul128_upper64(uint64_t x, uint64_t y) noexcept -> uint64_t {
|
||||
|
||||
// Computes upper 128 bits of multiplication of a 64-bit unsigned integer and a
|
||||
// 128-bit unsigned integer.
|
||||
inline auto umul192_upper128(uint64_t x, uint128_fallback y) noexcept
|
||||
-> uint128_fallback {
|
||||
uint128_fallback r = umul128(x, y.high());
|
||||
inline auto umul192_upper128(uint64_t x, uint128 y) noexcept -> uint128 {
|
||||
uint128 r = umul128(x, y.high());
|
||||
r += umul128_upper64(x, y.low());
|
||||
return r;
|
||||
}
|
||||
|
||||
FMT_API auto get_cached_power(int k) noexcept -> uint128_fallback;
|
||||
FMT_API auto get_cached_power(int k) noexcept -> uint128;
|
||||
|
||||
// Type-specific information that Dragonbox uses.
|
||||
template <typename T, typename Enable = void> struct float_info;
|
||||
|
||||
@ -43,7 +43,7 @@ using fmt::memory_buffer;
|
||||
using fmt::runtime;
|
||||
using fmt::string_view;
|
||||
using fmt::detail::max_value;
|
||||
using fmt::detail::uint128_fallback;
|
||||
using fmt::detail::uint128;
|
||||
|
||||
using testing::Return;
|
||||
using testing::StrictMock;
|
||||
@ -55,15 +55,15 @@ static_assert(std::output_iterator<fmt::appender, char>);
|
||||
enum { buffer_size = 256 };
|
||||
|
||||
TEST(uint128_test, ctor) {
|
||||
auto n = uint128_fallback();
|
||||
auto n = uint128();
|
||||
EXPECT_EQ(n, 0);
|
||||
n = uint128_fallback(42);
|
||||
n = uint128(42);
|
||||
EXPECT_EQ(n, 42);
|
||||
EXPECT_EQ(static_cast<uint64_t>(n), 42);
|
||||
}
|
||||
|
||||
TEST(uint128_test, shift) {
|
||||
auto n = uint128_fallback(42);
|
||||
auto n = uint128(42);
|
||||
n = n << 64;
|
||||
EXPECT_EQ(static_cast<uint64_t>(n), 0);
|
||||
n = n >> 64;
|
||||
@ -73,26 +73,26 @@ TEST(uint128_test, shift) {
|
||||
EXPECT_EQ(static_cast<uint64_t>(n), 0x8000000000000000);
|
||||
n = n >> 62;
|
||||
EXPECT_EQ(static_cast<uint64_t>(n), 42);
|
||||
EXPECT_EQ(uint128_fallback(1) << 112, uint128_fallback(0x1000000000000, 0));
|
||||
EXPECT_EQ(uint128_fallback(0x1000000000000, 0) >> 112, uint128_fallback(1));
|
||||
EXPECT_EQ(uint128(1) << 112, uint128(0x1000000000000, 0));
|
||||
EXPECT_EQ(uint128(0x1000000000000, 0) >> 112, uint128(1));
|
||||
}
|
||||
|
||||
TEST(uint128_test, minus) {
|
||||
auto n = uint128_fallback(42);
|
||||
auto n = uint128(42);
|
||||
EXPECT_EQ(n - 2, 40);
|
||||
}
|
||||
|
||||
TEST(uint128_test, plus_assign) {
|
||||
auto n = uint128_fallback(32);
|
||||
n += uint128_fallback(10);
|
||||
auto n = uint128(32);
|
||||
n += uint128(10);
|
||||
EXPECT_EQ(n, 42);
|
||||
n = uint128_fallback(max_value<uint64_t>());
|
||||
n += uint128_fallback(1);
|
||||
EXPECT_EQ(n, uint128_fallback(1) << 64);
|
||||
n = uint128(max_value<uint64_t>());
|
||||
n += uint128(1);
|
||||
EXPECT_EQ(n, uint128(1) << 64);
|
||||
}
|
||||
|
||||
TEST(uint128_test, multiply) {
|
||||
auto n = uint128_fallback(2251799813685247);
|
||||
auto n = uint128(2251799813685247);
|
||||
n = n * 3611864890;
|
||||
EXPECT_EQ(static_cast<uint64_t>(n >> 64), 440901);
|
||||
}
|
||||
@ -1723,14 +1723,13 @@ TEST(format_test, format_pointer) {
|
||||
}
|
||||
|
||||
TEST(format_test, write_uintptr_fallback) {
|
||||
// Test that formatting a pointer by converting it to uint128_fallback works.
|
||||
// Test that formatting a pointer by converting it to uint128 works.
|
||||
// This is needed to support systems without uintptr_t.
|
||||
auto s = std::string();
|
||||
fmt::detail::write_ptr<char>(
|
||||
std::back_inserter(s),
|
||||
fmt::detail::bit_cast<fmt::detail::uint128_fallback>(
|
||||
reinterpret_cast<void*>(0xface)),
|
||||
nullptr);
|
||||
fmt::detail::write_ptr<char>(std::back_inserter(s),
|
||||
fmt::detail::bit_cast<fmt::detail::uint128>(
|
||||
reinterpret_cast<void*>(0xface)),
|
||||
nullptr);
|
||||
EXPECT_EQ(s, "0xface");
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user