mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-31 19:24:48 +02:00
Make sign a proper enum class
This commit is contained in:
@@ -2051,20 +2051,6 @@ FMT_END_EXPORT
|
|||||||
// between clang and gcc on ARM (#1919).
|
// between clang and gcc on ARM (#1919).
|
||||||
FMT_EXPORT using format_args = basic_format_args<format_context>;
|
FMT_EXPORT using format_args = basic_format_args<format_context>;
|
||||||
|
|
||||||
// We cannot use enum classes as bit fields because of a gcc bug, so we put them
|
|
||||||
// in namespaces instead (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414).
|
|
||||||
// Additionally, if an underlying type is specified, older gcc incorrectly warns
|
|
||||||
// that the type is too small. Both bugs are fixed in gcc 9.3.
|
|
||||||
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 903
|
|
||||||
# define FMT_ENUM_UNDERLYING_TYPE(type)
|
|
||||||
#else
|
|
||||||
# define FMT_ENUM_UNDERLYING_TYPE(type) : type
|
|
||||||
#endif
|
|
||||||
namespace sign {
|
|
||||||
enum type FMT_ENUM_UNDERLYING_TYPE(unsigned char){none, minus, plus, space};
|
|
||||||
}
|
|
||||||
using sign_t = sign::type;
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <typename T, typename Enable = void>
|
template <typename T, typename Enable = void>
|
||||||
@@ -2115,6 +2101,7 @@ enum class presentation_type : unsigned char {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum class align { none, left, right, center, numeric };
|
enum class align { none, left, right, center, numeric };
|
||||||
|
enum class sign { none, minus, plus, space };
|
||||||
|
|
||||||
// Basic format specifiers for built-in and string types.
|
// Basic format specifiers for built-in and string types.
|
||||||
class basic_specs {
|
class basic_specs {
|
||||||
@@ -2201,11 +2188,11 @@ class basic_specs {
|
|||||||
return (data_ & (width_mask | precision_mask)) != 0;
|
return (data_ & (width_mask | precision_mask)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto sign() const -> sign_t {
|
constexpr auto sign() const -> sign {
|
||||||
return static_cast<sign_t>((data_ & sign_mask) >> sign_shift);
|
return static_cast<fmt::sign>((data_ & sign_mask) >> sign_shift);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR void set_sign(sign_t a) {
|
FMT_CONSTEXPR void set_sign(fmt::sign s) {
|
||||||
data_ = (data_ & ~sign_mask) | (static_cast<unsigned>(a) << sign_shift);
|
data_ = (data_ & ~sign_mask) | (static_cast<unsigned>(s) << sign_shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto upper() const -> bool { return (data_ & uppercase_mask) != 0; }
|
constexpr auto upper() const -> bool { return (data_ & uppercase_mask) != 0; }
|
||||||
|
@@ -1130,11 +1130,12 @@ inline auto digits2(size_t value) -> const char* {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sign is a template parameter to workaround a bug in gcc 4.8.
|
// Sign is a template parameter to workaround a bug in gcc 4.8.
|
||||||
template <typename Char, typename Sign> constexpr auto sign(Sign s) -> Char {
|
template <typename Char, typename Sign> constexpr auto getsign(Sign s) -> Char {
|
||||||
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604
|
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604
|
||||||
static_assert(std::is_same<Sign, sign_t>::value, "");
|
static_assert(std::is_same<Sign, sign>::value, "");
|
||||||
#endif
|
#endif
|
||||||
return static_cast<char>(((' ' << 24) | ('+' << 16) | ('-' << 8)) >> (s * 8));
|
return static_cast<char>(((' ' << 24) | ('+' << 16) | ('-' << 8)) >>
|
||||||
|
(static_cast<int>(s) * 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> FMT_CONSTEXPR auto count_digits_fallback(T n) -> int {
|
template <typename T> FMT_CONSTEXPR auto count_digits_fallback(T n) -> int {
|
||||||
@@ -2136,7 +2137,7 @@ template <typename UInt> struct write_int_arg {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign)
|
FMT_CONSTEXPR auto make_write_int_arg(T value, sign s)
|
||||||
-> write_int_arg<uint32_or_64_or_128_t<T>> {
|
-> write_int_arg<uint32_or_64_or_128_t<T>> {
|
||||||
auto prefix = 0u;
|
auto prefix = 0u;
|
||||||
auto abs_value = static_cast<uint32_or_64_or_128_t<T>>(value);
|
auto abs_value = static_cast<uint32_or_64_or_128_t<T>>(value);
|
||||||
@@ -2146,7 +2147,7 @@ FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign)
|
|||||||
} else {
|
} else {
|
||||||
constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+',
|
constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+',
|
||||||
0x1000000u | ' '};
|
0x1000000u | ' '};
|
||||||
prefix = prefixes[sign];
|
prefix = prefixes[static_cast<int>(s)];
|
||||||
}
|
}
|
||||||
return {abs_value, prefix};
|
return {abs_value, prefix};
|
||||||
}
|
}
|
||||||
@@ -2363,19 +2364,19 @@ FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
|
|||||||
|
|
||||||
template <typename Char, typename OutputIt>
|
template <typename Char, typename OutputIt>
|
||||||
FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan,
|
FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan,
|
||||||
format_specs specs, sign_t sign)
|
format_specs specs, sign s) -> OutputIt {
|
||||||
-> OutputIt {
|
|
||||||
auto str =
|
auto str =
|
||||||
isnan ? (specs.upper() ? "NAN" : "nan") : (specs.upper() ? "INF" : "inf");
|
isnan ? (specs.upper() ? "NAN" : "nan") : (specs.upper() ? "INF" : "inf");
|
||||||
constexpr size_t str_size = 3;
|
constexpr size_t str_size = 3;
|
||||||
auto size = str_size + (sign ? 1 : 0);
|
auto size = str_size + (s != sign::none ? 1 : 0);
|
||||||
// Replace '0'-padding with space for non-finite values.
|
// Replace '0'-padding with space for non-finite values.
|
||||||
const bool is_zero_fill =
|
const bool is_zero_fill =
|
||||||
specs.fill_size() == 1 && specs.fill_unit<Char>() == '0';
|
specs.fill_size() == 1 && specs.fill_unit<Char>() == '0';
|
||||||
if (is_zero_fill) specs.set_fill(' ');
|
if (is_zero_fill) specs.set_fill(' ');
|
||||||
return write_padded<Char>(out, specs, size,
|
return write_padded<Char>(out, specs, size,
|
||||||
[=](reserve_iterator<OutputIt> it) {
|
[=](reserve_iterator<OutputIt> it) {
|
||||||
if (sign) *it++ = detail::sign<Char>(sign);
|
if (s != sign::none)
|
||||||
|
*it++ = detail::getsign<Char>(s);
|
||||||
return copy<Char>(str, str + str_size, it);
|
return copy<Char>(str, str + str_size, it);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2486,12 +2487,12 @@ FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand,
|
|||||||
template <typename Char, typename OutputIt, typename DecimalFP,
|
template <typename Char, typename OutputIt, typename DecimalFP,
|
||||||
typename Grouping = digit_grouping<Char>>
|
typename Grouping = digit_grouping<Char>>
|
||||||
FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
|
FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
|
||||||
const format_specs& specs, sign_t sign,
|
const format_specs& specs, sign s,
|
||||||
locale_ref loc) -> OutputIt {
|
locale_ref loc) -> OutputIt {
|
||||||
auto significand = f.significand;
|
auto significand = f.significand;
|
||||||
int significand_size = get_significand_size(f);
|
int significand_size = get_significand_size(f);
|
||||||
const Char zero = static_cast<Char>('0');
|
const Char zero = static_cast<Char>('0');
|
||||||
size_t size = to_unsigned(significand_size) + (sign ? 1 : 0);
|
size_t size = to_unsigned(significand_size) + (s != sign::none ? 1 : 0);
|
||||||
using iterator = reserve_iterator<OutputIt>;
|
using iterator = reserve_iterator<OutputIt>;
|
||||||
|
|
||||||
Char decimal_point = specs.localized() ? detail::decimal_point<Char>(loc)
|
Char decimal_point = specs.localized() ? detail::decimal_point<Char>(loc)
|
||||||
@@ -2523,7 +2524,7 @@ FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
|
|||||||
size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits);
|
size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits);
|
||||||
char exp_char = specs.upper() ? 'E' : 'e';
|
char exp_char = specs.upper() ? 'E' : 'e';
|
||||||
auto write = [=](iterator it) {
|
auto write = [=](iterator it) {
|
||||||
if (sign) *it++ = detail::sign<Char>(sign);
|
if (s != sign::none) *it++ = detail::getsign<Char>(s);
|
||||||
// Insert a decimal point after the first digit and add an exponent.
|
// Insert a decimal point after the first digit and add an exponent.
|
||||||
it = write_significand(it, significand, significand_size, 1,
|
it = write_significand(it, significand, significand_size, 1,
|
||||||
decimal_point);
|
decimal_point);
|
||||||
@@ -2551,7 +2552,7 @@ FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
|
|||||||
auto grouping = Grouping(loc, specs.localized());
|
auto grouping = Grouping(loc, specs.localized());
|
||||||
size += to_unsigned(grouping.count_separators(exp));
|
size += to_unsigned(grouping.count_separators(exp));
|
||||||
return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
|
return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
|
||||||
if (sign) *it++ = detail::sign<Char>(sign);
|
if (s != sign::none) *it++ = detail::getsign<Char>(s);
|
||||||
it = write_significand<Char>(it, significand, significand_size,
|
it = write_significand<Char>(it, significand, significand_size,
|
||||||
f.exponent, grouping);
|
f.exponent, grouping);
|
||||||
if (!specs.alt()) return it;
|
if (!specs.alt()) return it;
|
||||||
@@ -2565,7 +2566,7 @@ FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
|
|||||||
auto grouping = Grouping(loc, specs.localized());
|
auto grouping = Grouping(loc, specs.localized());
|
||||||
size += to_unsigned(grouping.count_separators(exp));
|
size += to_unsigned(grouping.count_separators(exp));
|
||||||
return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
|
return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
|
||||||
if (sign) *it++ = detail::sign<Char>(sign);
|
if (s != sign::none) *it++ = detail::getsign<Char>(s);
|
||||||
it = write_significand(it, significand, significand_size, exp,
|
it = write_significand(it, significand, significand_size, exp,
|
||||||
decimal_point, grouping);
|
decimal_point, grouping);
|
||||||
return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
|
return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
|
||||||
@@ -2580,7 +2581,7 @@ FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
|
|||||||
bool pointy = num_zeros != 0 || significand_size != 0 || specs.alt();
|
bool pointy = num_zeros != 0 || significand_size != 0 || specs.alt();
|
||||||
size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros);
|
size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros);
|
||||||
return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
|
return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
|
||||||
if (sign) *it++ = detail::sign<Char>(sign);
|
if (s != sign::none) *it++ = detail::getsign<Char>(s);
|
||||||
*it++ = zero;
|
*it++ = zero;
|
||||||
if (!pointy) return it;
|
if (!pointy) return it;
|
||||||
*it++ = decimal_point;
|
*it++ = decimal_point;
|
||||||
@@ -2605,14 +2606,13 @@ template <typename Char> class fallback_digit_grouping {
|
|||||||
|
|
||||||
template <typename Char, typename OutputIt, typename DecimalFP>
|
template <typename Char, typename OutputIt, typename DecimalFP>
|
||||||
FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& f,
|
FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& f,
|
||||||
const format_specs& specs, sign_t sign,
|
const format_specs& specs, sign s,
|
||||||
locale_ref loc) -> OutputIt {
|
locale_ref loc) -> OutputIt {
|
||||||
if (is_constant_evaluated()) {
|
if (is_constant_evaluated()) {
|
||||||
return do_write_float<Char, OutputIt, DecimalFP,
|
return do_write_float<Char, OutputIt, DecimalFP,
|
||||||
fallback_digit_grouping<Char>>(out, f, specs, sign,
|
fallback_digit_grouping<Char>>(out, f, specs, s, loc);
|
||||||
loc);
|
|
||||||
} else {
|
} else {
|
||||||
return do_write_float<Char>(out, f, specs, sign, loc);
|
return do_write_float<Char>(out, f, specs, s, loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3464,14 +3464,14 @@ template <typename Char, typename OutputIt, typename T>
|
|||||||
FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
|
FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
|
||||||
locale_ref loc) -> OutputIt {
|
locale_ref loc) -> OutputIt {
|
||||||
// Use signbit because value < 0 is false for NaN.
|
// Use signbit because value < 0 is false for NaN.
|
||||||
sign_t sign = detail::signbit(value) ? sign::minus : specs.sign();
|
sign s = detail::signbit(value) ? sign::minus : specs.sign();
|
||||||
|
|
||||||
if (!detail::isfinite(value))
|
if (!detail::isfinite(value))
|
||||||
return write_nonfinite<Char>(out, detail::isnan(value), specs, sign);
|
return write_nonfinite<Char>(out, detail::isnan(value), specs, s);
|
||||||
|
|
||||||
if (specs.align() == align::numeric && sign) {
|
if (specs.align() == align::numeric && s != sign::none) {
|
||||||
*out++ = detail::sign<Char>(sign);
|
*out++ = detail::getsign<Char>(s);
|
||||||
sign = sign::none;
|
s = sign::none;
|
||||||
if (specs.width != 0) --specs.width;
|
if (specs.width != 0) --specs.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3483,13 +3483,13 @@ FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
|
|||||||
// Use Dragonbox for the shortest format.
|
// Use Dragonbox for the shortest format.
|
||||||
using floaty = conditional_t<sizeof(T) >= sizeof(double), double, float>;
|
using floaty = conditional_t<sizeof(T) >= sizeof(double), double, float>;
|
||||||
auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
|
auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
|
||||||
return write_float<Char>(out, dec, specs, sign, loc);
|
return write_float<Char>(out, dec, specs, s, loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
if (specs.type() == presentation_type::hexfloat) {
|
if (specs.type() == presentation_type::hexfloat) {
|
||||||
if (sign) buffer.push_back(detail::sign<char>(sign));
|
if (s != sign::none) buffer.push_back(detail::getsign<char>(s));
|
||||||
format_hexfloat(convert_float(value), specs, buffer);
|
format_hexfloat(convert_float(value), specs, buffer);
|
||||||
return write_bytes<Char, align::right>(out, {buffer.data(), buffer.size()},
|
return write_bytes<Char, align::right>(out, {buffer.data(), buffer.size()},
|
||||||
specs);
|
specs);
|
||||||
@@ -3511,7 +3511,7 @@ FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
|
|||||||
|
|
||||||
specs.precision = precision;
|
specs.precision = precision;
|
||||||
auto f = big_decimal_fp{buffer.data(), static_cast<int>(buffer.size()), exp};
|
auto f = big_decimal_fp{buffer.data(), static_cast<int>(buffer.size()), exp};
|
||||||
return write_float<Char>(out, f, specs, sign, loc);
|
return write_float<Char>(out, f, specs, s, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename OutputIt, typename T,
|
template <typename Char, typename OutputIt, typename T,
|
||||||
@@ -3530,17 +3530,17 @@ FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt {
|
|||||||
if (is_constant_evaluated()) return write<Char>(out, value, format_specs());
|
if (is_constant_evaluated()) return write<Char>(out, value, format_specs());
|
||||||
if (const_check(!is_supported_floating_point(value))) return out;
|
if (const_check(!is_supported_floating_point(value))) return out;
|
||||||
|
|
||||||
auto sign = detail::signbit(value) ? sign::minus : sign_t::none;
|
auto s = detail::signbit(value) ? sign::minus : sign::none;
|
||||||
|
|
||||||
constexpr auto specs = format_specs();
|
constexpr auto specs = format_specs();
|
||||||
using floaty = conditional_t<sizeof(T) >= sizeof(double), double, float>;
|
using floaty = conditional_t<sizeof(T) >= sizeof(double), double, float>;
|
||||||
using floaty_uint = typename dragonbox::float_info<floaty>::carrier_uint;
|
using floaty_uint = typename dragonbox::float_info<floaty>::carrier_uint;
|
||||||
floaty_uint mask = exponent_mask<floaty>();
|
floaty_uint mask = exponent_mask<floaty>();
|
||||||
if ((bit_cast<floaty_uint>(value) & mask) == mask)
|
if ((bit_cast<floaty_uint>(value) & mask) == mask)
|
||||||
return write_nonfinite<Char>(out, std::isnan(value), specs, sign);
|
return write_nonfinite<Char>(out, std::isnan(value), specs, s);
|
||||||
|
|
||||||
auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
|
auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
|
||||||
return write_float<Char>(out, dec, specs, sign, {});
|
return write_float<Char>(out, dec, specs, s, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename OutputIt, typename T,
|
template <typename Char, typename OutputIt, typename T,
|
||||||
|
Reference in New Issue
Block a user