Skip to content

Commit

Permalink
Fix handling of _BitInt
Browse files Browse the repository at this point in the history
  • Loading branch information
vitaut committed Sep 3, 2024
1 parent 7a6a2a7 commit 894b71d
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 60 deletions.
33 changes: 17 additions & 16 deletions include/fmt/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -417,22 +417,15 @@ template <typename T> auto convert_for_visit(T) -> monostate { return {}; }
# define FMT_USE_BITINT (FMT_CLANG_VERSION >= 1400)
#endif

template <typename T, int N = 0> struct bitint_traits {};
#if FMT_USE_BITINT
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wbit-int-extension"

template <int N> struct bitint_traits<_BitInt(N)> {
static constexpr bool is_formattable = N <= 128;
using format_type = conditional_t<(N <= 64), long long, __int128>;
};
template <int N> struct bitint_traits<unsigned _BitInt(N)> {
static constexpr bool is_formattable = N <= 128;
using format_type =
conditional_t<(N <= 64), unsigned long long, unsigned __int128>;
};

template <int N> using bitint = _BitInt(N);
template <int N> using ubitint = unsigned _BitInt(N);
# pragma clang diagnostic pop
#else
template <int N> struct bitint {};
template <int N> struct ubitint {};
#endif // FMT_USE_BITINT

// Casts a nonnegative integer to unsigned.
Expand Down Expand Up @@ -1170,12 +1163,20 @@ template <typename Char> struct arg_mapper {
FMT_MAP_API auto map(double x) -> double { return x; }
FMT_MAP_API auto map(long double x) -> long double { return x; }

template <typename T, FMT_ENABLE_IF(bitint_traits<T>::is_formattable)>
FMT_MAP_API auto map(T x) -> typename bitint_traits<T>::format_type {
template <int N, FMT_ENABLE_IF(N <= 64)>
FMT_MAP_API auto map(bitint<N> x) -> long long {
return x;
}
template <typename T, FMT_ENABLE_IF(!bitint_traits<T>::is_formattable)>
FMT_MAP_API auto map(T) -> unformattable {
template <int N, FMT_ENABLE_IF(N <= 64)>
FMT_MAP_API auto map(ubitint<N> x) -> unsigned long long {
return x;
}
template <int N, FMT_ENABLE_IF(N > 64)>
FMT_MAP_API auto map(bitint<N>) -> unformattable {
return {};
}
template <int N, FMT_ENABLE_IF(N > 64)>
FMT_MAP_API auto map(ubitint<N>) -> unformattable {
return {};
}

Expand Down
9 changes: 5 additions & 4 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -3973,10 +3973,11 @@ template <typename Char, typename Traits, typename Allocator>
class formatter<std::basic_string<Char, Traits, Allocator>, Char>
: public formatter<basic_string_view<Char>, Char> {};

template <typename T, typename Char>
struct formatter<T, Char,
enable_if_t<(detail::bitint_traits<T>::is_formattable)>>
: formatter<typename detail::bitint_traits<T>::format_type, Char> {};
template <int N, typename Char>
struct formatter<detail::bitint<N>, Char> : formatter<long long, Char> {};
template <int N, typename Char>
struct formatter<detail::ubitint<N>, Char>
: formatter<unsigned long long, Char> {};

/**
* Converts `p` to `const void*` for pointer formatting.
Expand Down
57 changes: 17 additions & 40 deletions test/format-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2518,59 +2518,36 @@ TEST(format_test, writer) {
#if FMT_USE_BITINT
# pragma clang diagnostic ignored "-Wbit-int-extension"

template <size_t N, bool is_signed>
using bitint_helper =
fmt::conditional_t<is_signed, _BitInt(N), unsigned _BitInt(N)>;
template <size_t N> using signed_bitint = bitint_helper<N, true>;
template <size_t N> using unsigned_bitint = bitint_helper<N, false>;

TEST(format_test, bitint) {
EXPECT_EQ(fmt::format("{}", unsigned_bitint<3>(7)), "7");
EXPECT_EQ(fmt::format("{}", signed_bitint<7>()), "0");
using fmt::detail::bitint;
using fmt::detail::ubitint;

EXPECT_EQ(fmt::format("{}", ubitint<3>(7)), "7");
EXPECT_EQ(fmt::format("{}", bitint<7>()), "0");

EXPECT_EQ(fmt::format("{}", unsigned_bitint<15>(31000)), "31000");
EXPECT_EQ(fmt::format("{}", signed_bitint<16>(INT16_MIN)), "-32768");
EXPECT_EQ(fmt::format("{}", signed_bitint<16>(INT16_MAX)), "32767");
EXPECT_EQ(fmt::format("{}", ubitint<15>(31000)), "31000");
EXPECT_EQ(fmt::format("{}", bitint<16>(INT16_MIN)), "-32768");
EXPECT_EQ(fmt::format("{}", bitint<16>(INT16_MAX)), "32767");

EXPECT_EQ(fmt::format("{}", unsigned_bitint<32>(4294967295)), "4294967295");
EXPECT_EQ(fmt::format("{}", ubitint<32>(4294967295)), "4294967295");

EXPECT_EQ(fmt::format("{}", unsigned_bitint<47>(140737488355327ULL)),
EXPECT_EQ(fmt::format("{}", ubitint<47>(140737488355327ULL)),
"140737488355327");
EXPECT_EQ(fmt::format("{}", signed_bitint<47>(-40737488355327LL)),
EXPECT_EQ(fmt::format("{}", bitint<47>(-40737488355327LL)),
"-40737488355327");

// Check lvalues and const
auto a = signed_bitint<8>(0);
auto b = unsigned_bitint<32>(4294967295);
const auto c = signed_bitint<7>(0);
const auto d = unsigned_bitint<32>(4294967295);
auto a = bitint<8>(0);
auto b = ubitint<32>(4294967295);
const auto c = bitint<7>(0);
const auto d = ubitint<32>(4294967295);
EXPECT_EQ(fmt::format("{}", a), "0");
EXPECT_EQ(fmt::format("{}", b), "4294967295");
EXPECT_EQ(fmt::format("{}", c), "0");
EXPECT_EQ(fmt::format("{}", d), "4294967295");

static_assert(fmt::is_formattable<signed_bitint<64>, char>{}, "");
static_assert(fmt::is_formattable<unsigned_bitint<64>, char>{}, "");

# if FMT_USE_INT128
static_assert(fmt::is_formattable<signed_bitint<128>, char>{}, "");
static_assert(fmt::is_formattable<unsigned_bitint<128>, char>{}, "");

EXPECT_EQ(fmt::format("{}", signed_bitint<128>(0)), "0");
EXPECT_EQ(fmt::format("{}", unsigned_bitint<128>(0)), "0");
EXPECT_EQ("9223372036854775808",
fmt::format("{}", signed_bitint<65>(INT64_MAX) + 1));
EXPECT_EQ("-9223372036854775809",
fmt::format("{}", signed_bitint<65>(INT64_MIN) - 1));
EXPECT_EQ("18446744073709551616",
fmt::format("{}", unsigned_bitint<66>(UINT64_MAX) + 1));
EXPECT_EQ("170141183460469231731687303715884105727",
fmt::format("{}", signed_bitint<128>(int128_max)));
EXPECT_EQ("-170141183460469231731687303715884105728",
fmt::format("{}", signed_bitint<128>(int128_min)));
EXPECT_EQ("340282366920938463463374607431768211455",
fmt::format("{}", unsigned_bitint<128>(uint128_max)));
# endif
static_assert(fmt::is_formattable<bitint<64>, char>{}, "");
static_assert(fmt::is_formattable<ubitint<64>, char>{}, "");
}
#endif

Expand Down

0 comments on commit 894b71d

Please sign in to comment.