Skip to content

Commit

Permalink
(:automated_merge:) Merge remote-tracking branch 'fmtlib-original/mas…
Browse files Browse the repository at this point in the history
…ter'
  • Loading branch information
GerHobbelt committed Aug 3, 2024
2 parents 1d59a29 + b9c0e4d commit 96cb351
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 60 deletions.
31 changes: 7 additions & 24 deletions include/fmt/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -2422,14 +2422,11 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
struct {
const Char*& begin;
dynamic_format_specs<Char>& specs;
format_specs& specs;
type arg_type;

FMT_CONSTEXPR auto operator()(pres pres_type, int set) -> const Char* {
if (!in(arg_type, set)) {
if (arg_type == type::none_type) return begin;
report_error("invalid format specifier");
}
if (!in(arg_type, set)) report_error("invalid format specifier");
specs.type = pres_type;
return begin + 1;
}
Expand All @@ -2445,35 +2442,23 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
++begin;
break;
case '+':
case '-':
FMT_FALLTHROUGH;
case ' ':
if (arg_type == type::none_type) return begin;
specs.sign = c == ' ' ? sign::space : sign::plus;
FMT_FALLTHROUGH;
case '-':
enter_state(state::sign, in(arg_type, sint_set | float_set));
switch (c) {
case '+':
specs.sign = sign::plus;
break;
case '-':
specs.sign = sign::minus;
break;
case ' ':
specs.sign = sign::space;
break;
}
++begin;
break;
case '#':
if (arg_type == type::none_type) return begin;
enter_state(state::hash, is_arithmetic_type(arg_type));
specs.alt = true;
++begin;
break;
case '0':
enter_state(state::zero);
if (!is_arithmetic_type(arg_type)) {
if (arg_type == type::none_type) return begin;
if (!is_arithmetic_type(arg_type))
report_error("format specifier requires numeric argument");
}
if (specs.align == align::none) {
// Ignore 0 if align is specified for compatibility with std::format.
specs.align = align::numeric;
Expand All @@ -2495,14 +2480,12 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
begin = parse_dynamic_spec(begin, end, specs.width, specs.width_ref, ctx);
break;
case '.':
if (arg_type == type::none_type) return begin;
enter_state(state::precision,
in(arg_type, float_set | string_set | cstring_set));
begin = parse_precision(begin, end, specs.precision, specs.precision_ref,
ctx);
break;
case 'L':
if (arg_type == type::none_type) return begin;
enter_state(state::locale, is_arithmetic_type(arg_type));
specs.localized = true;
++begin;
Expand Down
2 changes: 1 addition & 1 deletion include/fmt/chrono.h
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ FMT_CONSTEXPR inline auto get_units() -> const char* {
if (std::is_same<Period, std::femto>::value) return "fs";
if (std::is_same<Period, std::pico>::value) return "ps";
if (std::is_same<Period, std::nano>::value) return "ns";
if (std::is_same<Period, std::micro>::value) return "µs";
if (std::is_same<Period, std::micro>::value) return use_utf8() ? "µs" : "us";
if (std::is_same<Period, std::milli>::value) return "ms";
if (std::is_same<Period, std::centi>::value) return "cs";
if (std::is_same<Period, std::deci>::value) return "ds";
Expand Down
59 changes: 25 additions & 34 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -2325,7 +2325,6 @@ FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt {
return format_decimal<Char>(out, abs_value, num_digits);
}

// DEPRECATED!
template <typename Char>
FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
format_specs& specs) -> const Char* {
Expand Down Expand Up @@ -3175,11 +3174,10 @@ FMT_CONSTEXPR20 auto format_float(Float value, int precision,
buffer<char>& buf) -> int {
// float is passed as double to reduce the number of instantiations.
static_assert(!std::is_same<Float, float>::value, "");
FMT_ASSERT(value >= 0, "value is negative");
auto converted_value = convert_float(value);

const bool fixed = specs.type == presentation_type::fixed;
if (value <= 0) { // <= instead of == to silence a warning.
if (value == 0) {
if (precision <= 0 || !fixed) {
buf.push_back('0');
return 0;
Expand All @@ -3204,16 +3202,6 @@ FMT_CONSTEXPR20 auto format_float(Float value, int precision,
exp = static_cast<int>(e);
if (e > exp) ++exp; // Compute ceil.
dragon_flags = dragon::fixup;
} else if (precision < 0) {
// Use Dragonbox for the shortest format.
if (binary32) {
auto dec = dragonbox::to_decimal(static_cast<float>(value));
write<char>(appender(buf), dec.significand);
return dec.exponent;
}
auto dec = dragonbox::to_decimal(static_cast<double>(value));
write<char>(appender(buf), dec.significand);
return dec.exponent;
} else {
// Extract significand bits and exponent bits.
using info = dragonbox::float_info<double>;
Expand Down Expand Up @@ -3482,13 +3470,8 @@ FMT_CONSTEXPR20 auto format_float(Float value, int precision,
template <typename Char, typename OutputIt, typename T>
FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
locale_ref loc) -> OutputIt {
sign_t sign = specs.sign;
if (detail::signbit(value)) { // value < 0 is false for NaN so use signbit.
sign = sign::minus;
value = -value;
} else if (sign == sign::minus) {
sign = sign::none;
}
// Use signbit because value < 0 is false for NaN.
sign_t sign = detail::signbit(value) ? sign::minus : specs.sign;

if (!detail::isfinite(value))
return write_nonfinite<Char>(out, detail::isnan(value), specs, sign);
Expand All @@ -3499,6 +3482,18 @@ FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
if (specs.width != 0) --specs.width;
}

int precision = specs.precision;
if (precision < 0) {
if (specs.type != presentation_type::none) {
precision = 6;
} else if (is_fast_float<T>::value && !is_constant_evaluated()) {
// Use Dragonbox for the shortest format.
using floaty = conditional_t<sizeof(T) >= sizeof(double), double, float>;
auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
return write_float<Char>(out, dec, specs, sign, loc);
}
}

memory_buffer buffer;
if (specs.type == presentation_type::hexfloat) {
if (sign) buffer.push_back(detail::sign<char>(sign));
Expand All @@ -3507,9 +3502,6 @@ FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
specs);
}

int precision = specs.precision >= 0 || specs.type == presentation_type::none
? specs.precision
: 6;
if (specs.type == presentation_type::exp) {
if (precision == max_value<int>())
report_error("number is too big");
Expand All @@ -3521,7 +3513,6 @@ FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
} else if (precision == 0) {
precision = 1;
}

int exp = format_float(convert_float(value), precision, specs,
std::is_same<T, float>(), buffer);

Expand All @@ -3546,14 +3537,10 @@ FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt {
if (is_constant_evaluated()) return write<Char>(out, value, format_specs());
if (const_check(!is_supported_floating_point(value))) return out;

auto sign = sign_t::none;
if (detail::signbit(value)) {
sign = sign::minus;
value = -value;
}
auto sign = detail::signbit(value) ? sign::minus : sign_t::none;

constexpr auto specs = format_specs();
using floaty = conditional_t<std::is_same<T, long double>::value, double, T>;
using floaty = conditional_t<sizeof(T) >= sizeof(double), double, float>;
using floaty_uint = typename dragonbox::float_info<floaty>::carrier_uint;
floaty_uint mask = exponent_mask<floaty>();
if ((bit_cast<floaty_uint>(value) & mask) == mask)
Expand Down Expand Up @@ -4090,12 +4077,16 @@ template <typename T, typename Char = char> struct nested_formatter {

FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) {
auto specs = detail::dynamic_format_specs<Char>();
auto it = parse_format_specs(ctx.begin(), ctx.end(), specs, ctx,
detail::type::none_type);
width_ = specs.width;
auto it = ctx.begin(), end = ctx.end();
if (it == end) return it;
auto specs = format_specs();
it = detail::parse_align(it, end, specs);
fill_ = specs.fill;
align_ = specs.align;
Char c = *it;
auto width_ref = detail::arg_ref<Char>();
if ((c >= '0' && c <= '9') || c == '{')
it = detail::parse_dynamic_spec(it, end, width_, width_ref, ctx);
ctx.advance_to(it);
return formatter_.parse(ctx);
}
Expand Down
2 changes: 1 addition & 1 deletion test/base-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ TEST(base_test, constexpr_parse_format_specs) {
static_assert(parse_test_specs("<").align == fmt::align::left, "");
static_assert(parse_test_specs("*^").fill.get<char>() == '*', "");
static_assert(parse_test_specs("+").sign == fmt::sign::plus, "");
static_assert(parse_test_specs("-").sign == fmt::sign::minus, "");
static_assert(parse_test_specs("-").sign == fmt::sign::none, "");
static_assert(parse_test_specs(" ").sign == fmt::sign::space, "");
static_assert(parse_test_specs("#").alt, "");
static_assert(parse_test_specs("0").align == fmt::align::numeric, "");
Expand Down

0 comments on commit 96cb351

Please sign in to comment.