mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-29 18:27:40 +02:00
Add support for 96-bit long double
This commit is contained in:
@ -237,11 +237,7 @@ struct fp {
|
||||
template <typename Float> explicit FMT_CONSTEXPR fp(Float n) { assign(n); }
|
||||
|
||||
template <typename Float>
|
||||
using is_supported =
|
||||
bool_constant<sizeof(Float) == sizeof(uint32_t) ||
|
||||
sizeof(Float) == sizeof(uint64_t) ||
|
||||
(sizeof(Float) == sizeof(uint128_t) &&
|
||||
std::numeric_limits<Float>::digits == 64)>;
|
||||
using is_supported = bool_constant<std::numeric_limits<Float>::digits <= 64>;
|
||||
|
||||
// Assigns d to this and return true iff predecessor is closer than successor.
|
||||
template <typename Float, FMT_ENABLE_IF(is_supported<Float>::value)>
|
||||
|
@ -288,9 +288,8 @@ template <typename Streambuf> class formatbuf : public Streambuf {
|
||||
};
|
||||
|
||||
// Implementation of std::bit_cast for pre-C++20.
|
||||
template <typename To, typename From>
|
||||
template <typename To, typename From, FMT_ENABLE_IF(sizeof(To) == sizeof(From))>
|
||||
FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To {
|
||||
static_assert(sizeof(To) == sizeof(From), "size mismatch");
|
||||
#ifdef __cpp_lib_bit_cast
|
||||
if (is_constant_evaluated()) return std::bit_cast<To>(from);
|
||||
#endif
|
||||
@ -369,28 +368,10 @@ using uint128_t = conditional_t<FMT_USE_INT128, uint128_opt, uint128_fallback>;
|
||||
|
||||
#ifdef UINTPTR_MAX
|
||||
using uintptr_t = ::uintptr_t;
|
||||
inline auto to_uintptr(const void* p) -> uintptr_t {
|
||||
return bit_cast<uintptr_t>(p);
|
||||
}
|
||||
#else
|
||||
using uintptr_t = uint128_t;
|
||||
#endif
|
||||
|
||||
// A fallback for systems that lack uintptr_t.
|
||||
template <typename T = uint128_t> inline auto to_uintptr(const void* p) -> T {
|
||||
constexpr auto size = static_cast<int>(sizeof(void*));
|
||||
struct data_t {
|
||||
unsigned char value[size];
|
||||
} data = bit_cast<data_t>(p);
|
||||
auto result = T();
|
||||
if (const_check(is_big_endian())) {
|
||||
for (int i = 0; i < size; ++i) result = (result << 8) | data.value[i];
|
||||
} else {
|
||||
for (int i = size - 1; i >= 0; --i) result = (result << 8) | data.value[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns the largest possible value for type T. Same as
|
||||
// std::numeric_limits<T>::max() but shorter and not affected by the max macro.
|
||||
template <typename T> constexpr auto max_value() -> T {
|
||||
@ -403,6 +384,25 @@ template <typename T> constexpr auto num_bits() -> int {
|
||||
template <> constexpr auto num_bits<int128_opt>() -> int { return 128; }
|
||||
template <> constexpr auto num_bits<uint128_t>() -> int { return 128; }
|
||||
|
||||
// A heterogeneous bit_cast used for converting 96-bit long double to uint128_t
|
||||
// and 128-bit pointers to uint128_fallback.
|
||||
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));
|
||||
struct data_t {
|
||||
unsigned value[size];
|
||||
} data = bit_cast<data_t>(from);
|
||||
auto result = To();
|
||||
if (const_check(is_big_endian())) {
|
||||
for (int i = 0; i < size; ++i)
|
||||
result = (result << num_bits<unsigned>()) | data.value[i];
|
||||
} else {
|
||||
for (int i = size - 1; i >= 0; --i)
|
||||
result = (result << num_bits<unsigned>()) | data.value[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
FMT_INLINE void assume(bool condition) {
|
||||
(void)condition;
|
||||
#if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION
|
||||
@ -1275,7 +1275,7 @@ template <> struct float_info<double> {
|
||||
template <typename T>
|
||||
struct float_info<T, enable_if_t<std::is_same<T, long double>::value &&
|
||||
std::numeric_limits<T>::digits == 64>> {
|
||||
using carrier_uint = detail::uint128_opt;
|
||||
using carrier_uint = detail::uint128_t;
|
||||
static const int significand_bits = 64;
|
||||
static const int exponent_bits = 15;
|
||||
};
|
||||
@ -1911,7 +1911,7 @@ FMT_CONSTEXPR auto write(OutputIt out, const Char* s,
|
||||
-> OutputIt {
|
||||
return check_cstring_type_spec(specs.type)
|
||||
? write(out, basic_string_view<Char>(s), specs, {})
|
||||
: write_ptr<Char>(out, to_uintptr(s), &specs);
|
||||
: write_ptr<Char>(out, bit_cast<uintptr_t>(s), &specs);
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt>
|
||||
@ -2394,7 +2394,7 @@ auto write(OutputIt out, const T* value,
|
||||
const basic_format_specs<Char>& specs = {}, locale_ref = {})
|
||||
-> OutputIt {
|
||||
check_pointer_type_spec(specs.type, error_handler());
|
||||
return write_ptr<Char>(out, to_uintptr(value), &specs);
|
||||
return write_ptr<Char>(out, bit_cast<uintptr_t>(value), &specs);
|
||||
}
|
||||
|
||||
// A write overload that handles implicit conversions.
|
||||
|
@ -340,16 +340,6 @@ TEST(format_impl_test, count_digits) {
|
||||
test_count_digits<uint64_t>();
|
||||
}
|
||||
|
||||
TEST(format_impl_test, write_uintptr_fallback) {
|
||||
std::string s;
|
||||
fmt::detail::write_ptr<char>(
|
||||
std::back_inserter(s),
|
||||
fmt::detail::to_uintptr<fmt::detail::uint128_fallback>(
|
||||
reinterpret_cast<void*>(0xface)),
|
||||
nullptr);
|
||||
EXPECT_EQ(s, "0xface");
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
@ -1445,6 +1445,18 @@ TEST(format_test, format_pointer) {
|
||||
EXPECT_EQ("0x0", fmt::format("{}", nullptr));
|
||||
}
|
||||
|
||||
TEST(format_test, write_uintptr_fallback) {
|
||||
// Test that formatting a pointer by converting it to uint128_fallback 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);
|
||||
EXPECT_EQ(s, "0xface");
|
||||
}
|
||||
|
||||
enum class color { red, green, blue };
|
||||
|
||||
TEST(format_test, format_enum_class) {
|
||||
|
Reference in New Issue
Block a user