From 993f56cff6f0c3f03953cae44c44693ca782725a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 11 Aug 2024 12:26:22 -0700 Subject: [PATCH] Make sign a proper enum class --- include/fmt/base.h | 23 ++++------------- include/fmt/format.h | 60 ++++++++++++++++++++++---------------------- 2 files changed, 35 insertions(+), 48 deletions(-) diff --git a/include/fmt/base.h b/include/fmt/base.h index 188aca5b..ab7a238f 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -2051,20 +2051,6 @@ FMT_END_EXPORT // between clang and gcc on ARM (#1919). FMT_EXPORT using format_args = basic_format_args; -// 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 { template @@ -2115,6 +2101,7 @@ enum class presentation_type : unsigned char { }; enum class align { none, left, right, center, numeric }; +enum class sign { none, minus, plus, space }; // Basic format specifiers for built-in and string types. class basic_specs { @@ -2201,11 +2188,11 @@ class basic_specs { return (data_ & (width_mask | precision_mask)) != 0; } - constexpr auto sign() const -> sign_t { - return static_cast((data_ & sign_mask) >> sign_shift); + constexpr auto sign() const -> sign { + return static_cast((data_ & sign_mask) >> sign_shift); } - FMT_CONSTEXPR void set_sign(sign_t a) { - data_ = (data_ & ~sign_mask) | (static_cast(a) << sign_shift); + FMT_CONSTEXPR void set_sign(fmt::sign s) { + data_ = (data_ & ~sign_mask) | (static_cast(s) << sign_shift); } constexpr auto upper() const -> bool { return (data_ & uppercase_mask) != 0; } diff --git a/include/fmt/format.h b/include/fmt/format.h index c3b1760f..d5c746e1 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -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. -template constexpr auto sign(Sign s) -> Char { +template constexpr auto getsign(Sign s) -> Char { #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604 - static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); #endif - return static_cast(((' ' << 24) | ('+' << 16) | ('-' << 8)) >> (s * 8)); + return static_cast(((' ' << 24) | ('+' << 16) | ('-' << 8)) >> + (static_cast(s) * 8)); } template FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { @@ -2136,7 +2137,7 @@ template struct write_int_arg { }; template -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> { auto prefix = 0u; auto abs_value = static_cast>(value); @@ -2146,7 +2147,7 @@ FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign) } else { constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', 0x1000000u | ' '}; - prefix = prefixes[sign]; + prefix = prefixes[static_cast(s)]; } return {abs_value, prefix}; } @@ -2363,19 +2364,19 @@ FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end, template FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan, - format_specs specs, sign_t sign) - -> OutputIt { + format_specs specs, sign s) -> OutputIt { auto str = isnan ? (specs.upper() ? "NAN" : "nan") : (specs.upper() ? "INF" : "inf"); 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. const bool is_zero_fill = specs.fill_size() == 1 && specs.fill_unit() == '0'; if (is_zero_fill) specs.set_fill(' '); return write_padded(out, specs, size, [=](reserve_iterator it) { - if (sign) *it++ = detail::sign(sign); + if (s != sign::none) + *it++ = detail::getsign(s); return copy(str, str + str_size, it); }); } @@ -2486,12 +2487,12 @@ FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, template > 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 { auto significand = f.significand; int significand_size = get_significand_size(f); const Char zero = static_cast('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; Char decimal_point = specs.localized() ? detail::decimal_point(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); char exp_char = specs.upper() ? 'E' : 'e'; auto write = [=](iterator it) { - if (sign) *it++ = detail::sign(sign); + if (s != sign::none) *it++ = detail::getsign(s); // Insert a decimal point after the first digit and add an exponent. it = write_significand(it, significand, significand_size, 1, decimal_point); @@ -2551,7 +2552,7 @@ FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f, auto grouping = Grouping(loc, specs.localized()); size += to_unsigned(grouping.count_separators(exp)); return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = detail::sign(sign); + if (s != sign::none) *it++ = detail::getsign(s); it = write_significand(it, significand, significand_size, f.exponent, grouping); 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()); size += to_unsigned(grouping.count_separators(exp)); return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = detail::sign(sign); + if (s != sign::none) *it++ = detail::getsign(s); it = write_significand(it, significand, significand_size, exp, decimal_point, grouping); 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(); size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros); return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = detail::sign(sign); + if (s != sign::none) *it++ = detail::getsign(s); *it++ = zero; if (!pointy) return it; *it++ = decimal_point; @@ -2605,14 +2606,13 @@ template class fallback_digit_grouping { template 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 { if (is_constant_evaluated()) { return do_write_float>(out, f, specs, sign, - loc); + fallback_digit_grouping>(out, f, specs, s, loc); } else { - return do_write_float(out, f, specs, sign, loc); + return do_write_float(out, f, specs, s, loc); } } @@ -3464,14 +3464,14 @@ template FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs, locale_ref loc) -> OutputIt { // 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)) - return write_nonfinite(out, detail::isnan(value), specs, sign); + return write_nonfinite(out, detail::isnan(value), specs, s); - if (specs.align() == align::numeric && sign) { - *out++ = detail::sign(sign); - sign = sign::none; + if (specs.align() == align::numeric && s != sign::none) { + *out++ = detail::getsign(s); + s = sign::none; 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. using floaty = conditional_t= sizeof(double), double, float>; auto dec = dragonbox::to_decimal(static_cast(value)); - return write_float(out, dec, specs, sign, loc); + return write_float(out, dec, specs, s, loc); } } memory_buffer buffer; if (specs.type() == presentation_type::hexfloat) { - if (sign) buffer.push_back(detail::sign(sign)); + if (s != sign::none) buffer.push_back(detail::getsign(s)); format_hexfloat(convert_float(value), specs, buffer); return write_bytes(out, {buffer.data(), buffer.size()}, specs); @@ -3511,7 +3511,7 @@ FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs, specs.precision = precision; auto f = big_decimal_fp{buffer.data(), static_cast(buffer.size()), exp}; - return write_float(out, f, specs, sign, loc); + return write_float(out, f, specs, s, loc); } template OutputIt { if (is_constant_evaluated()) return write(out, value, format_specs()); 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(); using floaty = conditional_t= sizeof(double), double, float>; using floaty_uint = typename dragonbox::float_info::carrier_uint; floaty_uint mask = exponent_mask(); if ((bit_cast(value) & mask) == mask) - return write_nonfinite(out, std::isnan(value), specs, sign); + return write_nonfinite(out, std::isnan(value), specs, s); auto dec = dragonbox::to_decimal(static_cast(value)); - return write_float(out, dec, specs, sign, {}); + return write_float(out, dec, specs, s, {}); } template