Skip to content

Commit e56a1ef

Browse files
committed
(unsigned) __int128 formatter for GCC/Clang
1 parent 52f9a39 commit e56a1ef

File tree

4 files changed

+112
-3
lines changed

4 files changed

+112
-3
lines changed

include/papilio/core.hpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4951,7 +4951,10 @@ inline constexpr std::basic_string_view<CharT> nan_name_upper = PAPILIO_TSTRING_
49514951
* - none: Same as `d`.
49524952
*/
49534953
template <std::integral T, typename CharT>
4954-
requires(!char_like<T>)
4954+
requires(
4955+
!char_like<T> &&
4956+
sizeof(T) <= sizeof(std::uintmax_t) // No extension like __int128
4957+
)
49554958
class int_formatter : public std_formatter_base
49564959
{
49574960
public:
@@ -6076,7 +6079,10 @@ class range_formatter
60766079
* @throw format_error If the integer value is to big for a Unicode code point for `c` type.
60776080
*/
60786081
PAPILIO_EXPORT template <std::integral T, typename CharT>
6079-
requires(!std::same_as<T, bool> && !char_like<T>)
6082+
requires(
6083+
!std::same_as<T, bool> && !char_like<T> &&
6084+
sizeof(T) <= sizeof(std::uintmax_t) // No extension like __int128
6085+
)
60806086
class formatter<T, CharT>
60816087
{
60826088
public:

include/papilio/formatter/int128.hpp

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,19 @@
88

99
#ifdef PAPILIO_STDLIB_MSVC_STL
1010
# define PAPILIO_IMPL_INT128_MSVC_STL
11-
# define PAPILIO_HAS_INT128 1
11+
# define PAPILIO_HAS_INT128 "std::_Unsigned128/_Signed128"
12+
// 128-bit integer provided by MSVC STL
1213
# include <__msvc_int128.hpp>
1314
#endif
1415

16+
#ifndef PAPILIO_HAS_INT128
17+
# ifdef __SIZEOF_INT128__
18+
// Built-in __int128 provided by GCC/Clang extension
19+
# define PAPILIO_IMPL_INT128_EXT__INT128
20+
# define PAPILIO_HAS_INT128 "(unsigned) __int128"
21+
# endif
22+
#endif
23+
1524
#include "../detail/prefix.hpp"
1625

1726
namespace papilio
@@ -61,6 +70,51 @@ namespace detail
6170

6271
#endif
6372

73+
#ifdef PAPILIO_IMPL_INT128_EXT__INT128
74+
75+
using int128_t = __int128;
76+
using uint128_t = unsigned __int128;
77+
78+
namespace detail
79+
{
80+
template <typename Int128>
81+
struct int128_is_unsigned;
82+
83+
template <>
84+
struct int128_is_unsigned<unsigned __int128> : std::false_type
85+
{};
86+
87+
template <>
88+
struct int128_is_unsigned<__int128> : std::true_type
89+
{};
90+
91+
// Check if val < 0
92+
constexpr bool i128_signbit(const __int128& val) noexcept
93+
{
94+
return static_cast<bool>(val >> 127);
95+
}
96+
97+
constexpr __int128 i128_abs(const __int128& val) noexcept
98+
{
99+
if(PAPILIO_NS detail::i128_signbit(val))
100+
return -val;
101+
else
102+
return val;
103+
}
104+
105+
constexpr std::uint64_t i128_low64bit(const __int128& val) noexcept
106+
{
107+
return static_cast<std::uint64_t>(val & (~0uLL));
108+
}
109+
110+
constexpr std::uint64_t u128_low64bit(const unsigned __int128& val) noexcept
111+
{
112+
return static_cast<std::uint64_t>(val & (~0uLL));
113+
}
114+
} // namespace detail
115+
116+
#endif
117+
64118
#ifdef PAPILIO_HAS_INT128
65119

66120
template <typename T>

test/test_format/int128.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,27 @@ static constexpr papilio::int128_t i128_data_b()
2929
return tmp + 1;
3030
}
3131

32+
# endif
33+
34+
# ifdef PAPILIO_IMPL_INT128_EXT__INT128
35+
36+
// == UINT64_MAX
37+
static constexpr papilio::int128_t i128_data_a()
38+
{
39+
return static_cast<__int128>(
40+
std::numeric_limits<std::uint64_t>::max()
41+
);
42+
}
43+
44+
// == UINT64_MAX + 1
45+
static constexpr papilio::int128_t i128_data_b()
46+
{
47+
auto tmp = static_cast<__int128>(
48+
std::numeric_limits<std::uint64_t>::max()
49+
);
50+
return tmp + 1;
51+
}
52+
3253
# endif
3354
} // namespace test_format
3455

@@ -37,6 +58,7 @@ TEST(int128_formatter, int128)
3758
using namespace test_format;
3859
using namespace papilio;
3960

61+
static_assert(papilio::integral_128bit<papilio::int128_t>);
4062
static_assert(formattable<papilio::int128_t>);
4163

4264
// UINT64_MAX
@@ -81,6 +103,27 @@ static constexpr papilio::uint128_t u128_data_b()
81103
return tmp + 1;
82104
}
83105

106+
# endif
107+
108+
# ifdef PAPILIO_IMPL_INT128_EXT__INT128
109+
110+
// == UINT64_MAX
111+
static constexpr papilio::uint128_t u128_data_a()
112+
{
113+
return static_cast<unsigned __int128>(
114+
std::numeric_limits<std::uint64_t>::max()
115+
);
116+
}
117+
118+
// == UINT64_MAX + 1
119+
static constexpr papilio::uint128_t u128_data_b()
120+
{
121+
auto tmp = static_cast<unsigned __int128>(
122+
std::numeric_limits<std::uint64_t>::max()
123+
);
124+
return tmp + 1;
125+
}
126+
84127
# endif
85128
} // namespace test_format
86129

@@ -89,6 +132,7 @@ TEST(int128_formatter, uint128)
89132
using namespace test_format;
90133
using namespace papilio;
91134

135+
static_assert(papilio::integral_128bit<papilio::uint128_t>);
92136
static_assert(formattable<papilio::uint128_t>);
93137

94138
// UINT64_MAX

test/test_format/test_format.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "test_format.hpp"
33
#include <papilio/print.hpp>
44
#include <papilio/chrono/chrono_utility.hpp>
5+
#include <papilio/formatter/int128.hpp>
56
#include <papilio_test/setup.hpp>
67

78
namespace test_format
@@ -23,6 +24,10 @@ int main(int argc, char* argv[])
2324
{
2425
testing::InitGoogleTest(&argc, argv);
2526

27+
#ifdef PAPILIO_HAS_INT128
28+
papilio::println(std::cerr, "PAPILIO_HAS_INT128 = {:?}", PAPILIO_HAS_INT128);
29+
#endif
30+
2631
#ifdef PAPILIO_HAS_LIB_STACKTRACE
2732
papilio::println(std::cerr, "PAPILIO_HAS_LIB_STACKTRACE = {:d}L", PAPILIO_HAS_LIB_STACKTRACE);
2833
#endif

0 commit comments

Comments
 (0)