forked from fmtlib/fmt
Reduce format specs size
This commit is contained in:
@@ -2136,6 +2136,9 @@ struct fill_t {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class arg_id_kind { none, index, name };
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
enum class presentation_type : unsigned char {
|
enum class presentation_type : unsigned char {
|
||||||
@@ -2168,6 +2171,7 @@ struct format_specs {
|
|||||||
presentation_type type;
|
presentation_type type;
|
||||||
align_t align : 4;
|
align_t align : 4;
|
||||||
sign_t sign : 3;
|
sign_t sign : 3;
|
||||||
|
unsigned char dynamic : 4;
|
||||||
bool upper : 1; // An uppercase version e.g. 'X' for 'x'.
|
bool upper : 1; // An uppercase version e.g. 'X' for 'x'.
|
||||||
bool alt : 1; // Alternate form ('#').
|
bool alt : 1; // Alternate form ('#').
|
||||||
bool localized : 1;
|
bool localized : 1;
|
||||||
@@ -2179,38 +2183,31 @@ struct format_specs {
|
|||||||
type(presentation_type::none),
|
type(presentation_type::none),
|
||||||
align(align::none),
|
align(align::none),
|
||||||
sign(sign::none),
|
sign(sign::none),
|
||||||
|
dynamic(0),
|
||||||
upper(false),
|
upper(false),
|
||||||
alt(false),
|
alt(false),
|
||||||
localized(false) {}
|
localized(false) {}
|
||||||
|
|
||||||
|
enum { dynamic_width_mask = 3, dynamic_precision_mask = 12 };
|
||||||
|
|
||||||
|
constexpr auto dynamic_width() const -> detail::arg_id_kind {
|
||||||
|
return static_cast<detail::arg_id_kind>(dynamic & dynamic_width_mask);
|
||||||
|
}
|
||||||
|
constexpr auto dynamic_precision() const -> detail::arg_id_kind {
|
||||||
|
return static_cast<detail::arg_id_kind>(
|
||||||
|
(dynamic & dynamic_precision_mask) >> 2);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
enum class arg_id_kind { none, index, name };
|
|
||||||
|
|
||||||
// An argument reference.
|
// An argument reference.
|
||||||
template <typename Char> struct arg_ref {
|
template <typename Char> union arg_ref {
|
||||||
FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {}
|
FMT_CONSTEXPR arg_ref(int idx = 0) : index(idx) {}
|
||||||
|
FMT_CONSTEXPR arg_ref(basic_string_view<Char> n) : name(n) {}
|
||||||
FMT_CONSTEXPR explicit arg_ref(int index)
|
|
||||||
: kind(arg_id_kind::index), val(index) {}
|
|
||||||
FMT_CONSTEXPR explicit arg_ref(basic_string_view<Char> name)
|
|
||||||
: kind(arg_id_kind::name), val(name) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR auto operator=(int idx) -> arg_ref& {
|
|
||||||
kind = arg_id_kind::index;
|
|
||||||
val.index = idx;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
arg_id_kind kind;
|
|
||||||
union value {
|
|
||||||
FMT_CONSTEXPR value(int idx = 0) : index(idx) {}
|
|
||||||
FMT_CONSTEXPR value(basic_string_view<Char> n) : name(n) {}
|
|
||||||
|
|
||||||
int index;
|
int index;
|
||||||
basic_string_view<Char> name;
|
basic_string_view<Char> name;
|
||||||
} val;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Format specifiers with width and precision resolved at formatting rather
|
// Format specifiers with width and precision resolved at formatting rather
|
||||||
@@ -2321,28 +2318,37 @@ FMT_CONSTEXPR auto parse_arg_id(const Char* begin, const Char* end,
|
|||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char> struct dynamic_spec_id_handler {
|
template <typename Char> struct dynamic_spec_handler {
|
||||||
basic_format_parse_context<Char>& ctx;
|
basic_format_parse_context<Char>& ctx;
|
||||||
arg_ref<Char>& ref;
|
arg_ref<Char>& ref;
|
||||||
|
arg_id_kind& kind;
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_index(int id) {
|
FMT_CONSTEXPR void on_index(int id) {
|
||||||
ref = arg_ref<Char>(id);
|
ref = id;
|
||||||
|
kind = arg_id_kind::index;
|
||||||
ctx.check_arg_id(id);
|
ctx.check_arg_id(id);
|
||||||
ctx.check_dynamic_spec(id);
|
ctx.check_dynamic_spec(id);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR void on_name(basic_string_view<Char> id) {
|
FMT_CONSTEXPR void on_name(basic_string_view<Char> id) {
|
||||||
ref = arg_ref<Char>(id);
|
ref = id;
|
||||||
|
kind = arg_id_kind::name;
|
||||||
ctx.check_arg_id(id);
|
ctx.check_arg_id(id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Char> struct parse_dynamic_spec_result {
|
||||||
|
const Char* end;
|
||||||
|
arg_id_kind kind;
|
||||||
|
};
|
||||||
|
|
||||||
// Parses integer | "{" [arg_id] "}".
|
// Parses integer | "{" [arg_id] "}".
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end,
|
FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end,
|
||||||
int& value, arg_ref<Char>& ref,
|
int& value, arg_ref<Char>& ref,
|
||||||
basic_format_parse_context<Char>& ctx)
|
basic_format_parse_context<Char>& ctx)
|
||||||
-> const Char* {
|
-> parse_dynamic_spec_result<Char> {
|
||||||
FMT_ASSERT(begin != end, "");
|
FMT_ASSERT(begin != end, "");
|
||||||
|
auto kind = arg_id_kind::none;
|
||||||
if ('0' <= *begin && *begin <= '9') {
|
if ('0' <= *begin && *begin <= '9') {
|
||||||
int val = parse_nonnegative_int(begin, end, -1);
|
int val = parse_nonnegative_int(begin, end, -1);
|
||||||
if (val == -1) report_error("number is too big");
|
if (val == -1) report_error("number is too big");
|
||||||
@@ -2354,31 +2360,48 @@ FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end,
|
|||||||
Char c = *begin;
|
Char c = *begin;
|
||||||
if (c == '}' || c == ':') {
|
if (c == '}' || c == ':') {
|
||||||
int id = ctx.next_arg_id();
|
int id = ctx.next_arg_id();
|
||||||
ref = arg_ref<Char>(id);
|
ref = id;
|
||||||
|
kind = arg_id_kind::index;
|
||||||
ctx.check_dynamic_spec(id);
|
ctx.check_dynamic_spec(id);
|
||||||
} else {
|
} else {
|
||||||
begin =
|
begin = parse_arg_id(begin, end,
|
||||||
parse_arg_id(begin, end, dynamic_spec_id_handler<Char>{ctx, ref});
|
dynamic_spec_handler<Char>{ctx, ref, kind});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (begin != end && *begin == '}') return ++begin;
|
if (begin != end && *begin == '}') return {++begin, kind};
|
||||||
}
|
}
|
||||||
report_error("invalid format string");
|
report_error("invalid format string");
|
||||||
}
|
}
|
||||||
return begin;
|
return {begin, kind};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end,
|
||||||
|
format_specs& specs, arg_ref<Char>& width_ref,
|
||||||
|
basic_format_parse_context<Char>& ctx)
|
||||||
|
-> const Char* {
|
||||||
|
auto result = parse_dynamic_spec(begin, end, specs.width, width_ref, ctx);
|
||||||
|
specs.dynamic = static_cast<unsigned char>(result.kind) & 0x3u;
|
||||||
|
return result.end;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
|
FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
|
||||||
int& value, arg_ref<Char>& ref,
|
format_specs& specs,
|
||||||
|
arg_ref<Char>& precision_ref,
|
||||||
basic_format_parse_context<Char>& ctx)
|
basic_format_parse_context<Char>& ctx)
|
||||||
-> const Char* {
|
-> const Char* {
|
||||||
++begin;
|
++begin;
|
||||||
if (begin != end)
|
if (begin == end) {
|
||||||
begin = parse_dynamic_spec(begin, end, value, ref, ctx);
|
|
||||||
else
|
|
||||||
report_error("invalid precision");
|
report_error("invalid precision");
|
||||||
return begin;
|
return begin;
|
||||||
|
}
|
||||||
|
auto result =
|
||||||
|
parse_dynamic_spec(begin, end, specs.precision, precision_ref, ctx);
|
||||||
|
auto kind_val = static_cast<unsigned char>(result.kind);
|
||||||
|
specs.dynamic =
|
||||||
|
static_cast<unsigned char>(specs.dynamic | (kind_val << 2)) & 0xfu;
|
||||||
|
return result.end;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class state { start, align, sign, hash, zero, width, precision, locale };
|
enum class state { start, align, sign, hash, zero, width, precision, locale };
|
||||||
@@ -2466,13 +2489,12 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
|
|||||||
case '9':
|
case '9':
|
||||||
case '{':
|
case '{':
|
||||||
enter_state(state::width);
|
enter_state(state::width);
|
||||||
begin = parse_dynamic_spec(begin, end, specs.width, specs.width_ref, ctx);
|
begin = parse_width(begin, end, specs, specs.width_ref, ctx);
|
||||||
break;
|
break;
|
||||||
case '.':
|
case '.':
|
||||||
enter_state(state::precision,
|
enter_state(state::precision,
|
||||||
in(arg_type, float_set | string_set | cstring_set));
|
in(arg_type, float_set | string_set | cstring_set));
|
||||||
begin = parse_precision(begin, end, specs.precision, specs.precision_ref,
|
begin = parse_precision(begin, end, specs, specs.precision_ref, ctx);
|
||||||
ctx);
|
|
||||||
break;
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
enter_state(state::locale, is_arithmetic_type(arg_type));
|
enter_state(state::locale, is_arithmetic_type(arg_type));
|
||||||
|
@@ -2253,15 +2253,14 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
|
|
||||||
Char c = *it;
|
Char c = *it;
|
||||||
if ((c >= '0' && c <= '9') || c == '{') {
|
if ((c >= '0' && c <= '9') || c == '{') {
|
||||||
it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
|
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
|
||||||
if (it == end) return it;
|
if (it == end) return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto checker = detail::chrono_format_checker();
|
auto checker = detail::chrono_format_checker();
|
||||||
if (*it == '.') {
|
if (*it == '.') {
|
||||||
checker.has_precision_integral = !std::is_floating_point<Rep>::value;
|
checker.has_precision_integral = !std::is_floating_point<Rep>::value;
|
||||||
it = detail::parse_precision(it, end, specs_.precision, precision_ref_,
|
it = detail::parse_precision(it, end, specs_, precision_ref_, ctx);
|
||||||
ctx);
|
|
||||||
}
|
}
|
||||||
if (it != end && *it == 'L') {
|
if (it != end && *it == 'L') {
|
||||||
localized_ = true;
|
localized_ = true;
|
||||||
@@ -2283,8 +2282,10 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
// is not specified.
|
// is not specified.
|
||||||
auto buf = basic_memory_buffer<Char>();
|
auto buf = basic_memory_buffer<Char>();
|
||||||
auto out = basic_appender<Char>(buf);
|
auto out = basic_appender<Char>(buf);
|
||||||
detail::handle_dynamic_spec(specs.width, width_ref_, ctx);
|
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
||||||
detail::handle_dynamic_spec(precision, precision_ref_, ctx);
|
ctx);
|
||||||
|
detail::handle_dynamic_spec(specs.dynamic_precision(), precision,
|
||||||
|
precision_ref_, ctx);
|
||||||
if (begin == end || *begin == '}') {
|
if (begin == end || *begin == '}') {
|
||||||
out = detail::format_duration_value<Char>(out, d.count(), precision);
|
out = detail::format_duration_value<Char>(out, d.count(), precision);
|
||||||
detail::format_duration_unit<Char, Period>(out);
|
detail::format_duration_unit<Char, Period>(out);
|
||||||
@@ -2390,7 +2391,8 @@ template <typename Char> struct formatter<std::tm, Char> {
|
|||||||
auto specs = specs_;
|
auto specs = specs_;
|
||||||
auto buf = basic_memory_buffer<Char>();
|
auto buf = basic_memory_buffer<Char>();
|
||||||
auto out = basic_appender<Char>(buf);
|
auto out = basic_appender<Char>(buf);
|
||||||
detail::handle_dynamic_spec(specs.width, width_ref_, ctx);
|
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
||||||
|
ctx);
|
||||||
|
|
||||||
auto loc_ref = ctx.locale();
|
auto loc_ref = ctx.locale();
|
||||||
detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
|
detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
|
||||||
@@ -2412,7 +2414,7 @@ template <typename Char> struct formatter<std::tm, Char> {
|
|||||||
|
|
||||||
Char c = *it;
|
Char c = *it;
|
||||||
if ((c >= '0' && c <= '9') || c == '{') {
|
if ((c >= '0' && c <= '9') || c == '{') {
|
||||||
it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
|
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
|
||||||
if (it == end) return it;
|
if (it == end) return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -269,6 +269,7 @@ constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char> struct arg_id_handler {
|
template <typename Char> struct arg_id_handler {
|
||||||
|
arg_id_kind kind;
|
||||||
arg_ref<Char> arg_id;
|
arg_ref<Char> arg_id;
|
||||||
|
|
||||||
constexpr int on_auto() {
|
constexpr int on_auto() {
|
||||||
@@ -276,25 +277,28 @@ template <typename Char> struct arg_id_handler {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
constexpr int on_index(int id) {
|
constexpr int on_index(int id) {
|
||||||
|
kind = arg_id_kind::index;
|
||||||
arg_id = arg_ref<Char>(id);
|
arg_id = arg_ref<Char>(id);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
constexpr int on_name(basic_string_view<Char> id) {
|
constexpr int on_name(basic_string_view<Char> id) {
|
||||||
|
kind = arg_id_kind::name;
|
||||||
arg_id = arg_ref<Char>(id);
|
arg_id = arg_ref<Char>(id);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char> struct parse_arg_id_result {
|
template <typename Char> struct parse_arg_id_result {
|
||||||
|
arg_id_kind kind;
|
||||||
arg_ref<Char> arg_id;
|
arg_ref<Char> arg_id;
|
||||||
const Char* arg_id_end;
|
const Char* arg_id_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <int ID, typename Char>
|
template <int ID, typename Char>
|
||||||
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
|
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
|
||||||
auto handler = arg_id_handler<Char>{arg_ref<Char>{}};
|
auto handler = arg_id_handler<Char>{arg_id_kind::none, arg_ref<Char>{}};
|
||||||
auto arg_id_end = parse_arg_id(begin, end, handler);
|
auto arg_id_end = parse_arg_id(begin, end, handler);
|
||||||
return parse_arg_id_result<Char>{handler.arg_id, arg_id_end};
|
return parse_arg_id_result<Char>{handler.kind, handler.arg_id, arg_id_end};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename Enable = void> struct field_type {
|
template <typename T, typename Enable = void> struct field_type {
|
||||||
@@ -357,18 +361,18 @@ constexpr auto compile_format_string(S fmt) {
|
|||||||
constexpr char_type c =
|
constexpr char_type c =
|
||||||
arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
|
arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
|
||||||
static_assert(c == '}' || c == ':', "missing '}' in format string");
|
static_assert(c == '}' || c == ':', "missing '}' in format string");
|
||||||
if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) {
|
if constexpr (arg_id_result.kind == arg_id_kind::index) {
|
||||||
static_assert(
|
static_assert(
|
||||||
ID == manual_indexing_id || ID == 0,
|
ID == manual_indexing_id || ID == 0,
|
||||||
"cannot switch from automatic to manual argument indexing");
|
"cannot switch from automatic to manual argument indexing");
|
||||||
constexpr auto arg_index = arg_id_result.arg_id.val.index;
|
constexpr auto arg_index = arg_id_result.arg_id.index;
|
||||||
return parse_replacement_field_then_tail<get_type<arg_index, Args>,
|
return parse_replacement_field_then_tail<get_type<arg_index, Args>,
|
||||||
Args, arg_id_end_pos,
|
Args, arg_id_end_pos,
|
||||||
arg_index, manual_indexing_id>(
|
arg_index, manual_indexing_id>(
|
||||||
fmt);
|
fmt);
|
||||||
} else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) {
|
} else if constexpr (arg_id_result.kind == arg_id_kind::name) {
|
||||||
constexpr auto arg_index =
|
constexpr auto arg_index =
|
||||||
get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{});
|
get_arg_index_by_name(arg_id_result.arg_id.name, Args{});
|
||||||
if constexpr (arg_index >= 0) {
|
if constexpr (arg_index >= 0) {
|
||||||
constexpr auto next_id =
|
constexpr auto next_id =
|
||||||
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
|
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
|
||||||
@@ -377,8 +381,7 @@ constexpr auto compile_format_string(S fmt) {
|
|||||||
arg_index, next_id>(fmt);
|
arg_index, next_id>(fmt);
|
||||||
} else if constexpr (c == '}') {
|
} else if constexpr (c == '}') {
|
||||||
return parse_tail<Args, arg_id_end_pos + 1, ID>(
|
return parse_tail<Args, arg_id_end_pos + 1, ID>(
|
||||||
runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
|
runtime_named_field<char_type>{arg_id_result.arg_id.name}, fmt);
|
||||||
fmt);
|
|
||||||
} else if constexpr (c == ':') {
|
} else if constexpr (c == ':') {
|
||||||
return unknown_format(); // no type info for specs parsing
|
return unknown_format(); // no type info for specs parsing
|
||||||
}
|
}
|
||||||
|
@@ -3696,10 +3696,11 @@ FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> basic_format_arg<Context> {
|
|||||||
|
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
FMT_CONSTEXPR int get_dynamic_spec(
|
FMT_CONSTEXPR int get_dynamic_spec(
|
||||||
const arg_ref<typename Context::char_type>& ref, Context& ctx) {
|
arg_id_kind kind, const arg_ref<typename Context::char_type>& ref,
|
||||||
FMT_ASSERT(ref.kind != arg_id_kind::none, "");
|
Context& ctx) {
|
||||||
auto arg = ref.kind == arg_id_kind::index ? ctx.arg(ref.val.index)
|
FMT_ASSERT(kind != arg_id_kind::none, "");
|
||||||
: ctx.arg(ref.val.name);
|
auto arg =
|
||||||
|
kind == arg_id_kind::index ? ctx.arg(ref.index) : ctx.arg(ref.name);
|
||||||
if (!arg) report_error("argument not found");
|
if (!arg) report_error("argument not found");
|
||||||
unsigned long long value = arg.visit(dynamic_spec_getter());
|
unsigned long long value = arg.visit(dynamic_spec_getter());
|
||||||
if (value > to_unsigned(max_value<int>()))
|
if (value > to_unsigned(max_value<int>()))
|
||||||
@@ -3709,8 +3710,9 @@ FMT_CONSTEXPR int get_dynamic_spec(
|
|||||||
|
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
FMT_CONSTEXPR void handle_dynamic_spec(
|
FMT_CONSTEXPR void handle_dynamic_spec(
|
||||||
int& value, const arg_ref<typename Context::char_type>& ref, Context& ctx) {
|
arg_id_kind kind, int& value,
|
||||||
if (ref.kind != arg_id_kind::none) value = get_dynamic_spec(ref, ctx);
|
const arg_ref<typename Context::char_type>& ref, Context& ctx) {
|
||||||
|
if (kind != arg_id_kind::none) value = get_dynamic_spec(kind, ref, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_USER_DEFINED_LITERALS
|
#if FMT_USE_USER_DEFINED_LITERALS
|
||||||
@@ -3965,8 +3967,10 @@ template <> struct formatter<bytes> {
|
|||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(bytes b, FormatContext& ctx) const -> decltype(ctx.out()) {
|
auto format(bytes b, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||||
auto specs = specs_;
|
auto specs = specs_;
|
||||||
detail::handle_dynamic_spec(specs.width, specs.width_ref, ctx);
|
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
|
||||||
detail::handle_dynamic_spec(specs.precision, specs.precision_ref, ctx);
|
specs.width_ref, ctx);
|
||||||
|
detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
|
||||||
|
specs.precision_ref, ctx);
|
||||||
return detail::write_bytes<char>(ctx.out(), b.data_, specs);
|
return detail::write_bytes<char>(ctx.out(), b.data_, specs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -4004,8 +4008,10 @@ template <typename T> struct formatter<group_digits_view<T>> : formatter<T> {
|
|||||||
auto format(group_digits_view<T> t, FormatContext& ctx) const
|
auto format(group_digits_view<T> t, FormatContext& ctx) const
|
||||||
-> decltype(ctx.out()) {
|
-> decltype(ctx.out()) {
|
||||||
auto specs = specs_;
|
auto specs = specs_;
|
||||||
detail::handle_dynamic_spec(specs.width, specs.width_ref, ctx);
|
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
|
||||||
detail::handle_dynamic_spec(specs.precision, specs.precision_ref, ctx);
|
specs.width_ref, ctx);
|
||||||
|
detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
|
||||||
|
specs.precision_ref, ctx);
|
||||||
auto arg = detail::make_write_int_arg(t.value, specs.sign);
|
auto arg = detail::make_write_int_arg(t.value, specs.sign);
|
||||||
return detail::write_int(
|
return detail::write_int(
|
||||||
ctx.out(), static_cast<detail::uint64_or_128_t<T>>(arg.abs_value),
|
ctx.out(), static_cast<detail::uint64_or_128_t<T>>(arg.abs_value),
|
||||||
@@ -4051,8 +4057,10 @@ template <typename T, typename Char = char> struct nested_formatter {
|
|||||||
align_ = specs.align;
|
align_ = specs.align;
|
||||||
Char c = *it;
|
Char c = *it;
|
||||||
auto width_ref = detail::arg_ref<Char>();
|
auto width_ref = detail::arg_ref<Char>();
|
||||||
if ((c >= '0' && c <= '9') || c == '{')
|
if ((c >= '0' && c <= '9') || c == '{') {
|
||||||
it = detail::parse_dynamic_spec(it, end, width_, width_ref, ctx);
|
it = detail::parse_width(it, end, specs, width_ref, ctx);
|
||||||
|
width_ = specs.width;
|
||||||
|
}
|
||||||
ctx.advance_to(it);
|
ctx.advance_to(it);
|
||||||
return formatter_.parse(ctx);
|
return formatter_.parse(ctx);
|
||||||
}
|
}
|
||||||
@@ -4149,12 +4157,14 @@ template <typename Char> struct format_handler {
|
|||||||
if (arg.format_custom(begin, parse_context, context))
|
if (arg.format_custom(begin, parse_context, context))
|
||||||
return parse_context.begin();
|
return parse_context.begin();
|
||||||
|
|
||||||
auto specs = detail::dynamic_format_specs<Char>();
|
auto specs = dynamic_format_specs<Char>();
|
||||||
begin = parse_format_specs(begin, end, specs, parse_context, arg.type());
|
begin = parse_format_specs(begin, end, specs, parse_context, arg.type());
|
||||||
if (specs.width_ref.kind != detail::arg_id_kind::none)
|
if (specs.dynamic != 0) {
|
||||||
specs.width = detail::get_dynamic_spec(specs.width_ref, context);
|
handle_dynamic_spec(specs.dynamic_width(), specs.width, specs.width_ref,
|
||||||
if (specs.precision_ref.kind != detail::arg_id_kind::none)
|
context);
|
||||||
specs.precision = detail::get_dynamic_spec(specs.precision_ref, context);
|
handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
|
||||||
|
specs.precision_ref, context);
|
||||||
|
}
|
||||||
|
|
||||||
if (begin == end || *begin != '}')
|
if (begin == end || *begin != '}')
|
||||||
report_error("missing '}' in format string");
|
report_error("missing '}' in format string");
|
||||||
@@ -4196,13 +4206,13 @@ template <typename T, typename Char, type TYPE>
|
|||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
FMT_CONSTEXPR FMT_INLINE auto native_formatter<T, Char, TYPE>::format(
|
FMT_CONSTEXPR FMT_INLINE auto native_formatter<T, Char, TYPE>::format(
|
||||||
const T& val, FormatContext& ctx) const -> decltype(ctx.out()) {
|
const T& val, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||||
if (specs_.width_ref.kind == arg_id_kind::none &&
|
if (specs_.dynamic == 0)
|
||||||
specs_.precision_ref.kind == arg_id_kind::none) {
|
|
||||||
return write<Char>(ctx.out(), val, specs_, ctx.locale());
|
return write<Char>(ctx.out(), val, specs_, ctx.locale());
|
||||||
}
|
|
||||||
auto specs = format_specs(specs_);
|
auto specs = format_specs(specs_);
|
||||||
handle_dynamic_spec(specs.width, specs_.width_ref, ctx);
|
handle_dynamic_spec(specs.dynamic_width(), specs.width, specs_.width_ref,
|
||||||
handle_dynamic_spec(specs.precision, specs_.precision_ref, ctx);
|
ctx);
|
||||||
|
handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
|
||||||
|
specs_.precision_ref, ctx);
|
||||||
return write<Char>(ctx.out(), val, specs, ctx.locale());
|
return write<Char>(ctx.out(), val, specs, ctx.locale());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -131,7 +131,7 @@ template <typename Char> struct formatter<std::filesystem::path, Char> {
|
|||||||
|
|
||||||
Char c = *it;
|
Char c = *it;
|
||||||
if ((c >= '0' && c <= '9') || c == '{')
|
if ((c >= '0' && c <= '9') || c == '{')
|
||||||
it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
|
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
|
||||||
if (it != end && *it == '?') {
|
if (it != end && *it == '?') {
|
||||||
debug_ = true;
|
debug_ = true;
|
||||||
++it;
|
++it;
|
||||||
@@ -147,7 +147,8 @@ template <typename Char> struct formatter<std::filesystem::path, Char> {
|
|||||||
!path_type_ ? p.native()
|
!path_type_ ? p.native()
|
||||||
: p.generic_string<std::filesystem::path::value_type>();
|
: p.generic_string<std::filesystem::path::value_type>();
|
||||||
|
|
||||||
detail::handle_dynamic_spec(specs.width, width_ref_, ctx);
|
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
||||||
|
ctx);
|
||||||
if (!debug_) {
|
if (!debug_) {
|
||||||
auto s = detail::get_path_string<Char>(p, path_string);
|
auto s = detail::get_path_string<Char>(p, path_string);
|
||||||
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
|
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
|
||||||
@@ -669,10 +670,11 @@ template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
|
|||||||
auto format(const std::complex<T>& c, FormatContext& ctx) const
|
auto format(const std::complex<T>& c, FormatContext& ctx) const
|
||||||
-> decltype(ctx.out()) {
|
-> decltype(ctx.out()) {
|
||||||
auto specs = specs_;
|
auto specs = specs_;
|
||||||
if (specs.width_ref.kind != detail::arg_id_kind::none ||
|
if (specs.dynamic != 0) {
|
||||||
specs.precision_ref.kind != detail::arg_id_kind::none) {
|
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
|
||||||
detail::handle_dynamic_spec(specs.width, specs.width_ref, ctx);
|
specs.width_ref, ctx);
|
||||||
detail::handle_dynamic_spec(specs.precision, specs.precision_ref, ctx);
|
detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
|
||||||
|
specs.precision_ref, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (specs.width == 0) return do_format(c, specs, ctx, ctx.out());
|
if (specs.width == 0) return do_format(c, specs, ctx, ctx.out());
|
||||||
|
@@ -525,9 +525,9 @@ TEST(base_test, constexpr_parse_format_specs) {
|
|||||||
static_assert(parse_test_specs("0").align == fmt::align::numeric, "");
|
static_assert(parse_test_specs("0").align == fmt::align::numeric, "");
|
||||||
static_assert(parse_test_specs("L").localized, "");
|
static_assert(parse_test_specs("L").localized, "");
|
||||||
static_assert(parse_test_specs("42").width == 42, "");
|
static_assert(parse_test_specs("42").width == 42, "");
|
||||||
static_assert(parse_test_specs("{42}").width_ref.val.index == 42, "");
|
static_assert(parse_test_specs("{42}").width_ref.index == 42, "");
|
||||||
static_assert(parse_test_specs(".42").precision == 42, "");
|
static_assert(parse_test_specs(".42").precision == 42, "");
|
||||||
static_assert(parse_test_specs(".{42}").precision_ref.val.index == 42, "");
|
static_assert(parse_test_specs(".{42}").precision_ref.index == 42, "");
|
||||||
static_assert(parse_test_specs("f").type == fmt::presentation_type::fixed,
|
static_assert(parse_test_specs("f").type == fmt::presentation_type::fixed,
|
||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user