mirror of
https://github.com/fmtlib/fmt.git
synced 2026-11-09 14:50:24 +08:00
Remove test-only code from the headers and move equal2 to format-inl.h
Its only user is vformat_to, which needs only the char overload.
This commit is contained in:
parent
32777676cf
commit
41f2838233
@ -188,11 +188,6 @@ FMT_FUNC auto vsystem_error(int error_code, string_view fmt, format_args args)
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename F>
|
||||
inline auto operator==(basic_fp<F> x, basic_fp<F> y) -> bool {
|
||||
return x.f == y.f && x.e == y.e;
|
||||
}
|
||||
|
||||
// Compilers should be able to optimize this into the ror instruction.
|
||||
FMT_INLINE auto rotr(uint32_t n, uint32_t r) noexcept -> uint32_t {
|
||||
r &= 31;
|
||||
@ -1397,32 +1392,6 @@ small_divisor_case_label:
|
||||
} // namespace dragonbox
|
||||
} // namespace detail
|
||||
|
||||
template <> struct formatter<detail::bigint> {
|
||||
FMT_CONSTEXPR auto parse(format_parse_context& ctx)
|
||||
-> format_parse_context::iterator {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
auto format(const detail::bigint& n, format_context& ctx) const
|
||||
-> format_context::iterator {
|
||||
auto out = ctx.out();
|
||||
bool first = true;
|
||||
for (auto i = n.bigits_.size(); i > 0; --i) {
|
||||
auto value = n.bigits_[i - 1u];
|
||||
if (first) {
|
||||
out = fmt::format_to(out, FMT_STRING("{:x}"), value);
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
out = fmt::format_to(out, FMT_STRING("{:08x}"), value);
|
||||
}
|
||||
if (n.exp_ > 0)
|
||||
out = fmt::format_to(out, FMT_STRING("p{}"),
|
||||
n.exp_ * detail::bigint::bigit_bits);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) {
|
||||
for_each_codepoint(s, [this](uint32_t cp, string_view) {
|
||||
if (cp == invalid_code_point) FMT_THROW(std::runtime_error("invalid utf8"));
|
||||
@ -1464,6 +1433,11 @@ FMT_FUNC auto vformat(string_view fmt, format_args args) -> std::string {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Compares two characters for equality.
|
||||
inline auto equal2(const char* lhs, const char* rhs) -> bool {
|
||||
return memcmp(lhs, rhs, 2) == 0;
|
||||
}
|
||||
|
||||
FMT_FUNC void vformat_to(buffer<char>& buf, string_view fmt, format_args args,
|
||||
locale_ref loc) {
|
||||
auto out = appender(buf);
|
||||
|
||||
@ -1389,14 +1389,6 @@ extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
|
||||
FMT_END_EXPORT
|
||||
#endif // FMT_HEADER_ONLY
|
||||
|
||||
// Compares two characters for equality.
|
||||
template <typename Char> auto equal2(const Char* lhs, const char* rhs) -> bool {
|
||||
return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]);
|
||||
}
|
||||
inline auto equal2(const char* lhs, const char* rhs) -> bool {
|
||||
return memcmp(lhs, rhs, 2) == 0;
|
||||
}
|
||||
|
||||
// Writes a two-digit value to out.
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR20 FMT_INLINE void write2digits(Char* out, size_t value) {
|
||||
@ -1842,11 +1834,7 @@ template <typename F> struct basic_fp {
|
||||
F f;
|
||||
int e;
|
||||
|
||||
static constexpr int num_significand_bits =
|
||||
static_cast<int>(sizeof(F) * num_bits<unsigned char>());
|
||||
|
||||
constexpr basic_fp() : f(0), e(0) {}
|
||||
constexpr basic_fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {}
|
||||
|
||||
// Constructs fp from an IEEE754 floating-point number.
|
||||
template <typename Float> FMT_CONSTEXPR basic_fp(Float n) { assign(n); }
|
||||
@ -1884,48 +1872,6 @@ template <typename F> struct basic_fp {
|
||||
}
|
||||
};
|
||||
|
||||
using fp = basic_fp<ullong>;
|
||||
|
||||
// Normalizes the value converted from double and multiplied by (1 << SHIFT).
|
||||
template <int SHIFT = 0, typename F>
|
||||
FMT_CONSTEXPR auto normalize(basic_fp<F> value) -> basic_fp<F> {
|
||||
// Handle subnormals.
|
||||
const auto implicit_bit = F(1) << num_significand_bits<double>();
|
||||
const auto shifted_implicit_bit = implicit_bit << SHIFT;
|
||||
while ((value.f & shifted_implicit_bit) == 0) {
|
||||
value.f <<= 1;
|
||||
--value.e;
|
||||
}
|
||||
// Subtract 1 to account for hidden bit.
|
||||
const auto offset = basic_fp<F>::num_significand_bits -
|
||||
num_significand_bits<double>() - SHIFT - 1;
|
||||
value.f <<= offset;
|
||||
value.e -= offset;
|
||||
return value;
|
||||
}
|
||||
|
||||
// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking.
|
||||
FMT_CONSTEXPR inline auto multiply(uint64_t lhs, uint64_t rhs) -> uint64_t {
|
||||
#if FMT_USE_INT128
|
||||
auto product = static_cast<uint128_t>(lhs) * rhs;
|
||||
auto f = static_cast<uint64_t>(product >> 64);
|
||||
return (static_cast<uint64_t>(product) & (1ULL << 63)) != 0 ? f + 1 : f;
|
||||
#else
|
||||
// Multiply 32-bit parts of significands.
|
||||
uint64_t mask = (1ULL << 32) - 1;
|
||||
uint64_t a = lhs >> 32, b = lhs & mask;
|
||||
uint64_t c = rhs >> 32, d = rhs & mask;
|
||||
uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
|
||||
// Compute mid 64-bit of result and round.
|
||||
uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
|
||||
return ac + (ad >> 32) + (bc >> 32) + (mid >> 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR inline auto operator*(fp x, fp y) -> fp {
|
||||
return {multiply(x.f, y.f), x.e + y.e + 64};
|
||||
}
|
||||
|
||||
template <typename T, bool doublish = num_bits<T>() == num_bits<double>()>
|
||||
using convert_float_result =
|
||||
conditional_t<std::is_same<T, float>::value || doublish, double, T>;
|
||||
|
||||
@ -15,9 +15,36 @@
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
using fmt::detail::bigint;
|
||||
using fmt::detail::fp;
|
||||
using fmt::detail::max_value;
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<detail::bigint> {
|
||||
FMT_CONSTEXPR auto parse(format_parse_context& ctx)
|
||||
-> format_parse_context::iterator {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
auto format(const detail::bigint& n, format_context& ctx) const
|
||||
-> format_context::iterator {
|
||||
auto out = ctx.out();
|
||||
bool first = true;
|
||||
for (auto i = n.bigits_.size(); i > 0; --i) {
|
||||
auto value = n.bigits_[i - 1u];
|
||||
if (first) {
|
||||
out = fmt::format_to(out, FMT_STRING("{:x}"), value);
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
out = fmt::format_to(out, FMT_STRING("{:08x}"), value);
|
||||
}
|
||||
if (n.exp_ > 0)
|
||||
out = fmt::format_to(out, FMT_STRING("p{}"),
|
||||
n.exp_ * detail::bigint::bigit_bits);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
static_assert(!std::is_copy_constructible<bigint>::value, "");
|
||||
static_assert(!std::is_copy_assignable<bigint>::value, "");
|
||||
|
||||
@ -171,29 +198,15 @@ template <bool is_iec559> void run_double_tests() {
|
||||
|
||||
template <> void run_double_tests<true>() {
|
||||
// Construct from double.
|
||||
EXPECT_EQ(fp(1.23), fp(0x13ae147ae147aeu, -52));
|
||||
auto v = fmt::detail::basic_fp<uint64_t>(1.23);
|
||||
EXPECT_EQ(v.f, 0x13ae147ae147aeu);
|
||||
EXPECT_EQ(v.e, -52);
|
||||
}
|
||||
|
||||
TEST(fp_test, double_tests) {
|
||||
run_double_tests<std::numeric_limits<double>::is_iec559>();
|
||||
}
|
||||
|
||||
TEST(fp_test, normalize) {
|
||||
const auto v = fp(0xbeef, 42);
|
||||
auto normalized = normalize(v);
|
||||
EXPECT_EQ(normalized.f, 0xbeef000000000000);
|
||||
EXPECT_EQ(normalized.e, -6);
|
||||
}
|
||||
|
||||
TEST(fp_test, multiply) {
|
||||
auto v = fp(123ULL << 32, 4) * fp(56ULL << 32, 7);
|
||||
EXPECT_EQ(v.f, 123u * 56u);
|
||||
EXPECT_EQ(v.e, 4 + 7 + 64);
|
||||
v = fp(123ULL << 32, 4) * fp(567ULL << 31, 8);
|
||||
EXPECT_EQ(v.f, (123 * 567 + 1u) / 2);
|
||||
EXPECT_EQ(v.e, 4 + 8 + 64);
|
||||
}
|
||||
|
||||
TEST(fp_test, dragonbox_max_k) {
|
||||
using fmt::detail::dragonbox::floor_log10_pow2;
|
||||
using float_info = fmt::detail::dragonbox::float_info<float>;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user