int128_t -> int128_opt

This commit is contained in:
Victor Zverovich 2022-02-17 19:05:25 -08:00
parent 532a69a639
commit 15c2a3bacc
5 changed files with 86 additions and 78 deletions

View File

@ -380,8 +380,8 @@ template <typename T> struct std_string_view {};
#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \ #elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \
!(FMT_CLANG_VERSION && FMT_MSC_VER) !(FMT_CLANG_VERSION && FMT_MSC_VER)
# define FMT_USE_INT128 1 # define FMT_USE_INT128 1
using int128_t = __int128_t; using int128_opt = __int128_t; // An optional 128-bit integer.
using uint128_t = __uint128_t; using uint128_opt = __uint128_t;
template <typename T> inline auto convert_for_visit(T value) -> T { template <typename T> inline auto convert_for_visit(T value) -> T {
return value; return value;
} }
@ -389,36 +389,8 @@ template <typename T> inline auto convert_for_visit(T value) -> T {
# define FMT_USE_INT128 0 # define FMT_USE_INT128 0
#endif #endif
#if !FMT_USE_INT128 #if !FMT_USE_INT128
enum class int128_t {}; enum class int128_opt {};
class uint128_t { enum class uint128_opt {};
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. // Reduce template instantiations.
template <typename T> inline auto convert_for_visit(T) -> monostate { template <typename T> inline auto convert_for_visit(T) -> monostate {
return {}; return {};
@ -1168,8 +1140,8 @@ FMT_TYPE_CONSTANT(int, int_type);
FMT_TYPE_CONSTANT(unsigned, uint_type); FMT_TYPE_CONSTANT(unsigned, uint_type);
FMT_TYPE_CONSTANT(long long, long_long_type); FMT_TYPE_CONSTANT(long long, long_long_type);
FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
FMT_TYPE_CONSTANT(int128_t, int128_type); FMT_TYPE_CONSTANT(int128_opt, int128_type);
FMT_TYPE_CONSTANT(uint128_t, uint128_type); FMT_TYPE_CONSTANT(uint128_opt, uint128_type);
FMT_TYPE_CONSTANT(bool, bool_type); FMT_TYPE_CONSTANT(bool, bool_type);
FMT_TYPE_CONSTANT(Char, char_type); FMT_TYPE_CONSTANT(Char, char_type);
FMT_TYPE_CONSTANT(float, float_type); FMT_TYPE_CONSTANT(float, float_type);
@ -1219,8 +1191,8 @@ template <typename Context> class value {
unsigned uint_value; unsigned uint_value;
long long long_long_value; long long long_long_value;
unsigned long long ulong_long_value; unsigned long long ulong_long_value;
int128_t int128_value; int128_opt int128_value;
uint128_t uint128_value; uint128_opt uint128_value;
bool bool_value; bool bool_value;
char_type char_value; char_type char_value;
float float_value; float float_value;
@ -1237,8 +1209,8 @@ template <typename Context> class value {
constexpr FMT_INLINE value(unsigned val) : uint_value(val) {} constexpr FMT_INLINE value(unsigned val) : uint_value(val) {}
constexpr FMT_INLINE value(long long val) : long_long_value(val) {} constexpr FMT_INLINE value(long long val) : long_long_value(val) {}
constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {} constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {}
FMT_INLINE value(int128_t val) : int128_value(val) {} FMT_INLINE value(int128_opt val) : int128_value(val) {}
FMT_INLINE value(uint128_t val) : uint128_value(val) {} FMT_INLINE value(uint128_opt val) : uint128_value(val) {}
constexpr FMT_INLINE value(float val) : float_value(val) {} constexpr FMT_INLINE value(float val) : float_value(val) {}
constexpr FMT_INLINE value(double val) : double_value(val) {} constexpr FMT_INLINE value(double val) : double_value(val) {}
FMT_INLINE value(long double val) : long_double_value(val) {} FMT_INLINE value(long double val) : long_double_value(val) {}
@ -1321,8 +1293,12 @@ template <typename Context> struct arg_mapper {
-> unsigned long long { -> unsigned long long {
return val; return val;
} }
FMT_CONSTEXPR FMT_INLINE auto map(int128_t val) -> int128_t { return val; } FMT_CONSTEXPR FMT_INLINE auto map(int128_opt val) -> int128_opt {
FMT_CONSTEXPR FMT_INLINE auto map(uint128_t val) -> uint128_t { return val; } return val;
}
FMT_CONSTEXPR FMT_INLINE auto map(uint128_opt val) -> uint128_opt {
return val;
}
FMT_CONSTEXPR FMT_INLINE auto map(bool val) -> bool { return val; } FMT_CONSTEXPR FMT_INLINE auto map(bool val) -> bool { return val; }
template <typename T, FMT_ENABLE_IF(std::is_same<T, char>::value || template <typename T, FMT_ENABLE_IF(std::is_same<T, char>::value ||

View File

@ -558,7 +558,8 @@ class bigint {
int num_result_bigits = 2 * num_bigits; int num_result_bigits = 2 * num_bigits;
basic_memory_buffer<bigit, bigits_capacity> n(std::move(bigits_)); basic_memory_buffer<bigit, bigits_capacity> n(std::move(bigits_));
bigits_.resize(to_unsigned(num_result_bigits)); bigits_.resize(to_unsigned(num_result_bigits));
using accumulator_t = conditional_t<FMT_USE_INT128, uint128_t, accumulator>; using accumulator_t =
conditional_t<FMT_USE_INT128, uint128_opt, accumulator>;
auto sum = accumulator_t(); auto sum = accumulator_t();
for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) { for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) {
// Compute bigit at position bigit_index of the result by adding // Compute bigit at position bigit_index of the result by adding
@ -833,7 +834,7 @@ namespace dragonbox {
// Computes 128-bit result of multiplication of two 64-bit unsigned integers. // Computes 128-bit result of multiplication of two 64-bit unsigned integers.
inline uint128_wrapper umul128(uint64_t x, uint64_t y) noexcept { inline uint128_wrapper umul128(uint64_t x, uint64_t y) noexcept {
#if FMT_USE_INT128 #if FMT_USE_INT128
auto p = static_cast<uint128_t>(x) * static_cast<uint128_t>(y); auto p = static_cast<uint128_opt>(x) * static_cast<uint128_opt>(y);
return {static_cast<uint64_t>(p >> 64), static_cast<uint64_t>(p)}; return {static_cast<uint64_t>(p >> 64), static_cast<uint64_t>(p)};
#elif defined(_MSC_VER) && defined(_M_X64) #elif defined(_MSC_VER) && defined(_M_X64)
uint128_wrapper result; uint128_wrapper result;
@ -863,7 +864,7 @@ inline uint128_wrapper umul128(uint64_t x, uint64_t y) noexcept {
// Computes upper 64 bits of multiplication of two 64-bit unsigned integers. // Computes upper 64 bits of multiplication of two 64-bit unsigned integers.
inline uint64_t umul128_upper64(uint64_t x, uint64_t y) noexcept { inline uint64_t umul128_upper64(uint64_t x, uint64_t y) noexcept {
#if FMT_USE_INT128 #if FMT_USE_INT128
auto p = static_cast<uint128_t>(x) * static_cast<uint128_t>(y); auto p = static_cast<uint128_opt>(x) * static_cast<uint128_opt>(y);
return static_cast<uint64_t>(p >> 64); return static_cast<uint64_t>(p >> 64);
#elif defined(_MSC_VER) && defined(_M_X64) #elif defined(_MSC_VER) && defined(_M_X64)
return __umulh(x, y); return __umulh(x, y);

View File

@ -339,6 +339,36 @@ inline auto to_uintptr(const void* p) -> fallback_uintptr {
} }
#endif #endif
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) : lo_(value), hi_(0) {}
explicit operator int() const { return static_cast<int>(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)};
}
};
// Returns the largest possible value for type T. Same as // Returns the largest possible value for type T. Same as
// std::numeric_limits<T>::max() but shorter and not affected by the max macro. // std::numeric_limits<T>::max() but shorter and not affected by the max macro.
template <typename T> constexpr auto max_value() -> T { template <typename T> constexpr auto max_value() -> T {
@ -348,7 +378,7 @@ template <typename T> constexpr auto num_bits() -> int {
return std::numeric_limits<T>::digits; return std::numeric_limits<T>::digits;
} }
// std::numeric_limits<T>::digits may return 0 for 128-bit ints. // std::numeric_limits<T>::digits may return 0 for 128-bit ints.
template <> constexpr auto num_bits<int128_t>() -> int { return 128; } template <> constexpr auto num_bits<int128_opt>() -> int { return 128; }
template <> constexpr auto num_bits<uint128_t>() -> int { return 128; } template <> constexpr auto num_bits<uint128_t>() -> int { return 128; }
template <> constexpr auto num_bits<fallback_uintptr>() -> int { template <> constexpr auto num_bits<fallback_uintptr>() -> int {
return static_cast<int>(sizeof(void*) * return static_cast<int>(sizeof(void*) *
@ -876,13 +906,13 @@ constexpr auto compile_string_to_view(detail::std_string_view<Char> s)
FMT_BEGIN_DETAIL_NAMESPACE FMT_BEGIN_DETAIL_NAMESPACE
template <typename T> struct is_integral : std::is_integral<T> {}; template <typename T> struct is_integral : std::is_integral<T> {};
template <> struct is_integral<int128_t> : std::true_type {}; template <> struct is_integral<int128_opt> : std::true_type {};
template <> struct is_integral<uint128_t> : std::true_type {}; template <> struct is_integral<uint128_t> : std::true_type {};
template <typename T> template <typename T>
using is_signed = using is_signed =
std::integral_constant<bool, std::numeric_limits<T>::is_signed || std::integral_constant<bool, std::numeric_limits<T>::is_signed ||
std::is_same<T, int128_t>::value>; std::is_same<T, int128_opt>::value>;
// Returns true if value is negative, false otherwise. // Returns true if value is negative, false otherwise.
// Same as `value < 0` but doesn't produce warnings if T is an unsigned type. // Same as `value < 0` but doesn't produce warnings if T is an unsigned type.
@ -908,9 +938,10 @@ template <typename T>
using uint32_or_64_or_128_t = using uint32_or_64_or_128_t =
conditional_t<num_bits<T>() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS, conditional_t<num_bits<T>() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS,
uint32_t, uint32_t,
conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>; conditional_t<num_bits<T>() <= 64, uint64_t, uint128_opt>>;
template <typename T> template <typename T>
using uint64_or_128_t = conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>; using uint64_or_128_t =
conditional_t<num_bits<T>() <= 64, uint64_t, uint128_opt>;
#define FMT_POWERS_OF_10(factor) \ #define FMT_POWERS_OF_10(factor) \
factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \ factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \
@ -950,7 +981,7 @@ template <typename T> FMT_CONSTEXPR auto count_digits_fallback(T n) -> int {
} }
} }
#if FMT_USE_INT128 #if FMT_USE_INT128
FMT_CONSTEXPR inline auto count_digits(uint128_t n) -> int { FMT_CONSTEXPR inline auto count_digits(uint128_opt n) -> int {
return count_digits_fallback(n); return count_digits_fallback(n);
} }
#endif #endif
@ -1044,7 +1075,7 @@ FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int {
template <typename Int> constexpr auto digits10() noexcept -> int { template <typename Int> constexpr auto digits10() noexcept -> int {
return std::numeric_limits<Int>::digits10; return std::numeric_limits<Int>::digits10;
} }
template <> constexpr auto digits10<int128_t>() noexcept -> int { return 38; } template <> constexpr auto digits10<int128_opt>() noexcept -> int { return 38; }
template <> constexpr auto digits10<uint128_t>() noexcept -> int { return 38; } template <> constexpr auto digits10<uint128_t>() noexcept -> int { return 38; }
template <typename Char> struct thousands_sep_result { template <typename Char> struct thousands_sep_result {
@ -1250,7 +1281,7 @@ template <> struct float_info<double> {
template <typename T> template <typename T>
struct float_info<T, enable_if_t<std::is_same<T, long double>::value && struct float_info<T, enable_if_t<std::is_same<T, long double>::value &&
std::numeric_limits<T>::digits == 64>> { std::numeric_limits<T>::digits == 64>> {
using carrier_uint = detail::uint128_t; using carrier_uint = detail::uint128_opt;
static const int significand_bits = 64; static const int significand_bits = 64;
static const int exponent_bits = 15; static const int exponent_bits = 15;
}; };

View File

@ -33,33 +33,6 @@ using testing::Return;
# error core-test includes format.h # error core-test includes format.h
#endif #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<uint64_t>(n), 42);
}
TEST(uint128_test, shift) {
auto n = fmt::detail::uint128_t(42);
n = n << 64;
EXPECT_EQ(static_cast<uint64_t>(n), 0);
n = n >> 64;
EXPECT_EQ(static_cast<uint64_t>(n), 42);
n = n << 62;
EXPECT_EQ(static_cast<uint64_t>(n >> 64), 0xa);
EXPECT_EQ(static_cast<uint64_t>(n), 0x8000000000000000);
n = n >> 62;
EXPECT_EQ(static_cast<uint64_t>(n), 42);
}
TEST(uint128_test, minus) {
auto n = fmt::detail::uint128_t(42);
EXPECT_EQ(n - 2, 40);
}
TEST(string_view_test, value_type) { TEST(string_view_test, value_type) {
static_assert(std::is_same<string_view::value_type, char>::value, ""); static_assert(std::is_same<string_view::value_type, char>::value, "");
} }

View File

@ -39,6 +39,33 @@ using testing::StrictMock;
enum { buffer_size = 256 }; enum { buffer_size = 256 };
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<uint64_t>(n), 42);
}
TEST(uint128_test, shift) {
auto n = fmt::detail::uint128_t(42);
n = n << 64;
EXPECT_EQ(static_cast<uint64_t>(n), 0);
n = n >> 64;
EXPECT_EQ(static_cast<uint64_t>(n), 42);
n = n << 62;
EXPECT_EQ(static_cast<uint64_t>(n >> 64), 0xa);
EXPECT_EQ(static_cast<uint64_t>(n), 0x8000000000000000);
n = n >> 62;
EXPECT_EQ(static_cast<uint64_t>(n), 42);
}
TEST(uint128_test, minus) {
auto n = fmt::detail::uint128_t(42);
EXPECT_EQ(n - 2, 40);
}
struct uint32_pair { struct uint32_pair {
uint32_t u[2]; uint32_t u[2];
}; };