diff --git a/README.md b/README.md index f5b93998d..a7497260b 100644 --- a/README.md +++ b/README.md @@ -121,8 +121,8 @@ int main() std::cout << std::setw(10) << std::setfill('*') << v2 << '\n'; // ***70 mi/h std::cout << std::format("{:*^10}\n", v3); // *110 km/h* std::println("{:%N in %U}", v4); // 70 in mi/h - std::println("{:{%N:.2f}%?%U}", v5); // 30.56 m/s - std::println("{:{%N:.2f}%?{%U:n}}", v6); // 31.29 m s⁻¹ + std::println("{::N[.2f]}", v5); // 30.56 m/s + std::println("{::N[.2f]U[n]}", v6); // 31.29 m s⁻¹ std::println("{:%N}", v7); // 31 } ``` diff --git a/docs/getting_started/look_and_feel.md b/docs/getting_started/look_and_feel.md index b67906a7b..8e896a5cc 100644 --- a/docs/getting_started/look_and_feel.md +++ b/docs/getting_started/look_and_feel.md @@ -100,8 +100,8 @@ performed without sacrificing accuracy. Please see the below example for a quick std::cout << std::setw(10) << std::setfill('*') << v2 << '\n'; // ***70 mi/h std::cout << std::format("{:*^10}\n", v3); // *110 km/h* std::println("{:%N in %U}", v4); // 70 in mi/h - std::println("{:{%N:.2f}%?%U}", v5); // 30.56 m/s - std::println("{:{%N:.2f}%?{%U:n}}", v6); // 31.29 m s⁻¹ + std::println("{::N[.2f]}", v5); // 30.56 m/s + std::println("{::N[.2f]U[n]}", v6); // 31.29 m s⁻¹ std::println("{:%N}", v7); // 31 } ``` @@ -144,8 +144,8 @@ performed without sacrificing accuracy. Please see the below example for a quick std::cout << std::setw(10) << std::setfill('*') << v2 << '\n'; // ***70 mi/h std::cout << std::format("{:*^10}\n", v3); // *110 km/h* std::println("{:%N in %U}", v4); // 70 in mi/h - std::println("{:{%N:.2f}%?%U}", v5); // 30.56 m/s - std::println("{:{%N:.2f}%?{%U:n}}", v6); // 31.29 m s⁻¹ + std::println("{::N[.2f]}", v5); // 30.56 m/s + std::println("{::N[.2f]U[n]}", v6); // 31.29 m s⁻¹ std::println("{:%N}", v7); // 31 } ``` diff --git a/docs/index.md b/docs/index.md index 4f98b54be..a7d2283ab 100644 --- a/docs/index.md +++ b/docs/index.md @@ -52,7 +52,7 @@ The library source code is hosted on [GitHub](https://github.com/mpusz/mp-units) int main() { constexpr quantity dist = 364.4 * smoot; - std::println("Harvard Bridge length = {:{%N:.5} %U} ({:{%N:.5} %U}, {:{%N:.5} %U}) ± 1 εar", + std::println("Harvard Bridge length = {::N[.5]} ({::N[.5]}, {::N[.5]}) ± 1 εar", dist, dist.in(usc::foot), dist.in(si::metre)); } ``` @@ -72,7 +72,7 @@ The library source code is hosted on [GitHub](https://github.com/mpusz/mp-units) int main() { constexpr quantity dist = 364.4 * smoot; - std::println("Harvard Bridge length = {:{%N:.5} %U} ({:{%N:.5} %U}, {:{%N:.5} %U}) ± 1 εar", + std::println("Harvard Bridge length = {::N[.5]} ({::N[.5]}, {::N[.5]}) ± 1 εar", dist, dist.in(usc::foot), dist.in(si::metre)); } ``` diff --git a/docs/users_guide/framework_basics/faster_than_lightspeed_constants.md b/docs/users_guide/framework_basics/faster_than_lightspeed_constants.md index b49450de9..34e3d4b3b 100644 --- a/docs/users_guide/framework_basics/faster_than_lightspeed_constants.md +++ b/docs/users_guide/framework_basics/faster_than_lightspeed_constants.md @@ -61,7 +61,7 @@ constexpr auto speed_of_light_in_vacuum = 1 * si::si2019::speed_of_light_in_vacu QuantityOf auto q = 1 / (permeability_of_vacuum * pow<2>(speed_of_light_in_vacuum)); -std::println("permittivity of vacuum = {} = {:{%N:.3e} %U}", q, q.in(F / m)); +std::println("permittivity of vacuum = {} = {::N[.3e]}", q, q.in(F / m)); ``` The above first prints the following: diff --git a/docs/users_guide/framework_basics/simple_and_typed_quantities.md b/docs/users_guide/framework_basics/simple_and_typed_quantities.md index 864289eb8..6162ce8d2 100644 --- a/docs/users_guide/framework_basics/simple_and_typed_quantities.md +++ b/docs/users_guide/framework_basics/simple_and_typed_quantities.md @@ -75,7 +75,7 @@ Here is a simple example showing how to deal with such quantities: const quantity duration = 2 * h; const quantity speed = avg_speed(distance, duration); - std::println("A car driving {} in {} has an average speed of {:{%N:.4} %U} ({:{%N:.4} %U})", + std::println("A car driving {} in {} has an average speed of {::N[.4]} ({::N[.4]})", distance, duration, speed, speed.in(km / h)); } ``` @@ -103,7 +103,7 @@ Here is a simple example showing how to deal with such quantities: const quantity duration = 2 * h; const quantity speed = avg_speed(distance, duration); - std::println("A car driving {} in {} has an average speed of {:{%N:.4} %U} ({:{%N:.4} %U})", + std::println("A car driving {} in {} has an average speed of {::N[.4]} ({::N[.4]})", distance, duration, speed, speed.in(km / h)); } ``` @@ -193,7 +193,7 @@ The previous example can be re-typed using typed quantities in the following way const quantity duration = isq::time(2 * h); const quantity speed = avg_speed(distance, duration); - std::println("A car driving {} in {} has an average speed of {:{%N:.4} %U} ({:{%N:.4} %U})", + std::println("A car driving {} in {} has an average speed of {::N[.4]} ({::N[.4]})", distance, duration, speed, speed.in(km / h)); } ``` @@ -221,7 +221,7 @@ The previous example can be re-typed using typed quantities in the following way const quantity duration = isq::time(2 * h); const quantity speed = avg_speed(distance, duration); - std::println("A car driving {} in {} has an average speed of {:{%N:.4} %U} ({:{%N:.4} %U})", + std::println("A car driving {} in {} has an average speed of {::N[.4]} ({::N[.4]})", distance, duration, speed, speed.in(km / h)); } ``` diff --git a/docs/users_guide/framework_basics/the_affine_space.md b/docs/users_guide/framework_basics/the_affine_space.md index bf7b5fe1a..7586b3bad 100644 --- a/docs/users_guide/framework_basics/the_affine_space.md +++ b/docs/users_guide/framework_basics/the_affine_space.md @@ -540,7 +540,7 @@ std::println("| {:<14} | {:^18} | {:^18} | {:^18} |", std::println("|{0:=^16}|{0:=^20}|{0:=^20}|{0:=^20}|", ""); auto print = [&](std::string_view label, auto v) { - std::println("| {:<14} | {:^18} | {:^18} | {:^18{%N:.2f} %U} |", label, + std::println("| {:<14} | {:^18} | {:^18} | {:^18:N[.2f]} |", label, v - room_reference_temp, (v - si::ice_point).in(deg_C), (v - si::absolute_zero).in(deg_C)); }; diff --git a/src/core/include/mp-units/format.h b/src/core/include/mp-units/format.h index 586550213..6d76a82c1 100644 --- a/src/core/include/mp-units/format.h +++ b/src/core/include/mp-units/format.h @@ -275,6 +275,9 @@ class MP_UNITS_STD_FMT::formatter, Char> { using format_specs = mp_units::detail::fill_align_width_format_specs; std::basic_string_view modifiers_format_str_; + std::basic_string_view default_number_format_str_ = {}; + std::basic_string_view default_unit_format_str_ = {}; + std::basic_string_view default_dimension_format_str_ = {}; std::vector format_str_lengths_; format_specs specs_{}; @@ -355,9 +358,9 @@ class MP_UNITS_STD_FMT::formatter, Char> { quantity_formatter(OutputIt, Args...) -> quantity_formatter; template - constexpr const Char* parse_quantity_specs(const Char* begin, const Char* end, Handler&& handler) const + constexpr const Char* parse_format_spec(const Char* begin, const Char* end, Handler&& handler) const { - if (begin == end || *begin == '}') return begin; + if (begin == end || *begin == ':' || *begin == '}') return begin; if (*begin != '%' && *begin != '{') throw MP_UNITS_STD_FMT::format_error( "`quantity-specs` should start with a `conversion-spec` ('%' or '{' characters expected)})"); @@ -365,6 +368,15 @@ class MP_UNITS_STD_FMT::formatter, Char> { while (ptr != end) { auto c = *ptr; if (c == '}') break; + if (c == ":") { + if (ptr + 1 != end && *(ptr + 1) == ":") { + handler.on_text(begin, ++ptr); // account for ':' + ++ptr; // consume the second ':' + continue; + } else + // default specs started + break; + } if (c == '{') { if (begin != ptr) handler.on_text(begin, ptr); begin = ptr = mp_units::detail::parse_subentity_replacement_field(ptr, end, handler); @@ -381,13 +393,13 @@ class MP_UNITS_STD_FMT::formatter, Char> { c = *ptr++; switch (c) { case 'N': - handler.on_number("{}"); + handler.on_number(default_number_format_str_); break; case 'U': - handler.on_unit("{}"); + handler.on_unit(default_unit_format_str_); break; case 'D': - handler.on_dimension("{}"); + handler.on_dimension(default_dimension_format_str_); break; case '?': handler.on_maybe_space(); @@ -401,19 +413,33 @@ class MP_UNITS_STD_FMT::formatter, Char> { begin = ptr; } if (begin != ptr) handler.on_text(begin, ptr); + if (ptr != end&&* ptr = ':') { + } return ptr; } + template + constexpr const Char* parse_default_specs(const Char* begin, const Char* end, Handler&& handler) const + { + } + + template + constexpr const Char* parse_quantity_specs(const Char* begin, const Char* end, Handler&& handler) const + { + auto it = parse_format_spec(begin, end, handler); + } + template OutputIt format_quantity(OutputIt out, const quantity_t& q, FormatContext& ctx) const { std::locale locale = MP_UNITS_FMT_LOCALE(ctx.locale()); if (modifiers_format_str_.empty()) { // default format should print value followed by the unit separated with 1 space - out = MP_UNITS_STD_FMT::vformat_to(out, locale, "{}", + out = MP_UNITS_STD_FMT::vformat_to(out, locale, default_number_format_str_, MP_UNITS_STD_FMT::make_format_args(q.numerical_value_ref_in(q.unit))); if constexpr (mp_units::space_before_unit_symbol) *out++ = ' '; - return MP_UNITS_STD_FMT::vformat_to(out, locale, "{}", MP_UNITS_STD_FMT::make_format_args(q.unit)); + return MP_UNITS_STD_FMT::vformat_to(out, locale, default_unit_format_str_, + MP_UNITS_STD_FMT::make_format_args(q.unit)); } else { // user provided format quantity_formatter f{out, q, format_str_lengths_.cbegin(), locale}; @@ -425,16 +451,16 @@ class MP_UNITS_STD_FMT::formatter, Char> { public: constexpr auto parse(MP_UNITS_STD_FMT::basic_format_parse_context& ctx) -> decltype(ctx.begin()) { - const auto begin = ctx.begin(); - auto end = ctx.end(); + auto begin = ctx.begin(), end = ctx.end(); - auto it = parse_fill_align_width(ctx, begin, end, specs_, mp_units::detail::fmt_align::right); - if (it == end) return it; + auto begin = parse_fill_align_width(ctx, begin, end, specs_, mp_units::detail::fmt_align::right); + if (begin == end) return begin; format_checker checker{ctx, format_str_lengths_}; - end = parse_quantity_specs(it, end, checker); - modifiers_format_str_ = {it, end}; - return end; + auto it = parse_quantity_specs(begin, end, checker); + modifiers_format_str_ = {begin, it}; + + return parse_default_specs(it, end, handler); } template