Skip to content

Commit 8e007d5

Browse files
committed
perf: formatters compile-time performance improved
1 parent 5c33f6c commit 8e007d5

File tree

5 files changed

+40
-46
lines changed

5 files changed

+40
-46
lines changed

example/kalman_filter/kalman.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,7 @@ class MP_UNITS_STD_FMT::formatter<kalman::system_state<QPs...>, Char> {
308308
std::basic_string<Char> quantity_buffer;
309309
format_system_state(std::back_inserter(quantity_buffer), s, ctx, std::index_sequence_for<QPs...>{});
310310

311-
std::basic_string<Char> fill_align_width_format_str;
312-
mp_units::detail::format_global_buffer(std::back_inserter(fill_align_width_format_str), specs);
313-
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), fill_align_width_format_str,
314-
MP_UNITS_STD_FMT::make_format_args(quantity_buffer));
311+
return mp_units::detail::write_padded<Char>(ctx.out(), std::basic_string_view<Char>{quantity_buffer}, specs.width,
312+
specs.align, specs.fill);
315313
}
316314
};

src/core/include/mp-units/bits/format.h

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -67,28 +67,28 @@ template<std::forward_iterator It, typename Specs>
6767
return mp_units::detail::parse_dynamic_spec(it, end, specs.width, specs.width_ref, ctx);
6868
}
6969

70-
template<typename Char, std::output_iterator<Char> It>
71-
constexpr It format_global_buffer(It out, const fill_align_width_format_specs<Char>& specs)
70+
/**
71+
* @brief Writes a string to an output iterator with fill/align/width padding.
72+
*
73+
* Avoids instantiating format_to/vformat_to infrastructure for the common padding use-case
74+
* inside formatter<Unit>, formatter<Dimension>, and formatter<quantity> specializations.
75+
*/
76+
template<typename Char, std::output_iterator<Char> Out>
77+
constexpr Out write_padded(Out out, std::basic_string_view<Char> s, int width, fmt_align align,
78+
const fill_t<Char>& fill)
7279
{
73-
MP_UNITS_STD_FMT::format_to(out, "{{:");
74-
if (specs.fill.size() != 1 || specs.fill[0] != ' ') {
75-
MP_UNITS_STD_FMT::format_to(out, "{}", specs.fill.data());
76-
}
77-
switch (specs.align) {
78-
case fmt_align::left:
79-
MP_UNITS_STD_FMT::format_to(out, "<");
80-
break;
81-
case fmt_align::right:
82-
MP_UNITS_STD_FMT::format_to(out, ">");
83-
break;
84-
case fmt_align::center:
85-
MP_UNITS_STD_FMT::format_to(out, "^");
86-
break;
87-
default:
88-
break;
89-
}
90-
if (specs.width >= 1) MP_UNITS_STD_FMT::format_to(out, "{}", specs.width);
91-
return MP_UNITS_STD_FMT::format_to(out, "}}");
80+
const int len = static_cast<int>(s.size());
81+
const int pad = (width > len) ? width - len : 0;
82+
const int lpad = (align == fmt_align::center) ? pad / 2 : (align == fmt_align::right) ? pad : 0;
83+
const int rpad = pad - lpad;
84+
auto write_fill = [&](int n) {
85+
for (int i = 0; i < n; ++i)
86+
for (std::size_t j = 0; j < fill.size(); ++j) *out++ = fill[j];
87+
};
88+
write_fill(lpad);
89+
for (Char c : s) *out++ = c;
90+
write_fill(rpad);
91+
return out;
9292
}
9393

9494
MP_UNITS_EXPORT_END

src/core/include/mp-units/framework/dimension.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,6 @@ template<typename D, typename Char>
345345
class MP_UNITS_STD_FMT::formatter<D, Char> {
346346
struct format_specs : mp_units::detail::fill_align_width_format_specs<Char>, mp_units::dimension_symbol_formatting {};
347347
format_specs specs_{};
348-
std::basic_string_view<Char> fill_align_width_format_str_;
349348

350349
template<std::forward_iterator It>
351350
constexpr It parse_dimension_specs(It begin, It end)
@@ -374,7 +373,6 @@ class MP_UNITS_STD_FMT::formatter<D, Char> {
374373
auto end = ctx.end();
375374

376375
auto it = parse_fill_align_width(ctx, begin, end, specs_);
377-
fill_align_width_format_str_ = {begin, it};
378376
if (it == end) return it;
379377

380378
return parse_dimension_specs(it, end);
@@ -391,11 +389,8 @@ class MP_UNITS_STD_FMT::formatter<D, Char> {
391389
return mp_units::dimension_symbol_to<Char>(ctx.out(), d, specs);
392390
std::basic_string<Char> unit_buffer;
393391
mp_units::dimension_symbol_to<Char>(std::back_inserter(unit_buffer), d, specs);
394-
395-
const std::basic_string<Char> global_format_buffer =
396-
"{:" + std::basic_string<Char>{fill_align_width_format_str_} + "}";
397-
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), global_format_buffer,
398-
MP_UNITS_STD_FMT::make_format_args(unit_buffer));
392+
return mp_units::detail::write_padded<Char>(ctx.out(), std::basic_string_view<Char>{unit_buffer}, specs.width,
393+
specs.align, specs.fill);
399394
}
400395
};
401396

src/core/include/mp-units/framework/quantity.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,18 +1080,25 @@ class MP_UNITS_STD_FMT::formatter<mp_units::quantity<Reference, Rep>, Char> {
10801080
auto specs = specs_;
10811081
mp_units::detail::handle_dynamic_spec<mp_units::detail::width_checker>(specs.width, specs.width_ref, ctx);
10821082

1083+
if (specs.width == 0 && modifiers_format_str_.empty()) {
1084+
// Common fast path: call pre-parsed sub-formatters directly — no vformat_to, no allocation
1085+
ctx.advance_to(rep_formatter_.format(q.numerical_value_ref_in(q.unit), ctx));
1086+
if constexpr (mp_units::space_before_unit_symbol<unit>) {
1087+
auto it = ctx.out();
1088+
*it++ = ' ';
1089+
ctx.advance_to(it);
1090+
}
1091+
return unit_formatter_.format(q.unit, ctx);
1092+
}
10831093
if (specs.width == 0) {
1084-
// Avoid extra copying if width is not specified
1094+
// Custom modifiers, no width
10851095
format_quantity(ctx.out(), q, ctx);
10861096
return ctx.out();
10871097
}
10881098
std::basic_string<Char> quantity_buffer;
10891099
format_quantity(std::back_inserter(quantity_buffer), q, ctx);
1090-
1091-
std::basic_string<Char> fill_align_width_format_str;
1092-
mp_units::detail::format_global_buffer(std::back_inserter(fill_align_width_format_str), specs);
1093-
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), fill_align_width_format_str,
1094-
MP_UNITS_STD_FMT::make_format_args(quantity_buffer));
1100+
return mp_units::detail::write_padded<Char>(ctx.out(), std::basic_string_view<Char>{quantity_buffer}, specs.width,
1101+
specs.align, specs.fill);
10951102
}
10961103
};
10971104

src/core/include/mp-units/framework/unit.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -984,8 +984,6 @@ class MP_UNITS_STD_FMT::formatter<U, Char> {
984984
struct format_specs : mp_units::detail::fill_align_width_format_specs<Char>, mp_units::unit_symbol_formatting {};
985985
format_specs specs_{};
986986

987-
std::basic_string_view<Char> fill_align_width_format_str_;
988-
989987
template<std::forward_iterator It>
990988
constexpr It parse_unit_specs(It begin, It end)
991989
{
@@ -1031,7 +1029,6 @@ class MP_UNITS_STD_FMT::formatter<U, Char> {
10311029
auto end = ctx.end();
10321030

10331031
auto it = parse_fill_align_width(ctx, begin, end, specs_);
1034-
fill_align_width_format_str_ = {begin, it};
10351032
if (it == end) return it;
10361033

10371034
return parse_unit_specs(it, end);
@@ -1048,11 +1045,8 @@ class MP_UNITS_STD_FMT::formatter<U, Char> {
10481045
return mp_units::unit_symbol_to<Char>(ctx.out(), u, specs);
10491046
std::basic_string<Char> unit_buffer;
10501047
mp_units::unit_symbol_to<Char>(std::back_inserter(unit_buffer), u, specs);
1051-
1052-
const std::basic_string<Char> global_format_buffer =
1053-
"{:" + std::basic_string<Char>{fill_align_width_format_str_} + "}";
1054-
return MP_UNITS_STD_FMT::vformat_to(ctx.out(), global_format_buffer,
1055-
MP_UNITS_STD_FMT::make_format_args(unit_buffer));
1048+
return mp_units::detail::write_padded<Char>(ctx.out(), std::basic_string_view<Char>{unit_buffer}, specs.width,
1049+
specs.align, specs.fill);
10561050
}
10571051
};
10581052

0 commit comments

Comments
 (0)