diff --git a/README.md b/README.md index aabb9b4d..97634d96 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 of %D}", v4); // 70 in mi/h of LT⁻¹ - std::println("{:{%N:.2f}%?%U}", v5); // 30.56 m/s - std::println("{:{%N:.2f}%?{%U:dn}}", v6); // 31.29 m⋅s⁻¹ + std::println("{::N[.2f]}", v5); // 30.56 m/s + std::println("{::N[.2f]U[dn]}", 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 545bb368..ed6052b1 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 of %D}", v4); // 70 in mi/h of LT⁻¹ - std::println("{:{%N:.2f}%?%U}", v5); // 30.56 m/s - std::println("{:{%N:.2f}%?{%U:dn}}", v6); // 31.29 m⋅s⁻¹ + std::println("{::N[.2f]}", v5); // 30.56 m/s + std::println("{::N[.2f]U[dn]}", 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 of %D}", v4); // 70 in mi/h of LT⁻¹ - std::println("{:{%N:.2f}%?%U}", v5); // 30.56 m/s - std::println("{:{%N:.2f}%?{%U:dn}}", v6); // 31.29 m⋅s⁻¹ + std::println("{::N[.2f]}", v5); // 30.56 m/s + std::println("{::N[.2f]U[dn]}", v6); // 31.29 m⋅s⁻¹ std::println("{:%N}", v7); // 31 } ``` diff --git a/docs/index.md b/docs/index.md index dcf78bf8..54b36c62 100644 --- a/docs/index.md +++ b/docs/index.md @@ -38,7 +38,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)); } ``` @@ -58,7 +58,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 13ce4e34..d69ef39c 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 35e4f83e..1204aef7 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)); } ``` @@ -194,7 +194,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)); } ``` @@ -223,7 +223,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 ee0def4c..e04f3eb3 100644 --- a/docs/users_guide/framework_basics/the_affine_space.md +++ b/docs/users_guide/framework_basics/the_affine_space.md @@ -501,7 +501,7 @@ std::println("| {:<18} | {:^18} | {:^18} | {:^18} |", std::println("|{0:=^20}|{0:=^20}|{0:=^20}|{0:=^20}|", ""); auto print_temp = [&](std::string_view label, auto v) { - std::println("| {:<18} | {:^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 2d81027e..510e66af 100644 --- a/src/core/include/mp-units/format.h +++ b/src/core/include/mp-units/format.h @@ -349,6 +349,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_{}; @@ -431,9 +434,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)})"); @@ -441,6 +444,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); @@ -457,13 +469,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(); @@ -477,19 +489,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}; @@ -501,16 +527,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