feat: std::format support for compliant compilers added

This commit is contained in:
Mateusz Pusz
2021-09-20 15:01:58 +02:00
parent 9b842ac879
commit b1bd4cab2d
40 changed files with 1447 additions and 975 deletions

View File

@ -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
}
```

View File

@ -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()

View File

@ -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

View File

@ -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 ``<units/format.h>`` 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 <tab>
fmt::print("{:%Q%n%q}", 123 * km); // 123\nkm <new line>
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 <tab>
std::cout << std::format("{:%Q%n%q}", 123 * km); // 123\nkm <new line>
std::cout << std::format("{:%Q%% %q}", 123 * km); // 123% km

View File

@ -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

View File

@ -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);
}

View File

@ -115,7 +115,7 @@ void calcs_comparison()
length::fm<float> L1A = fm<>(2.f);
length::fm<float> L2A = fm<>(3.f);
length::fm<float> 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<float> L1B = L1A;
length::m<float> L2B = L2A;
length::m<float> 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<float> 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<float> 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

View File

@ -55,24 +55,24 @@ struct Ship {
template<class ...Args, units::Quantity Q>
auto fmt_line(const Q a)
{
return fmt::format("{:22}", a) + (fmt::format(",{:20}", units::quantity_cast<Args>(a)) + ...);
return STD_FMT::format("{:22}", a) + (STD_FMT::format(",{:20}", units::quantity_cast<Args>(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::fps::length::yd<>, si::length::m<>>(ship.length))
<< fmt::format("{:20} : {}\n", "draft", fmt_line<si::fps::length::yd<>, si::length::m<>>(ship.draft))
<< fmt::format("{:20} : {}\n", "beam", fmt_line<si::fps::length::yd<>, si::length::m<>>(ship.beam))
<< fmt::format("{:20} : {}\n", "mass", fmt_line<si::fps::mass::lton<>, si::mass::t<>>(ship.mass))
<< fmt::format("{:20} : {}\n", "speed", fmt_line<si::fps::speed::knot<>, si::speed::km_per_h<>>(ship.speed))
<< fmt::format("{:20} : {}\n", "power", fmt_line<si::fps::power::hp<>, si::power::kW<>>(ship.power))
<< fmt::format("{:20} : {}\n", "main guns", fmt_line<si::fps::length::in<>, si::length::mm<>>(ship.mainGuns))
<< fmt::format("{:20} : {}\n", "fire shells weighing",fmt_line<si::fps::mass::lton<>, si::mass::kg<>>(ship.shellMass))
<< fmt::format("{:20} : {}\n", "fire shells at",fmt_line<si::fps::speed::mph<>, si::speed::km_per_h<>>(ship.shellSpeed))
<< fmt::format("{:20} : {}\n", "volume underwater", fmt_line<si::volume::m3<>, si::volume::l<>>(ship.mass / waterDensity));
std::cout << STD_FMT::format("{}\n", description);
std::cout << STD_FMT::format("{:20} : {}\n", "length", fmt_line<si::fps::length::yd<>, si::length::m<>>(ship.length))
<< STD_FMT::format("{:20} : {}\n", "draft", fmt_line<si::fps::length::yd<>, si::length::m<>>(ship.draft))
<< STD_FMT::format("{:20} : {}\n", "beam", fmt_line<si::fps::length::yd<>, si::length::m<>>(ship.beam))
<< STD_FMT::format("{:20} : {}\n", "mass", fmt_line<si::fps::mass::lton<>, si::mass::t<>>(ship.mass))
<< STD_FMT::format("{:20} : {}\n", "speed", fmt_line<si::fps::speed::knot<>, si::speed::km_per_h<>>(ship.speed))
<< STD_FMT::format("{:20} : {}\n", "power", fmt_line<si::fps::power::hp<>, si::power::kW<>>(ship.power))
<< STD_FMT::format("{:20} : {}\n", "main guns", fmt_line<si::fps::length::in<>, si::length::mm<>>(ship.mainGuns))
<< STD_FMT::format("{:20} : {}\n", "fire shells weighing",fmt_line<si::fps::mass::lton<>, si::mass::kg<>>(ship.shellMass))
<< STD_FMT::format("{:20} : {}\n", "fire shells at",fmt_line<si::fps::speed::mph<>, si::speed::km_per_h<>>(ship.shellSpeed))
<< STD_FMT::format("{:20} : {}\n", "volume underwater", fmt_line<si::volume::m3<>, si::volume::l<>>(ship.mass / waterDensity));
}
int main()

View File

@ -21,16 +21,11 @@
// SOFTWARE.
#include "glide_computer.h"
#include <units/bits/external/hacks.h>
#include <units/bits/fmt_hacks.h>
#include <units/chrono.h>
#include <units/generic/dimensionless.h>
#include <units/isq/si/international/length.h>
UNITS_DIAGNOSTIC_PUSH
UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE
#include <fmt/format.h>
UNITS_DIAGNOSTIC_POP
#include <array>
#include <exception>
#include <iostream>
@ -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<units::one>(glide_ratio(g.polar[0])));
std::cout << STD_FMT::format(" * {:%.4Q %q} @ {:%.1Q %q} -> {:%.1Q %q}\n", p.climb, p.v, units::quantity_cast<units::one>(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);

View File

@ -36,7 +36,7 @@ std::ostream& operator<<(std::ostream& os, const vector<ET, OT>& 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<ET, OT>& 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" : " |");
}

View File

@ -49,12 +49,12 @@ int main()
constexpr length<metre> lengthA(2.0);
constexpr length<millimetre> 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));
}

View File

@ -21,6 +21,7 @@
// SOFTWARE.
#include "glide_computer.h"
#include <iostream>
#include <numeric>
#include <string_view>
@ -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);

View File

@ -22,15 +22,10 @@
#pragma once
#include <units/bits/external/hacks.h>
#include <units/bits/fmt_hacks.h>
#include <units/isq/si/length.h>
#include <units/quantity_kind.h>
UNITS_DIAGNOSTIC_PUSH
UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE
#include <fmt/format.h>
UNITS_DIAGNOSTIC_POP
#include <limits>
#include <ostream>
@ -106,21 +101,21 @@ class std::numeric_limits<geographic::longitude> : public numeric_limits<geograp
};
template<>
struct fmt::formatter<geographic::latitude> : formatter<geographic::latitude::value_type> {
struct STD_FMT::formatter<geographic::latitude> : formatter<geographic::latitude::value_type> {
template<typename FormatContext>
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<geographic::latitude::value_type>::format(lat.value() > 0 ? lat.value() : -lat.value(), ctx);
}
};
template<>
struct fmt::formatter<geographic::longitude> : formatter<geographic::longitude::value_type> {
struct STD_FMT::formatter<geographic::longitude> : formatter<geographic::longitude::value_type> {
template<typename FormatContext>
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<geographic::longitude::value_type>::format(lon.value() > 0 ? lon.value() : -lon.value(), ctx);
}
};

View File

@ -57,7 +57,7 @@
// - flight path exactly on a shortest possible line to destination
template<units::QuantityKind QK>
struct fmt::formatter<QK> : formatter<typename QK::quantity_type> {
struct STD_FMT::formatter<QK> : formatter<typename QK::quantity_type> {
template<typename FormatContext>
auto format(const QK& v, FormatContext& ctx)
{
@ -105,12 +105,12 @@ std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>&
} // namespace glide_computer
template<>
struct fmt::formatter<glide_computer::altitude> : formatter<units::isq::si::length<units::isq::si::metre>> {
struct STD_FMT::formatter<glide_computer::altitude> : formatter<units::isq::si::length<units::isq::si::metre>> {
template<typename FormatContext>
auto format(glide_computer::altitude a, FormatContext& ctx)
{
formatter<units::isq::si::length<units::isq::si::metre>>::format(a.relative().common(), ctx);
return fmt::format_to(ctx.out(), " AMSL");
return STD_FMT::format_to(ctx.out(), " AMSL");
}
};

View File

@ -55,11 +55,11 @@ int main()
#endif
constexpr Speed auto v7 = quantity_cast<int>(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
}

View File

@ -22,7 +22,7 @@
#pragma once
#include <units/bits/external/hacks.h>
#include <units/bits/fmt_hacks.h>
#include <units/format.h>
#include <units/generic/dimensionless.h>
#include <units/isq/dimensions/time.h>
@ -151,52 +151,51 @@ constexpr Q covariance_extrapolation(Q uncertainty, Q process_noise_variance)
} // namespace kalman
template<typename... Qs>
struct fmt::formatter<kalman::state<Qs...>> {
struct STD_FMT::formatter<kalman::state<Qs...>> {
constexpr auto parse(format_parse_context& ctx)
{
detail::dynamic_specs_handler<format_parse_context> 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<typename FormatContext>
auto format(const kalman::state<Qs...>& 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<char> global_format_buffer;
units::detail::global_format_specs<char> global_specs = { specs.fill, specs.align, specs.width };
std::string global_format_buffer;
units::detail::quantity_global_format_specs<char> 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<char> specs;
units::detail::dynamic_format_specs<char> specs;
};
template<typename Q>
struct fmt::formatter<kalman::estimation<Q>> {
struct STD_FMT::formatter<kalman::estimation<Q>> {
constexpr auto parse(format_parse_context& ctx)
{
detail::dynamic_specs_handler<format_parse_context> 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<typename FormatContext>
@ -209,22 +208,21 @@ struct fmt::formatter<kalman::estimation<Q>> {
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<char> global_format_buffer;
units::detail::global_format_specs<char> global_specs = { specs.fill, specs.align, specs.width };
std::string global_format_buffer;
units::detail::quantity_global_format_specs<char> 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<char> specs;
units::detail::dynamic_format_specs<char> specs;
};

View File

@ -25,6 +25,7 @@
#include <units/format.h>
#include <units/generic/dimensionless.h>
#include <array>
#include <iostream>
// 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()

View File

@ -27,6 +27,7 @@
#include <units/format.h>
#include <units/generic/dimensionless.h>
#include <array>
#include <iostream>
// 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()

View File

@ -27,6 +27,7 @@
#include <units/format.h>
#include <units/generic/dimensionless.h>
#include <array>
#include <iostream>
// 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()

View File

@ -28,6 +28,7 @@
#include <units/format.h>
#include <units/generic/dimensionless.h>
#include <array>
#include <iostream>
// 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()

View File

@ -25,6 +25,7 @@
#include <units/format.h>
#include <units/math.h>
#include <array>
#include <iostream>
// Based on: https://www.kalmanfilter.net/kalman1d.html#ex5
@ -33,14 +34,14 @@ using namespace units;
template<Quantity Q>
void print_header(kalman::estimation<Q> 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<Quantity Q, Dimensionless K>
void print(auto iteration, K gain, Q measured, kalman::estimation<Q> current, kalman::estimation<Q> 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()

View File

@ -27,6 +27,7 @@
#include <units/quantity_point.h>
#include <units/unit.h>
#include <array>
#include <iostream>
// TODO Fix when Celsius is properly supported (#232)
namespace units::isq::si {
@ -54,14 +55,14 @@ using namespace units;
template<QuantityPoint QP>
void print_header(kalman::estimation<QP> 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<QuantityPoint QP, Dimensionless K>
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> 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()

View File

@ -27,6 +27,7 @@
#include <units/quantity_point.h>
#include <units/unit.h>
#include <array>
#include <iostream>
// TODO Fix when Celsius is properly supported (#232)
namespace units::isq::si {
@ -54,14 +55,14 @@ using namespace units;
template<QuantityPoint QP>
void print_header(kalman::estimation<QP> 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<QuantityPoint QP, Dimensionless K>
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> 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()

View File

@ -27,6 +27,7 @@
#include <units/quantity_point.h>
#include <units/unit.h>
#include <array>
#include <iostream>
// TODO Fix when Celsius is properly supported (#232)
namespace units::isq::si {
@ -54,14 +55,14 @@ using namespace units;
template<QuantityPoint QP>
void print_header(kalman::estimation<QP> 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<QuantityPoint QP, Dimensionless K>
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> 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()

View File

@ -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);
}

View File

@ -114,7 +114,7 @@ void calcs_comparison()
const length<femtometre, float> L1A = 2._q_fm;
const length<femtometre, float> L2A = 3._q_fm;
const length<femtometre, float> 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<metre, float> L1B = L1A;
const length<metre, float> L2B = L2A;
const length<metre, float> 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<square_femtometre, float> 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<square_metre, float> 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

View File

@ -56,7 +56,7 @@ struct Ship {
template<class ...Args, units::Quantity Q>
auto fmt_line(const Q a)
{
return fmt::format("{:22}", a) + (fmt::format(",{:20}", units::quantity_cast<Args>(a)) + ...);
return STD_FMT::format("{:22}", a) + (STD_FMT::format(",{:20}", units::quantity_cast<Args>(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::fps::length<si::fps::yard>, si::length<si::metre>>(ship.length))
<< fmt::format("{:20} : {}\n", "draft", fmt_line<si::fps::length<si::fps::yard>, si::length<si::metre>>(ship.draft))
<< fmt::format("{:20} : {}\n", "beam", fmt_line<si::fps::length<si::fps::yard>, si::length<si::metre>>(ship.beam))
<< fmt::format("{:20} : {}\n", "mass", fmt_line<si::fps::mass<si::fps::long_ton>, si::mass<si::tonne>>(ship.mass))
<< fmt::format("{:20} : {}\n", "speed", fmt_line<si::fps::speed<si::fps::knot>, si::speed<si::kilometre_per_hour>>(ship.speed))
<< fmt::format("{:20} : {}\n", "power", fmt_line<si::fps::power<si::fps::horse_power>, si::power<si::kilowatt>>(ship.power))
<< fmt::format("{:20} : {}\n", "main guns", fmt_line<si::fps::length<si::fps::inch>, si::length<si::millimetre>>(ship.mainGuns))
<< fmt::format("{:20} : {}\n", "fire shells weighing",fmt_line<si::fps::mass<si::fps::long_ton>, si::mass<si::kilogram>>(ship.shellMass))
<< fmt::format("{:20} : {}\n", "fire shells at",fmt_line<si::fps::speed<si::fps::mile_per_hour>, si::speed<si::kilometre_per_hour>>(ship.shellSpeed))
<< fmt::format("{:20} : {}\n", "volume underwater", fmt_line<si::volume<si::cubic_metre>, si::volume<si::litre>>(ship.mass / waterDensity));
std::cout << STD_FMT::format("{}\n", description);
std::cout << STD_FMT::format("{:20} : {}\n", "length", fmt_line<si::fps::length<si::fps::yard>, si::length<si::metre>>(ship.length))
<< STD_FMT::format("{:20} : {}\n", "draft", fmt_line<si::fps::length<si::fps::yard>, si::length<si::metre>>(ship.draft))
<< STD_FMT::format("{:20} : {}\n", "beam", fmt_line<si::fps::length<si::fps::yard>, si::length<si::metre>>(ship.beam))
<< STD_FMT::format("{:20} : {}\n", "mass", fmt_line<si::fps::mass<si::fps::long_ton>, si::mass<si::tonne>>(ship.mass))
<< STD_FMT::format("{:20} : {}\n", "speed", fmt_line<si::fps::speed<si::fps::knot>, si::speed<si::kilometre_per_hour>>(ship.speed))
<< STD_FMT::format("{:20} : {}\n", "power", fmt_line<si::fps::power<si::fps::horse_power>, si::power<si::kilowatt>>(ship.power))
<< STD_FMT::format("{:20} : {}\n", "main guns", fmt_line<si::fps::length<si::fps::inch>, si::length<si::millimetre>>(ship.mainGuns))
<< STD_FMT::format("{:20} : {}\n", "fire shells weighing",fmt_line<si::fps::mass<si::fps::long_ton>, si::mass<si::kilogram>>(ship.shellMass))
<< STD_FMT::format("{:20} : {}\n", "fire shells at",fmt_line<si::fps::speed<si::fps::mile_per_hour>, si::speed<si::kilometre_per_hour>>(ship.shellSpeed))
<< STD_FMT::format("{:20} : {}\n", "volume underwater", fmt_line<si::volume<si::cubic_metre>, si::volume<si::litre>>(ship.mass / waterDensity));
}
int main()

View File

@ -21,16 +21,11 @@
// SOFTWARE.
#include "glide_computer.h"
#include <units/bits/external/hacks.h>
#include <units/bits/fmt_hacks.h>
#include <units/chrono.h>
#include <units/generic/dimensionless.h>
#include <units/isq/si/international/length.h>
UNITS_DIAGNOSTIC_PUSH
UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE
#include <fmt/format.h>
UNITS_DIAGNOSTIC_POP
#include <array>
#include <exception>
#include <iostream>
@ -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<units::one>(glide_ratio(g.polar[0])));
std::cout << STD_FMT::format(" * {:%.4Q %q} @ {:%.1Q %q} -> {:%.1Q %q}\n", p.climb, p.v, units::quantity_cast<units::one>(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);

View File

@ -36,7 +36,7 @@ std::ostream& operator<<(std::ostream& os, const vector<ET, OT>& 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<ET, OT>& 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" : " |");
}

View File

@ -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);
}

View File

@ -123,7 +123,7 @@ void calcs_comparison()
const length<femtometre, float> L1A = 2.f * fm;
const length<femtometre, float> L2A = 3.f * fm;
const length<femtometre, float> 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<metre, float> L1B = L1A;
const length<metre, float> L2B = L2A;
const length<metre, float> 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<square_femtometre, float> 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<square_metre, float> 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

View File

@ -59,7 +59,7 @@ struct Ship {
template<class ...Args, units::Quantity Q>
auto fmt_line(const Q a)
{
return fmt::format("{:22}", a) + (fmt::format(",{:20}", units::quantity_cast<Args>(a)) + ...);
return STD_FMT::format("{:22}", a) + (STD_FMT::format(",{:20}", units::quantity_cast<Args>(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::fps::length<si::fps::yard>, si::length<si::metre>>(ship.length))
<< fmt::format("{:20} : {}\n", "draft", fmt_line<si::fps::length<si::fps::yard>, si::length<si::metre>>(ship.draft))
<< fmt::format("{:20} : {}\n", "beam", fmt_line<si::fps::length<si::fps::yard>, si::length<si::metre>>(ship.beam))
<< fmt::format("{:20} : {}\n", "mass", fmt_line<si::fps::mass<si::fps::long_ton>, si::mass<si::tonne>>(ship.mass))
<< fmt::format("{:20} : {}\n", "speed", fmt_line<si::fps::speed<si::fps::knot>, si::speed<si::kilometre_per_hour>>(ship.speed))
<< fmt::format("{:20} : {}\n", "power", fmt_line<si::fps::power<si::fps::horse_power>, si::power<si::kilowatt>>(ship.power))
<< fmt::format("{:20} : {}\n", "main guns", fmt_line<si::fps::length<si::fps::inch>, si::length<si::millimetre>>(ship.mainGuns))
<< fmt::format("{:20} : {}\n", "fire shells weighing", fmt_line<si::fps::mass<si::fps::long_ton>, si::mass<si::kilogram>>(ship.shellMass))
<< fmt::format("{:20} : {}\n", "fire shells at", fmt_line<si::fps::speed<si::fps::mile_per_hour>, si::speed<si::kilometre_per_hour>>(ship.shellSpeed))
<< fmt::format("{:20} : {}\n", "volume underwater", fmt_line<si::volume<si::cubic_metre>, si::volume<si::litre>>(ship.mass / waterDensity));
std::cout << STD_FMT::format("{}\n", description);
std::cout << STD_FMT::format("{:20} : {}\n", "length", fmt_line<si::fps::length<si::fps::yard>, si::length<si::metre>>(ship.length))
<< STD_FMT::format("{:20} : {}\n", "draft", fmt_line<si::fps::length<si::fps::yard>, si::length<si::metre>>(ship.draft))
<< STD_FMT::format("{:20} : {}\n", "beam", fmt_line<si::fps::length<si::fps::yard>, si::length<si::metre>>(ship.beam))
<< STD_FMT::format("{:20} : {}\n", "mass", fmt_line<si::fps::mass<si::fps::long_ton>, si::mass<si::tonne>>(ship.mass))
<< STD_FMT::format("{:20} : {}\n", "speed", fmt_line<si::fps::speed<si::fps::knot>, si::speed<si::kilometre_per_hour>>(ship.speed))
<< STD_FMT::format("{:20} : {}\n", "power", fmt_line<si::fps::power<si::fps::horse_power>, si::power<si::kilowatt>>(ship.power))
<< STD_FMT::format("{:20} : {}\n", "main guns", fmt_line<si::fps::length<si::fps::inch>, si::length<si::millimetre>>(ship.mainGuns))
<< STD_FMT::format("{:20} : {}\n", "fire shells weighing", fmt_line<si::fps::mass<si::fps::long_ton>, si::mass<si::kilogram>>(ship.shellMass))
<< STD_FMT::format("{:20} : {}\n", "fire shells at", fmt_line<si::fps::speed<si::fps::mile_per_hour>, si::speed<si::kilometre_per_hour>>(ship.shellSpeed))
<< STD_FMT::format("{:20} : {}\n", "volume underwater", fmt_line<si::volume<si::cubic_metre>, si::volume<si::litre>>(ship.mass / waterDensity));
}
int main()

View File

@ -21,16 +21,11 @@
// SOFTWARE.
#include "glide_computer.h"
#include <units/bits/external/hacks.h>
#include <units/bits/fmt_hacks.h>
#include <units/chrono.h>
#include <units/generic/dimensionless.h>
#include <units/isq/si/international/length.h>
UNITS_DIAGNOSTIC_PUSH
UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE
#include <fmt/format.h>
UNITS_DIAGNOSTIC_POP
#include <array>
#include <exception>
#include <iostream>
@ -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<units::one>(glide_ratio(g.polar[0])));
std::cout << STD_FMT::format(" * {:%.4Q %q} @ {:%.1Q %q} -> {:%.1Q %q}\n", p.climb, p.v, units::quantity_cast<units::one>(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);

View File

@ -36,7 +36,7 @@ std::ostream& operator<<(std::ostream& os, const vector<ET, OT>& 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<ET, OT>& 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" : " |");
}

View File

@ -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()

View File

@ -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 <gsl/gsl-lite.hpp>
#include <units/bits/fmt_hacks.h>
#include <concepts>
#include <limits>
#include <string_view>
// 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<typename Char>
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<Char> 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<unsigned char>(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<typename T>
inline constexpr bool is_integer = std::is_integral<T>::value && !std::is_same<T, bool>::value &&
!std::is_same<T, char>::value && !std::is_same<T, wchar_t>::value;
template<typename Char>
[[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<std::integral Char>
[[nodiscard]] constexpr Char to_ascii(Char value)
{
return value;
}
template<typename Char>
requires std::is_enum_v<Char>
[[nodiscard]] constexpr auto to_ascii(Char value) -> std::underlying_type_t<Char> { return value; }
struct width_checker {
template<typename T>
[[nodiscard]] constexpr unsigned long long operator()(T value) const
{
if constexpr (is_integer<T>) {
if constexpr (std::numeric_limits<T>::is_signed) {
if (value < 0) throw STD_FMT::format_error("negative width");
}
return static_cast<unsigned long long>(value);
} else {
throw STD_FMT::format_error("width is not integer");
}
}
};
struct precision_checker {
template<typename T>
[[nodiscard]] constexpr unsigned long long operator()(T value) const
{
if constexpr (is_integer<T>) {
if constexpr (std::numeric_limits<T>::is_signed) {
if (value < 0) throw STD_FMT::format_error("negative precision");
}
return static_cast<unsigned long long>(value);
} else {
throw STD_FMT::format_error("precision is not integer");
}
}
};
// Format specifiers for built-in and string types.
template<typename Char>
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<Char> 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<typename Char>
struct dynamic_format_specs : basic_format_specs<Char> {
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<size_t>(std::numeric_limits<int>::max())) {
throw STD_FMT::format_error("Dynamic width or precision index too large.");
}
return static_cast<int>(idx);
}
template<typename CharT>
[[nodiscard]] constexpr int on_dynamic_arg(size_t arg_id, STD_FMT::basic_format_parse_context<CharT>& context)
{
context.check_arg_id(FMT_ARG_ID(arg_id));
return verify_dynamic_arg_index_in_range(arg_id);
}
template<typename CharT>
[[nodiscard]] constexpr int on_dynamic_arg(auto_id, STD_FMT::basic_format_parse_context<CharT>& context)
{
return verify_dynamic_arg_index_in_range(context.next_arg_id());
}
template<class Handler, typename FormatContext>
[[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<size_t>(index)));
if (value > static_cast<unsigned long long>(std::numeric_limits<int>::max())) {
throw STD_FMT::format_error("number is too big");
}
return static_cast<int>(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<std::forward_iterator It, std::sentinel_for<It> 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<int>::digits10) return static_cast<int>(value);
// Check for overflow.
const unsigned max = static_cast<unsigned>(std::numeric_limits<int>::max());
return num_digits == std::numeric_limits<int>::digits10 + 1 && prev * 10ull + unsigned(p[-1] - '0') <= max
? static_cast<int>(value)
: error_value;
}
template<std::forward_iterator It, std::sentinel_for<It> 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<int>::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<std::forward_iterator It, std::sentinel_for<It> 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<std::forward_iterator It, std::sentinel_for<It> 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<std::forward_iterator It, std::sentinel_for<It> 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<std::forward_iterator It, std::sentinel_for<It> 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<It>();
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<std::forward_iterator It>
constexpr int code_point_length(It begin)
{
if constexpr (sizeof(std::iter_value_t<It>) != 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<unsigned char>(*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<std::forward_iterator It, std::sentinel_for<It> 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<std::iter_value_t<It>>(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<std::forward_iterator It, std::sentinel_for<It> 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<typename Char>
class specs_setter {
protected:
basic_format_specs<Char>& specs_;
public:
constexpr explicit specs_setter(basic_format_specs<Char>& specs) : specs_(specs) {}
constexpr void on_align(fmt_align align) { specs_.align = align; }
constexpr void on_fill(std::basic_string_view<Char> 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<char>(type); }
};
// Format spec handler that saves references to arguments representing dynamic
// width and precision to be resolved at formatting time.
template<typename ParseContext>
class dynamic_specs_handler : public specs_setter<typename ParseContext::char_type> {
public:
using char_type = TYPENAME ParseContext::char_type;
constexpr dynamic_specs_handler(dynamic_format_specs<char_type>& specs, ParseContext& ctx) :
specs_setter<char_type>(specs), specs_(specs), context_(ctx)
{}
template<typename T>
constexpr void on_dynamic_width(T t)
{
specs_.dynamic_width_index = on_dynamic_arg(t, context_);
}
template<typename T>
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<char_type>& specs_;
ParseContext& context_;
};
} // namespace units::detail

View File

@ -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 <units/bits/external/hacks.h>
#if UNITS_USE_LIBFMT
UNITS_DIAGNOSTIC_PUSH
UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE
UNITS_DIAGNOSTIC_IGNORE_SHADOW
#include <fmt/format.h>
UNITS_DIAGNOSTIC_POP
#define STD_FMT fmt
#define FMT_RUNTIME(arg) fmt::runtime(arg)
#define FMT_LOCALE(loc) (loc).template get<std::locale>()
#define FMT_ARG_ID(arg) static_cast<int>(arg)
#else
#ifndef __cpp_lib_format
#error "std::formatting facility not supported"
#endif
#include <format>
#define STD_FMT std
#define FMT_RUNTIME(arg) arg
#define FMT_LOCALE(loc) loc
#define FMT_ARG_ID(arg) arg
#endif

View File

@ -22,24 +22,18 @@
#pragma once
#include <units/bits/fmt.h>
#include <units/customization_points.h>
#include <units/quantity.h>
#include <algorithm>
#include <string_view>
#include <cstdint>
// IWYU pragma: begin_exports
#include <units/bits/unit_text.h>
UNITS_DIAGNOSTIC_PUSH
UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE
UNITS_DIAGNOSTIC_IGNORE_SHADOW
#include <fmt/format.h>
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<Rep>, this behavior should be disabled manually
// if the symbol has no meaning for STD_FMT::formatter<Rep>, 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<typename CharT>
struct quantity_global_format_specs {
fill_t<CharT> fill;
fmt_align align = fmt_align::none;
int width = 0;
int dynamic_width_index = -1;
};
// Holds specs about the whole object
template<typename CharT>
struct global_format_specs
{
fmt::detail::fill_t<CharT> 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<typename CharT>
struct quantity_format_specs {
quantity_global_format_specs<CharT> global;
quantity_rep_format_specs rep;
quantity_unit_format_specs unit;
};
// Parse a `units-rep-modifier`
template <typename CharT, typename Handler>
constexpr const CharT* parse_units_rep(const CharT* begin, const CharT* end, Handler&& handler, bool treat_as_floating_point)
{
// parse sign
switch(static_cast<char>(*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<std::forward_iterator It, std::sentinel_for<It> 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<std::forward_iterator It, std::sentinel_for<It> 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<typename CharT, typename Handler>
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<typename CharT, typename Rep, typename OutputIt, typename LocaleRef>
inline OutputIt format_units_quantity_value(OutputIt out, const Rep& val, const rep_format_specs& rep_specs, LocaleRef loc)
{
fmt::basic_memory_buffer<CharT> 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<Rep>) {
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<bool>(loc)) {
return fmt::format_to(out, loc.template get<std::locale>(), 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<typename CharT, typename OutputIt>
inline OutputIt format_global_buffer(OutputIt out, const global_format_specs<CharT>& 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<typename OutputIt, typename Dimension, typename Unit, typename Rep, typename LocaleRef, typename CharT>
struct units_formatter {
OutputIt out;
Rep val;
global_format_specs<CharT> 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<typename CharT, typename Rep, typename OutputIt, typename Locale>
[[nodiscard]] OutputIt format_units_quantity_value(OutputIt out, const Rep& val,
const quantity_rep_format_specs& rep_specs, const Locale& loc)
{
std::basic_string<CharT> buffer;
auto to_buffer = std::back_inserter(buffer);
explicit units_formatter(
OutputIt o, quantity<Dimension, Unit, Rep> q,
global_format_specs<CharT> 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<typename CharT2>
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<Rep>) {
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<CharT>(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<Dimension, Unit>();
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<typename CharT, std::output_iterator<CharT> OutputIt>
OutputIt format_global_buffer(OutputIt out, const quantity_global_format_specs<CharT>& 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<typename Dimension, typename Unit, typename Rep, typename Locale, typename CharT,
std::output_iterator<CharT> OutputIt>
struct quantity_formatter {
OutputIt out;
Rep val;
const quantity_format_specs<CharT>& specs;
Locale loc;
} // namespace units
explicit quantity_formatter(OutputIt o, quantity<Dimension, Unit, Rep> q, const quantity_format_specs<CharT>& fspecs,
Locale lc) :
out(o), val(std::move(q).number()), specs(fspecs), loc(std::move(lc))
{}
template<std::forward_iterator It, std::sentinel_for<It> S>
void on_text(It begin, S end)
{
std::copy(begin, end, out);
}
template<std::forward_iterator It, std::sentinel_for<It> S>
void on_quantity_value([[maybe_unused]] It, [[maybe_unused]] S)
{
out = format_units_quantity_value<CharT>(out, val, specs.rep, loc);
}
void on_quantity_unit([[maybe_unused]] CharT)
{
auto txt = unit_text<Dimension, Unit>();
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<typename Dimension, typename Unit, typename Rep, typename CharT>
struct fmt::formatter<units::quantity<Dimension, Unit, Rep>, CharT> {
struct STD_FMT::formatter<units::quantity<Dimension, Unit, Rep>, CharT> {
private:
using quantity = units::quantity<Dimension, Unit, Rep>;
using iterator = TYPENAME fmt::basic_format_parse_context<CharT>::iterator;
using arg_ref_type = fmt::detail::arg_ref<CharT>;
using iterator = TYPENAME STD_FMT::basic_format_parse_context<CharT>::iterator;
units::detail::global_format_specs<CharT> 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<CharT> format_str;
units::detail::quantity_format_specs<CharT> specs;
std::basic_string_view<CharT> format_str;
struct spec_handler {
formatter& f;
fmt::basic_format_parse_context<CharT>& context;
fmt::basic_string_view<CharT> format_str;
STD_FMT::basic_format_parse_context<CharT>& context;
template<typename Id>
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<CharT> 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<CharT> 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<CharT> 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<typename Id>
constexpr void on_dynamic_width(Id arg_id)
{
f.width_ref = make_arg_ref(arg_id);
}
template<typename Id>
constexpr void on_dynamic_precision(Id arg_id)
template<typename T>
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<typename T>
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<Rep>);
}
if (begin != end) units::detail::parse_units_rep(begin, end, *this, units::treat_as_floating_point<Rep>);
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<CharT>& ctx)
[[nodiscard]] constexpr std::ranges::subrange<iterator> do_parse(STD_FMT::basic_format_parse_context<CharT>& 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<std::output_iterator<CharT> 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<CharT>(out, q.number(), specs.rep, ctx.locale());
constexpr auto symbol = units::detail::unit_text<Dimension, Unit>();
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<CharT>& ctx)
[[nodiscard]] constexpr auto parse(STD_FMT::basic_format_parse_context<CharT>& ctx)
{
auto range = do_parse(ctx);
format_str = fmt::basic_string_view<CharT>(&*range.begin, fmt::detail::to_unsigned(range.end - range.begin));
return range.end;
format_str = std::basic_string_view<CharT>(range.begin(), range.end());
return range.end();
}
template<typename FormatContext>
auto format(const units::quantity<Dimension, Unit, Rep>& 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<fmt::detail::width_checker>(global_specs.width, width_ref, ctx);
fmt::detail::handle_dynamic_spec<fmt::detail::precision_checker>(rep_specs.precision, precision_ref, ctx);
if (specs.global.dynamic_width_index >= 0)
specs.global.width =
units::detail::get_dynamic_spec<units::detail::width_checker>(specs.global.dynamic_width_index, ctx);
if (specs.rep.dynamic_precision_index >= 0)
specs.rep.precision =
units::detail::get_dynamic_spec<units::detail::precision_checker>(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<CharT> 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<CharT> 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<CharT>(to_quantity_buffer, q.number(), rep_specs, ctx.locale());
constexpr auto symbol = units::detail::unit_text<Dimension, Unit>();
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<CharT> global_format_buffer;
units::detail::format_global_buffer<CharT>(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<CharT> global_format_buffer;
units::detail::format_global_buffer<CharT>(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<CharT>(global_format_buffer.data(), global_format_buffer.size())), std::string_view(quantity_buffer.data(), quantity_buffer.size()));
}
};

View File

@ -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<metre>(std::numeric_limits<double>::quiet_NaN())) == "nan");
CHECK(STD_FMT::format("{:%Q}", length<metre>(std::numeric_limits<double>::quiet_NaN())) == "nan");
}
SECTION("inf")
{
CHECK(fmt::format("{:%Q}", length<metre>(std::numeric_limits<double>::infinity())) == "inf");
CHECK(STD_FMT::format("{:%Q}", length<metre>(std::numeric_limits<double>::infinity())) == "inf");
}
SECTION("-inf")
{
CHECK(fmt::format("{:%Q}", length<metre>(-std::numeric_limits<double>::infinity())) == "-inf");
CHECK(STD_FMT::format("{:%Q}", length<metre>(-std::numeric_limits<double>::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) == "");
CHECK(STD_FMT::format("{:%q}", 123_q_kR) == "");
}
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");
}
}

View File

@ -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<baud>(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<baud>(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<units::scaled_unit<units::ratio(2, 3), gram>>(1)) == "1 [2/3 × 10⁻³] kg");
CHECK(fmt::format("{:%Q %Aq}", mass<units::scaled_unit<units::ratio(2, 3), gram>>(1)) == "1 [2/3 x 10^-3] kg");
CHECK(STD_FMT::format("{}", mass<units::scaled_unit<units::ratio(2, 3), gram>>(1)) == "1 [2/3 × 10⁻³] kg");
CHECK(STD_FMT::format("{:%Q %Aq}", mass<units::scaled_unit<units::ratio(2, 3), gram>>(1)) == "1 [2/3 x 10^-3] kg");
}
}