|
7 | 7 | #include <type_traits>
|
8 | 8 | #include <utility>
|
9 | 9 | #include <algorithm>
|
| 10 | +#include <format> |
10 | 11 |
|
11 | 12 | // define M_PI if not already defined
|
12 | 13 | #ifndef M_PI
|
@@ -183,6 +184,38 @@ template <isQuantity Q, typename quotient> using Rooted = Named<
|
183 | 184 | std::ratio_divide<typename Q::angle, quotient>, std::ratio_divide<typename Q::temperature, quotient>,
|
184 | 185 | std::ratio_divide<typename Q::luminosity, quotient>, std::ratio_divide<typename Q::moles, quotient>>>;
|
185 | 186 |
|
| 187 | +template <isQuantity Q> struct std::formatter<Q> : std::formatter<double> { |
| 188 | + auto format(const Q& quantity, std::format_context& ctx) const { |
| 189 | + constinit static std::array<std::pair<intmax_t, intmax_t>, 8> dims {{ |
| 190 | + {Q::mass::num, Q::mass::den}, |
| 191 | + {Q::length::num, Q::length::den}, |
| 192 | + {Q::time::num, Q::time::den}, |
| 193 | + {Q::current::num, Q::current::den}, |
| 194 | + {Q::angle::num, Q::angle::den}, |
| 195 | + {Q::temperature::num, Q::temperature::den}, |
| 196 | + {Q::luminosity::num, Q::luminosity::den}, |
| 197 | + {Q::moles::num, Q::moles::den}, |
| 198 | + }}; |
| 199 | + std::array<const char*, 8> prefixes {"_kg", "_m", "_s", "_A", "_rad", "_K", "_cd", "_mol"}; |
| 200 | + |
| 201 | + auto out = ctx.out(); |
| 202 | + |
| 203 | + // Format the quantity value |
| 204 | + out = std::formatter<double>::format(quantity.internal(), ctx); |
| 205 | + |
| 206 | + // Add dimensions and prefixes |
| 207 | + for (size_t i = 0; i != 8; i++) { |
| 208 | + if (dims[i].first != 0) { |
| 209 | + out = std::format_to(out, "{}", prefixes[i]); |
| 210 | + if (dims[i].first != 1 || dims[i].second != 1) { out = std::format_to(out, "^{}", dims[i].first); } |
| 211 | + if (dims[i].second != 1) { out = std::format_to(out, "/{}", dims[i].second); } |
| 212 | + } |
| 213 | + } |
| 214 | + |
| 215 | + return out; |
| 216 | + } |
| 217 | +}; |
| 218 | + |
186 | 219 | inline void unit_printer_helper(std::ostream& os, double quantity,
|
187 | 220 | const std::array<std::pair<intmax_t, intmax_t>, 8>& dims) {
|
188 | 221 | static constinit std::array<const char*, 8> prefixes {"_kg", "_m", "_s", "_A", "_rad", "_K", "_cd", "_mol"};
|
@@ -313,6 +346,12 @@ template <isQuantity Q, isQuantity R> constexpr bool operator>(const Q& lhs, con
|
313 | 346 | return Name(Quantity<std::ratio<m>, std::ratio<l>, std::ratio<t>, std::ratio<i>, std::ratio<a>, std::ratio<o>, \
|
314 | 347 | std::ratio<j>, std::ratio<n>>(static_cast<double>(value))); \
|
315 | 348 | } \
|
| 349 | + template <> struct std::formatter<Name> : std::formatter<double> { \ |
| 350 | + auto format(const Name& number, std::format_context& ctx) const { \ |
| 351 | + auto formatted_double = std::formatter<double>::format(number.internal(), ctx); \ |
| 352 | + return std::format_to(formatted_double, "_" #suffix); \ |
| 353 | + } \ |
| 354 | + }; \ |
316 | 355 | inline std::ostream& operator<<(std::ostream& os, const Name& quantity) { \
|
317 | 356 | os << quantity.internal() << " " << #suffix; \
|
318 | 357 | return os; \
|
@@ -355,6 +394,12 @@ constexpr Number operator""_num(unsigned long long value) {
|
355 | 394 | std::ratio<0>, std::ratio<0>>(static_cast<double>(value)));
|
356 | 395 | }
|
357 | 396 |
|
| 397 | +template <> struct std::formatter<Number> : std::formatter<double> { |
| 398 | + auto format(const Number& number, std::format_context& ctx) const { |
| 399 | + return std::formatter<double>::format(number.internal(), ctx); |
| 400 | + } |
| 401 | +}; |
| 402 | + |
358 | 403 | inline std::ostream& operator<<(std::ostream& os, const Number& quantity) {
|
359 | 404 | os << quantity.internal() << " " << num;
|
360 | 405 | return os;
|
@@ -598,25 +643,30 @@ template <isQuantity Q, isQuantity R> constexpr Q round(const Q& lhs, const R& r
|
598 | 643 |
|
599 | 644 | // Convert an angular unit `Q` to a linear unit correctly;
|
600 | 645 | // mostly useful for velocities
|
601 |
| -template <isQuantity Q> Quantity<typename Q::mass, typename Q::angle, typename Q::time, typename Q::current, |
602 |
| - typename Q::length, typename Q::temperature, typename Q::luminosity, typename Q::moles> |
603 |
| -toLinear(Quantity<typename Q::mass, typename Q::length, typename Q::time, typename Q::current, typename Q::angle, |
604 |
| - typename Q::temperature, typename Q::luminosity, typename Q::moles> |
605 |
| - angular, |
606 |
| - Length diameter) { |
| 646 | +template <isQuantity Q> |
| 647 | +Quantity<typename Q::mass, typename Q::angle, typename Q::time, typename Q::current, typename Q::length, |
| 648 | + typename Q::temperature, typename Q::luminosity, |
| 649 | + typename Q::moles> constexpr toLinear(Quantity<typename Q::mass, typename Q::length, typename Q::time, |
| 650 | + typename Q::current, typename Q::angle, typename Q::temperature, |
| 651 | + typename Q::luminosity, typename Q::moles> |
| 652 | + angular, |
| 653 | + Length diameter) { |
607 | 654 | return unit_cast<Quantity<typename Q::mass, typename Q::angle, typename Q::time, typename Q::current,
|
608 | 655 | typename Q::length, typename Q::temperature, typename Q::luminosity, typename Q::moles>>(
|
609 | 656 | angular * (diameter / 2.0));
|
610 | 657 | }
|
611 | 658 |
|
612 | 659 | // Convert an linear unit `Q` to a angular unit correctly;
|
613 | 660 | // mostly useful for velocities
|
614 |
| -template <isQuantity Q> Quantity<typename Q::mass, typename Q::angle, typename Q::time, typename Q::current, |
615 |
| - typename Q::length, typename Q::temperature, typename Q::luminosity, typename Q::moles> |
616 |
| -toAngular(Quantity<typename Q::mass, typename Q::length, typename Q::time, typename Q::current, typename Q::angle, |
617 |
| - typename Q::temperature, typename Q::luminosity, typename Q::moles> |
618 |
| - linear, |
619 |
| - Length diameter) { |
| 661 | +template <isQuantity Q> |
| 662 | +Quantity<typename Q::mass, typename Q::angle, typename Q::time, typename Q::current, typename Q::length, |
| 663 | + typename Q::temperature, typename Q::luminosity, |
| 664 | + typename Q::moles> constexpr toAngular(Quantity<typename Q::mass, typename Q::length, typename Q::time, |
| 665 | + typename Q::current, typename Q::angle, |
| 666 | + typename Q::temperature, typename Q::luminosity, |
| 667 | + typename Q::moles> |
| 668 | + linear, |
| 669 | + Length diameter) { |
620 | 670 | return unit_cast<Quantity<typename Q::mass, typename Q::angle, typename Q::time, typename Q::current,
|
621 | 671 | typename Q::length, typename Q::temperature, typename Q::luminosity, typename Q::moles>>(
|
622 | 672 | linear / (diameter / 2.0));
|
|
0 commit comments