diff --git a/README.md b/README.md index 4899d9d7..f18c929d 100644 --- a/README.md +++ b/README.md @@ -101,11 +101,11 @@ int main() std::cout << v1 << '\n'; // 110 km/h std::cout << v2 << '\n'; // 70 mi/h - std::cout << fmt::format("{}", v3) << '\n'; // 110 km/h - std::cout << fmt::format("{:*^14}", v4) << '\n'; // ***70 mi/h**** - std::cout << fmt::format("{:%Q in %q}", v5) << '\n'; // 30.5556 in m/s - std::cout << fmt::format("{0:%Q} in {0:%q}", v6) << '\n'; // 31.2928 in m/s - std::cout << fmt::format("{:%Q}", v7) << '\n'; // 31 + std::cout << std::format("{}", v3) << '\n'; // 110 km/h + std::cout << std::format("{:*^14}", v4) << '\n'; // ***70 mi/h**** + std::cout << std::format("{:%Q in %q}", v5) << '\n'; // 30.5556 in m/s + std::cout << std::format("{0:%Q} in {0:%q}", v6) << '\n'; // 31.2928 in m/s + std::cout << std::format("{:%Q}", v7) << '\n'; // 31 } ``` diff --git a/conanfile.py b/conanfile.py index 8ee6e8e5..d383f49b 100644 --- a/conanfile.py +++ b/conanfile.py @@ -37,7 +37,6 @@ class UnitsConan(ConanFile): url = "https://github.com/mpusz/units" settings = "os", "compiler", "build_type", "arch" requires = ( - "fmt/8.0.1", "gsl-lite/0.38.1" ) options = { @@ -62,6 +61,12 @@ class UnitsConan(ConanFile): def _run_tests(self): return tools.get_env("CONAN_RUN_TESTS", False) + @property + def _use_libfmt(self): + # compiler = self.settings.compiler + # return compiler != "Visual Studio" and compiler != "msvc" # TODO Enable when VS std::format_to(ctx.out, ...) is fixed + return True + def set_version(self): content = tools.load(os.path.join(self.recipe_folder, "src/CMakeLists.txt")) version = re.search(r"project\([^\)]+VERSION (\d+\.\d+\.\d+)[^\)]*\)", content).group(1) @@ -69,6 +74,9 @@ class UnitsConan(ConanFile): def requirements(self): compiler = self.settings.compiler + if self._use_libfmt: + self.requires("fmt/8.0.1") + if compiler == "clang" and compiler.libcxx == "libc++": self.requires("range-v3/0.11.0") @@ -105,7 +113,8 @@ class UnitsConan(ConanFile): tc = CMakeToolchain(self) tc.variables["UNITS_DOWNCAST_MODE"] = str(self.options.downcast_mode).upper() # if self._run_tests: # TODO Enable this when environment is supported in the Conan toolchain - tc.variables["UNITS_BUILD_DOCS"] = self.options.build_docs + tc.variables["UNITS_BUILD_DOCS"] = self.options.build_docs == "True" + tc.variables["UNITS_USE_LIBFMT"] = self._use_libfmt tc.generate() deps = CMakeDeps(self) deps.generate() diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 9610f43a..13aa077e 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -3,6 +3,7 @@ - **0.8.0 WIP** - (!) refactor: `common_quantity`, `common_quantity_for`, `common_quantity_point`, `common_quantity_kind`, and `common_quantity_point_kind` removed - refactor: `quantity` `op+()` and `op-()` reimplemented in terms of `reference` rather then `quantity` types + - feat: `std::format` support for compliant compilers added - feat: HEP system support added (thanks [@RalphSteinhagen](https://github.com/RalphSteinhagen)) - (!) fix: add `quantity_point::origin`, like `std::chrono::time_point::clock` - fix: account for different dimensions in `quantity_point_cast`'s constraint diff --git a/docs/framework/text_output.rst b/docs/framework/text_output.rst index c87e8970..e760a2da 100644 --- a/docs/framework/text_output.rst +++ b/docs/framework/text_output.rst @@ -51,14 +51,14 @@ over width, fill, and alignment:: os << "|" << std::setw(10) << std::setfill('*') << 123 * m << "|"; // |*****123 m| -fmt::format +std::format ----------- .. tip:: The text formatting support is provided via the ```` header file. -The **mp-units** via ``fmt::format`` provides a fine-grained control over what +The **mp-units** via ``std::format`` provides a fine-grained control over what and how is being printed on the text output. @@ -101,8 +101,8 @@ default formatting is also applied to the output streams. This is why the follow code lines produce the same output:: std::cout << "Distance: " << 123 * km << "\n"; - fmt::print("Distance: {}\n", 123 * km); - fmt::print("Distance: {:%Q %q}\n", 123 * km); + std::cout << std::format("Distance: {}\n", 123 * km); + std::cout << std::format("Distance: {:%Q %q}\n", 123 * km); Quantity Value, Symbol, or Both? @@ -111,9 +111,9 @@ Quantity Value, Symbol, or Both? The user can easily decide to either print a whole quantity (value and symbol) or only its parts. Also a different quantity formatting might be applied:: - fmt::print("{:%Q}", 123 * km); // 123 - fmt::print("{:%q}", 123 * km); // km - fmt::print("{:%Q%q}", 123 * km); // 123km + std::cout << std::format("{:%Q}", 123 * km); // 123 + std::cout << std::format("{:%q}", 123 * km); // km + std::cout << std::format("{:%Q%q}", 123 * km); // 123km Controlling Width, Fill, and Alignment @@ -123,14 +123,14 @@ To control width, fill, and alignment the C++ standard grammar tokens ``fill-and and ``width`` are being used and they treat a quantity value and symbol as a contiguous text:: - fmt::print("|{:0}|", 123 * m); // |123 m| - fmt::print("|{:10}|", 123 * m); // | 123 m| - fmt::print("|{:<10}|", 123 * m); // |123 m | - fmt::print("|{:>10}|", 123 * m); // | 123 m| - fmt::print("|{:^10}|", 123 * m); // | 123 m | - fmt::print("|{:*<10}|", 123 * m); // |123 m*****| - fmt::print("|{:*>10}|", 123 * m); // |*****123 m| - fmt::print("|{:*^10}|", 123 * m); // |**123 m***| + std::cout << std::format("|{:0}|", 123 * m); // |123 m| + std::cout << std::format("|{:10}|", 123 * m); // | 123 m| + std::cout << std::format("|{:<10}|", 123 * m); // |123 m | + std::cout << std::format("|{:>10}|", 123 * m); // | 123 m| + std::cout << std::format("|{:^10}|", 123 * m); // | 123 m | + std::cout << std::format("|{:*<10}|", 123 * m); // |123 m*****| + std::cout << std::format("|{:*>10}|", 123 * m); // |*****123 m| + std::cout << std::format("|{:*^10}|", 123 * m); // |**123 m***| ASCII-only Quantity Symbols @@ -142,13 +142,13 @@ this by default. From the engineering point of view sometimes Unicode text migh not be a solution as terminals of many (especially embedded) devices are ASCII-only. In such a case the unit symbol can be forced to be printed using ASCII-only characters:: - fmt::print("{}", 10 * R); // 10 Ω - fmt::print("{:%Q %Aq}", 10 * R); // 10 ohm - fmt::print("{}", 125 * us); // 125 µs - fmt::print("{:%Q %Aq}", 125 * us); // 125 us + std::cout << std::format("{}", 10 * R); // 10 Ω + std::cout << std::format("{:%Q %Aq}", 10 * R); // 10 ohm + std::cout << std::format("{}", 125 * us); // 125 µs + std::cout << std::format("{:%Q %Aq}", 125 * us); // 125 us inline constexpr auto s2 = s * s; - fmt::print("{}", 9.8 * (m / s2)); // 9.8 m/s² - fmt::print("{:%Q %Aq}", 9.8 * (m / s2)); // 9.8 m/s^2 + std::cout << std::format("{}", 9.8 * (m / s2)); // 9.8 m/s² + std::cout << std::format("{:%Q %Aq}", 9.8 * (m / s2)); // 9.8 m/s^2 Controlling on How the Quantity Value Is Being Printed @@ -156,8 +156,8 @@ Controlling on How the Quantity Value Is Being Printed ``sign`` token allows us to specify on how the value's sign is being printed:: - fmt::print("{0:%Q %q},{0:%+Q %q},{0:%-Q %q},{0:% Q %q}", 1 * m); // 1 m,+1 m,1 m, 1 m - fmt::print("{0:%Q %q},{0:%+Q %q},{0:%-Q %q},{0:% Q %q}", -1 * m); // -1 m,-1 m,-1 m,-1 m + std::cout << std::format("{0:%Q %q},{0:%+Q %q},{0:%-Q %q},{0:% Q %q}", 1 * m); // 1 m,+1 m,1 m, 1 m + std::cout << std::format("{0:%Q %q},{0:%+Q %q},{0:%-Q %q},{0:% Q %q}", -1 * m); // -1 m,-1 m,-1 m,-1 m where: @@ -169,47 +169,47 @@ where: ``precision`` token is allowed only for floating-point representation types:: - fmt::print("{:%.0Q %q}", 1.2345 * m); // 1 m - fmt::print("{:%.1Q %q}", 1.2345 * m); // 1.2 m - fmt::print("{:%.2Q %q}", 1.2345 * m); // 1.23 m + std::cout << std::format("{:%.0Q %q}", 1.2345 * m); // 1 m + std::cout << std::format("{:%.1Q %q}", 1.2345 * m); // 1.2 m + std::cout << std::format("{:%.2Q %q}", 1.2345 * m); // 1.23 m :token:`units-rep-type` specifies how a value of the representation type is being printed. For integral types:: - fmt::print("{:%bQ %q}", 42 * m); // 101010 m - fmt::print("{:%BQ %q}", 42 * m); // 101010 m - fmt::print("{:%dQ %q}", 42 * m); // 42 m - fmt::print("{:%oQ %q}", 42 * m); // 52 m - fmt::print("{:%xQ %q}", 42 * m); // 2a m - fmt::print("{:%XQ %q}", 42 * m); // 2A m + std::cout << std::format("{:%bQ %q}", 42 * m); // 101010 m + std::cout << std::format("{:%BQ %q}", 42 * m); // 101010 m + std::cout << std::format("{:%dQ %q}", 42 * m); // 42 m + std::cout << std::format("{:%oQ %q}", 42 * m); // 52 m + std::cout << std::format("{:%xQ %q}", 42 * m); // 2a m + std::cout << std::format("{:%XQ %q}", 42 * m); // 2A m The above can be printed in an alternate version thanks to the ``#`` token:: - fmt::print("{:%#bQ %q}", 42 * m); // 0b101010 m - fmt::print("{:%#BQ %q}", 42 * m); // 0B101010 m - fmt::print("{:%#oQ %q}", 42 * m); // 052 m - fmt::print("{:%#xQ %q}", 42 * m); // 0x2a m - fmt::print("{:%#XQ %q}", 42 * m); // 0X2A m + std::cout << std::format("{:%#bQ %q}", 42 * m); // 0b101010 m + std::cout << std::format("{:%#BQ %q}", 42 * m); // 0B101010 m + std::cout << std::format("{:%#oQ %q}", 42 * m); // 052 m + std::cout << std::format("{:%#xQ %q}", 42 * m); // 0x2a m + std::cout << std::format("{:%#XQ %q}", 42 * m); // 0X2A m For floating-point values the :token:`units-rep-type` token works as follows:: - fmt::print("{:%aQ %q}", 1.2345678 * m); // 0x9.e065152d8eae841p-3 m - fmt::print("{:%.3aQ %q}", 1.2345678 * m); // 0x9.e06p-3 m - fmt::print("{:%AQ %q}", 1.2345678 * m); // 0X9.E065152D8EAE841P-3 m - fmt::print("{:%.3AQ %q}", 1.2345678 * m); // 0X9.E06P-3 m - fmt::print("{:%eQ %q}", 1.2345678 * m); // 1.234568e+00 m - fmt::print("{:%.3eQ %q}", 1.2345678 * m); // 1.235e+00 m - fmt::print("{:%EQ %q}", 1.2345678 * m); // 1.234568E+00 m - fmt::print("{:%.3EQ %q}", 1.2345678 * m); // 1.235E+00 m - fmt::print("{:%gQ %q}", 1.2345678 * m); // 1.23457 m - fmt::print("{:%gQ %q}", 1.2345678e8 * m); // 1.23457e+08 m - fmt::print("{:%.3gQ %q}", 1.2345678 * m); // 1.23 m - fmt::print("{:%.3gQ %q}", 1.2345678e8 * m); // 1.23e+08 m - fmt::print("{:%GQ %q}", 1.2345678 * m); // 1.23457 m - fmt::print("{:%GQ %q}", 1.2345678e8 * m); // 1.23457E+08 m - fmt::print("{:%.3GQ %q}", 1.2345678 * m); // 1.23 m - fmt::print("{:%.3GQ %q}", 1.2345678e8 * m); // 1.23E+08 m + std::cout << std::format("{:%aQ %q}", 1.2345678 * m); // 0x9.e065152d8eae841p-3 m + std::cout << std::format("{:%.3aQ %q}", 1.2345678 * m); // 0x9.e06p-3 m + std::cout << std::format("{:%AQ %q}", 1.2345678 * m); // 0X9.E065152D8EAE841P-3 m + std::cout << std::format("{:%.3AQ %q}", 1.2345678 * m); // 0X9.E06P-3 m + std::cout << std::format("{:%eQ %q}", 1.2345678 * m); // 1.234568e+00 m + std::cout << std::format("{:%.3eQ %q}", 1.2345678 * m); // 1.235e+00 m + std::cout << std::format("{:%EQ %q}", 1.2345678 * m); // 1.234568E+00 m + std::cout << std::format("{:%.3EQ %q}", 1.2345678 * m); // 1.235E+00 m + std::cout << std::format("{:%gQ %q}", 1.2345678 * m); // 1.23457 m + std::cout << std::format("{:%gQ %q}", 1.2345678e8 * m); // 1.23457e+08 m + std::cout << std::format("{:%.3gQ %q}", 1.2345678 * m); // 1.23 m + std::cout << std::format("{:%.3gQ %q}", 1.2345678e8 * m); // 1.23e+08 m + std::cout << std::format("{:%GQ %q}", 1.2345678 * m); // 1.23457 m + std::cout << std::format("{:%GQ %q}", 1.2345678e8 * m); // 1.23457E+08 m + std::cout << std::format("{:%.3GQ %q}", 1.2345678 * m); // 1.23 m + std::cout << std::format("{:%.3GQ %q}", 1.2345678e8 * m); // 1.23E+08 m Special Signs @@ -218,7 +218,7 @@ Special Signs Beside adding any list of regular characters as a separator between the value and the symbol, it is possible to type a few special signs there too:: - fmt::print("{:%Q_%q}", 123 * km); // 123_km - fmt::print("{:%Q%t%q}", 123 * km); // 123\tkm - fmt::print("{:%Q%n%q}", 123 * km); // 123\nkm - fmt::print("{:%Q%% %q}", 123 * km); // 123% km + std::cout << std::format("{:%Q_%q}", 123 * km); // 123_km + std::cout << std::format("{:%Q%t%q}", 123 * km); // 123\tkm + std::cout << std::format("{:%Q%n%q}", 123 * km); // 123\nkm + std::cout << std::format("{:%Q%% %q}", 123 * km); // 123% km diff --git a/docs/quick_start.rst b/docs/quick_start.rst index 54168803..2e468ccd 100644 --- a/docs/quick_start.rst +++ b/docs/quick_start.rst @@ -77,11 +77,11 @@ of basic library features:: std::cout << v1 << '\n'; // 110 km/h std::cout << v2 << '\n'; // 70 mi/h - std::cout << fmt::format("{}", v3) << '\n'; // 110 km/h - std::cout << fmt::format("{:*^14}", v4) << '\n'; // ***70 mi/h**** - std::cout << fmt::format("{:%Q in %q}", v5) << '\n'; // 30.5556 in m/s - std::cout << fmt::format("{0:%Q} in {0:%q}", v6) << '\n'; // 31.2928 in m/s - std::cout << fmt::format("{:%Q}", v7) << '\n'; // 31 + std::cout << std::format("{}", v3) << '\n'; // 110 km/h + std::cout << std::format("{:*^14}", v4) << '\n'; // ***70 mi/h**** + std::cout << std::format("{:%Q in %q}", v5) << '\n'; // 30.5556 in m/s + std::cout << std::format("{0:%Q} in {0:%q}", v6) << '\n'; // 31.2928 in m/s + std::cout << std::format("{:%Q}", v7) << '\n'; // 31 } .. admonition:: Try it on Compiler Explorer diff --git a/example/aliases/box_example.cpp b/example/aliases/box_example.cpp index ad9443a5..869c337d 100644 --- a/example/aliases/box_example.cpp +++ b/example/aliases/box_example.cpp @@ -97,9 +97,9 @@ int main() const Time auto fill_time_left = (height / fill_level - 1) * fill_time; std::cout << "mp-units box example...\n"; - std::cout << fmt::format("fill height at {} = {} ({} full)\n", fill_time, fill_level, fill_percent); - std::cout << fmt::format("spare_capacity at {} = {}\n", fill_time, spare_capacity); - std::cout << fmt::format("input flow rate after {} = {}\n", fill_time, input_flow_rate); - std::cout << fmt::format("float rise rate = {}\n", float_rise_rate); - std::cout << fmt::format("box full E.T.A. at current flow rate = {}\n", fill_time_left); + std::cout << STD_FMT::format("fill height at {} = {} ({} full)\n", fill_time, fill_level, fill_percent); + std::cout << STD_FMT::format("spare_capacity at {} = {}\n", fill_time, spare_capacity); + std::cout << STD_FMT::format("input flow rate after {} = {}\n", fill_time, input_flow_rate); + std::cout << STD_FMT::format("float rise rate = {}\n", float_rise_rate); + std::cout << STD_FMT::format("box full E.T.A. at current flow rate = {}\n", fill_time_left); } diff --git a/example/aliases/clcpp_response.cpp b/example/aliases/clcpp_response.cpp index f6feba1f..102a84a7 100644 --- a/example/aliases/clcpp_response.cpp +++ b/example/aliases/clcpp_response.cpp @@ -115,7 +115,7 @@ void calcs_comparison() length::fm L1A = fm<>(2.f); length::fm L2A = fm<>(3.f); length::fm LrA = L1A + L2A; - fmt::print("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, LrA); + std::cout << STD_FMT::format("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, LrA); std::cout << "The single unit method must convert large\n" "or small values in other units to the base unit.\n" @@ -124,17 +124,17 @@ void calcs_comparison() length::m L1B = L1A; length::m L2B = L2A; length::m LrB = L1B + L2B; - fmt::print("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, LrB); + std::cout << STD_FMT::format("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, LrB); std::cout << "In multiplication and division:\n\n"; area::fm2 ArA = L1A * L2A; - fmt::print("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, ArA); + std::cout << STD_FMT::format("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, ArA); std::cout << "similar problems arise\n\n"; area::m2 ArB = L1B * L2B; - fmt::print("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, ArB); + std::cout << STD_FMT::format("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, ArB); } } // namespace diff --git a/example/aliases/foot_pound_second.cpp b/example/aliases/foot_pound_second.cpp index ff5a6c28..2655014f 100644 --- a/example/aliases/foot_pound_second.cpp +++ b/example/aliases/foot_pound_second.cpp @@ -55,24 +55,24 @@ struct Ship { template auto fmt_line(const Q a) { - return fmt::format("{:22}", a) + (fmt::format(",{:20}", units::quantity_cast(a)) + ...); + return STD_FMT::format("{:22}", a) + (STD_FMT::format(",{:20}", units::quantity_cast(a)) + ...); } // Print the ship details in the units as defined in the Ship struct, in other si::imperial units, and in SI void print_details(std::string_view description, const Ship& ship) { const auto waterDensity = si::fps::density::lb_per_ft3<>(62.4); - std::cout << fmt::format("{}\n", description); - std::cout << fmt::format("{:20} : {}\n", "length", fmt_line, si::length::m<>>(ship.length)) - << fmt::format("{:20} : {}\n", "draft", fmt_line, si::length::m<>>(ship.draft)) - << fmt::format("{:20} : {}\n", "beam", fmt_line, si::length::m<>>(ship.beam)) - << fmt::format("{:20} : {}\n", "mass", fmt_line, si::mass::t<>>(ship.mass)) - << fmt::format("{:20} : {}\n", "speed", fmt_line, si::speed::km_per_h<>>(ship.speed)) - << fmt::format("{:20} : {}\n", "power", fmt_line, si::power::kW<>>(ship.power)) - << fmt::format("{:20} : {}\n", "main guns", fmt_line, si::length::mm<>>(ship.mainGuns)) - << fmt::format("{:20} : {}\n", "fire shells weighing",fmt_line, si::mass::kg<>>(ship.shellMass)) - << fmt::format("{:20} : {}\n", "fire shells at",fmt_line, si::speed::km_per_h<>>(ship.shellSpeed)) - << fmt::format("{:20} : {}\n", "volume underwater", fmt_line, si::volume::l<>>(ship.mass / waterDensity)); + std::cout << STD_FMT::format("{}\n", description); + std::cout << STD_FMT::format("{:20} : {}\n", "length", fmt_line, si::length::m<>>(ship.length)) + << STD_FMT::format("{:20} : {}\n", "draft", fmt_line, si::length::m<>>(ship.draft)) + << STD_FMT::format("{:20} : {}\n", "beam", fmt_line, si::length::m<>>(ship.beam)) + << STD_FMT::format("{:20} : {}\n", "mass", fmt_line, si::mass::t<>>(ship.mass)) + << STD_FMT::format("{:20} : {}\n", "speed", fmt_line, si::speed::km_per_h<>>(ship.speed)) + << STD_FMT::format("{:20} : {}\n", "power", fmt_line, si::power::kW<>>(ship.power)) + << STD_FMT::format("{:20} : {}\n", "main guns", fmt_line, si::length::mm<>>(ship.mainGuns)) + << STD_FMT::format("{:20} : {}\n", "fire shells weighing",fmt_line, si::mass::kg<>>(ship.shellMass)) + << STD_FMT::format("{:20} : {}\n", "fire shells at",fmt_line, si::speed::km_per_h<>>(ship.shellSpeed)) + << STD_FMT::format("{:20} : {}\n", "volume underwater", fmt_line, si::volume::l<>>(ship.mass / waterDensity)); } int main() diff --git a/example/aliases/glide_computer_example.cpp b/example/aliases/glide_computer_example.cpp index 5644a55b..a6c30052 100644 --- a/example/aliases/glide_computer_example.cpp +++ b/example/aliases/glide_computer_example.cpp @@ -21,16 +21,11 @@ // SOFTWARE. #include "glide_computer.h" -#include +#include #include #include #include -UNITS_DIAGNOSTIC_PUSH -UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE -#include -UNITS_DIAGNOSTIC_POP - #include #include #include @@ -90,7 +85,7 @@ void print(const R& gliders) std::cout << "- Name: " << g.name << "\n"; std::cout << "- Polar:\n"; for (const auto& p : g.polar) - fmt::print(" * {:%.4Q %q} @ {:%.1Q %q} -> {:%.1Q %q}\n", p.climb, p.v, units::quantity_cast(glide_ratio(g.polar[0]))); + std::cout << STD_FMT::format(" * {:%.4Q %q} @ {:%.1Q %q} -> {:%.1Q %q}\n", p.climb, p.v, units::quantity_cast(glide_ratio(g.polar[0]))); std::cout << "\n"; } } @@ -104,8 +99,8 @@ void print(const R& conditions) for (const auto& c : conditions) { std::cout << "- " << c.first << "\n"; const auto& w = c.second; - std::cout << " * Cloud base: " << fmt::format("{:%.0Q %q}", w.cloud_base) << " AGL\n"; - std::cout << " * Thermals strength: " << fmt::format("{:%.1Q %q}", w.thermal_strength) << "\n"; + std::cout << " * Cloud base: " << STD_FMT::format("{:%.0Q %q}", w.cloud_base) << " AGL\n"; + std::cout << " * Thermals strength: " << STD_FMT::format("{:%.1Q %q}", w.thermal_strength) << "\n"; std::cout << "\n"; } } @@ -117,7 +112,7 @@ void print(const R& waypoints) std::cout << "Waypoints:\n"; std::cout << "==========\n"; for (const auto& w : waypoints) - std::cout << fmt::format("- {}: {} {}, {:%.1Q %q}\n", w.name, w.pos.lat, w.pos.lon, w.alt); + std::cout << STD_FMT::format("- {}: {} {}, {:%.1Q %q}\n", w.name, w.pos.lat, w.pos.lon, w.alt); std::cout << "\n"; } @@ -128,11 +123,11 @@ void print(const task& t) std::cout << "- Start: " << t.get_start().name << "\n"; std::cout << "- Finish: " << t.get_finish().name << "\n"; - std::cout << "- Length: " << fmt::format("{:%.1Q %q}", t.get_length()) << "\n"; + std::cout << "- Length: " << STD_FMT::format("{:%.1Q %q}", t.get_length()) << "\n"; std::cout << "- Legs: " << "\n"; for (const auto& l : t.get_legs()) - std::cout << fmt::format(" * {} -> {} ({:%.1Q %q})\n", l.begin().name, l.end().name, l.get_length()); + std::cout << STD_FMT::format(" * {} -> {} ({:%.1Q %q})\n", l.begin().name, l.end().name, l.get_length()); std::cout << "\n"; } @@ -140,7 +135,7 @@ void print(const safety& s) { std::cout << "Safety:\n"; std::cout << "=======\n"; - std::cout << "- Min AGL separation: " << fmt::format("{:%.0Q %q}", s.min_agl_height) << "\n"; + std::cout << "- Min AGL separation: " << STD_FMT::format("{:%.0Q %q}", s.min_agl_height) << "\n"; std::cout << "\n"; } @@ -149,8 +144,8 @@ void print(const aircraft_tow& tow) std::cout << "Tow:\n"; std::cout << "====\n"; std::cout << "- Type: aircraft\n"; - std::cout << "- Height: " << fmt::format("{:%.0Q %q}", tow.height_agl) << "\n"; - std::cout << "- Performance: " << fmt::format("{:%.1Q %q}", tow.performance) << "\n"; + std::cout << "- Height: " << STD_FMT::format("{:%.0Q %q}", tow.height_agl) << "\n"; + std::cout << "- Performance: " << STD_FMT::format("{:%.1Q %q}", tow.performance) << "\n"; std::cout << "\n"; } @@ -179,7 +174,7 @@ void example() for (const auto& c : weather_conditions) { std::string txt = "Scenario: Glider = " + g.name + ", Weather = " + c.first; std::cout << txt << "\n"; - fmt::print("{0:=^{1}}\n\n", "", txt.size()); + std::cout << STD_FMT::format("{0:=^{1}}\n\n", "", txt.size()); estimate(start_time, g, c.second, t, sfty, tow); diff --git a/example/aliases/linear_algebra.cpp b/example/aliases/linear_algebra.cpp index 1414a768..493d6cfd 100644 --- a/example/aliases/linear_algebra.cpp +++ b/example/aliases/linear_algebra.cpp @@ -36,7 +36,7 @@ std::ostream& operator<<(std::ostream& os, const vector& v) { os << "|"; for (auto i = 0U; i < v.size(); ++i) { - os << fmt::format(" {:>9}", v(i)); + os << STD_FMT::format(" {:>9}", v(i)); } os << " |"; return os; @@ -48,7 +48,7 @@ std::ostream& operator<<(std::ostream& os, const matrix& v) for (auto i = 0U; i < v.rows(); ++i) { os << "|"; for (auto j = 0U; j < v.columns(); ++j) { - os << fmt::format(" {:>9}", v(i, j)); + os << STD_FMT::format(" {:>9}", v(i, j)); } os << (i != v.rows() - 1U ? " |\n" : " |"); } diff --git a/example/conversion_factor.cpp b/example/conversion_factor.cpp index fa3b66f3..665b16e2 100644 --- a/example/conversion_factor.cpp +++ b/example/conversion_factor.cpp @@ -49,12 +49,12 @@ int main() constexpr length lengthA(2.0); constexpr length lengthB = lengthA; - std::cout << fmt::format("lengthA( {} ) and lengthB( {} )\n", lengthA, lengthB) + std::cout << STD_FMT::format("lengthA( {} ) and lengthB( {} )\n", lengthA, lengthB) << "represent the same length in different units.\n\n"; - std::cout << fmt::format("therefore ratio lengthA / lengthB == {}\n\n", lengthA / lengthB); + std::cout << STD_FMT::format("therefore ratio lengthA / lengthB == {}\n\n", lengthA / lengthB); - std::cout << fmt::format("conversion factor from lengthA::unit of {:%q} to lengthB::unit of {:%q}:\n\n", lengthA, lengthB) - << fmt::format("lengthB.number( {} ) == lengthA.number( {} ) * conversion_factor( {} )\n", + std::cout << STD_FMT::format("conversion factor from lengthA::unit of {:%q} to lengthB::unit of {:%q}:\n\n", lengthA, lengthB) + << STD_FMT::format("lengthB.number( {} ) == lengthA.number( {} ) * conversion_factor( {} )\n", lengthB.number(), lengthA.number(), conversion_factor(lengthB, lengthA)); } diff --git a/example/glide_computer/glide_computer.cpp b/example/glide_computer/glide_computer.cpp index 6325ca46..4595609b 100644 --- a/example/glide_computer/glide_computer.cpp +++ b/example/glide_computer/glide_computer.cpp @@ -21,6 +21,7 @@ // SOFTWARE. #include "glide_computer.h" +#include #include #include @@ -136,8 +137,8 @@ namespace glide_computer { void estimate(timestamp start_ts, const glider& g, const weather& w, const task& t, const safety& s, const aircraft_tow& at) { - fmt::print("| {:<12} | {:^28} | {:^26} | {:^21} |\n", "Flight phase", "Duration", "Distance", "Height"); - fmt::print("|{0:-^14}|{0:-^30}|{0:-^28}|{0:-^23}|\n", ""); + std::cout << STD_FMT::format("| {:<12} | {:^28} | {:^26} | {:^21} |\n", "Flight phase", "Duration", "Distance", "Height"); + std::cout << STD_FMT::format("|{0:-^14}|{0:-^30}|{0:-^28}|{0:-^23}|\n", ""); // ready to takeoff flight_point pos = takeoff(start_ts, t); diff --git a/example/glide_computer/include/geographic.h b/example/glide_computer/include/geographic.h index dac2e625..a8c7ae7a 100644 --- a/example/glide_computer/include/geographic.h +++ b/example/glide_computer/include/geographic.h @@ -22,15 +22,10 @@ #pragma once -#include +#include #include #include -UNITS_DIAGNOSTIC_PUSH -UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE -#include -UNITS_DIAGNOSTIC_POP - #include #include @@ -106,21 +101,21 @@ class std::numeric_limits : public numeric_limits -struct fmt::formatter : formatter { +struct STD_FMT::formatter : formatter { template auto format(geographic::latitude lat, FormatContext& ctx) { - fmt::format_to(ctx.out(), fmt::runtime(lat.value() > 0 ? "N" : "S")); + STD_FMT::format_to(ctx.out(), FMT_RUNTIME(lat.value() > 0 ? "N" : "S")); return formatter::format(lat.value() > 0 ? lat.value() : -lat.value(), ctx); } }; template<> -struct fmt::formatter : formatter { +struct STD_FMT::formatter : formatter { template auto format(geographic::longitude lon, FormatContext& ctx) { - fmt::format_to(ctx.out(), fmt::runtime(lon.value() > 0 ? "E" : "W")); + STD_FMT::format_to(ctx.out(), FMT_RUNTIME(lon.value() > 0 ? "E" : "W")); return formatter::format(lon.value() > 0 ? lon.value() : -lon.value(), ctx); } }; diff --git a/example/glide_computer/include/glide_computer.h b/example/glide_computer/include/glide_computer.h index bc5416fd..7202005a 100644 --- a/example/glide_computer/include/glide_computer.h +++ b/example/glide_computer/include/glide_computer.h @@ -57,7 +57,7 @@ // - flight path exactly on a shortest possible line to destination template -struct fmt::formatter : formatter { +struct STD_FMT::formatter : formatter { template auto format(const QK& v, FormatContext& ctx) { @@ -105,12 +105,12 @@ std::basic_ostream& operator<<(std::basic_ostream& } // namespace glide_computer template<> -struct fmt::formatter : formatter> { +struct STD_FMT::formatter : formatter> { template auto format(glide_computer::altitude a, FormatContext& ctx) { formatter>::format(a.relative().common(), ctx); - return fmt::format_to(ctx.out(), " AMSL"); + return STD_FMT::format_to(ctx.out(), " AMSL"); } }; diff --git a/example/hello_units.cpp b/example/hello_units.cpp index ec1713fa..6b339036 100644 --- a/example/hello_units.cpp +++ b/example/hello_units.cpp @@ -55,11 +55,11 @@ int main() #endif constexpr Speed auto v7 = quantity_cast(v6); - std::cout << v1 << '\n'; // 110 km/h - std::cout << v2 << '\n'; // 70 mi/h - std::cout << fmt::format("{}", v3) << '\n'; // 110 km/h - std::cout << fmt::format("{:*^14}", v4) << '\n'; // ***70 mi/h**** - std::cout << fmt::format("{:%Q in %q}", v5) << '\n'; // 30.5556 in m/s - std::cout << fmt::format("{0:%Q} in {0:%q}", v6) << '\n'; // 31.2928 in m/s - std::cout << fmt::format("{:%Q}", v7) << '\n'; // 31 + std::cout << v1 << '\n'; // 110 km/h + std::cout << v2 << '\n'; // 70 mi/h + std::cout << STD_FMT::format("{}", v3) << '\n'; // 110 km/h + std::cout << STD_FMT::format("{:*^14}", v4) << '\n'; // ***70 mi/h**** + std::cout << STD_FMT::format("{:%Q in %q}", v5) << '\n'; // 30.5556 in m/s + std::cout << STD_FMT::format("{0:%Q} in {0:%q}", v6) << '\n'; // 31.2928 in m/s + std::cout << STD_FMT::format("{:%Q}", v7) << '\n'; // 31 } diff --git a/example/kalman_filter/kalman.h b/example/kalman_filter/kalman.h index dfa4a334..5f92e55a 100644 --- a/example/kalman_filter/kalman.h +++ b/example/kalman_filter/kalman.h @@ -22,7 +22,7 @@ #pragma once -#include +#include #include #include #include @@ -151,52 +151,51 @@ constexpr Q covariance_extrapolation(Q uncertainty, Q process_noise_variance) } // namespace kalman template -struct fmt::formatter> { +struct STD_FMT::formatter> { constexpr auto parse(format_parse_context& ctx) { - detail::dynamic_specs_handler handler(specs, ctx); - return detail::parse_format_specs(ctx.begin(), ctx.end(), handler); + units::detail::dynamic_specs_handler handler(specs, ctx); + return units::detail::parse_format_specs(ctx.begin(), ctx.end(), handler); } template auto format(const kalman::state& s, FormatContext& ctx) { - memory_buffer value_buffer; + std::string value_buffer; auto to_value_buffer = std::back_inserter(value_buffer); if (specs.precision != -1) { if constexpr(sizeof...(Qs) == 1) - fmt::format_to(to_value_buffer, "{1:%.{0}Q %q}", specs.precision, kalman::get<0>(s)); + STD_FMT::format_to(to_value_buffer, "{1:%.{0}Q %q}", specs.precision, kalman::get<0>(s)); else if constexpr(sizeof...(Qs) == 2) - fmt::format_to(to_value_buffer, "{{ {1:%.{0}Q %q}, {2:%.{0}Q %q} }}", specs.precision, kalman::get<0>(s), kalman::get<1>(s)); + STD_FMT::format_to(to_value_buffer, "{{ {1:%.{0}Q %q}, {2:%.{0}Q %q} }}", specs.precision, kalman::get<0>(s), kalman::get<1>(s)); else - fmt::format_to(to_value_buffer, "{{ {1:%.{0}Q %q}, {2:%.{0}Q %q}, {3:%.{0}Q %q} }}", specs.precision, kalman::get<0>(s), kalman::get<1>(s), kalman::get<2>(s)); + STD_FMT::format_to(to_value_buffer, "{{ {1:%.{0}Q %q}, {2:%.{0}Q %q}, {3:%.{0}Q %q} }}", specs.precision, kalman::get<0>(s), kalman::get<1>(s), kalman::get<2>(s)); } else { if constexpr(sizeof...(Qs) == 1) - fmt::format_to(to_value_buffer, "{}", kalman::get<0>(s)); + STD_FMT::format_to(to_value_buffer, "{}", kalman::get<0>(s)); else if constexpr(sizeof...(Qs) == 2) - fmt::format_to(to_value_buffer, "{{ {}, {} }}", kalman::get<0>(s), kalman::get<1>(s)); + STD_FMT::format_to(to_value_buffer, "{{ {}, {} }}", kalman::get<0>(s), kalman::get<1>(s)); else - fmt::format_to(to_value_buffer, "{{ {}, {}, {} }}", kalman::get<0>(s), kalman::get<1>(s), kalman::get<2>(s)); + STD_FMT::format_to(to_value_buffer, "{{ {}, {}, {} }}", kalman::get<0>(s), kalman::get<1>(s), kalman::get<2>(s)); } - basic_memory_buffer global_format_buffer; - units::detail::global_format_specs global_specs = { specs.fill, specs.align, specs.width }; + std::string global_format_buffer; + units::detail::quantity_global_format_specs global_specs = { specs.fill, specs.align, specs.width }; units::detail::format_global_buffer(std::back_inserter(global_format_buffer), global_specs); - return fmt::format_to(ctx.out(), fmt::runtime(std::string_view(global_format_buffer.data(), global_format_buffer.size())), - std::string_view(value_buffer.data(), value_buffer.size())); + return STD_FMT::format_to(ctx.out(), FMT_RUNTIME(global_format_buffer), value_buffer); } private: - detail::dynamic_format_specs specs; + units::detail::dynamic_format_specs specs; }; template -struct fmt::formatter> { +struct STD_FMT::formatter> { constexpr auto parse(format_parse_context& ctx) { - detail::dynamic_specs_handler handler(specs, ctx); - return detail::parse_format_specs(ctx.begin(), ctx.end(), handler); + units::detail::dynamic_specs_handler handler(specs, ctx); + return units::detail::parse_format_specs(ctx.begin(), ctx.end(), handler); } template @@ -209,22 +208,21 @@ struct fmt::formatter> { return t.relative(); }(kalman::get<0>(e.state)); - memory_buffer value_buffer; + std::string value_buffer; auto to_value_buffer = std::back_inserter(value_buffer); if (specs.precision != -1) { - fmt::format_to(to_value_buffer, "{0:%.{2}Q} ± {1:%.{2}Q} {0:%q}", q, sqrt(e.uncertainty), specs.precision); + STD_FMT::format_to(to_value_buffer, "{0:%.{2}Q} ± {1:%.{2}Q} {0:%q}", q, sqrt(e.uncertainty), specs.precision); } else { - fmt::format_to(to_value_buffer, "{0:%Q} ± {1:%Q} {0:%q}", q, sqrt(e.uncertainty)); + STD_FMT::format_to(to_value_buffer, "{0:%Q} ± {1:%Q} {0:%q}", q, sqrt(e.uncertainty)); } - basic_memory_buffer global_format_buffer; - units::detail::global_format_specs global_specs = { specs.fill, specs.align, specs.width }; + std::string global_format_buffer; + units::detail::quantity_global_format_specs global_specs = { specs.fill, specs.align, specs.width }; units::detail::format_global_buffer(std::back_inserter(global_format_buffer), global_specs); - return fmt::format_to(ctx.out(), fmt::runtime(std::string_view(global_format_buffer.data(), global_format_buffer.size())), - std::string_view(value_buffer.data(), value_buffer.size())); + return STD_FMT::format_to(ctx.out(), FMT_RUNTIME(global_format_buffer), value_buffer); } private: - detail::dynamic_format_specs specs; + units::detail::dynamic_format_specs specs; }; diff --git a/example/kalman_filter/kalman_filter-example_1.cpp b/example/kalman_filter/kalman_filter-example_1.cpp index cf6f66f3..91057277 100644 --- a/example/kalman_filter/kalman_filter-example_1.cpp +++ b/example/kalman_filter/kalman_filter-example_1.cpp @@ -25,6 +25,7 @@ #include #include #include +#include // Based on: https://www.kalmanfilter.net/alphabeta.html#ex1 @@ -32,13 +33,13 @@ using namespace units; void print_header(const kalman::State auto& initial) { - fmt::print("Initial: {}\n", initial); - fmt::print("{:>2} | {:>9} | {:>8} | {:>14} | {:>14}\n", "N", "Gain", "Measured", "Curr. Estimate", "Next Estimate"); + std::cout << STD_FMT::format("Initial: {}\n", initial); + std::cout << STD_FMT::format("{:>2} | {:>9} | {:>8} | {:>14} | {:>14}\n", "N", "Gain", "Measured", "Curr. Estimate", "Next Estimate"); } void print(auto iteration, Dimensionless auto gain, Quantity auto measured, const kalman::State auto& current, const kalman::State auto& next) { - fmt::print("{:2} | {:9} | {:8} | {:14} | {:14}\n", iteration, gain, measured, current, next); + std::cout << STD_FMT::format("{:2} | {:9} | {:8} | {:14} | {:14}\n", iteration, gain, measured, current, next); } int main() diff --git a/example/kalman_filter/kalman_filter-example_2.cpp b/example/kalman_filter/kalman_filter-example_2.cpp index cfb9c51d..222bd165 100644 --- a/example/kalman_filter/kalman_filter-example_2.cpp +++ b/example/kalman_filter/kalman_filter-example_2.cpp @@ -27,6 +27,7 @@ #include #include #include +#include // Based on: https://www.kalmanfilter.net/alphabeta.html#ex2 @@ -34,13 +35,13 @@ using namespace units; void print_header(const kalman::State auto& initial) { - fmt::print("Initial: {}\n", initial); - fmt::print("{:>2} | {:>8} | {:>23} | {:>23}\n", "N", "Measured", "Curr. Estimate", "Next Estimate"); + std::cout << STD_FMT::format("Initial: {}\n", initial); + std::cout << STD_FMT::format("{:>2} | {:>8} | {:>23} | {:>23}\n", "N", "Measured", "Curr. Estimate", "Next Estimate"); } void print(auto iteration, Quantity auto measured, const kalman::State auto& current, const kalman::State auto& next) { - fmt::print("{:2} | {:8} | {:.1} | {:.1}\n", iteration, measured, current, next); + std::cout << STD_FMT::format("{:2} | {:8} | {:.1} | {:.1}\n", iteration, measured, current, next); } int main() diff --git a/example/kalman_filter/kalman_filter-example_3.cpp b/example/kalman_filter/kalman_filter-example_3.cpp index 32cb41ed..7a7c0291 100644 --- a/example/kalman_filter/kalman_filter-example_3.cpp +++ b/example/kalman_filter/kalman_filter-example_3.cpp @@ -27,6 +27,7 @@ #include #include #include +#include // Based on: https://www.kalmanfilter.net/alphabeta.html#ex3 @@ -34,13 +35,13 @@ using namespace units; void print_header(const kalman::State auto& initial) { - fmt::print("Initial: {}\n", initial); - fmt::print("{:>2} | {:>8} | {:>24} | {:>24}\n", "N", "Measured", "Curr. Estimate", "Next Estimate"); + std::cout << STD_FMT::format("Initial: {}\n", initial); + std::cout << STD_FMT::format("{:>2} | {:>8} | {:>24} | {:>24}\n", "N", "Measured", "Curr. Estimate", "Next Estimate"); } void print(auto iteration, Quantity auto measured, const kalman::State auto& current, const kalman::State auto& next) { - fmt::print("{:2} | {:8} | {:>24.1} | {:>24.1}\n", iteration, measured, current, next); + std::cout << STD_FMT::format("{:2} | {:8} | {:>24.1} | {:>24.1}\n", iteration, measured, current, next); } int main() diff --git a/example/kalman_filter/kalman_filter-example_4.cpp b/example/kalman_filter/kalman_filter-example_4.cpp index 41cdea07..c6692b12 100644 --- a/example/kalman_filter/kalman_filter-example_4.cpp +++ b/example/kalman_filter/kalman_filter-example_4.cpp @@ -28,6 +28,7 @@ #include #include #include +#include // Based on: https://www.kalmanfilter.net/alphabeta.html#ex4 @@ -35,13 +36,13 @@ using namespace units; void print_header(const kalman::State auto& initial) { - fmt::print("Initial: {}\n", initial); - fmt::print("{:>2} | {:>8} | {:>35} | {:>35}\n", "N", "Measured", "Curr. Estimate", "Next Estimate"); + std::cout << STD_FMT::format("Initial: {}\n", initial); + std::cout << STD_FMT::format("{:>2} | {:>8} | {:>35} | {:>35}\n", "N", "Measured", "Curr. Estimate", "Next Estimate"); } void print(auto iteration, Quantity auto measured, const kalman::State auto& current, const kalman::State auto& next) { - fmt::print("{:2} | {:8} | {:>35.1} | {:>35.1}\n", iteration, measured, current, next); + std::cout << STD_FMT::format("{:2} | {:8} | {:>35.1} | {:>35.1}\n", iteration, measured, current, next); } int main() diff --git a/example/kalman_filter/kalman_filter-example_5.cpp b/example/kalman_filter/kalman_filter-example_5.cpp index 1a5b9834..47db0134 100644 --- a/example/kalman_filter/kalman_filter-example_5.cpp +++ b/example/kalman_filter/kalman_filter-example_5.cpp @@ -25,6 +25,7 @@ #include #include #include +#include // Based on: https://www.kalmanfilter.net/kalman1d.html#ex5 @@ -33,14 +34,14 @@ using namespace units; template void print_header(kalman::estimation initial) { - fmt::print("Initial: {}\n", initial); - fmt::print("{:>2} | {:>5} | {:>8} | {:>16} | {:>16}\n", "N", "Gain", "Measured", "Curr. Estimate", "Next Estimate"); + std::cout << STD_FMT::format("Initial: {}\n", initial); + std::cout << STD_FMT::format("{:>2} | {:>5} | {:>8} | {:>16} | {:>16}\n", "N", "Gain", "Measured", "Curr. Estimate", "Next Estimate"); } template void print(auto iteration, K gain, Q measured, kalman::estimation current, kalman::estimation next) { - fmt::print("{:2} | {:5%.2Q} | {:8} | {:>16.2} | {:>16.2}\n", iteration, gain, measured, current, next); + std::cout << STD_FMT::format("{:2} | {:5%.2Q} | {:8} | {:>16.2} | {:>16.2}\n", iteration, gain, measured, current, next); } int main() diff --git a/example/kalman_filter/kalman_filter-example_6.cpp b/example/kalman_filter/kalman_filter-example_6.cpp index d170bcf6..b30a5cbd 100644 --- a/example/kalman_filter/kalman_filter-example_6.cpp +++ b/example/kalman_filter/kalman_filter-example_6.cpp @@ -27,6 +27,7 @@ #include #include #include +#include // TODO Fix when Celsius is properly supported (#232) namespace units::isq::si { @@ -54,14 +55,14 @@ using namespace units; template void print_header(kalman::estimation initial) { - fmt::print("Initial: {}\n", initial); - fmt::print("{:>2} | {:>7} | {:>10} | {:>18} | {:>18}\n", "N", "Gain", "Measured", "Curr. Estimate", "Next Estimate"); + std::cout << STD_FMT::format("Initial: {}\n", initial); + std::cout << STD_FMT::format("{:>2} | {:>7} | {:>10} | {:>18} | {:>18}\n", "N", "Gain", "Measured", "Curr. Estimate", "Next Estimate"); } template void print(auto iteration, K gain, QP measured, kalman::estimation current, kalman::estimation next) { - fmt::print("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain, measured.relative(), current, next); + std::cout << STD_FMT::format("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain, measured.relative(), current, next); } int main() diff --git a/example/kalman_filter/kalman_filter-example_7.cpp b/example/kalman_filter/kalman_filter-example_7.cpp index 65808aa1..6a48c3a5 100644 --- a/example/kalman_filter/kalman_filter-example_7.cpp +++ b/example/kalman_filter/kalman_filter-example_7.cpp @@ -27,6 +27,7 @@ #include #include #include +#include // TODO Fix when Celsius is properly supported (#232) namespace units::isq::si { @@ -54,14 +55,14 @@ using namespace units; template void print_header(kalman::estimation initial) { - fmt::print("Initial: {}\n", initial); - fmt::print("{:>2} | {:>7} | {:>10} | {:>18} | {:>18}\n", "N", "Gain", "Measured", "Curr. Estimate", "Next Estimate"); + std::cout << STD_FMT::format("Initial: {}\n", initial); + std::cout << STD_FMT::format("{:>2} | {:>7} | {:>10} | {:>18} | {:>18}\n", "N", "Gain", "Measured", "Curr. Estimate", "Next Estimate"); } template void print(auto iteration, K gain, QP measured, kalman::estimation current, kalman::estimation next) { - fmt::print("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain, measured.relative(), current, next); + std::cout << STD_FMT::format("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain, measured.relative(), current, next); } int main() diff --git a/example/kalman_filter/kalman_filter-example_8.cpp b/example/kalman_filter/kalman_filter-example_8.cpp index 2ea5138e..e3cee52a 100644 --- a/example/kalman_filter/kalman_filter-example_8.cpp +++ b/example/kalman_filter/kalman_filter-example_8.cpp @@ -27,6 +27,7 @@ #include #include #include +#include // TODO Fix when Celsius is properly supported (#232) namespace units::isq::si { @@ -54,14 +55,14 @@ using namespace units; template void print_header(kalman::estimation initial) { - fmt::print("Initial: {}\n", initial); - fmt::print("{:>2} | {:>7} | {:>10} | {:>16} | {:>16}\n", "N", "Gain", "Measured", "Curr. Estimate", "Next Estimate"); + std::cout << STD_FMT::format("Initial: {}\n", initial); + std::cout << STD_FMT::format("{:>2} | {:>7} | {:>10} | {:>16} | {:>16}\n", "N", "Gain", "Measured", "Curr. Estimate", "Next Estimate"); } template void print(auto iteration, K gain, QP measured, kalman::estimation current, kalman::estimation next) { - fmt::print("{:2} | {:7%.3Q} | {:10%.3Q %q} | {:>16.2} | {:>16.2}\n", iteration, gain, measured.relative(), current, next); + std::cout << STD_FMT::format("{:2} | {:7%.3Q} | {:10%.3Q %q} | {:>16.2} | {:>16.2}\n", iteration, gain, measured.relative(), current, next); } int main() diff --git a/example/literals/box_example.cpp b/example/literals/box_example.cpp index 0e7afbaf..a736f6bd 100644 --- a/example/literals/box_example.cpp +++ b/example/literals/box_example.cpp @@ -105,9 +105,9 @@ int main() const Time auto fill_time_left = (height / fill_level - 1) * fill_time; std::cout << "mp-units box example...\n"; - std::cout << fmt::format("fill height at {} = {} ({} full)\n", fill_time, fill_level, fill_percent); - std::cout << fmt::format("spare_capacity at {} = {}\n", fill_time, spare_capacity); - std::cout << fmt::format("input flow rate after {} = {}\n", fill_time, input_flow_rate); - std::cout << fmt::format("float rise rate = {}\n", float_rise_rate); - std::cout << fmt::format("box full E.T.A. at current flow rate = {}\n", fill_time_left); + std::cout << STD_FMT::format("fill height at {} = {} ({} full)\n", fill_time, fill_level, fill_percent); + std::cout << STD_FMT::format("spare_capacity at {} = {}\n", fill_time, spare_capacity); + std::cout << STD_FMT::format("input flow rate after {} = {}\n", fill_time, input_flow_rate); + std::cout << STD_FMT::format("float rise rate = {}\n", float_rise_rate); + std::cout << STD_FMT::format("box full E.T.A. at current flow rate = {}\n", fill_time_left); } diff --git a/example/literals/clcpp_response.cpp b/example/literals/clcpp_response.cpp index 3e45be77..eea96de0 100644 --- a/example/literals/clcpp_response.cpp +++ b/example/literals/clcpp_response.cpp @@ -114,7 +114,7 @@ void calcs_comparison() const length L1A = 2._q_fm; const length L2A = 3._q_fm; const length LrA = L1A + L2A; - fmt::print("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, LrA); + std::cout << STD_FMT::format("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, LrA); std::cout << "The single unit method must convert large\n" "or small values in other units to the base unit.\n" @@ -123,17 +123,17 @@ void calcs_comparison() const length L1B = L1A; const length L2B = L2A; const length LrB = L1B + L2B; - fmt::print("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, LrB); + std::cout << STD_FMT::format("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, LrB); std::cout << "In multiplication and division:\n\n"; const area ArA = L1A * L2A; - fmt::print("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, ArA); + std::cout << STD_FMT::format("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, ArA); std::cout << "similar problems arise\n\n"; const area ArB = L1B * L2B; - fmt::print("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, ArB); + std::cout << STD_FMT::format("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, ArB); } } // namespace diff --git a/example/literals/foot_pound_second.cpp b/example/literals/foot_pound_second.cpp index 841068f7..4f3548ae 100644 --- a/example/literals/foot_pound_second.cpp +++ b/example/literals/foot_pound_second.cpp @@ -56,7 +56,7 @@ struct Ship { template auto fmt_line(const Q a) { - return fmt::format("{:22}", a) + (fmt::format(",{:20}", units::quantity_cast(a)) + ...); + return STD_FMT::format("{:22}", a) + (STD_FMT::format(",{:20}", units::quantity_cast(a)) + ...); } // Print the ship details in the units as defined in the Ship struct, in other si::imperial units, and in SI @@ -64,17 +64,17 @@ void print_details(std::string_view description, const Ship& ship) { using namespace units::isq::si::fps::literals; const auto waterDensity = 62.4_q_lb_per_ft3; - std::cout << fmt::format("{}\n", description); - std::cout << fmt::format("{:20} : {}\n", "length", fmt_line, si::length>(ship.length)) - << fmt::format("{:20} : {}\n", "draft", fmt_line, si::length>(ship.draft)) - << fmt::format("{:20} : {}\n", "beam", fmt_line, si::length>(ship.beam)) - << fmt::format("{:20} : {}\n", "mass", fmt_line, si::mass>(ship.mass)) - << fmt::format("{:20} : {}\n", "speed", fmt_line, si::speed>(ship.speed)) - << fmt::format("{:20} : {}\n", "power", fmt_line, si::power>(ship.power)) - << fmt::format("{:20} : {}\n", "main guns", fmt_line, si::length>(ship.mainGuns)) - << fmt::format("{:20} : {}\n", "fire shells weighing",fmt_line, si::mass>(ship.shellMass)) - << fmt::format("{:20} : {}\n", "fire shells at",fmt_line, si::speed>(ship.shellSpeed)) - << fmt::format("{:20} : {}\n", "volume underwater", fmt_line, si::volume>(ship.mass / waterDensity)); + std::cout << STD_FMT::format("{}\n", description); + std::cout << STD_FMT::format("{:20} : {}\n", "length", fmt_line, si::length>(ship.length)) + << STD_FMT::format("{:20} : {}\n", "draft", fmt_line, si::length>(ship.draft)) + << STD_FMT::format("{:20} : {}\n", "beam", fmt_line, si::length>(ship.beam)) + << STD_FMT::format("{:20} : {}\n", "mass", fmt_line, si::mass>(ship.mass)) + << STD_FMT::format("{:20} : {}\n", "speed", fmt_line, si::speed>(ship.speed)) + << STD_FMT::format("{:20} : {}\n", "power", fmt_line, si::power>(ship.power)) + << STD_FMT::format("{:20} : {}\n", "main guns", fmt_line, si::length>(ship.mainGuns)) + << STD_FMT::format("{:20} : {}\n", "fire shells weighing",fmt_line, si::mass>(ship.shellMass)) + << STD_FMT::format("{:20} : {}\n", "fire shells at",fmt_line, si::speed>(ship.shellSpeed)) + << STD_FMT::format("{:20} : {}\n", "volume underwater", fmt_line, si::volume>(ship.mass / waterDensity)); } int main() diff --git a/example/literals/glide_computer_example.cpp b/example/literals/glide_computer_example.cpp index ae63734c..58f96c06 100644 --- a/example/literals/glide_computer_example.cpp +++ b/example/literals/glide_computer_example.cpp @@ -21,16 +21,11 @@ // SOFTWARE. #include "glide_computer.h" -#include +#include #include #include #include -UNITS_DIAGNOSTIC_PUSH -UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE -#include -UNITS_DIAGNOSTIC_POP - #include #include #include @@ -90,7 +85,7 @@ void print(const R& gliders) std::cout << "- Name: " << g.name << "\n"; std::cout << "- Polar:\n"; for (const auto& p : g.polar) - fmt::print(" * {:%.4Q %q} @ {:%.1Q %q} -> {:%.1Q %q}\n", p.climb, p.v, units::quantity_cast(glide_ratio(g.polar[0]))); + std::cout << STD_FMT::format(" * {:%.4Q %q} @ {:%.1Q %q} -> {:%.1Q %q}\n", p.climb, p.v, units::quantity_cast(glide_ratio(g.polar[0]))); std::cout << "\n"; } } @@ -104,8 +99,8 @@ void print(const R& conditions) for (const auto& c : conditions) { std::cout << "- " << c.first << "\n"; const auto& w = c.second; - std::cout << " * Cloud base: " << fmt::format("{:%.0Q %q}", w.cloud_base) << " AGL\n"; - std::cout << " * Thermals strength: " << fmt::format("{:%.1Q %q}", w.thermal_strength) << "\n"; + std::cout << " * Cloud base: " << STD_FMT::format("{:%.0Q %q}", w.cloud_base) << " AGL\n"; + std::cout << " * Thermals strength: " << STD_FMT::format("{:%.1Q %q}", w.thermal_strength) << "\n"; std::cout << "\n"; } } @@ -117,7 +112,7 @@ void print(const R& waypoints) std::cout << "Waypoints:\n"; std::cout << "==========\n"; for (const auto& w : waypoints) - std::cout << fmt::format("- {}: {} {}, {:%.1Q %q}\n", w.name, w.pos.lat, w.pos.lon, w.alt); + std::cout << STD_FMT::format("- {}: {} {}, {:%.1Q %q}\n", w.name, w.pos.lat, w.pos.lon, w.alt); std::cout << "\n"; } @@ -128,11 +123,11 @@ void print(const task& t) std::cout << "- Start: " << t.get_start().name << "\n"; std::cout << "- Finish: " << t.get_finish().name << "\n"; - std::cout << "- Length: " << fmt::format("{:%.1Q %q}", t.get_length()) << "\n"; + std::cout << "- Length: " << STD_FMT::format("{:%.1Q %q}", t.get_length()) << "\n"; std::cout << "- Legs: " << "\n"; for (const auto& l : t.get_legs()) - std::cout << fmt::format(" * {} -> {} ({:%.1Q %q})\n", l.begin().name, l.end().name, l.get_length()); + std::cout << STD_FMT::format(" * {} -> {} ({:%.1Q %q})\n", l.begin().name, l.end().name, l.get_length()); std::cout << "\n"; } @@ -140,7 +135,7 @@ void print(const safety& s) { std::cout << "Safety:\n"; std::cout << "=======\n"; - std::cout << "- Min AGL separation: " << fmt::format("{:%.0Q %q}", s.min_agl_height) << "\n"; + std::cout << "- Min AGL separation: " << STD_FMT::format("{:%.0Q %q}", s.min_agl_height) << "\n"; std::cout << "\n"; } @@ -149,8 +144,8 @@ void print(const aircraft_tow& tow) std::cout << "Tow:\n"; std::cout << "====\n"; std::cout << "- Type: aircraft\n"; - std::cout << "- Height: " << fmt::format("{:%.0Q %q}", tow.height_agl) << "\n"; - std::cout << "- Performance: " << fmt::format("{:%.1Q %q}", tow.performance) << "\n"; + std::cout << "- Height: " << STD_FMT::format("{:%.0Q %q}", tow.height_agl) << "\n"; + std::cout << "- Performance: " << STD_FMT::format("{:%.1Q %q}", tow.performance) << "\n"; std::cout << "\n"; } @@ -179,7 +174,7 @@ void example() for (const auto& c : weather_conditions) { std::string txt = "Scenario: Glider = " + g.name + ", Weather = " + c.first; std::cout << txt << "\n"; - fmt::print("{0:=^{1}}\n\n", "", txt.size()); + std::cout << STD_FMT::format("{0:=^{1}}\n\n", "", txt.size()); estimate(start_time, g, c.second, t, sfty, tow); diff --git a/example/literals/linear_algebra.cpp b/example/literals/linear_algebra.cpp index e98b69bd..75812b2b 100644 --- a/example/literals/linear_algebra.cpp +++ b/example/literals/linear_algebra.cpp @@ -36,7 +36,7 @@ std::ostream& operator<<(std::ostream& os, const vector& v) { os << "|"; for (auto i = 0U; i < v.size(); ++i) { - os << fmt::format(" {:>9}", v(i)); + os << STD_FMT::format(" {:>9}", v(i)); } os << " |"; return os; @@ -48,7 +48,7 @@ std::ostream& operator<<(std::ostream& os, const matrix& v) for (auto i = 0U; i < v.rows(); ++i) { os << "|"; for (auto j = 0U; j < v.columns(); ++j) { - os << fmt::format(" {:>9}", v(i, j)); + os << STD_FMT::format(" {:>9}", v(i, j)); } os << (i != v.rows() - 1U ? " |\n" : " |"); } diff --git a/example/references/box_example.cpp b/example/references/box_example.cpp index c4ad8d95..48a8656e 100644 --- a/example/references/box_example.cpp +++ b/example/references/box_example.cpp @@ -101,9 +101,9 @@ int main() const Time auto fill_time_left = (height / fill_level - 1) * fill_time; std::cout << "mp-units box example...\n"; - std::cout << fmt::format("fill height at {} = {} ({} full)\n", fill_time, fill_level, fill_percent); - std::cout << fmt::format("spare_capacity at {} = {}\n", fill_time, spare_capacity); - std::cout << fmt::format("input flow rate after {} = {}\n", fill_time, input_flow_rate); - std::cout << fmt::format("float rise rate = {}\n", float_rise_rate); - std::cout << fmt::format("box full E.T.A. at current flow rate = {}\n", fill_time_left); + std::cout << STD_FMT::format("fill height at {} = {} ({} full)\n", fill_time, fill_level, fill_percent); + std::cout << STD_FMT::format("spare_capacity at {} = {}\n", fill_time, spare_capacity); + std::cout << STD_FMT::format("input flow rate after {} = {}\n", fill_time, input_flow_rate); + std::cout << STD_FMT::format("float rise rate = {}\n", float_rise_rate); + std::cout << STD_FMT::format("box full E.T.A. at current flow rate = {}\n", fill_time_left); } diff --git a/example/references/clcpp_response.cpp b/example/references/clcpp_response.cpp index e12fc64c..758dafa9 100644 --- a/example/references/clcpp_response.cpp +++ b/example/references/clcpp_response.cpp @@ -123,7 +123,7 @@ void calcs_comparison() const length L1A = 2.f * fm; const length L2A = 3.f * fm; const length LrA = L1A + L2A; - fmt::print("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, LrA); + std::cout << STD_FMT::format("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, LrA); std::cout << "The single unit method must convert large\n" "or small values in other units to the base unit.\n" @@ -132,17 +132,17 @@ void calcs_comparison() const length L1B = L1A; const length L2B = L2A; const length LrB = L1B + L2B; - fmt::print("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, LrB); + std::cout << STD_FMT::format("{:%.30Q %q}\n + {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, LrB); std::cout << "In multiplication and division:\n\n"; const area ArA = L1A * L2A; - fmt::print("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, ArA); + std::cout << STD_FMT::format("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1A, L2A, ArA); std::cout << "similar problems arise\n\n"; const area ArB = L1B * L2B; - fmt::print("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, ArB); + std::cout << STD_FMT::format("{:%.30Q %q}\n * {:%.30Q %q}\n = {:%.30Q %q}\n\n", L1B, L2B, ArB); } } // namespace diff --git a/example/references/foot_pound_second.cpp b/example/references/foot_pound_second.cpp index 669ed082..a00a096e 100644 --- a/example/references/foot_pound_second.cpp +++ b/example/references/foot_pound_second.cpp @@ -59,7 +59,7 @@ struct Ship { template auto fmt_line(const Q a) { - return fmt::format("{:22}", a) + (fmt::format(",{:20}", units::quantity_cast(a)) + ...); + return STD_FMT::format("{:22}", a) + (STD_FMT::format(",{:20}", units::quantity_cast(a)) + ...); } // Print the ship details in the units as defined in the Ship struct, in other si::imperial units, and in SI @@ -67,17 +67,17 @@ void print_details(std::string_view description, const Ship& ship) { using namespace units::isq::si::fps::references; const auto waterDensity = 62.4 * (lb / ft3); - std::cout << fmt::format("{}\n", description); - std::cout << fmt::format("{:20} : {}\n", "length", fmt_line, si::length>(ship.length)) - << fmt::format("{:20} : {}\n", "draft", fmt_line, si::length>(ship.draft)) - << fmt::format("{:20} : {}\n", "beam", fmt_line, si::length>(ship.beam)) - << fmt::format("{:20} : {}\n", "mass", fmt_line, si::mass>(ship.mass)) - << fmt::format("{:20} : {}\n", "speed", fmt_line, si::speed>(ship.speed)) - << fmt::format("{:20} : {}\n", "power", fmt_line, si::power>(ship.power)) - << fmt::format("{:20} : {}\n", "main guns", fmt_line, si::length>(ship.mainGuns)) - << fmt::format("{:20} : {}\n", "fire shells weighing", fmt_line, si::mass>(ship.shellMass)) - << fmt::format("{:20} : {}\n", "fire shells at", fmt_line, si::speed>(ship.shellSpeed)) - << fmt::format("{:20} : {}\n", "volume underwater", fmt_line, si::volume>(ship.mass / waterDensity)); + std::cout << STD_FMT::format("{}\n", description); + std::cout << STD_FMT::format("{:20} : {}\n", "length", fmt_line, si::length>(ship.length)) + << STD_FMT::format("{:20} : {}\n", "draft", fmt_line, si::length>(ship.draft)) + << STD_FMT::format("{:20} : {}\n", "beam", fmt_line, si::length>(ship.beam)) + << STD_FMT::format("{:20} : {}\n", "mass", fmt_line, si::mass>(ship.mass)) + << STD_FMT::format("{:20} : {}\n", "speed", fmt_line, si::speed>(ship.speed)) + << STD_FMT::format("{:20} : {}\n", "power", fmt_line, si::power>(ship.power)) + << STD_FMT::format("{:20} : {}\n", "main guns", fmt_line, si::length>(ship.mainGuns)) + << STD_FMT::format("{:20} : {}\n", "fire shells weighing", fmt_line, si::mass>(ship.shellMass)) + << STD_FMT::format("{:20} : {}\n", "fire shells at", fmt_line, si::speed>(ship.shellSpeed)) + << STD_FMT::format("{:20} : {}\n", "volume underwater", fmt_line, si::volume>(ship.mass / waterDensity)); } int main() diff --git a/example/references/glide_computer_example.cpp b/example/references/glide_computer_example.cpp index 50d67dfa..002d8172 100644 --- a/example/references/glide_computer_example.cpp +++ b/example/references/glide_computer_example.cpp @@ -21,16 +21,11 @@ // SOFTWARE. #include "glide_computer.h" -#include +#include #include #include #include -UNITS_DIAGNOSTIC_PUSH -UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE -#include -UNITS_DIAGNOSTIC_POP - #include #include #include @@ -90,7 +85,7 @@ void print(const R& gliders) std::cout << "- Name: " << g.name << "\n"; std::cout << "- Polar:\n"; for (const auto& p : g.polar) - fmt::print(" * {:%.4Q %q} @ {:%.1Q %q} -> {:%.1Q %q}\n", p.climb, p.v, units::quantity_cast(glide_ratio(g.polar[0]))); + std::cout << STD_FMT::format(" * {:%.4Q %q} @ {:%.1Q %q} -> {:%.1Q %q}\n", p.climb, p.v, units::quantity_cast(glide_ratio(g.polar[0]))); std::cout << "\n"; } } @@ -104,8 +99,8 @@ void print(const R& conditions) for (const auto& c : conditions) { std::cout << "- " << c.first << "\n"; const auto& w = c.second; - std::cout << " * Cloud base: " << fmt::format("{:%.0Q %q}", w.cloud_base) << " AGL\n"; - std::cout << " * Thermals strength: " << fmt::format("{:%.1Q %q}", w.thermal_strength) << "\n"; + std::cout << " * Cloud base: " << STD_FMT::format("{:%.0Q %q}", w.cloud_base) << " AGL\n"; + std::cout << " * Thermals strength: " << STD_FMT::format("{:%.1Q %q}", w.thermal_strength) << "\n"; std::cout << "\n"; } } @@ -117,7 +112,7 @@ void print(const R& waypoints) std::cout << "Waypoints:\n"; std::cout << "==========\n"; for (const auto& w : waypoints) - std::cout << fmt::format("- {}: {} {}, {:%.1Q %q}\n", w.name, w.pos.lat, w.pos.lon, w.alt); + std::cout << STD_FMT::format("- {}: {} {}, {:%.1Q %q}\n", w.name, w.pos.lat, w.pos.lon, w.alt); std::cout << "\n"; } @@ -128,11 +123,11 @@ void print(const task& t) std::cout << "- Start: " << t.get_start().name << "\n"; std::cout << "- Finish: " << t.get_finish().name << "\n"; - std::cout << "- Length: " << fmt::format("{:%.1Q %q}", t.get_length()) << "\n"; + std::cout << "- Length: " << STD_FMT::format("{:%.1Q %q}", t.get_length()) << "\n"; std::cout << "- Legs: " << "\n"; for (const auto& l : t.get_legs()) - std::cout << fmt::format(" * {} -> {} ({:%.1Q %q})\n", l.begin().name, l.end().name, l.get_length()); + std::cout << STD_FMT::format(" * {} -> {} ({:%.1Q %q})\n", l.begin().name, l.end().name, l.get_length()); std::cout << "\n"; } @@ -140,7 +135,7 @@ void print(const safety& s) { std::cout << "Safety:\n"; std::cout << "=======\n"; - std::cout << "- Min AGL separation: " << fmt::format("{:%.0Q %q}", s.min_agl_height) << "\n"; + std::cout << "- Min AGL separation: " << STD_FMT::format("{:%.0Q %q}", s.min_agl_height) << "\n"; std::cout << "\n"; } @@ -149,8 +144,8 @@ void print(const aircraft_tow& tow) std::cout << "Tow:\n"; std::cout << "====\n"; std::cout << "- Type: aircraft\n"; - std::cout << "- Height: " << fmt::format("{:%.0Q %q}", tow.height_agl) << "\n"; - std::cout << "- Performance: " << fmt::format("{:%.1Q %q}", tow.performance) << "\n"; + std::cout << "- Height: " << STD_FMT::format("{:%.0Q %q}", tow.height_agl) << "\n"; + std::cout << "- Performance: " << STD_FMT::format("{:%.1Q %q}", tow.performance) << "\n"; std::cout << "\n"; } @@ -179,7 +174,7 @@ void example() for (const auto& c : weather_conditions) { std::string txt = "Scenario: Glider = " + g.name + ", Weather = " + c.first; std::cout << txt << "\n"; - fmt::print("{0:=^{1}}\n\n", "", txt.size()); + std::cout << STD_FMT::format("{0:=^{1}}\n\n", "", txt.size()); estimate(start_time, g, c.second, t, sfty, tow); diff --git a/example/references/linear_algebra.cpp b/example/references/linear_algebra.cpp index 94214542..9290f2e5 100644 --- a/example/references/linear_algebra.cpp +++ b/example/references/linear_algebra.cpp @@ -36,7 +36,7 @@ std::ostream& operator<<(std::ostream& os, const vector& v) { os << "|"; for (auto i = 0U; i < v.size(); ++i) { - os << fmt::format(" {:>9}", v(i)); + os << STD_FMT::format(" {:>9}", v(i)); } os << " |"; return os; @@ -48,7 +48,7 @@ std::ostream& operator<<(std::ostream& os, const matrix& v) for (auto i = 0U; i < v.rows(); ++i) { os << "|"; for (auto j = 0U; j < v.columns(); ++j) { - os << fmt::format(" {:>9}", v(i, j)); + os << STD_FMT::format(" {:>9}", v(i, j)); } os << (i != v.rows() - 1U ? " |\n" : " |"); } diff --git a/src/core-fmt/CMakeLists.txt b/src/core-fmt/CMakeLists.txt index 49389d5c..51f8544b 100644 --- a/src/core-fmt/CMakeLists.txt +++ b/src/core-fmt/CMakeLists.txt @@ -22,7 +22,14 @@ cmake_minimum_required(VERSION 3.15) +option(UNITS_USE_LIBFMT "Enables usage of libfmt instead of the one from 'std'" OFF) +message(STATUS "UNITS_USE_LIBFMT: ${UNITS_USE_LIBFMT}") + # find dependencies find_package(fmt CONFIG REQUIRED) -add_units_module(core-fmt mp-units::core fmt::fmt) +add_units_module(core-fmt mp-units::core) +if(UNITS_USE_LIBFMT) + target_link_libraries(mp-units-core-fmt INTERFACE fmt::fmt) + target_compile_definitions(mp-units-core-fmt INTERFACE UNITS_USE_LIBFMT) +endif() diff --git a/src/core-fmt/include/units/bits/fmt.h b/src/core-fmt/include/units/bits/fmt.h new file mode 100644 index 00000000..ce783799 --- /dev/null +++ b/src/core-fmt/include/units/bits/fmt.h @@ -0,0 +1,461 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// Formatting library for C++ - the core API for char/UTF-8 +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include +#include +#include +#include +#include + +// most of the below code is based on/copied from libfmt + +namespace units::detail { + +struct auto_id {}; + +enum class fmt_align { none, left, right, center }; +enum class fmt_sign { none, minus, plus, space }; +enum class arg_id_kind { none, index, name }; + +template +struct fill_t { +private: + static constexpr size_t max_size = 4 / sizeof(Char); + // At most one codepoint (so one char32_t or four utf-8 char8_t) + Char data_[max_size] = {Char{' '}}; + unsigned char size_ = 1; + +public: + constexpr void operator=(std::basic_string_view s) + { + auto size = s.size(); + if (size > max_size) return throw STD_FMT::format_error("invalid fill"); + for (size_t i = 0; i < size; ++i) data_[i] = s[i]; + size_ = static_cast(size); + } + + [[nodiscard]] constexpr size_t size() const { return size_; } + [[nodiscard]] constexpr const Char* data() const { return data_; } + + [[nodiscard]] constexpr Char& operator[](size_t index) { return data_[index]; } + [[nodiscard]] constexpr const Char& operator[](size_t index) const { return data_[index]; } +}; + +template +inline constexpr bool is_integer = std::is_integral::value && !std::is_same::value && + !std::is_same::value && !std::is_same::value; + +template +[[nodiscard]] constexpr bool is_ascii_letter(Char c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +// Converts a character to ASCII. Returns a number > 127 on conversion failure. +template +[[nodiscard]] constexpr Char to_ascii(Char value) +{ + return value; +} + +template + requires std::is_enum_v +[[nodiscard]] constexpr auto to_ascii(Char value) -> std::underlying_type_t { return value; } + +struct width_checker { + template + [[nodiscard]] constexpr unsigned long long operator()(T value) const + { + if constexpr (is_integer) { + if constexpr (std::numeric_limits::is_signed) { + if (value < 0) throw STD_FMT::format_error("negative width"); + } + return static_cast(value); + } else { + throw STD_FMT::format_error("width is not integer"); + } + } +}; + +struct precision_checker { + template + [[nodiscard]] constexpr unsigned long long operator()(T value) const + { + if constexpr (is_integer) { + if constexpr (std::numeric_limits::is_signed) { + if (value < 0) throw STD_FMT::format_error("negative precision"); + } + return static_cast(value); + } else { + throw STD_FMT::format_error("precision is not integer"); + } + } +}; + +// Format specifiers for built-in and string types. +template +struct basic_format_specs { + int width = 0; + int precision = -1; + char type = '\0'; + fmt_align align : 4 = fmt_align::none; + fmt_sign sign : 3 = fmt_sign::none; + bool alt : 1 = false; // Alternate form ('#'). + bool localized : 1 = false; + fill_t fill; +}; + +// Format specifiers with width and precision resolved at formatting rather +// than parsing time to allow re-using the same parsed specifiers with +// different sets of arguments (precompilation of format strings). +template +struct dynamic_format_specs : basic_format_specs { + int dynamic_width_index = -1; + int dynamic_precision_index = -1; +}; + +[[nodiscard]] constexpr int verify_dynamic_arg_index_in_range(size_t idx) +{ + if (idx > static_cast(std::numeric_limits::max())) { + throw STD_FMT::format_error("Dynamic width or precision index too large."); + } + return static_cast(idx); +} + +template +[[nodiscard]] constexpr int on_dynamic_arg(size_t arg_id, STD_FMT::basic_format_parse_context& context) +{ + context.check_arg_id(FMT_ARG_ID(arg_id)); + return verify_dynamic_arg_index_in_range(arg_id); +} + +template +[[nodiscard]] constexpr int on_dynamic_arg(auto_id, STD_FMT::basic_format_parse_context& context) +{ + return verify_dynamic_arg_index_in_range(context.next_arg_id()); +} + +template +[[nodiscard]] constexpr int get_dynamic_spec(int index, FormatContext& ctx) +{ + const unsigned long long value = STD_FMT::visit_format_arg(Handler{}, ctx.arg(static_cast(index))); + if (value > static_cast(std::numeric_limits::max())) { + throw STD_FMT::format_error("number is too big"); + } + return static_cast(value); +} + +// Parses the range [begin, end) as an unsigned integer. This function assumes +// that the range is non-empty and the first character is a digit. +template S> +[[nodiscard]] constexpr int parse_nonnegative_int(It& begin, S end, int error_value) noexcept +{ + gsl_Expects(begin != end && '0' <= *begin && *begin <= '9'); + unsigned value = 0, prev = 0; + auto p = begin; + do { + prev = value; + value = value * 10 + unsigned(*p - '0'); + ++p; + } while (p != end && '0' <= *p && *p <= '9'); + auto num_digits = p - begin; + begin = p; + if (num_digits <= std::numeric_limits::digits10) return static_cast(value); + // Check for overflow. + const unsigned max = static_cast(std::numeric_limits::max()); + return num_digits == std::numeric_limits::digits10 + 1 && prev * 10ull + unsigned(p[-1] - '0') <= max + ? static_cast(value) + : error_value; +} + +template S, typename IDHandler> +[[nodiscard]] constexpr It do_parse_arg_id(It begin, S end, IDHandler&& handler) +{ + gsl_Expects(begin != end); + auto c = *begin; + if (c >= '0' && c <= '9') { + int index = 0; + if (c != '0') + index = parse_nonnegative_int(begin, end, std::numeric_limits::max()); + else + ++begin; + if (begin == end || (*begin != '}' && *begin != ':')) + handler.on_error("invalid format string"); + else + handler(index); + return begin; + } + handler.on_error("invalid format string"); + return begin; +} + +template S, typename IDHandler> +[[nodiscard]] constexpr It parse_arg_id(It begin, S end, IDHandler&& handler) +{ + auto c = *begin; + if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler); + handler(); + return begin; +} + +template S, typename Handler> +[[nodiscard]] constexpr It parse_sign(It begin, S end, Handler&& handler) +{ + gsl_Expects(begin != end); + switch (to_ascii(*begin)) { + case '+': + handler.on_sign(fmt_sign::plus); + ++begin; + break; + case '-': + handler.on_sign(fmt_sign::minus); + ++begin; + break; + case ' ': + handler.on_sign(fmt_sign::space); + ++begin; + break; + default: + break; + } + return begin; +} + +template S, typename Handler> +[[nodiscard]] constexpr It parse_width(It begin, S end, Handler&& handler) +{ + struct width_adapter { + Handler& handler; + constexpr void operator()() { handler.on_dynamic_width(auto_id{}); } + constexpr void operator()(int id) { handler.on_dynamic_width(id); } + constexpr void on_error(const char* message) + { + if (message) handler.on_error(message); + } + }; + + gsl_Expects(begin != end); + if ('0' <= *begin && *begin <= '9') { + int width = parse_nonnegative_int(begin, end, -1); + if (width != -1) + handler.on_width(width); + else + handler.on_error("number is too big"); + } else if (*begin == '{') { + ++begin; + if (begin != end) begin = parse_arg_id(begin, end, width_adapter{handler}); + if (begin == end || *begin != '}') return handler.on_error("invalid format string"), begin; + ++begin; + } + return begin; +} + +template S, typename Handler> +[[nodiscard]] constexpr It parse_precision(It begin, S end, Handler&& handler) +{ + struct precision_adapter { + Handler& handler; + constexpr void operator()() { handler.on_dynamic_precision(auto_id{}); } + constexpr void operator()(int id) { handler.on_dynamic_precision(id); } + constexpr void on_error(const char* message) + { + if (message) handler.on_error(message); + } + }; + + ++begin; + auto c = begin != end ? *begin : std::iter_value_t(); + if ('0' <= c && c <= '9') { + auto precision = parse_nonnegative_int(begin, end, -1); + if (precision != -1) + handler.on_precision(precision); + else + handler.on_error("number is too big"); + } else if (c == '{') { + ++begin; + if (begin != end) begin = parse_arg_id(begin, end, precision_adapter{handler}); + if (begin == end || *begin++ != '}') return handler.on_error("invalid format string"), begin; + } else { + return handler.on_error("missing precision specifier"), begin; + } + return begin; +} + +template +constexpr int code_point_length(It begin) +{ + if constexpr (sizeof(std::iter_value_t) != 1) return 1; + constexpr char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0}; + int len = lengths[static_cast(*begin) >> 3]; + + // Compute the pointer to the next character early so that the next + // iteration can start working on the next character. Neither Clang + // nor GCC figure out this reordering on their own. + return len + !len; +} + +// Parses fill and alignment. +template S, typename Handler> +[[nodiscard]] constexpr It parse_align(It begin, S end, Handler&& handler) +{ + gsl_Expects(begin != end); + auto align = fmt_align::none; + auto p = begin + code_point_length(begin); + if (p >= end) p = begin; + for (;;) { + switch (to_ascii(*p)) { + case '<': + align = fmt_align::left; + break; + case '>': + align = fmt_align::right; + break; + case '^': + align = fmt_align::center; + break; + default: + break; + } + if (align != fmt_align::none) { + if (p != begin) { + auto c = *begin; + if (c == '{') return handler.on_error("invalid fill character '{'"), begin; + handler.on_fill(std::basic_string_view>(begin, p)); + begin = p + 1; + } else + ++begin; + handler.on_align(align); + break; + } else if (p == begin) { + break; + } + p = begin; + } + return begin; +} + +// Parses standard format specifiers and sends notifications about parsed +// components to handler. +template S, typename SpecHandler> +[[nodiscard]] constexpr It parse_format_specs(It begin, S end, SpecHandler&& handler) +{ + if (begin + 1 < end && begin[1] == '}' && is_ascii_letter(*begin) && *begin != 'L') { + handler.on_type(*begin++); + return begin; + } + + if (begin == end) return begin; + + begin = ::units::detail::parse_align(begin, end, handler); + if (begin == end) return begin; + + // Parse sign. + begin = ::units::detail::parse_sign(begin, end, handler); + if (begin == end) return begin; + + if (*begin == '#') { + handler.on_hash(); + if (++begin == end) return begin; + } + + // Parse zero flag. + if (*begin == '0') { + handler.on_zero(); + if (++begin == end) return begin; + } + + begin = ::units::detail::parse_width(begin, end, handler); + if (begin == end) return begin; + + // Parse precision. + if (*begin == '.') { + begin = ::units::detail::parse_precision(begin, end, handler); + if (begin == end) return begin; + } + + if (*begin == 'L') { + handler.on_localized(); + ++begin; + } + + // Parse type. + if (begin != end && *begin != '}') handler.on_type(*begin++); + return begin; +} + +// A format specifier handler that sets fields in basic_format_specs. +template +class specs_setter { +protected: + basic_format_specs& specs_; +public: + constexpr explicit specs_setter(basic_format_specs& specs) : specs_(specs) {} + constexpr void on_align(fmt_align align) { specs_.align = align; } + constexpr void on_fill(std::basic_string_view fill) { specs_.fill = fill; } + constexpr void on_sign(fmt_sign s) { specs_.sign = s; } + constexpr void on_hash() { specs_.alt = true; } + constexpr void on_localized() { specs_.localized = true; } + constexpr void on_zero() { specs_.fill[0] = Char('0'); } + constexpr void on_width(int width) { specs_.width = width; } + constexpr void on_precision(int precision) { specs_.precision = precision; } + constexpr void on_type(Char type) { specs_.type = static_cast(type); } +}; + +// Format spec handler that saves references to arguments representing dynamic +// width and precision to be resolved at formatting time. +template +class dynamic_specs_handler : public specs_setter { +public: + using char_type = TYPENAME ParseContext::char_type; + + constexpr dynamic_specs_handler(dynamic_format_specs& specs, ParseContext& ctx) : + specs_setter(specs), specs_(specs), context_(ctx) + {} + + template + constexpr void on_dynamic_width(T t) + { + specs_.dynamic_width_index = on_dynamic_arg(t, context_); + } + + template + constexpr void on_dynamic_precision(T t) + { + specs_.dynamic_precision_index = on_dynamic_arg(t, context_); + } + + constexpr void on_error(const char* message) { context_.on_error(message); } + +private: + dynamic_format_specs& specs_; + ParseContext& context_; +}; + +} // namespace units::detail diff --git a/src/core-fmt/include/units/bits/fmt_hacks.h b/src/core-fmt/include/units/bits/fmt_hacks.h new file mode 100644 index 00000000..687dae57 --- /dev/null +++ b/src/core-fmt/include/units/bits/fmt_hacks.h @@ -0,0 +1,58 @@ +// The MIT License (MIT) +// +// Copyright (c) 2018 Mateusz Pusz +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// Formatting library for C++ - the core API for char/UTF-8 +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include + +#if UNITS_USE_LIBFMT + +UNITS_DIAGNOSTIC_PUSH +UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE +UNITS_DIAGNOSTIC_IGNORE_SHADOW +#include +UNITS_DIAGNOSTIC_POP + +#define STD_FMT fmt +#define FMT_RUNTIME(arg) fmt::runtime(arg) +#define FMT_LOCALE(loc) (loc).template get() +#define FMT_ARG_ID(arg) static_cast(arg) + +#else + +#ifndef __cpp_lib_format +#error "std::formatting facility not supported" +#endif + +#include + +#define STD_FMT std +#define FMT_RUNTIME(arg) arg +#define FMT_LOCALE(loc) loc +#define FMT_ARG_ID(arg) arg + +#endif diff --git a/src/core-fmt/include/units/format.h b/src/core-fmt/include/units/format.h index 8da93474..3703f556 100644 --- a/src/core-fmt/include/units/format.h +++ b/src/core-fmt/include/units/format.h @@ -22,24 +22,18 @@ #pragma once +#include #include #include - #include -#include +#include // IWYU pragma: begin_exports #include - -UNITS_DIAGNOSTIC_PUSH -UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE -UNITS_DIAGNOSTIC_IGNORE_SHADOW -#include -UNITS_DIAGNOSTIC_POP // IWYU pragma: end_exports // Grammar -// +// // units-format-spec ::= [fill-and-align] [width] [units-specs] // units-specs ::= conversion-spec // units-specs conversion-spec @@ -60,457 +54,412 @@ UNITS_DIAGNOSTIC_POP // - Add the new symbol in the `units_types` variable in the `parse_units_format` function // - Add a new case in the `if` following the format_error in `parse_units_format` function; // this should invoke `handler.on_[...]` -// - Edit `fmt::formatter`: +// - Edit `STD_FMT::formatter`: // - Add a new field for the flag/specs -// - Add to the `fmt::formatter::spec_handler` a `on_[...]` function that set the flag/specs if needed -// - Edit `units_formatter`: +// - Add to the `STD_FMT::formatter::spec_handler` a `on_[...]` function that set the flag/specs if needed +// - Edit `quantity_formatter`: // - Add a new field for the flag/specs // - write a `on_[...]` function that writes to the `out` iterator the correct output -// +// // If you want to add a new `units-rep-type`: // - Add the new symbol in the `valid_rep_types` variable (which is in the -// fmt::formatter::spec_handler::on_type member function) +// STD_FMT::formatter::spec_handler::on_type member function) // NB: currently this function forward the modifier to the value that must be formatted; -// if the symbol has no meaning for fmt::formatter, this behavior should be disabled manually +// if the symbol has no meaning for STD_FMT::formatter, this behavior should be disabled manually // (as is done for '\0') // - Implement the effect of the new flag in `format_units_quantity_value` -// +// // If you want to add a new `units-unit-modifier`: // - Add the new symbol in the `valid_modifiers` variable (which is in the -// fmt::formatter::spec_handler::on_modifier member function) -// - Implement the effect of the new flag in the `units_formatter::on_quantity_unit` member function +// STD_FMT::formatter::spec_handler::on_unit_modifier member function) +// - Implement the effect of the new flag in the `quantity_formatter::on_quantity_unit` member function -namespace units { +namespace units::detail { - namespace detail { +// Holds specs about the whole object +template +struct quantity_global_format_specs { + fill_t fill; + fmt_align align = fmt_align::none; + int width = 0; + int dynamic_width_index = -1; +}; - // Holds specs about the whole object - template - struct global_format_specs - { - fmt::detail::fill_t fill; - fmt::align_t align = fmt::align_t::none; - int width = 0; - }; +// Holds specs about the representation (%[specs]Q) +struct quantity_rep_format_specs { + fmt_sign sign = fmt_sign::none; + int precision = -1; + int dynamic_precision_index = -1; + char type = '\0'; + bool alt = false; + bool localized = false; +}; - // Holds specs about the representation (%[specs]Q) - struct rep_format_specs - { - fmt::sign_t sign = fmt::sign_t::none; - int precision = -1; - char type = '\0'; - bool alt = false; - bool use_locale = false; - }; +// Holds specs about the unit (%[specs]q) +struct quantity_unit_format_specs { + bool ascii_only = false; +}; - // Holds specs about the unit (%[specs]q) - struct unit_format_specs - { - char modifier = '\0'; - }; +template +struct quantity_format_specs { + quantity_global_format_specs global; + quantity_rep_format_specs rep; + quantity_unit_format_specs unit; +}; - // Parse a `units-rep-modifier` - template - constexpr const CharT* parse_units_rep(const CharT* begin, const CharT* end, Handler&& handler, bool treat_as_floating_point) - { - // parse sign - switch(static_cast(*begin)) { - case '+': - handler.on_plus(); - ++begin; - break; - case '-': - handler.on_minus(); - ++begin; - break; - case ' ': - handler.on_space(); - ++begin; - break; - } - if(begin == end) - return begin; +// Parse a `units-rep-modifier` +template S, typename Handler> +constexpr const It parse_units_rep(It begin, S end, Handler&& handler, bool treat_as_floating_point) +{ + // parse sign + begin = parse_sign(begin, end, handler); + if (begin == end) return begin; - // parse # - if (*begin == '#') { - handler.on_alt(); - if (++begin == end) return begin; - } + // parse # + if (*begin == '#') { + handler.on_hash(); + if (++begin == end) return begin; + } - // parse precision if a floating point - if(*begin == '.') { - if (treat_as_floating_point) - begin = fmt::detail::parse_precision(begin, end, handler); - else - handler.on_error("precision not allowed for integral quantity representation"); - } + // parse precision if a floating point + if (*begin == '.') { + if (treat_as_floating_point) { + begin = parse_precision(begin, end, handler); + } else + handler.on_error("precision not allowed for integral quantity representation"); + if (begin == end) return begin; + } - // parse L to enable the locale-specific form - if (*begin == 'L') { - handler.on_locale(); - ++begin; - } + // parse L to enable the locale-specific form + if (*begin == 'L') { + handler.on_localized(); + ++begin; + } - if(begin != end && *begin != '}' && *begin != '%') { - handler.on_type(*begin++); - } - return begin; + if (begin != end && *begin != '}' && *begin != '%') { + handler.on_type(*begin++); + } + return begin; +} + +// parse units-specs +template S, typename Handler> +constexpr It parse_units_format(It begin, S end, Handler&& handler) +{ + auto ptr = begin; + while (ptr != end) { + auto c = *ptr; + if (c == '}') break; + if (c != '%') { + ++ptr; + continue; } + if (begin != ptr) handler.on_text(begin, ptr); + begin = ++ptr; // consume '%' + if (ptr == end) throw STD_FMT::format_error("invalid format"); + c = *ptr++; - // parse units-specs - template - constexpr const CharT* parse_units_format(const CharT* begin, const CharT* end, Handler&& handler) - { - auto ptr = begin; - while(ptr != end) { - auto c = *ptr; - if(c == '}') - break; - if(c != '%') { - ++ptr; - continue; - } - if(begin != ptr) - handler.on_text(begin, ptr); - begin = ++ptr; // consume '%' - if(ptr == end) - throw fmt::format_error("invalid format"); - c = *ptr++; - - switch(c) { - // units-type - case '%': - handler.on_text(ptr - 1, ptr); - break; - case 'n': { - const char newline[] = "\n"; - handler.on_text(newline, newline + 1); - break; - } - case 't': { - const char tab[] = "\t"; - handler.on_text(tab, tab + 1); - break; - } - default: - constexpr auto units_types = std::string_view{"Qq"}; - auto const new_end = std::find_first_of(begin, end, units_types.begin(), units_types.end()); - if (new_end == end) { - throw fmt::format_error("invalid format"); - } - if (*new_end == 'Q') { - handler.on_quantity_value(begin, new_end); // Edit `on_quantity_value` to add rep modifiers - } else { - handler.on_quantity_unit(*begin); // Edit `on_quantity_unit` to add an unit modifier - } - ptr = new_end + 1; - } - begin = ptr; - } - if(begin != ptr) - handler.on_text(begin, ptr); - return ptr; - } - - // build the 'representation' as requested in the format string, applying only units-rep-modifiers - template - inline OutputIt format_units_quantity_value(OutputIt out, const Rep& val, const rep_format_specs& rep_specs, LocaleRef loc) - { - fmt::basic_memory_buffer buffer; - auto to_buffer = std::back_inserter(buffer); - - fmt::format_to(to_buffer, "{{:"); - switch(rep_specs.sign) { - case fmt::sign::none: + switch (c) { + // units-type + case '%': + handler.on_text(ptr - 1, ptr); break; - case fmt::sign::plus: - fmt::format_to(to_buffer, "+"); - break; - case fmt::sign::minus: - fmt::format_to(to_buffer, "-"); - break; - case fmt::sign::space: - fmt::format_to(to_buffer, " "); + case 'n': { + const char newline[] = "\n"; + handler.on_text(newline, newline + 1); break; } - - if (rep_specs.alt) { - fmt::format_to(to_buffer, "#"); - } - auto type = rep_specs.type; - if (auto precision = rep_specs.precision; precision >= 0) { - fmt::format_to(to_buffer, ".{}{}", precision, type == '\0' ? 'f' : type); - } else if constexpr (treat_as_floating_point) { - fmt::format_to(to_buffer, "{}", type == '\0' ? 'g' : type); - } else { - if (type != '\0') { - fmt::format_to(to_buffer, "{}", type); - } - } - if (rep_specs.use_locale) { - fmt::format_to(to_buffer, "L"); - } - fmt::format_to(to_buffer, "}}"); - if (rep_specs.use_locale and static_cast(loc)) { - return fmt::format_to(out, loc.template get(), fmt::runtime(std::string_view(buffer.data(), buffer.size())), val); - } - return fmt::format_to(out, fmt::runtime(std::string_view(buffer.data(), buffer.size())), val); - } - - // Creates a global format string - // e.g. "{:*^10%.1Q_%q}, 1.23_q_m" => "{:*^10}" - template - inline OutputIt format_global_buffer(OutputIt out, const global_format_specs& specs) - { - fmt::format_to(out, "{{:"); - if (specs.fill.size() != 1 || specs.fill[0] != ' ') { - fmt::format_to(out, "{}", specs.fill.data()); - } - switch (specs.align) { - case fmt::align_t::left: - fmt::format_to(out, "<"); - break; - case fmt::align_t::right: - fmt::format_to(out, ">"); - break; - case fmt::align_t::center: - fmt::format_to(out, "^"); + case 't': { + const char tab[] = "\t"; + handler.on_text(tab, tab + 1); break; + } default: - break; - } - if (specs.width >= 1) { - fmt::format_to(out, "{}", specs.width); - } - return fmt::format_to(out, "}}"); + constexpr auto units_types = std::string_view{"Qq"}; + auto const new_end = std::find_first_of(begin, end, units_types.begin(), units_types.end()); + if (new_end == end) throw STD_FMT::format_error("invalid format"); + if (*new_end == 'Q') { + handler.on_quantity_value(begin, new_end); // Edit `on_quantity_value` to add rep modifiers + } else { + handler.on_quantity_unit(*begin); // Edit `on_quantity_unit` to add an unit modifier + } + ptr = new_end + 1; } + begin = ptr; + } + if (begin != ptr) handler.on_text(begin, ptr); + return ptr; +} - template - struct units_formatter { - OutputIt out; - Rep val; - global_format_specs const & global_specs; - rep_format_specs const & rep_specs; - unit_format_specs const & unit_specs; - LocaleRef loc; +// build the 'representation' as requested in the format string, applying only units-rep-modifiers +template +[[nodiscard]] OutputIt format_units_quantity_value(OutputIt out, const Rep& val, + const quantity_rep_format_specs& rep_specs, const Locale& loc) +{ + std::basic_string buffer; + auto to_buffer = std::back_inserter(buffer); - explicit units_formatter( - OutputIt o, quantity q, - global_format_specs const & gspecs, - rep_format_specs const & rspecs, unit_format_specs const & uspecs, - LocaleRef lc - ): - out(o), val(q.number()), global_specs(gspecs), rep_specs(rspecs), unit_specs(uspecs), loc(lc) - { - } + STD_FMT::format_to(to_buffer, "{{:"); + switch (rep_specs.sign) { + case fmt_sign::none: + break; + case fmt_sign::plus: + STD_FMT::format_to(to_buffer, "+"); + break; + case fmt_sign::minus: + STD_FMT::format_to(to_buffer, "-"); + break; + case fmt_sign::space: + STD_FMT::format_to(to_buffer, " "); + break; + } - template - void on_text(const CharT2* begin, const CharT2* end) - { - std::copy(begin, end, out); - } + if (rep_specs.alt) { + STD_FMT::format_to(to_buffer, "#"); + } + auto type = rep_specs.type; + if (auto precision = rep_specs.precision; precision >= 0) { + STD_FMT::format_to(to_buffer, ".{}{}", precision, type == '\0' ? 'f' : type); + } else if constexpr (treat_as_floating_point) { + STD_FMT::format_to(to_buffer, "{}", type == '\0' ? 'g' : type); + } else { + if (type != '\0') { + STD_FMT::format_to(to_buffer, "{}", type); + } + } + if (rep_specs.localized) { + STD_FMT::format_to(to_buffer, "L"); + } - void on_quantity_value([[maybe_unused]] const CharT*, [[maybe_unused]] const CharT*) - { - out = format_units_quantity_value(out, val, rep_specs, loc); - } + STD_FMT::format_to(to_buffer, "}}"); + if (rep_specs.localized) { + return STD_FMT::format_to(out, FMT_LOCALE(loc), FMT_RUNTIME(buffer), val); + } + return STD_FMT::format_to(out, FMT_RUNTIME(buffer), val); +} - void on_quantity_unit([[maybe_unused]] const CharT) - { - auto txt = unit_text(); - if(unit_specs.modifier == 'A') { - fmt::format_to(out, "{}", txt.ascii().c_str()); - } - else { - fmt::format_to(out, "{}", txt.standard().c_str()); - } - } - }; +// Creates a global format string +// e.g. "{:*^10%.1Q_%q}, 1.23_q_m" => "{:*^10}" +template OutputIt> +OutputIt format_global_buffer(OutputIt out, const quantity_global_format_specs& specs) +{ + STD_FMT::format_to(out, "{{:"); + if (specs.fill.size() != 1 || specs.fill[0] != ' ') { + STD_FMT::format_to(out, "{}", specs.fill.data()); + } + switch (specs.align) { + case fmt_align::left: + STD_FMT::format_to(out, "<"); + break; + case fmt_align::right: + STD_FMT::format_to(out, ">"); + break; + case fmt_align::center: + STD_FMT::format_to(out, "^"); + break; + default: + break; + } + if (specs.width >= 1) STD_FMT::format_to(out, "{}", specs.width); + return STD_FMT::format_to(out, "}}"); +} - } // namespace detail +template OutputIt> +struct quantity_formatter { + OutputIt out; + Rep val; + const quantity_format_specs& specs; + Locale loc; -} // namespace units + explicit quantity_formatter(OutputIt o, quantity q, const quantity_format_specs& fspecs, + Locale lc) : + out(o), val(std::move(q).number()), specs(fspecs), loc(std::move(lc)) + {} + + template S> + void on_text(It begin, S end) + { + std::copy(begin, end, out); + } + + template S> + void on_quantity_value([[maybe_unused]] It, [[maybe_unused]] S) + { + out = format_units_quantity_value(out, val, specs.rep, loc); + } + + void on_quantity_unit([[maybe_unused]] CharT) + { + auto txt = unit_text(); + if (specs.unit.ascii_only) { + STD_FMT::format_to(out, "{}", txt.ascii().c_str()); + } else { + STD_FMT::format_to(out, "{}", txt.standard().c_str()); + } + } +}; + +} // namespace units::detail template -struct fmt::formatter, CharT> { +struct STD_FMT::formatter, CharT> { private: using quantity = units::quantity; - using iterator = TYPENAME fmt::basic_format_parse_context::iterator; - using arg_ref_type = fmt::detail::arg_ref; + using iterator = TYPENAME STD_FMT::basic_format_parse_context::iterator; - units::detail::global_format_specs global_specs; - units::detail::rep_format_specs rep_specs; - units::detail::unit_format_specs unit_specs; bool quantity_value = false; bool quantity_unit = false; - bool quantity_unit_ascii_only = false; - arg_ref_type width_ref; - arg_ref_type precision_ref; - fmt::basic_string_view format_str; + units::detail::quantity_format_specs specs; + std::basic_string_view format_str; struct spec_handler { formatter& f; - fmt::basic_format_parse_context& context; - fmt::basic_string_view format_str; + STD_FMT::basic_format_parse_context& context; - template - constexpr arg_ref_type make_arg_ref(Id arg_id) - { - context.check_arg_id(arg_id); - return arg_ref_type(arg_id); - } + void on_error(const char* msg) { throw STD_FMT::format_error(msg); } + constexpr void on_fill(std::basic_string_view fill) { f.specs.global.fill = fill; } + constexpr void on_align(units::detail::fmt_align align) { f.specs.global.align = align; } + constexpr void on_width(int width) { f.specs.global.width = width; } + constexpr void on_sign(units::detail::fmt_sign s) { f.specs.rep.sign = s; } + constexpr void on_hash() { f.specs.rep.alt = true; } + constexpr void on_precision(int precision) { f.specs.rep.precision = precision; } + constexpr void on_localized() { f.specs.rep.localized = true; } - constexpr arg_ref_type make_arg_ref(fmt::basic_string_view arg_id) - { - context.check_arg_id(arg_id); - return arg_ref_type(arg_id); - } - - constexpr arg_ref_type make_arg_ref(fmt::detail::auto_id) - { - return arg_ref_type(context.next_arg_id()); - } - - void on_error(const char* msg) { throw fmt::format_error(msg); } - constexpr void on_fill(basic_string_view fill) { f.global_specs.fill = fill; } // global - constexpr void on_align(align_t align) { f.global_specs.align = align; } // global - constexpr void on_width(int width) { f.global_specs.width = width; } // global - constexpr void on_plus() { f.rep_specs.sign = fmt::sign::plus; } // rep - constexpr void on_minus() { f.rep_specs.sign = fmt::sign::minus; } // rep - constexpr void on_space() { f.rep_specs.sign = fmt::sign::space; } // rep - constexpr void on_alt() { f.rep_specs.alt = true; } // rep - constexpr void on_precision(int precision) { f.rep_specs.precision = precision; } // rep - constexpr void on_locale() { f.rep_specs.use_locale = true; } // rep - constexpr void on_type(char type) // rep + constexpr void on_type(char type) { constexpr auto valid_rep_types = std::string_view{"aAbBdeEfFgGoxX"}; if (valid_rep_types.find(type) != std::string_view::npos) { - f.rep_specs.type = type; + f.specs.rep.type = type; } else { on_error("invalid quantity type specifier"); } } - constexpr void on_modifier(char mod) { + + constexpr void on_unit_modifier(char mod) + { constexpr auto valid_modifiers = std::string_view{"A"}; if (valid_modifiers.find(mod) != std::string_view::npos) { - f.unit_specs.modifier = mod; + f.specs.unit.ascii_only = true; } else { on_error("invalid unit modifier specified"); } - } // unit - constexpr void end_precision() {} - - template - constexpr void on_dynamic_width(Id arg_id) - { - f.width_ref = make_arg_ref(arg_id); } - template - constexpr void on_dynamic_precision(Id arg_id) + template + constexpr void on_dynamic_width(T t) { - f.precision_ref = make_arg_ref(arg_id); + f.specs.global.dynamic_width_index = units::detail::on_dynamic_arg(t, context); + } + + template + constexpr void on_dynamic_precision(T t) + { + f.specs.rep.dynamic_precision_index = units::detail::on_dynamic_arg(t, context); } constexpr void on_text(const CharT*, const CharT*) {} constexpr void on_quantity_value(const CharT* begin, const CharT* end) { - if (begin != end) { - units::detail::parse_units_rep(begin, end, *this, units::treat_as_floating_point); - } + if (begin != end) units::detail::parse_units_rep(begin, end, *this, units::treat_as_floating_point); f.quantity_value = true; } - constexpr void on_quantity_unit(const CharT mod) + constexpr void on_quantity_unit(CharT mod) { - if (mod != 'q') { - f.unit_specs.modifier = mod; - } + if (mod != 'q') on_unit_modifier(mod); f.quantity_unit = true; } - }; - struct parse_range { - iterator begin; - iterator end; - }; - - constexpr parse_range do_parse(fmt::basic_format_parse_context& ctx) + [[nodiscard]] constexpr std::ranges::subrange do_parse(STD_FMT::basic_format_parse_context& ctx) { - auto begin = ctx.begin(), end = ctx.end(); - if(begin == end || *begin == '}') - return {begin, begin}; + auto begin = ctx.begin(); + auto end = ctx.end(); + + if (begin == end || *begin == '}') return {begin, begin}; // handler to assign parsed data to formatter data members - spec_handler handler{*this, ctx, format_str}; + spec_handler handler{*this, ctx}; // parse alignment - begin = fmt::detail::parse_align(begin, end, handler); - if(begin == end) - return {begin, begin}; + begin = units::detail::parse_align(begin, end, handler); + if (begin == end) return {begin, begin}; // parse width - begin = fmt::detail::parse_width(begin, end, handler); - if(begin == end) - return {begin, begin}; + begin = units::detail::parse_width(begin, end, handler); + if (begin == end) return {begin, begin}; // parse units-specific specification end = units::detail::parse_units_format(begin, end, handler); - if(global_specs.align == fmt::align_t::none && (!quantity_unit || quantity_value)) + if (specs.global.align == units::detail::fmt_align::none && (!quantity_unit || quantity_value)) // quantity values should behave like numbers (by default aligned to right) - global_specs.align = fmt::align_t::right; + specs.global.align = units::detail::fmt_align::right; return {begin, end}; } + template OutputIt, typename FormatContext> + OutputIt format_quantity_content(OutputIt out, const quantity& q, FormatContext& ctx) + { + auto begin = format_str.begin(); + auto end = format_str.end(); + + if (begin == end || *begin == '}') { + // default format should print value followed by the unit separated with 1 space + out = units::detail::format_units_quantity_value(out, q.number(), specs.rep, ctx.locale()); + constexpr auto symbol = units::detail::unit_text(); + if constexpr (symbol.standard().size()) { + *out++ = CharT(' '); + STD_FMT::format_to(out, "{}", symbol.standard().c_str()); + } + } else { + // user provided format + units::detail::quantity_formatter f(out, q, specs, ctx.locale()); + units::detail::parse_units_format(begin, end, f); + } + return out; + } + public: - constexpr auto parse(fmt::basic_format_parse_context& ctx) + [[nodiscard]] constexpr auto parse(STD_FMT::basic_format_parse_context& ctx) { auto range = do_parse(ctx); - format_str = fmt::basic_string_view(&*range.begin, fmt::detail::to_unsigned(range.end - range.begin)); - return range.end; + format_str = std::basic_string_view(range.begin(), range.end()); + return range.end(); } template - auto format(const units::quantity& q, FormatContext& ctx) + auto format(const quantity& q, FormatContext& ctx) { - auto begin = format_str.begin(), end = format_str.end(); - // process dynamic width and precision - fmt::detail::handle_dynamic_spec(global_specs.width, width_ref, ctx); - fmt::detail::handle_dynamic_spec(rep_specs.precision, precision_ref, ctx); + if (specs.global.dynamic_width_index >= 0) + specs.global.width = + units::detail::get_dynamic_spec(specs.global.dynamic_width_index, ctx); + if (specs.rep.dynamic_precision_index >= 0) + specs.rep.precision = + units::detail::get_dynamic_spec(specs.rep.dynamic_precision_index, ctx); - // In `quantity_buffer` we will have the representation and the unit formatted according to their - // specification, ignoring global specifiers - // e.g. "{:*^10%.1Q_%q}, 1.23_q_m" => "1.2_m" - // TODO Avoid extra copying if width is not specified - fmt::basic_memory_buffer quantity_buffer; - auto to_quantity_buffer = std::back_inserter(quantity_buffer); + if (specs.global.width == 0) { + // Avoid extra copying if width is not specified + return format_quantity_content(ctx.out(), q, ctx); + } else { + // In `quantity_buffer` we will have the representation and the unit formatted according to their + // specification, ignoring global specifiers + // e.g. "{:*^10%.1Q_%q}, 1.23_q_m" => "1.2_m" + std::basic_string quantity_buffer; - // deal with quantity content - if(begin == end || *begin == '}') { - // default format should print value followed by the unit separated with 1 space - to_quantity_buffer = units::detail::format_units_quantity_value(to_quantity_buffer, q.number(), rep_specs, ctx.locale()); - constexpr auto symbol = units::detail::unit_text(); - if(symbol.standard().size()) { - *to_quantity_buffer++ = CharT(' '); - fmt::format_to(to_quantity_buffer, "{}", symbol.standard().c_str()); - } + // deal with quantity content + format_quantity_content(std::back_inserter(quantity_buffer), q, ctx); + + // In `global_format_buffer` we will create a global format string + // e.g. "{:*^10%.1Q_%q}, 1.23_q_m" => "{:*^10}" + std::basic_string global_format_buffer; + units::detail::format_global_buffer(std::back_inserter(global_format_buffer), specs.global); + + // Format the `quantity buffer` using specs from `global_format_buffer` + // In the example, equivalent to STD_FMT::format("{:*^10}", "1.2_m") + return STD_FMT::format_to(ctx.out(), FMT_RUNTIME(global_format_buffer), quantity_buffer); } - else { - // user provided format - units::detail::units_formatter f(to_quantity_buffer, q, global_specs, rep_specs, unit_specs, ctx.locale()); - parse_units_format(begin, end, f); - } - - // In `global_format_buffer` we will create a global format string - // e.g. "{:*^10%.1Q_%q}, 1.23_q_m" => "{:*^10}" - fmt::basic_memory_buffer global_format_buffer; - units::detail::format_global_buffer(std::back_inserter(global_format_buffer), global_specs); - - // Format the `quantity buffer` using specs from `global_format_buffer` - // In the example, equivalent to fmt::format("{:*^10}", "1.2_m") - return fmt::format_to(ctx.out(), fmt::runtime(std::basic_string_view(global_format_buffer.data(), global_format_buffer.size())), std::string_view(quantity_buffer.data(), quantity_buffer.size())); } }; diff --git a/test/unit_test/runtime/fmt_test.cpp b/test/unit_test/runtime/fmt_test.cpp index 89a34b1e..2c0e4265 100644 --- a/test/unit_test/runtime/fmt_test.cpp +++ b/test/unit_test/runtime/fmt_test.cpp @@ -55,12 +55,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -76,12 +76,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } } @@ -98,12 +98,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -121,12 +121,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -142,12 +142,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } } @@ -164,12 +164,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -185,12 +185,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -210,12 +210,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -231,12 +231,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -252,12 +252,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } } @@ -276,12 +276,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -298,12 +298,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } } @@ -323,12 +323,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -344,12 +344,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -365,12 +365,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -386,12 +386,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -407,12 +407,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } } @@ -431,12 +431,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == "2 "); + CHECK(STD_FMT::format("{:%Q %q}", q) == "2 "); } } @@ -452,12 +452,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == "2 × 10³"); + CHECK(STD_FMT::format("{:%Q %q}", q) == "2 × 10³"); } } @@ -477,12 +477,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } } @@ -503,12 +503,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -524,12 +524,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } } @@ -546,12 +546,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -567,12 +567,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -588,12 +588,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -609,12 +609,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -630,12 +630,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -651,12 +651,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -672,12 +672,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -693,12 +693,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -714,12 +714,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -735,12 +735,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } @@ -756,12 +756,12 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]") SECTION("fmt with default format {} on a quantity") { - CHECK(fmt::format("{}", q) == os.str()); + CHECK(STD_FMT::format("{}", q) == os.str()); } SECTION("fmt with format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%Q %q}", q) == os.str()); + CHECK(STD_FMT::format("{:%Q %q}", q) == os.str()); } } } @@ -773,12 +773,12 @@ TEST_CASE("format string with only %Q should print quantity value only", "[text] { SECTION("positive value") { - CHECK(fmt::format("{:%Q}", 123_q_km_per_h) == "123"); + CHECK(STD_FMT::format("{:%Q}", 123_q_km_per_h) == "123"); } SECTION("negative value") { - CHECK(fmt::format("{:%Q}", 5_q_m - 10_q_m) == "-5"); + CHECK(STD_FMT::format("{:%Q}", 5_q_m - 10_q_m) == "-5"); } } @@ -786,27 +786,27 @@ TEST_CASE("format string with only %Q should print quantity value only", "[text] { SECTION("positive value") { - CHECK(fmt::format("{:%Q}", 221._q_km / 2_q_h) == "110.5"); + CHECK(STD_FMT::format("{:%Q}", 221._q_km / 2_q_h) == "110.5"); } SECTION("negative value") { - CHECK(fmt::format("{:%Q}", 3.14_q_m - 10_q_m) == "-6.86"); + CHECK(STD_FMT::format("{:%Q}", 3.14_q_m - 10_q_m) == "-6.86"); } SECTION("nan") { - CHECK(fmt::format("{:%Q}", length(std::numeric_limits::quiet_NaN())) == "nan"); + CHECK(STD_FMT::format("{:%Q}", length(std::numeric_limits::quiet_NaN())) == "nan"); } SECTION("inf") { - CHECK(fmt::format("{:%Q}", length(std::numeric_limits::infinity())) == "inf"); + CHECK(STD_FMT::format("{:%Q}", length(std::numeric_limits::infinity())) == "inf"); } SECTION("-inf") { - CHECK(fmt::format("{:%Q}", length(-std::numeric_limits::infinity())) == "-inf"); + CHECK(STD_FMT::format("{:%Q}", length(-std::numeric_limits::infinity())) == "-inf"); } } } @@ -815,24 +815,24 @@ TEST_CASE("format string with only %q should print quantity unit symbol only", " { SECTION("standard format for a unit without Unicode symbols") { - CHECK(fmt::format("{:%q}", 123_q_km_per_h) == "km/h"); + CHECK(STD_FMT::format("{:%q}", 123_q_km_per_h) == "km/h"); } SECTION("ASCII format for a unit without Unicode symbols") { - CHECK(fmt::format("{:%Aq}", 123_q_km_per_h) == "km/h"); + CHECK(STD_FMT::format("{:%Aq}", 123_q_km_per_h) == "km/h"); } SECTION("standard format for a unit with Unicode symbols") { SECTION("Unicode signs in a unit symbol") { - CHECK(fmt::format("{:%q}", 123_q_kR) == "kΩ"); + CHECK(STD_FMT::format("{:%q}", 123_q_kR) == "kΩ"); } SECTION("Unicode signs in a unit symbol prefix") { - CHECK(fmt::format("{:%q}", 123_q_uV) == "µV"); + CHECK(STD_FMT::format("{:%q}", 123_q_uV) == "µV"); } } @@ -840,12 +840,12 @@ TEST_CASE("format string with only %q should print quantity unit symbol only", " { SECTION("Unicode signs in a unit symbol") { - CHECK(fmt::format("{:%Aq}", 123_q_kR) == "kohm"); + CHECK(STD_FMT::format("{:%Aq}", 123_q_kR) == "kohm"); } SECTION("Unicode signs in a unit symbol prefix") { - CHECK(fmt::format("{:%Aq}", 123_q_uV) == "uV"); + CHECK(STD_FMT::format("{:%Aq}", 123_q_uV) == "uV"); } } } @@ -854,32 +854,32 @@ TEST_CASE("%q and %Q can be put anywhere in a format string", "[text][fmt]") { SECTION("no space") { - CHECK(fmt::format("{:%Q%q}", 123_q_km_per_h) == "123km/h"); + CHECK(STD_FMT::format("{:%Q%q}", 123_q_km_per_h) == "123km/h"); } SECTION("separator") { - CHECK(fmt::format("{:%Q###%q}", 123_q_km_per_h) == "123###km/h"); + CHECK(STD_FMT::format("{:%Q###%q}", 123_q_km_per_h) == "123###km/h"); } SECTION("opposite order") { - CHECK(fmt::format("{:%q %Q}", 123_q_km_per_h) == "km/h 123"); + CHECK(STD_FMT::format("{:%q %Q}", 123_q_km_per_h) == "km/h 123"); } SECTION("tabulator") { - CHECK(fmt::format("{:%Q%t%q}", 123_q_km_per_h) == "123\tkm/h"); + CHECK(STD_FMT::format("{:%Q%t%q}", 123_q_km_per_h) == "123\tkm/h"); } SECTION("new line") { - CHECK(fmt::format("{:%Q%n%q}", 123_q_km_per_h) == "123\nkm/h"); + CHECK(STD_FMT::format("{:%Q%n%q}", 123_q_km_per_h) == "123\nkm/h"); } SECTION("% sign") { - CHECK(fmt::format("{:%Q%% %q}", 123_q_km_per_h) == "123% km/h"); + CHECK(STD_FMT::format("{:%Q%% %q}", 123_q_km_per_h) == "123% km/h"); } } @@ -928,50 +928,50 @@ TEST_CASE("fill and align specification", "[text][fmt][ostream]") SECTION("default format {} on a quantity") { - CHECK(fmt::format("|{:0}|", 123_q_m) == "|123 m|"); - CHECK(fmt::format("|{:10}|", 123_q_m) == "| 123 m|"); - CHECK(fmt::format("|{:<10}|", 123_q_m) == "|123 m |"); - CHECK(fmt::format("|{:>10}|", 123_q_m) == "| 123 m|"); - CHECK(fmt::format("|{:^10}|", 123_q_m) == "| 123 m |"); - CHECK(fmt::format("|{:*<10}|", 123_q_m) == "|123 m*****|"); - CHECK(fmt::format("|{:*>10}|", 123_q_m) == "|*****123 m|"); - CHECK(fmt::format("|{:*^10}|", 123_q_m) == "|**123 m***|"); + CHECK(STD_FMT::format("|{:0}|", 123_q_m) == "|123 m|"); + CHECK(STD_FMT::format("|{:10}|", 123_q_m) == "| 123 m|"); + CHECK(STD_FMT::format("|{:<10}|", 123_q_m) == "|123 m |"); + CHECK(STD_FMT::format("|{:>10}|", 123_q_m) == "| 123 m|"); + CHECK(STD_FMT::format("|{:^10}|", 123_q_m) == "| 123 m |"); + CHECK(STD_FMT::format("|{:*<10}|", 123_q_m) == "|123 m*****|"); + CHECK(STD_FMT::format("|{:*>10}|", 123_q_m) == "|*****123 m|"); + CHECK(STD_FMT::format("|{:*^10}|", 123_q_m) == "|**123 m***|"); } SECTION("full format {:%Q %q} on a quantity") { - CHECK(fmt::format("|{:0%Q%q}|", 123_q_m) == "|123m|"); - CHECK(fmt::format("|{:10%Q%q}|", 123_q_m) == "| 123m|"); - CHECK(fmt::format("|{:<10%Q%q}|", 123_q_m) == "|123m |"); - CHECK(fmt::format("|{:>10%Q%q}|", 123_q_m) == "| 123m|"); - CHECK(fmt::format("|{:^10%Q%q}|", 123_q_m) == "| 123m |"); - CHECK(fmt::format("|{:*<10%Q%q}|", 123_q_m) == "|123m******|"); - CHECK(fmt::format("|{:*>10%Q%q}|", 123_q_m) == "|******123m|"); - CHECK(fmt::format("|{:*^10%Q%q}|", 123_q_m) == "|***123m***|"); + CHECK(STD_FMT::format("|{:0%Q%q}|", 123_q_m) == "|123m|"); + CHECK(STD_FMT::format("|{:10%Q%q}|", 123_q_m) == "| 123m|"); + CHECK(STD_FMT::format("|{:<10%Q%q}|", 123_q_m) == "|123m |"); + CHECK(STD_FMT::format("|{:>10%Q%q}|", 123_q_m) == "| 123m|"); + CHECK(STD_FMT::format("|{:^10%Q%q}|", 123_q_m) == "| 123m |"); + CHECK(STD_FMT::format("|{:*<10%Q%q}|", 123_q_m) == "|123m******|"); + CHECK(STD_FMT::format("|{:*>10%Q%q}|", 123_q_m) == "|******123m|"); + CHECK(STD_FMT::format("|{:*^10%Q%q}|", 123_q_m) == "|***123m***|"); } SECTION("value only format {:%Q} on a quantity") { - CHECK(fmt::format("|{:0%Q}|", 123_q_m) == "|123|"); - CHECK(fmt::format("|{:10%Q}|", 123_q_m) == "| 123|"); - CHECK(fmt::format("|{:<10%Q}|", 123_q_m) == "|123 |"); - CHECK(fmt::format("|{:>10%Q}|", 123_q_m) == "| 123|"); - CHECK(fmt::format("|{:^10%Q}|", 123_q_m) == "| 123 |"); - CHECK(fmt::format("|{:*<10%Q}|", 123_q_m) == "|123*******|"); - CHECK(fmt::format("|{:*>10%Q}|", 123_q_m) == "|*******123|"); - CHECK(fmt::format("|{:*^10%Q}|", 123_q_m) == "|***123****|"); + CHECK(STD_FMT::format("|{:0%Q}|", 123_q_m) == "|123|"); + CHECK(STD_FMT::format("|{:10%Q}|", 123_q_m) == "| 123|"); + CHECK(STD_FMT::format("|{:<10%Q}|", 123_q_m) == "|123 |"); + CHECK(STD_FMT::format("|{:>10%Q}|", 123_q_m) == "| 123|"); + CHECK(STD_FMT::format("|{:^10%Q}|", 123_q_m) == "| 123 |"); + CHECK(STD_FMT::format("|{:*<10%Q}|", 123_q_m) == "|123*******|"); + CHECK(STD_FMT::format("|{:*>10%Q}|", 123_q_m) == "|*******123|"); + CHECK(STD_FMT::format("|{:*^10%Q}|", 123_q_m) == "|***123****|"); } SECTION("symbol only format {:%q} on a quantity") { - CHECK(fmt::format("|{:0%q}|", 123_q_m) == "|m|"); - CHECK(fmt::format("|{:10%q}|", 123_q_m) == "|m |"); - CHECK(fmt::format("|{:<10%q}|", 123_q_m) == "|m |"); - CHECK(fmt::format("|{:>10%q}|", 123_q_m) == "| m|"); - CHECK(fmt::format("|{:^10%q}|", 123_q_m) == "| m |"); - CHECK(fmt::format("|{:*<10%q}|", 123_q_m) == "|m*********|"); - CHECK(fmt::format("|{:*>10%q}|", 123_q_m) == "|*********m|"); - CHECK(fmt::format("|{:*^10%q}|", 123_q_m) == "|****m*****|"); + CHECK(STD_FMT::format("|{:0%q}|", 123_q_m) == "|m|"); + CHECK(STD_FMT::format("|{:10%q}|", 123_q_m) == "|m |"); + CHECK(STD_FMT::format("|{:<10%q}|", 123_q_m) == "|m |"); + CHECK(STD_FMT::format("|{:>10%q}|", 123_q_m) == "| m|"); + CHECK(STD_FMT::format("|{:^10%q}|", 123_q_m) == "| m |"); + CHECK(STD_FMT::format("|{:*<10%q}|", 123_q_m) == "|m*********|"); + CHECK(STD_FMT::format("|{:*>10%q}|", 123_q_m) == "|*********m|"); + CHECK(STD_FMT::format("|{:*^10%q}|", 123_q_m) == "|****m*****|"); } } @@ -982,18 +982,18 @@ TEST_CASE("sign specification", "[text][fmt]") SECTION("full format {:%Q %q} on a quantity") { - CHECK(fmt::format("{0:%Q%q},{0:%+Q%q},{0:%-Q%q},{0:% Q%q}", 1_q_m) == "1m,+1m,1m, 1m"); - CHECK(fmt::format("{0:%Q%q},{0:%+Q%q},{0:%-Q%q},{0:% Q%q}", -1_q_m) == "-1m,-1m,-1m,-1m"); - CHECK(fmt::format("{0:%Q%q},{0:%+Q%q},{0:%-Q%q},{0:% Q%q}", inf) == "infm,+infm,infm, infm"); - CHECK(fmt::format("{0:%Q%q},{0:%+Q%q},{0:%-Q%q},{0:% Q%q}", nan) == "nanm,+nanm,nanm, nanm"); + CHECK(STD_FMT::format("{0:%Q%q},{0:%+Q%q},{0:%-Q%q},{0:% Q%q}", 1_q_m) == "1m,+1m,1m, 1m"); + CHECK(STD_FMT::format("{0:%Q%q},{0:%+Q%q},{0:%-Q%q},{0:% Q%q}", -1_q_m) == "-1m,-1m,-1m,-1m"); + CHECK(STD_FMT::format("{0:%Q%q},{0:%+Q%q},{0:%-Q%q},{0:% Q%q}", inf) == "infm,+infm,infm, infm"); + CHECK(STD_FMT::format("{0:%Q%q},{0:%+Q%q},{0:%-Q%q},{0:% Q%q}", nan) == "nanm,+nanm,nanm, nanm"); } SECTION("value only format {:%Q} on a quantity") { - CHECK(fmt::format("{0:%Q},{0:%+Q},{0:%-Q},{0:% Q}", 1_q_m) == "1,+1,1, 1"); - CHECK(fmt::format("{0:%Q},{0:%+Q},{0:%-Q},{0:% Q}", -1_q_m) == "-1,-1,-1,-1"); - CHECK(fmt::format("{0:%Q},{0:%+Q},{0:%-Q},{0:% Q}", inf) == "inf,+inf,inf, inf"); - CHECK(fmt::format("{0:%Q},{0:%+Q},{0:%-Q},{0:% Q}", nan) == "nan,+nan,nan, nan"); + CHECK(STD_FMT::format("{0:%Q},{0:%+Q},{0:%-Q},{0:% Q}", 1_q_m) == "1,+1,1, 1"); + CHECK(STD_FMT::format("{0:%Q},{0:%+Q},{0:%-Q},{0:% Q}", -1_q_m) == "-1,-1,-1,-1"); + CHECK(STD_FMT::format("{0:%Q},{0:%+Q},{0:%-Q},{0:% Q}", inf) == "inf,+inf,inf, inf"); + CHECK(STD_FMT::format("{0:%Q},{0:%+Q},{0:%-Q},{0:% Q}", nan) == "nan,+nan,nan, nan"); } } @@ -1001,32 +1001,32 @@ TEST_CASE("precision specification", "[text][fmt]") { SECTION("full format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%.0Q %q}", 1.2345_q_m) == "1 m"); - CHECK(fmt::format("{:%.1Q %q}", 1.2345_q_m) == "1.2 m"); - CHECK(fmt::format("{:%.2Q %q}", 1.2345_q_m) == "1.23 m"); + CHECK(STD_FMT::format("{:%.0Q %q}", 1.2345_q_m) == "1 m"); + CHECK(STD_FMT::format("{:%.1Q %q}", 1.2345_q_m) == "1.2 m"); + CHECK(STD_FMT::format("{:%.2Q %q}", 1.2345_q_m) == "1.23 m"); #ifdef UNITS_COMP_MSVC - CHECK(fmt::format("{:%.3Q %q}", 1.2345_q_m) == "1.234 m"); + CHECK(STD_FMT::format("{:%.3Q %q}", 1.2345_q_m) == "1.234 m"); #else - CHECK(fmt::format("{:%.3Q %q}", 1.2345_q_m) == "1.235 m"); + CHECK(STD_FMT::format("{:%.3Q %q}", 1.2345_q_m) == "1.235 m"); #endif - CHECK(fmt::format("{:%.4Q %q}", 1.2345_q_m) == "1.2345 m"); - CHECK(fmt::format("{:%.5Q %q}", 1.2345_q_m) == "1.23450 m"); - CHECK(fmt::format("{:%.10Q %q}", 1.2345_q_m) == "1.2345000000 m"); + CHECK(STD_FMT::format("{:%.4Q %q}", 1.2345_q_m) == "1.2345 m"); + CHECK(STD_FMT::format("{:%.5Q %q}", 1.2345_q_m) == "1.23450 m"); + CHECK(STD_FMT::format("{:%.10Q %q}", 1.2345_q_m) == "1.2345000000 m"); } SECTION("value only format {:%Q} on a quantity") { - CHECK(fmt::format("{:%.0Q}", 1.2345_q_m) == "1"); - CHECK(fmt::format("{:%.1Q}", 1.2345_q_m) == "1.2"); - CHECK(fmt::format("{:%.2Q}", 1.2345_q_m) == "1.23"); + CHECK(STD_FMT::format("{:%.0Q}", 1.2345_q_m) == "1"); + CHECK(STD_FMT::format("{:%.1Q}", 1.2345_q_m) == "1.2"); + CHECK(STD_FMT::format("{:%.2Q}", 1.2345_q_m) == "1.23"); #ifdef UNITS_COMP_MSVC - CHECK(fmt::format("{:%.3Q}", 1.2345_q_m) == "1.234"); + CHECK(STD_FMT::format("{:%.3Q}", 1.2345_q_m) == "1.234"); #else - CHECK(fmt::format("{:%.3Q}", 1.2345_q_m) == "1.235"); + CHECK(STD_FMT::format("{:%.3Q}", 1.2345_q_m) == "1.235"); #endif - CHECK(fmt::format("{:%.4Q}", 1.2345_q_m) == "1.2345"); - CHECK(fmt::format("{:%.5Q}", 1.2345_q_m) == "1.23450"); - CHECK(fmt::format("{:%.10Q}", 1.2345_q_m) == "1.2345000000"); + CHECK(STD_FMT::format("{:%.4Q}", 1.2345_q_m) == "1.2345"); + CHECK(STD_FMT::format("{:%.5Q}", 1.2345_q_m) == "1.23450"); + CHECK(STD_FMT::format("{:%.10Q}", 1.2345_q_m) == "1.2345000000"); } } @@ -1034,12 +1034,12 @@ TEST_CASE("precision specification for integral representation should throw", "[ { SECTION("full format {:%Q %q} on a quantity") { - REQUIRE_THROWS_MATCHES(fmt::format(fmt::runtime("{:%.1Q %q}"), 1_q_m), fmt::format_error, Message("precision not allowed for integral quantity representation")); + REQUIRE_THROWS_MATCHES(STD_FMT::format(FMT_RUNTIME("{:%.1Q %q}"), 1_q_m), STD_FMT::format_error, Message("precision not allowed for integral quantity representation")); } SECTION("value only format {:%Q} on a quantity") { - REQUIRE_THROWS_MATCHES(fmt::format(fmt::runtime("{:%.1Q}"), 1_q_m), fmt::format_error, Message("precision not allowed for integral quantity representation")); + REQUIRE_THROWS_MATCHES(STD_FMT::format(FMT_RUNTIME("{:%.1Q}"), 1_q_m), STD_FMT::format_error, Message("precision not allowed for integral quantity representation")); } } @@ -1047,70 +1047,70 @@ TEST_CASE("type specification", "[text][fmt]") { SECTION("full format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%bQ %q}", 42_q_m) == "101010 m"); - CHECK(fmt::format("{:%BQ %q}", 42_q_m) == "101010 m"); - CHECK(fmt::format("{:%dQ %q}", 42_q_m) == "42 m"); - CHECK(fmt::format("{:%oQ %q}", 42_q_m) == "52 m"); - CHECK(fmt::format("{:%xQ %q}", 42_q_m) == "2a m"); - CHECK(fmt::format("{:%XQ %q}", 42_q_m) == "2A m"); + CHECK(STD_FMT::format("{:%bQ %q}", 42_q_m) == "101010 m"); + CHECK(STD_FMT::format("{:%BQ %q}", 42_q_m) == "101010 m"); + CHECK(STD_FMT::format("{:%dQ %q}", 42_q_m) == "42 m"); + CHECK(STD_FMT::format("{:%oQ %q}", 42_q_m) == "52 m"); + CHECK(STD_FMT::format("{:%xQ %q}", 42_q_m) == "2a m"); + CHECK(STD_FMT::format("{:%XQ %q}", 42_q_m) == "2A m"); #ifdef UNITS_COMP_MSVC - CHECK(fmt::format("{:%aQ %q}", 1.2345678_q_m) == "0x1.3c0ca2a5b1d5dp+0 m"); - CHECK(fmt::format("{:%.3aQ %q}", 1.2345678_q_m) == "0x1.3c1p+0 m"); - CHECK(fmt::format("{:%AQ %q}", 1.2345678_q_m) == "0X1.3C0CA2A5B1D5DP+0 m"); - CHECK(fmt::format("{:%.3AQ %q}", 1.2345678_q_m) == "0X1.3C1P+0 m"); + CHECK(STD_FMT::format("{:%aQ %q}", 1.2345678_q_m) == "0x1.3c0ca2a5b1d5dp+0 m"); + CHECK(STD_FMT::format("{:%.3aQ %q}", 1.2345678_q_m) == "0x1.3c1p+0 m"); + CHECK(STD_FMT::format("{:%AQ %q}", 1.2345678_q_m) == "0X1.3C0CA2A5B1D5DP+0 m"); + CHECK(STD_FMT::format("{:%.3AQ %q}", 1.2345678_q_m) == "0X1.3C1P+0 m"); #else - CHECK(fmt::format("{:%aQ %q}", 1.2345678_q_m) == "0x9.e065152d8eae841p-3 m"); - CHECK(fmt::format("{:%.3aQ %q}", 1.2345678_q_m) == "0x9.e06p-3 m"); - CHECK(fmt::format("{:%AQ %q}", 1.2345678_q_m) == "0X9.E065152D8EAE841P-3 m"); - CHECK(fmt::format("{:%.3AQ %q}", 1.2345678_q_m) == "0X9.E06P-3 m"); + CHECK(STD_FMT::format("{:%aQ %q}", 1.2345678_q_m) == "0x9.e065152d8eae841p-3 m"); + CHECK(STD_FMT::format("{:%.3aQ %q}", 1.2345678_q_m) == "0x9.e06p-3 m"); + CHECK(STD_FMT::format("{:%AQ %q}", 1.2345678_q_m) == "0X9.E065152D8EAE841P-3 m"); + CHECK(STD_FMT::format("{:%.3AQ %q}", 1.2345678_q_m) == "0X9.E06P-3 m"); #endif - CHECK(fmt::format("{:%eQ %q}", 1.2345678_q_m) == "1.234568e+00 m"); - CHECK(fmt::format("{:%.3eQ %q}", 1.2345678_q_m) == "1.235e+00 m"); - CHECK(fmt::format("{:%EQ %q}", 1.2345678_q_m) == "1.234568E+00 m"); - CHECK(fmt::format("{:%.3EQ %q}", 1.2345678_q_m) == "1.235E+00 m"); - CHECK(fmt::format("{:%gQ %q}", 1.2345678_q_m) == "1.23457 m"); - CHECK(fmt::format("{:%gQ %q}", 1.2345678e8_q_m) == "1.23457e+08 m"); - CHECK(fmt::format("{:%.3gQ %q}", 1.2345678_q_m) == "1.23 m"); - CHECK(fmt::format("{:%.3gQ %q}", 1.2345678e8_q_m) == "1.23e+08 m"); - CHECK(fmt::format("{:%GQ %q}", 1.2345678_q_m) == "1.23457 m"); - CHECK(fmt::format("{:%GQ %q}", 1.2345678e8_q_m) == "1.23457E+08 m"); - CHECK(fmt::format("{:%.3GQ %q}", 1.2345678_q_m) == "1.23 m"); - CHECK(fmt::format("{:%.3GQ %q}", 1.2345678e8_q_m) == "1.23E+08 m"); + CHECK(STD_FMT::format("{:%eQ %q}", 1.2345678_q_m) == "1.234568e+00 m"); + CHECK(STD_FMT::format("{:%.3eQ %q}", 1.2345678_q_m) == "1.235e+00 m"); + CHECK(STD_FMT::format("{:%EQ %q}", 1.2345678_q_m) == "1.234568E+00 m"); + CHECK(STD_FMT::format("{:%.3EQ %q}", 1.2345678_q_m) == "1.235E+00 m"); + CHECK(STD_FMT::format("{:%gQ %q}", 1.2345678_q_m) == "1.23457 m"); + CHECK(STD_FMT::format("{:%gQ %q}", 1.2345678e8_q_m) == "1.23457e+08 m"); + CHECK(STD_FMT::format("{:%.3gQ %q}", 1.2345678_q_m) == "1.23 m"); + CHECK(STD_FMT::format("{:%.3gQ %q}", 1.2345678e8_q_m) == "1.23e+08 m"); + CHECK(STD_FMT::format("{:%GQ %q}", 1.2345678_q_m) == "1.23457 m"); + CHECK(STD_FMT::format("{:%GQ %q}", 1.2345678e8_q_m) == "1.23457E+08 m"); + CHECK(STD_FMT::format("{:%.3GQ %q}", 1.2345678_q_m) == "1.23 m"); + CHECK(STD_FMT::format("{:%.3GQ %q}", 1.2345678e8_q_m) == "1.23E+08 m"); } SECTION("value only format {:%Q} on a quantity") { - CHECK(fmt::format("{:%bQ}", 42_q_m) == "101010"); - CHECK(fmt::format("{:%BQ}", 42_q_m) == "101010"); - CHECK(fmt::format("{:%dQ}", 42_q_m) == "42"); - CHECK(fmt::format("{:%oQ}", 42_q_m) == "52"); - CHECK(fmt::format("{:%xQ}", 42_q_m) == "2a"); - CHECK(fmt::format("{:%XQ}", 42_q_m) == "2A"); + CHECK(STD_FMT::format("{:%bQ}", 42_q_m) == "101010"); + CHECK(STD_FMT::format("{:%BQ}", 42_q_m) == "101010"); + CHECK(STD_FMT::format("{:%dQ}", 42_q_m) == "42"); + CHECK(STD_FMT::format("{:%oQ}", 42_q_m) == "52"); + CHECK(STD_FMT::format("{:%xQ}", 42_q_m) == "2a"); + CHECK(STD_FMT::format("{:%XQ}", 42_q_m) == "2A"); #ifdef UNITS_COMP_MSVC - CHECK(fmt::format("{:%aQ}", 1.2345678_q_m) == "0x1.3c0ca2a5b1d5dp+0"); - CHECK(fmt::format("{:%.3aQ}", 1.2345678_q_m) == "0x1.3c1p+0"); - CHECK(fmt::format("{:%AQ}", 1.2345678_q_m) == "0X1.3C0CA2A5B1D5DP+0"); - CHECK(fmt::format("{:%.3AQ}", 1.2345678_q_m) == "0X1.3C1P+0"); + CHECK(STD_FMT::format("{:%aQ}", 1.2345678_q_m) == "0x1.3c0ca2a5b1d5dp+0"); + CHECK(STD_FMT::format("{:%.3aQ}", 1.2345678_q_m) == "0x1.3c1p+0"); + CHECK(STD_FMT::format("{:%AQ}", 1.2345678_q_m) == "0X1.3C0CA2A5B1D5DP+0"); + CHECK(STD_FMT::format("{:%.3AQ}", 1.2345678_q_m) == "0X1.3C1P+0"); #else - CHECK(fmt::format("{:%aQ}", 1.2345678_q_m) == "0x9.e065152d8eae841p-3"); - CHECK(fmt::format("{:%.3aQ}", 1.2345678_q_m) == "0x9.e06p-3"); - CHECK(fmt::format("{:%AQ}", 1.2345678_q_m) == "0X9.E065152D8EAE841P-3"); - CHECK(fmt::format("{:%.3AQ}", 1.2345678_q_m) == "0X9.E06P-3"); + CHECK(STD_FMT::format("{:%aQ}", 1.2345678_q_m) == "0x9.e065152d8eae841p-3"); + CHECK(STD_FMT::format("{:%.3aQ}", 1.2345678_q_m) == "0x9.e06p-3"); + CHECK(STD_FMT::format("{:%AQ}", 1.2345678_q_m) == "0X9.E065152D8EAE841P-3"); + CHECK(STD_FMT::format("{:%.3AQ}", 1.2345678_q_m) == "0X9.E06P-3"); #endif - CHECK(fmt::format("{:%eQ}", 1.2345678_q_m) == "1.234568e+00"); - CHECK(fmt::format("{:%.3eQ}", 1.2345678_q_m) == "1.235e+00"); - CHECK(fmt::format("{:%EQ}", 1.2345678_q_m) == "1.234568E+00"); - CHECK(fmt::format("{:%.3EQ}", 1.2345678_q_m) == "1.235E+00"); - CHECK(fmt::format("{:%gQ}", 1.2345678_q_m) == "1.23457"); - CHECK(fmt::format("{:%gQ}", 1.2345678e8_q_m) == "1.23457e+08"); - CHECK(fmt::format("{:%.3gQ}", 1.2345678_q_m) == "1.23"); - CHECK(fmt::format("{:%.3gQ}", 1.2345678e8_q_m) == "1.23e+08"); - CHECK(fmt::format("{:%GQ}", 1.2345678_q_m) == "1.23457"); - CHECK(fmt::format("{:%GQ}", 1.2345678e8_q_m) == "1.23457E+08"); - CHECK(fmt::format("{:%.3GQ}", 1.2345678_q_m) == "1.23"); - CHECK(fmt::format("{:%.3GQ}", 1.2345678e8_q_m) == "1.23E+08"); + CHECK(STD_FMT::format("{:%eQ}", 1.2345678_q_m) == "1.234568e+00"); + CHECK(STD_FMT::format("{:%.3eQ}", 1.2345678_q_m) == "1.235e+00"); + CHECK(STD_FMT::format("{:%EQ}", 1.2345678_q_m) == "1.234568E+00"); + CHECK(STD_FMT::format("{:%.3EQ}", 1.2345678_q_m) == "1.235E+00"); + CHECK(STD_FMT::format("{:%gQ}", 1.2345678_q_m) == "1.23457"); + CHECK(STD_FMT::format("{:%gQ}", 1.2345678e8_q_m) == "1.23457e+08"); + CHECK(STD_FMT::format("{:%.3gQ}", 1.2345678_q_m) == "1.23"); + CHECK(STD_FMT::format("{:%.3gQ}", 1.2345678e8_q_m) == "1.23e+08"); + CHECK(STD_FMT::format("{:%GQ}", 1.2345678_q_m) == "1.23457"); + CHECK(STD_FMT::format("{:%GQ}", 1.2345678e8_q_m) == "1.23457E+08"); + CHECK(STD_FMT::format("{:%.3GQ}", 1.2345678_q_m) == "1.23"); + CHECK(STD_FMT::format("{:%.3GQ}", 1.2345678e8_q_m) == "1.23E+08"); } } @@ -1118,20 +1118,20 @@ TEST_CASE("different base types with the # specifier", "[text][fmt]") { SECTION("full format {:%Q %q} on a quantity") { - CHECK(fmt::format("{:%#bQ %q}", 42_q_m) == "0b101010 m"); - CHECK(fmt::format("{:%#BQ %q}", 42_q_m) == "0B101010 m"); - CHECK(fmt::format("{:%#oQ %q}", 42_q_m) == "052 m"); - CHECK(fmt::format("{:%#xQ %q}", 42_q_m) == "0x2a m"); - CHECK(fmt::format("{:%#XQ %q}", 42_q_m) == "0X2A m"); + CHECK(STD_FMT::format("{:%#bQ %q}", 42_q_m) == "0b101010 m"); + CHECK(STD_FMT::format("{:%#BQ %q}", 42_q_m) == "0B101010 m"); + CHECK(STD_FMT::format("{:%#oQ %q}", 42_q_m) == "052 m"); + CHECK(STD_FMT::format("{:%#xQ %q}", 42_q_m) == "0x2a m"); + CHECK(STD_FMT::format("{:%#XQ %q}", 42_q_m) == "0X2A m"); } SECTION("value only format {:%Q} on a quantity") { - CHECK(fmt::format("{:%#bQ}", 42_q_m) == "0b101010"); - CHECK(fmt::format("{:%#BQ}", 42_q_m) == "0B101010"); - CHECK(fmt::format("{:%#oQ}", 42_q_m) == "052"); - CHECK(fmt::format("{:%#xQ}", 42_q_m) == "0x2a"); - CHECK(fmt::format("{:%#XQ}", 42_q_m) == "0X2A"); + CHECK(STD_FMT::format("{:%#bQ}", 42_q_m) == "0b101010"); + CHECK(STD_FMT::format("{:%#BQ}", 42_q_m) == "0B101010"); + CHECK(STD_FMT::format("{:%#oQ}", 42_q_m) == "052"); + CHECK(STD_FMT::format("{:%#xQ}", 42_q_m) == "0x2a"); + CHECK(STD_FMT::format("{:%#XQ}", 42_q_m) == "0X2A"); } } @@ -1154,8 +1154,8 @@ TEST_CASE("localization with the 'L' specifier", "[text][fmt][localization]") SECTION("full format {:%LQ %q} on a quantity") { - CHECK(fmt::format(grp2, "{:%LQ %q}", 299792458_q_m_per_s) == "2_99_79_24_58 m/s"); - CHECK(fmt::format(grp3, "{:%LQ %q}", 299792458_q_m_per_s) == "299'792'458 m/s"); + CHECK(STD_FMT::format(grp2, "{:%LQ %q}", 299792458_q_m_per_s) == "2_99_79_24_58 m/s"); + CHECK(STD_FMT::format(grp3, "{:%LQ %q}", 299792458_q_m_per_s) == "299'792'458 m/s"); } } diff --git a/test/unit_test/runtime/fmt_units_test.cpp b/test/unit_test/runtime/fmt_units_test.cpp index af270bd2..05070590 100644 --- a/test/unit_test/runtime/fmt_units_test.cpp +++ b/test/unit_test/runtime/fmt_units_test.cpp @@ -41,323 +41,323 @@ using namespace units::isq::si::imperial::references; using namespace units::isq::si::typographic; using namespace units::isq::iec80000::references; -TEST_CASE("fmt::format on synthesized unit symbols", "[text][fmt]") +TEST_CASE("std::format on synthesized unit symbols", "[text][fmt]") { SECTION("time") { - CHECK(fmt::format("{}", 1_q_ns) == "1 ns"); - CHECK(fmt::format("{}", 1_q_us) == "1 µs"); - CHECK(fmt::format("{}", 1_q_ms) == "1 ms"); + CHECK(STD_FMT::format("{}", 1_q_ns) == "1 ns"); + CHECK(STD_FMT::format("{}", 1_q_us) == "1 µs"); + CHECK(STD_FMT::format("{}", 1_q_ms) == "1 ms"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_us) == "1 us"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_us) == "1 us"); } SECTION("length") { - CHECK(fmt::format("{}", 1_q_mm) == "1 mm"); - CHECK(fmt::format("{}", 1_q_cm) == "1 cm"); - CHECK(fmt::format("{}", 1_q_km) == "1 km"); - CHECK(fmt::format("{}", 1 * ft) == "1 ft"); - CHECK(fmt::format("{}", 1_q_ft_us) == "1 ft(us)"); - CHECK(fmt::format("{}", 1_q_yd) == "1 yd"); - CHECK(fmt::format("{}", 1_q_in) == "1 in"); - CHECK(fmt::format("{}", 1_q_fathom) == "1 fathom"); - CHECK(fmt::format("{}", 1_q_fathom_us) == "1 fathom(us)"); - CHECK(fmt::format("{}", 1_q_mi) == "1 mi"); - CHECK(fmt::format("{}", 1_q_mi_us) == "1 mi(us)"); - CHECK(fmt::format("{}", 1_q_naut_mi) == "1 mi(naut)"); - CHECK(fmt::format("{}", 1_q_ch) == "1 ch"); - CHECK(fmt::format("{}", 1_q_rd) == "1 rd"); - CHECK(fmt::format("{}", 1_q_thou) == "1 thou"); - CHECK(fmt::format("{}", 1_q_pc) == "1 pc"); - CHECK(fmt::format("{}", 1_q_ly) == "1 ly"); - CHECK(fmt::format("{}", 1_q_pc) == "1 pc"); - CHECK(fmt::format("{}", 1_q_angstrom) == "1 angstrom"); - CHECK(fmt::format("{}", 1_q_au) == "1 au"); - CHECK(fmt::format("{}", 1_q_pica_comp) == "1 pica(comp)"); - CHECK(fmt::format("{}", 1_q_pica_prn) == "1 pica(prn)"); - CHECK(fmt::format("{}", 1_q_point_comp) == "1 point(comp)"); - CHECK(fmt::format("{}", 1_q_point_prn) == "1 point(prn)"); + CHECK(STD_FMT::format("{}", 1_q_mm) == "1 mm"); + CHECK(STD_FMT::format("{}", 1_q_cm) == "1 cm"); + CHECK(STD_FMT::format("{}", 1_q_km) == "1 km"); + CHECK(STD_FMT::format("{}", 1 * ft) == "1 ft"); + CHECK(STD_FMT::format("{}", 1_q_ft_us) == "1 ft(us)"); + CHECK(STD_FMT::format("{}", 1_q_yd) == "1 yd"); + CHECK(STD_FMT::format("{}", 1_q_in) == "1 in"); + CHECK(STD_FMT::format("{}", 1_q_fathom) == "1 fathom"); + CHECK(STD_FMT::format("{}", 1_q_fathom_us) == "1 fathom(us)"); + CHECK(STD_FMT::format("{}", 1_q_mi) == "1 mi"); + CHECK(STD_FMT::format("{}", 1_q_mi_us) == "1 mi(us)"); + CHECK(STD_FMT::format("{}", 1_q_naut_mi) == "1 mi(naut)"); + CHECK(STD_FMT::format("{}", 1_q_ch) == "1 ch"); + CHECK(STD_FMT::format("{}", 1_q_rd) == "1 rd"); + CHECK(STD_FMT::format("{}", 1_q_thou) == "1 thou"); + CHECK(STD_FMT::format("{}", 1_q_pc) == "1 pc"); + CHECK(STD_FMT::format("{}", 1_q_ly) == "1 ly"); + CHECK(STD_FMT::format("{}", 1_q_pc) == "1 pc"); + CHECK(STD_FMT::format("{}", 1_q_angstrom) == "1 angstrom"); + CHECK(STD_FMT::format("{}", 1_q_au) == "1 au"); + CHECK(STD_FMT::format("{}", 1_q_pica_comp) == "1 pica(comp)"); + CHECK(STD_FMT::format("{}", 1_q_pica_prn) == "1 pica(prn)"); + CHECK(STD_FMT::format("{}", 1_q_point_comp) == "1 point(comp)"); + CHECK(STD_FMT::format("{}", 1_q_point_prn) == "1 point(prn)"); } SECTION("mass") { - CHECK(fmt::format("{}", 1_q_kg) == "1 kg"); + CHECK(STD_FMT::format("{}", 1_q_kg) == "1 kg"); } SECTION("area") { - CHECK(fmt::format("{}", 1_q_m2) == "1 m²"); - CHECK(fmt::format("{}", 1_q_mm2) == "1 mm²"); - CHECK(fmt::format("{}", 1_q_cm2) == "1 cm²"); - CHECK(fmt::format("{}", 1_q_km2) == "1 km²"); - CHECK(fmt::format("{}", 1_q_ft2) == "1 ft²"); + CHECK(STD_FMT::format("{}", 1_q_m2) == "1 m²"); + CHECK(STD_FMT::format("{}", 1_q_mm2) == "1 mm²"); + CHECK(STD_FMT::format("{}", 1_q_cm2) == "1 cm²"); + CHECK(STD_FMT::format("{}", 1_q_km2) == "1 km²"); + CHECK(STD_FMT::format("{}", 1_q_ft2) == "1 ft²"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_m2) == "1 m^2"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_mm2) == "1 mm^2"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_cm2) == "1 cm^2"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_km2) == "1 km^2"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_ft2) == "1 ft^2"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_m2) == "1 m^2"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_mm2) == "1 mm^2"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_cm2) == "1 cm^2"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_km2) == "1 km^2"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_ft2) == "1 ft^2"); } SECTION("density") { - CHECK(fmt::format("{}", 1_q_kg_per_m3) == "1 kg/m³"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_kg_per_m3) == "1 kg/m^3"); + CHECK(STD_FMT::format("{}", 1_q_kg_per_m3) == "1 kg/m³"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_kg_per_m3) == "1 kg/m^3"); } SECTION("resistance") { - CHECK(fmt::format("{}", 1_q_R) == "1 Ω"); - CHECK(fmt::format("{}", 1_q_kR) == "1 kΩ"); - CHECK(fmt::format("{}", 1_q_mR) == "1 mΩ"); - CHECK(fmt::format("{}", 1_q_MR) == "1 MΩ"); + CHECK(STD_FMT::format("{}", 1_q_R) == "1 Ω"); + CHECK(STD_FMT::format("{}", 1_q_kR) == "1 kΩ"); + CHECK(STD_FMT::format("{}", 1_q_mR) == "1 mΩ"); + CHECK(STD_FMT::format("{}", 1_q_MR) == "1 MΩ"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_R) == "1 ohm"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_kR) == "1 kohm"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_mR) == "1 mohm"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_MR) == "1 Mohm"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_R) == "1 ohm"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_kR) == "1 kohm"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_mR) == "1 mohm"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_MR) == "1 Mohm"); } SECTION("voltage") { - CHECK(fmt::format("{}", 1_q_V) == "1 V"); - CHECK(fmt::format("{}", 1_q_mV) == "1 mV"); - CHECK(fmt::format("{}", 1_q_uV) == "1 µV"); - CHECK(fmt::format("{}", 1_q_nV) == "1 nV"); - CHECK(fmt::format("{}", 1_q_pV) == "1 pV"); + CHECK(STD_FMT::format("{}", 1_q_V) == "1 V"); + CHECK(STD_FMT::format("{}", 1_q_mV) == "1 mV"); + CHECK(STD_FMT::format("{}", 1_q_uV) == "1 µV"); + CHECK(STD_FMT::format("{}", 1_q_nV) == "1 nV"); + CHECK(STD_FMT::format("{}", 1_q_pV) == "1 pV"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_uV) == "1 uV"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_uV) == "1 uV"); } SECTION("volume") { - CHECK(fmt::format("{}", 1_q_m3) == "1 m³"); - CHECK(fmt::format("{}", 1_q_mm3) == "1 mm³"); - CHECK(fmt::format("{}", 1_q_cm3) == "1 cm³"); - CHECK(fmt::format("{}", 1_q_km3) == "1 km³"); - CHECK(fmt::format("{}", 1_q_ft3) == "1 ft³"); + CHECK(STD_FMT::format("{}", 1_q_m3) == "1 m³"); + CHECK(STD_FMT::format("{}", 1_q_mm3) == "1 mm³"); + CHECK(STD_FMT::format("{}", 1_q_cm3) == "1 cm³"); + CHECK(STD_FMT::format("{}", 1_q_km3) == "1 km³"); + CHECK(STD_FMT::format("{}", 1_q_ft3) == "1 ft³"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_m3) == "1 m^3"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_mm3) == "1 mm^3"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_cm3) == "1 cm^3"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_km3) == "1 km^3"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_ft3) == "1 ft^3"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_m3) == "1 m^3"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_mm3) == "1 mm^3"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_cm3) == "1 cm^3"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_km3) == "1 km^3"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_ft3) == "1 ft^3"); } SECTION("frequency") { - CHECK(fmt::format("{}", 1_q_mHz) == "1 mHz"); - CHECK(fmt::format("{}", 1_q_kHz) == "1 kHz"); - CHECK(fmt::format("{}", 1_q_MHz) == "1 MHz"); - CHECK(fmt::format("{}", 1_q_GHz) == "1 GHz"); - CHECK(fmt::format("{}", 1_q_THz) == "1 THz"); + CHECK(STD_FMT::format("{}", 1_q_mHz) == "1 mHz"); + CHECK(STD_FMT::format("{}", 1_q_kHz) == "1 kHz"); + CHECK(STD_FMT::format("{}", 1_q_MHz) == "1 MHz"); + CHECK(STD_FMT::format("{}", 1_q_GHz) == "1 GHz"); + CHECK(STD_FMT::format("{}", 1_q_THz) == "1 THz"); } SECTION("speed") { - CHECK(fmt::format("{}", 1_q_m_per_s) == "1 m/s"); - CHECK(fmt::format("{}", 1_q_km_per_h) == "1 km/h"); - CHECK(fmt::format("{}", 1_q_mi_per_h) == "1 mi/h"); + CHECK(STD_FMT::format("{}", 1_q_m_per_s) == "1 m/s"); + CHECK(STD_FMT::format("{}", 1_q_km_per_h) == "1 km/h"); + CHECK(STD_FMT::format("{}", 1_q_mi_per_h) == "1 mi/h"); } SECTION("acceleration") { - CHECK(fmt::format("{}", 1_q_m_per_s2) == "1 m/s²"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_m_per_s2) == "1 m/s^2"); + CHECK(STD_FMT::format("{}", 1_q_m_per_s2) == "1 m/s²"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_m_per_s2) == "1 m/s^2"); } SECTION("momentum") { - CHECK(fmt::format("{}", 1_q_kg_m_per_s) == "1 kg ⋅ m/s"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_kg_m_per_s) == "1 kg m/s"); + CHECK(STD_FMT::format("{}", 1_q_kg_m_per_s) == "1 kg ⋅ m/s"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_kg_m_per_s) == "1 kg m/s"); } SECTION("energy") { - CHECK(fmt::format("{}", 1_q_mJ) == "1 mJ"); - CHECK(fmt::format("{}", 1_q_kJ) == "1 kJ"); - CHECK(fmt::format("{}", 1_q_MJ) == "1 MJ"); - CHECK(fmt::format("{}", 1_q_GJ) == "1 GJ"); + CHECK(STD_FMT::format("{}", 1_q_mJ) == "1 mJ"); + CHECK(STD_FMT::format("{}", 1_q_kJ) == "1 kJ"); + CHECK(STD_FMT::format("{}", 1_q_MJ) == "1 MJ"); + CHECK(STD_FMT::format("{}", 1_q_GJ) == "1 GJ"); } SECTION("power") { - CHECK(fmt::format("{}", 1_q_mW) == "1 mW"); - CHECK(fmt::format("{}", 1_q_kW) == "1 kW"); - CHECK(fmt::format("{}", 1_q_MW) == "1 MW"); - CHECK(fmt::format("{}", 1_q_GW) == "1 GW"); + CHECK(STD_FMT::format("{}", 1_q_mW) == "1 mW"); + CHECK(STD_FMT::format("{}", 1_q_kW) == "1 kW"); + CHECK(STD_FMT::format("{}", 1_q_MW) == "1 MW"); + CHECK(STD_FMT::format("{}", 1_q_GW) == "1 GW"); } SECTION("surface tension") { - CHECK(fmt::format("{}", 1_q_N_per_m) == "1 N/m"); + CHECK(STD_FMT::format("{}", 1_q_N_per_m) == "1 N/m"); } SECTION("magnetic induction") { - CHECK(fmt::format("{}", 1_q_T) == "1 T"); + CHECK(STD_FMT::format("{}", 1_q_T) == "1 T"); } SECTION("magnetic flux") { - CHECK(fmt::format("{}", 1_q_Wb) == "1 Wb"); - CHECK(fmt::format("{}", 1_q_G) == "1 G"); + CHECK(STD_FMT::format("{}", 1_q_Wb) == "1 Wb"); + CHECK(STD_FMT::format("{}", 1_q_G) == "1 G"); } SECTION("inductance") { - CHECK(fmt::format("{}", 1_q_H) == "1 H"); - CHECK(fmt::format("{}", 1_q_mH) == "1 mH"); + CHECK(STD_FMT::format("{}", 1_q_H) == "1 H"); + CHECK(STD_FMT::format("{}", 1_q_mH) == "1 mH"); } SECTION("conductance") { - CHECK(fmt::format("{}", 1_q_S) == "1 S"); - CHECK(fmt::format("{}", 1_q_nS) == "1 nS"); + CHECK(STD_FMT::format("{}", 1_q_S) == "1 S"); + CHECK(STD_FMT::format("{}", 1_q_nS) == "1 nS"); } SECTION("catalytic activity") { - CHECK(fmt::format("{}", 1_q_kat) == "1 kat"); - CHECK(fmt::format("{}", 1_q_U) == "1 U"); + CHECK(STD_FMT::format("{}", 1_q_kat) == "1 kat"); + CHECK(STD_FMT::format("{}", 1_q_U) == "1 U"); } SECTION("absorbed dose") { - CHECK(fmt::format("{}", 1_q_Gy) == "1 Gy"); - CHECK(fmt::format("{}", 1_q_kGy) == "1 kGy"); - CHECK(fmt::format("{}", 1_q_mGy) == "1 mGy"); + CHECK(STD_FMT::format("{}", 1_q_Gy) == "1 Gy"); + CHECK(STD_FMT::format("{}", 1_q_kGy) == "1 kGy"); + CHECK(STD_FMT::format("{}", 1_q_mGy) == "1 mGy"); } SECTION("addition with common ratio") { - CHECK(fmt::format("{}", 1_q_in + 1_q_yd) == "37 in"); + CHECK(STD_FMT::format("{}", 1_q_in + 1_q_yd) == "37 in"); } SECTION("current density") { - CHECK(fmt::format("{}", 1_q_A_per_m2) == "1 A/m²"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_A_per_m2) == "1 A/m^2"); + CHECK(STD_FMT::format("{}", 1_q_A_per_m2) == "1 A/m²"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_A_per_m2) == "1 A/m^2"); } SECTION("concentration") { - CHECK(fmt::format("{}", 1_q_mol_per_m3) == "1 mol/m³"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_mol_per_m3) == "1 mol/m^3"); + CHECK(STD_FMT::format("{}", 1_q_mol_per_m3) == "1 mol/m³"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_mol_per_m3) == "1 mol/m^3"); } SECTION("luminance") { - CHECK(fmt::format("{}", 1_q_cd_per_m2) == "1 cd/m²"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_cd_per_m2) == "1 cd/m^2"); + CHECK(STD_FMT::format("{}", 1_q_cd_per_m2) == "1 cd/m²"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_cd_per_m2) == "1 cd/m^2"); } SECTION("dynamic viscosity") { - CHECK(fmt::format("{}", 1_q_Pa_s) == "1 Pa ⋅ s"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_Pa_s) == "1 Pa s"); + CHECK(STD_FMT::format("{}", 1_q_Pa_s) == "1 Pa ⋅ s"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_Pa_s) == "1 Pa s"); } SECTION("heat capacity") { - CHECK(fmt::format("{}", 1_q_J_per_K) == "1 J/K"); + CHECK(STD_FMT::format("{}", 1_q_J_per_K) == "1 J/K"); } SECTION("specific heat capacity") { - CHECK(fmt::format("{}", 1_q_J_per_kg_K) == "1 J ⋅ K⁻¹ ⋅ kg⁻¹"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_J_per_kg_K) == "1 J K^-1 kg^-1"); + CHECK(STD_FMT::format("{}", 1_q_J_per_kg_K) == "1 J ⋅ K⁻¹ ⋅ kg⁻¹"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_J_per_kg_K) == "1 J K^-1 kg^-1"); } SECTION("molar heath capacity") { - CHECK(fmt::format("{}", 1_q_J_per_mol_K) == "1 J ⋅ K⁻¹ ⋅ mol⁻¹"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_J_per_mol_K) == "1 J K^-1 mol^-1"); + CHECK(STD_FMT::format("{}", 1_q_J_per_mol_K) == "1 J ⋅ K⁻¹ ⋅ mol⁻¹"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_J_per_mol_K) == "1 J K^-1 mol^-1"); } SECTION("thermal conductivity") { - CHECK(fmt::format("{}", 1_q_W_per_m_K) == "1 W ⋅ m⁻¹ ⋅ K⁻¹"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_W_per_m_K) == "1 W m^-1 K^-1"); + CHECK(STD_FMT::format("{}", 1_q_W_per_m_K) == "1 W ⋅ m⁻¹ ⋅ K⁻¹"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_W_per_m_K) == "1 W m^-1 K^-1"); } SECTION("electric field strength") { - CHECK(fmt::format("{}", 1_q_V_per_m) == "1 V/m"); + CHECK(STD_FMT::format("{}", 1_q_V_per_m) == "1 V/m"); } SECTION("charge density") { - CHECK(fmt::format("{}", 1_q_C_per_m3) == "1 C/m³"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_C_per_m3) == "1 C/m^3"); - CHECK(fmt::format("{}", 1_q_C_per_m2) == "1 C/m²"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_C_per_m2) == "1 C/m^2"); + CHECK(STD_FMT::format("{}", 1_q_C_per_m3) == "1 C/m³"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_C_per_m3) == "1 C/m^3"); + CHECK(STD_FMT::format("{}", 1_q_C_per_m2) == "1 C/m²"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_C_per_m2) == "1 C/m^2"); } SECTION("permittivity") { - CHECK(fmt::format("{}", 1_q_F_per_m) == "1 F/m"); + CHECK(STD_FMT::format("{}", 1_q_F_per_m) == "1 F/m"); } SECTION("permeability") { - CHECK(fmt::format("{}", 1_q_H_per_m) == "1 H/m"); + CHECK(STD_FMT::format("{}", 1_q_H_per_m) == "1 H/m"); } SECTION("molar energy") { - CHECK(fmt::format("{}", 1_q_J_per_mol) == "1 J/mol"); + CHECK(STD_FMT::format("{}", 1_q_J_per_mol) == "1 J/mol"); } SECTION("torque") { - CHECK(fmt::format("{}", 1_q_N_m_per_rad) == "1 N ⋅ m/rad"); + CHECK(STD_FMT::format("{}", 1_q_N_m_per_rad) == "1 N ⋅ m/rad"); } SECTION("storage_capacity") { - CHECK(fmt::format("{}", 1 * bit) == "1 bit"); - CHECK(fmt::format("{}", 1 * kbit) == "1 kbit"); - CHECK(fmt::format("{}", 1 * Tibit) == "1 Tibit"); - CHECK(fmt::format("{}", 1 * B) == "1 B"); - CHECK(fmt::format("{}", 1 * kB) == "1 kB"); - CHECK(fmt::format("{}", 1 * TiB) == "1 TiB"); + CHECK(STD_FMT::format("{}", 1 * bit) == "1 bit"); + CHECK(STD_FMT::format("{}", 1 * kbit) == "1 kbit"); + CHECK(STD_FMT::format("{}", 1 * Tibit) == "1 Tibit"); + CHECK(STD_FMT::format("{}", 1 * B) == "1 B"); + CHECK(STD_FMT::format("{}", 1 * kB) == "1 kB"); + CHECK(STD_FMT::format("{}", 1 * TiB) == "1 TiB"); } SECTION("transfer_rate") { - CHECK(fmt::format("{}", 1 * (B / s)) == "1 B/s"); - CHECK(fmt::format("{}", 1 * (kB / s)) == "1 kB/s"); - CHECK(fmt::format("{}", 1 * (TB / s)) == "1 TB/s"); + CHECK(STD_FMT::format("{}", 1 * (B / s)) == "1 B/s"); + CHECK(STD_FMT::format("{}", 1 * (kB / s)) == "1 kB/s"); + CHECK(STD_FMT::format("{}", 1 * (TB / s)) == "1 TB/s"); } SECTION("traffic_intesity") { - CHECK(fmt::format("{}", 1 * E) == "1 E"); + CHECK(STD_FMT::format("{}", 1 * E) == "1 E"); } SECTION("modulation_rate") { using namespace units::isq::iec80000; - CHECK(fmt::format("{}", 1 * Bd) == "1 Bd"); - CHECK(fmt::format("{}", 1 * kBd) == "1 kBd"); - CHECK(fmt::format("{}", 1 * TBd) == "1 TBd"); - CHECK(fmt::format("{}", quantity_cast(4 / (2 * s))) == "2 Bd"); + CHECK(STD_FMT::format("{}", 1 * Bd) == "1 Bd"); + CHECK(STD_FMT::format("{}", 1 * kBd) == "1 kBd"); + CHECK(STD_FMT::format("{}", 1 * TBd) == "1 TBd"); + CHECK(STD_FMT::format("{}", quantity_cast(4 / (2 * s))) == "2 Bd"); } SECTION("incoherent units with powers") { - CHECK(fmt::format("{}", 1_q_mi * 1_q_mi * 1_q_mi) == "1 [15900351812136/3814697265625 × 10⁹] m³"); - CHECK(fmt::format("{}", 1_q_au * 1_q_au) == "1 [2237952291797391849 × 10⁴] m²"); + CHECK(STD_FMT::format("{}", 1_q_mi * 1_q_mi * 1_q_mi) == "1 [15900351812136/3814697265625 × 10⁹] m³"); + CHECK(STD_FMT::format("{}", 1_q_au * 1_q_au) == "1 [2237952291797391849 × 10⁴] m²"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_mi * 1_q_mi * 1_q_mi) == "1 [15900351812136/3814697265625 x 10^9] m^3"); - CHECK(fmt::format("{:%Q %Aq}", 1_q_au * 1_q_au) == "1 [2237952291797391849 x 10^4] m^2"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_mi * 1_q_mi * 1_q_mi) == "1 [15900351812136/3814697265625 x 10^9] m^3"); + CHECK(STD_FMT::format("{:%Q %Aq}", 1_q_au * 1_q_au) == "1 [2237952291797391849 x 10^4] m^2"); } SECTION("unknown scaled unit with reference different than the dimension's coherent unit") { - CHECK(fmt::format("{}", mass>(1)) == "1 [2/3 × 10⁻³] kg"); - CHECK(fmt::format("{:%Q %Aq}", mass>(1)) == "1 [2/3 x 10^-3] kg"); + CHECK(STD_FMT::format("{}", mass>(1)) == "1 [2/3 × 10⁻³] kg"); + CHECK(STD_FMT::format("{:%Q %Aq}", mass>(1)) == "1 [2/3 x 10^-3] kg"); } }