quanta 0.1.0
Type-safe units for temperature, frequency, electrical and spatial quantities, modeled after std::chrono
Loading...
Searching...
No Matches
spatial.hpp
Go to the documentation of this file.
1#pragma once
2
8#include <charconv>
9#include <cmath>
10#include <compare>
11#include <concepts>
12#include <cstdint>
13#include <limits>
14#include <quanta/core.hpp>
15#include <ratio>
16#include <string>
17
101
102// The shared trait, re-exported for convenience; specialize quanta::treat_as_inexact.
105
106template<typename Unit, typename Rep, typename Precision = std::ratio<1>>
107class quantity;
108
113template<typename T>
114struct is_quantity : std::false_type {};
115
116template<typename Unit, typename Rep, typename Precision>
117struct is_quantity<quantity<Unit, Rep, Precision>> : std::true_type {};
118
119template<typename T>
120inline constexpr bool is_quantity_v = is_quantity<T>::value;
121
123template<typename Rep>
124concept not_quantity = !is_quantity_v<Rep>;
131template<typename Rep>
134 static constexpr Rep zero() noexcept { return Rep(0); }
135
137 static constexpr Rep max() noexcept { return std::numeric_limits<Rep>::max(); }
138
140 static constexpr Rep min() noexcept { return std::numeric_limits<Rep>::lowest(); }
141};
142
143// ============================================================================
144// Units
145// ============================================================================
146
160 static constexpr const char* symbol = "m";
161};
162
165 static constexpr const char* symbol = "m²";
166};
167
170 static constexpr const char* symbol = "m³";
171};
172
// end of SpatialUnits group
174
176// Base of quantity that supplies the nested `period` alias for lengths only.
177// Generic code that recognises duration-like or distance-like types by their
178// `period` member must not accept areas or volumes, so other units get an
179// empty base. Non-ratio precisions also get the empty base, leaving the
180// diagnostic to quantity's own static_assert.
181template<typename Unit, typename Precision>
182struct _period_base {};
183
184template<typename Precision>
185 requires _is_ratio<Precision>::value
186struct _period_base<meter_unit, Precision> {
187 using period = typename Precision::type;
188};
230template<typename Unit, typename Rep, typename Precision>
231class quantity : public _period_base<Unit, Precision> {
232 static_assert(!is_quantity_v<Rep>, "rep cannot be a quanta::spatial::quantity");
233 static_assert(_is_ratio<Precision>::value, "precision must be a specialization of std::ratio");
234 static_assert(Precision::num > 0, "precision must be positive");
235
236public:
238 using unit = Unit;
240 using rep = Rep;
242 using precision = typename Precision::type;
243
245 constexpr quantity() = default;
246 quantity(const quantity&) = default;
247
257 template<typename Rep2>
258 requires std::convertible_to<const Rep2&, rep> && (treat_as_inexact_v<rep> || !treat_as_inexact_v<Rep2>)
259 constexpr explicit quantity(const Rep2& r)
260 : _r(static_cast<rep>(r)) {}
261
276 template<typename Rep2, typename Precision2>
277 requires std::convertible_to<const Rep2&, rep> &&
278 detail::_lossless_conversion<Rep2, Precision2, rep, precision> &&
279 detail::_quantity_castable<quantity<Unit, Rep2, Precision2>, quantity>
282
299 template<typename Rep2, typename Precision2>
300 requires(!detail::_lossless_conversion<Rep2, Precision2, rep, precision> ||
301 !std::convertible_to<const Rep2&, rep>) &&
302 detail::_quantity_castable<quantity<Unit, Rep2, Precision2>, quantity>
303 constexpr explicit quantity(const quantity<Unit, Rep2, Precision2>& q)
304 : _r(quantity_cast<quantity>(q).count()) {}
305
306 ~quantity() = default;
307 quantity& operator=(const quantity&) = default;
308
310 constexpr rep count() const { return _r; }
311
316
321
322 constexpr quantity& operator++() {
323 ++_r;
324 return *this;
325 }
326
327 constexpr quantity operator++(int) { return quantity(_r++); }
328
329 constexpr quantity& operator--() {
330 --_r;
331 return *this;
332 }
333
334 constexpr quantity operator--(int) { return quantity(_r--); }
335
336 constexpr quantity& operator+=(const quantity& q) {
337 _r += q.count();
338 return *this;
339 }
340
341 constexpr quantity& operator-=(const quantity& q) {
342 _r -= q.count();
343 return *this;
344 }
345
346 constexpr quantity& operator*=(const rep& r) {
347 _r *= r;
348 return *this;
349 }
350
351 constexpr quantity& operator/=(const rep& r) {
352 _r /= r;
353 return *this;
354 }
355
356 constexpr quantity& operator%=(const rep& r)
357 requires(!treat_as_inexact_v<rep>)
358 {
359 _r %= r;
360 return *this;
361 }
362
363 constexpr quantity& operator%=(const quantity& q)
364 requires(!treat_as_inexact_v<rep>)
365 {
366 _r %= q.count();
367 return *this;
368 }
369
371 static constexpr quantity zero() noexcept { return quantity(quantity_values<rep>::zero()); }
372
374 static constexpr quantity min() noexcept { return quantity(quantity_values<rep>::min()); }
375
377 static constexpr quantity max() noexcept { return quantity(quantity_values<rep>::max()); }
378
379private:
380 rep _r{};
381};
382
404template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
405 requires(!std::is_same_v<typename ToQuantity::unit, Unit>) ||
406 detail::_quantity_cast_requirements<quantity<Unit, Rep, Precision>, ToQuantity>
407constexpr ToQuantity quantity_cast(const quantity<Unit, Rep, Precision>& q) {
408 // The constraint admits a cast between units, so that this reports it.
409 static_assert(
410 std::is_same_v<typename ToQuantity::unit, Unit>, "quantity_cast cannot convert between different units"
411 );
412 return detail::_quantity_cast<ToQuantity>(q);
413}
414
434template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
435constexpr ToQuantity floor(const quantity<Unit, Rep, Precision>& q) {
436 return detail::_floor_cast(quantity_cast<ToQuantity>(q), q);
437}
438
458template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
459constexpr ToQuantity ceil(const quantity<Unit, Rep, Precision>& q) {
460 return detail::_ceil_cast(quantity_cast<ToQuantity>(q), q);
461}
462
481template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
482constexpr ToQuantity trunc(const quantity<Unit, Rep, Precision>& q) {
483 return quantity_cast<ToQuantity>(q);
484}
485
505template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
506constexpr ToQuantity round(const quantity<Unit, Rep, Precision>& q) {
507 return detail::_round_cast<ToQuantity>(q, [&q] { return floor<ToQuantity>(q); });
508}
509
520template<typename Unit, typename Rep, typename Precision>
522 return detail::_abs(q);
523}
524
525// ============================================================================
526// Same-unit arithmetic
527// ============================================================================
528
530template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
532 -> std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>> {
533 using cq = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
534 return cq(cq(lhs).count() + cq(rhs).count());
535}
536
538template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
540 -> std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>> {
541 using cq = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
542 return cq(cq(lhs).count() - cq(rhs).count());
543}
544
546template<typename Unit, typename Rep1, typename Precision, typename Rep2>
547 requires not_quantity<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>>
548constexpr auto operator*(const quantity<Unit, Rep1, Precision>& q, const Rep2& r)
551 return cq(cq(q).count() * r);
552}
553
555template<typename Unit, typename Rep1, typename Rep2, typename Precision>
556 requires not_quantity<Rep1> && std::convertible_to<const Rep1&, std::common_type_t<Rep1, Rep2>>
557constexpr auto operator*(const Rep1& r, const quantity<Unit, Rep2, Precision>& q)
559 return q * r;
560}
561
563template<typename Unit, typename Rep1, typename Precision, typename Rep2>
564 requires not_quantity<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>>
565constexpr auto operator/(const quantity<Unit, Rep1, Precision>& q, const Rep2& s)
568 return cq(cq(q).count() / s);
569}
570
572template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
574 -> std::common_type_t<Rep1, Rep2> {
575 using cq = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
576 return cq(lhs).count() / cq(rhs).count();
577}
578
580template<typename Unit, typename Rep1, typename Precision, typename Rep2>
581 requires not_quantity<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>> &&
582 (!treat_as_inexact_v<Rep1> && !treat_as_inexact_v<Rep2>)
583constexpr auto operator%(const quantity<Unit, Rep1, Precision>& q, const Rep2& s)
586 return cq(cq(q).count() % s);
587}
588
590template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
591 requires(!treat_as_inexact_v<Rep1> && !treat_as_inexact_v<Rep2>)
592constexpr auto operator%(const quantity<Unit, Rep1, Precision1>& lhs, const quantity<Unit, Rep2, Precision2>& rhs)
593 -> std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>> {
594 using cq = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
595 return cq(cq(lhs).count() % cq(rhs).count());
596}
597
598template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
600 using ct = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
601 return ct(lhs).count() == ct(rhs).count();
602}
603
604template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
605 requires std::three_way_comparable<std::common_type_t<Rep1, Rep2>>
607 using ct = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
608 return ct(lhs).count() <=> ct(rhs).count();
609}
610
611// ============================================================================
612// Cross-unit arithmetic
613// ============================================================================
614
616// Product of two quantities, in the given result unit. Counts multiply and
617// precisions multiply, so no conversion factor is needed and the result is
618// exact for integer representations.
619template<typename ToUnit, typename U1, typename R1, typename P1, typename U2, typename R2, typename P2>
620constexpr auto _product(const quantity<U1, R1, P1>& lhs, const quantity<U2, R2, P2>& rhs) {
621 using cr = std::common_type_t<R1, R2>;
622 using result_t = quantity<ToUnit, cr, std::ratio_multiply<P1, P2>>;
623 return result_t(static_cast<cr>(lhs.count()) * static_cast<cr>(rhs.count()));
624}
625
626// Quotient of two quantities, in the given result unit. Counts divide and
627// precisions divide; for integer representations the count division truncates.
628template<typename ToUnit, typename U1, typename R1, typename P1, typename U2, typename R2, typename P2>
629constexpr auto _quotient(const quantity<U1, R1, P1>& lhs, const quantity<U2, R2, P2>& rhs) {
630 using cr = std::common_type_t<R1, R2>;
631 using result_t = quantity<ToUnit, cr, std::ratio_divide<P1, P2>>;
632 return result_t(static_cast<cr>(lhs.count()) / static_cast<cr>(rhs.count()));
633}
660template<typename R1, typename P1, typename R2, typename P2>
662 return _product<square_meter_unit>(lhs, rhs);
663}
664
666template<typename R1, typename P1, typename R2, typename P2>
668 return _product<cubic_meter_unit>(lhs, rhs);
669}
670
672template<typename R1, typename P1, typename R2, typename P2>
674 return _product<cubic_meter_unit>(lhs, rhs);
675}
676
678template<typename R1, typename P1, typename R2, typename P2>
680 return _quotient<meter_unit>(lhs, rhs);
681}
682
684template<typename R1, typename P1, typename R2, typename P2>
686 return _quotient<square_meter_unit>(lhs, rhs);
687}
688
690template<typename R1, typename P1, typename R2, typename P2>
691constexpr auto
693 return _quotient<meter_unit>(lhs, rhs);
694}
695
// end of SpatialCrossUnit group
697
698// ============================================================================
699// Type aliases
700// ============================================================================
701
719template<typename Rep, typename Precision = std::ratio<1>>
721
734
747
749template<typename Rep, typename Precision = std::ratio<1>>
751
762
773
775template<typename Rep, typename Precision = std::ratio<1>>
777
790
799
// end of SpatialQuantityTypes group
801
802// ============================================================================
803// String conversion and formatting
804// ============================================================================
805
813template<typename Precision>
815
817template<>
818struct si_prefix<std::femto> {
819 static constexpr const char* symbol = "f";
820};
821
822template<>
823struct si_prefix<std::pico> {
824 static constexpr const char* symbol = "p";
825};
826
827template<>
828struct si_prefix<std::nano> {
829 static constexpr const char* symbol = "n";
830};
831
832template<>
833struct si_prefix<std::micro> {
834 static constexpr const char* symbol = "µ";
835};
836
837template<>
838struct si_prefix<std::milli> {
839 static constexpr const char* symbol = "m";
840};
841
842template<>
843struct si_prefix<std::centi> {
844 static constexpr const char* symbol = "c";
845};
846
847template<>
848struct si_prefix<std::ratio<1>> {
849 static constexpr const char* symbol = "";
850};
851
852template<>
853struct si_prefix<std::kilo> {
854 static constexpr const char* symbol = "k";
855};
856
857template<>
858struct si_prefix<std::mega> {
859 static constexpr const char* symbol = "M";
860};
861
862template<>
863struct si_prefix<std::giga> {
864 static constexpr const char* symbol = "G";
865};
866
867template<>
868struct si_prefix<std::tera> {
869 static constexpr const char* symbol = "T";
870};
908template<typename Unit, typename Precision>
911 static std::string value()
912 requires requires { si_prefix<Precision>::symbol; }
913 {
914 return std::string(si_prefix<Precision>::symbol) + Unit::symbol;
915 }
916};
917
919template<typename R>
920using _square_ratio = std::ratio_multiply<R, R>;
921
922template<typename R>
923using _cube_ratio = std::ratio_multiply<std::ratio_multiply<R, R>, R>;
924
925// Areas and volumes have no SI prefix rule: only the explicit specializations
926// below have suffixes.
927template<typename Precision>
928struct quantity_suffix<square_meter_unit, Precision> {};
929
930template<typename Precision>
931struct quantity_suffix<cubic_meter_unit, Precision> {};
932
933template<>
934struct quantity_suffix<meter_unit, std::ratio<127, 5000000>> {
935 static std::string value() { return "mil"; }
936};
937
938template<>
939struct quantity_suffix<meter_unit, std::ratio<127, 5000>> {
940 static std::string value() { return "in"; }
941};
942
943template<>
944struct quantity_suffix<meter_unit, std::ratio<381, 1250>> {
945 static std::string value() { return "ft"; }
946};
947
948template<>
949struct quantity_suffix<meter_unit, std::ratio<1143, 1250>> {
950 static std::string value() { return "yd"; }
951};
952
953template<>
954struct quantity_suffix<meter_unit, std::ratio<201168, 125>> {
955 static std::string value() { return "mi"; }
956};
957
958template<>
959struct quantity_suffix<meter_unit, std::ratio<1852>> {
960 static std::string value() { return "nmi"; }
961};
962
963// Area
964template<>
965struct quantity_suffix<square_meter_unit, _square_ratio<std::nano>> {
966 static std::string value() { return "nm²"; }
967};
968
969template<>
970struct quantity_suffix<square_meter_unit, _square_ratio<std::micro>> {
971 static std::string value() { return "µm²"; }
972};
973
974template<>
975struct quantity_suffix<square_meter_unit, _square_ratio<std::milli>> {
976 static std::string value() { return "mm²"; }
977};
978
979template<>
980struct quantity_suffix<square_meter_unit, _square_ratio<std::centi>> {
981 static std::string value() { return "cm²"; }
982};
983
984template<>
985struct quantity_suffix<square_meter_unit, std::ratio<1>> {
986 static std::string value() { return "m²"; }
987};
988
989template<>
990struct quantity_suffix<square_meter_unit, _square_ratio<std::hecto>> {
991 static std::string value() { return "ha"; }
992 static std::string power_value() { return "hm²"; }
993};
994
995template<>
996struct quantity_suffix<square_meter_unit, _square_ratio<std::kilo>> {
997 static std::string value() { return "km²"; }
998};
999
1000template<>
1001struct quantity_suffix<square_meter_unit, _square_ratio<mils::precision>> {
1002 static std::string value() { return "mil²"; }
1003};
1004
1005template<>
1006struct quantity_suffix<square_meter_unit, _square_ratio<inches::precision>> {
1007 static std::string value() { return "in²"; }
1008};
1009
1010template<>
1011struct quantity_suffix<square_meter_unit, _square_ratio<feet::precision>> {
1012 static std::string value() { return "ft²"; }
1013};
1014
1015template<>
1016struct quantity_suffix<square_meter_unit, _square_ratio<yards::precision>> {
1017 static std::string value() { return "yd²"; }
1018};
1019
1020template<>
1021struct quantity_suffix<square_meter_unit, acres::precision> {
1022 static std::string value() { return "ac"; }
1023};
1024
1025template<>
1026struct quantity_suffix<square_meter_unit, _square_ratio<miles::precision>> {
1027 static std::string value() { return "mi²"; }
1028};
1029
1030template<>
1031struct quantity_suffix<square_meter_unit, _square_ratio<nautical_miles::precision>> {
1032 static std::string value() { return "nmi²"; }
1033};
1034
1035// Volume
1036template<>
1037struct quantity_suffix<cubic_meter_unit, _cube_ratio<std::micro>> {
1038 static std::string value() { return "µm³"; }
1039};
1040
1041template<>
1042struct quantity_suffix<cubic_meter_unit, _cube_ratio<std::milli>> {
1043 static std::string value() { return "µL"; }
1044 static std::string power_value() { return "mm³"; }
1045};
1046
1047template<>
1048struct quantity_suffix<cubic_meter_unit, _cube_ratio<std::centi>> {
1049 static std::string value() { return "mL"; }
1050 static std::string power_value() { return "cm³"; }
1051};
1052
1053template<>
1054struct quantity_suffix<cubic_meter_unit, _cube_ratio<std::deci>> {
1055 static std::string value() { return "L"; }
1056 static std::string power_value() { return "dm³"; }
1057};
1058
1059template<>
1060struct quantity_suffix<cubic_meter_unit, std::ratio<1>> {
1061 static std::string value() { return "m³"; }
1062};
1063
1064template<>
1065struct quantity_suffix<cubic_meter_unit, _cube_ratio<std::kilo>> {
1066 static std::string value() { return "km³"; }
1067};
1068
1069template<>
1070struct quantity_suffix<cubic_meter_unit, _cube_ratio<inches::precision>> {
1071 static std::string value() { return "in³"; }
1072};
1073
1074template<>
1075struct quantity_suffix<cubic_meter_unit, _cube_ratio<feet::precision>> {
1076 static std::string value() { return "ft³"; }
1077};
1078
1079template<>
1080struct quantity_suffix<cubic_meter_unit, _cube_ratio<yards::precision>> {
1081 static std::string value() { return "yd³"; }
1082};
1083
1084template<>
1085struct quantity_suffix<cubic_meter_unit, _cube_ratio<miles::precision>> {
1086 static std::string value() { return "mi³"; }
1087};
1088
1089template<>
1090struct quantity_suffix<cubic_meter_unit, _cube_ratio<nautical_miles::precision>> {
1091 static std::string value() { return "nmi³"; }
1092};
1093
1094template<>
1095struct quantity_suffix<cubic_meter_unit, us_gallons::precision> {
1096 static std::string value() { return "gal"; }
1097};
1098
1099template<typename Unit, typename Precision>
1100concept _has_suffix = requires { quantity_suffix<Unit, Precision>::value(); };
1101
1102// The power-form suffix: power_value() when the specialization provides it,
1103// otherwise the default suffix.
1104template<typename Unit, typename Precision>
1105std::string _power_suffix() {
1106 if constexpr (requires { quantity_suffix<Unit, Precision>::power_value(); }) {
1107 return quantity_suffix<Unit, Precision>::power_value();
1108 } else {
1110 }
1111}
1112
1113// A value and suffix to display, for the base-unit and scaled forms.
1114struct _display {
1115 double value;
1116 std::string suffix;
1117};
1118
1119// Metric precisions are exactly the powers of ten (of the base unit); the
1120// imperial, nautical and US customary ones are not.
1121template<typename Precision>
1122concept _metric_precision = detail::_power_of_ten_precision<Precision>;
1123
1124// The units the scaled form chooses between, by power-of-ten exponent of the
1125// base unit, in ascending order. Units without a list render in their own
1126// precision.
1127template<typename Unit>
1128struct _scale_units {};
1129
1130template<>
1131struct _scale_units<meter_unit> {
1132 static constexpr detail::_scale_entry values[] = {{-9, "nm"}, {-6, "µm"}, {-3, "mm"}, {0, "m"}, {3, "km"}};
1133};
1134
1135template<>
1136struct _scale_units<square_meter_unit> {
1137 static constexpr detail::_scale_entry values[] = {{-18, "nm²"}, {-12, "µm²"}, {-6, "mm²"}, {0, "m²"}, {6, "km²"}};
1138};
1139
1140template<>
1141struct _scale_units<cubic_meter_unit> {
1142 static constexpr detail::_scale_entry values[] = {{-9, "µL"}, {-6, "mL"}, {-3, "L"}, {0, "m³"}};
1143};
1144
1145// The quantity in the unit's base unit (m, m² or m³), as a double.
1146template<typename Unit, typename Rep, typename Precision>
1147_display _base_unit_display(const quantity<Unit, Rep, Precision>& q) {
1148 using p = typename Precision::type;
1149 return {detail::_ratio_value<p>(q.count()), Unit::symbol};
1150}
1151
1152// The quantity in the largest candidate unit in which its magnitude is at
1153// least 1, else the smallest; zero (keeping its sign) and non-finite values
1154// are shown in the base unit, as the base-unit form would show them. Non-metric
1155// precisions are shown in their own unit. Each candidate's value is computed
1156// from the count with a single scaling by a power of ten, so values that
1157// land exactly on a unit (1000 mm) are exactly 1 in it.
1158template<typename Unit, typename Rep, typename Precision>
1159_display _scaled_display(const quantity<Unit, Rep, Precision>& q) {
1160 using p = typename Precision::type;
1161 const double count = static_cast<double>(q.count());
1162 if constexpr (_metric_precision<p> && requires { _scale_units<Unit>::values; }) {
1163 if (count == 0 || !std::isfinite(count)) {
1164 return {count, Unit::symbol};
1165 }
1166 const detail::_scaled s = detail::_pick_scale(count, _precision_exponent<p>, _scale_units<Unit>::values);
1167 return {s.value, s.label};
1168 } else {
1169 return {count, quantity_suffix<Unit, p>::value()};
1170 }
1171}
1172
1173#if CONFIG_QUANTA_STD_FORMAT
1174// How std::format renders a quantity of the given unit and (reduced)
1175// precision, with the power form ('p'); see detail::_unit_formatter.
1176template<typename Unit, typename Precision>
1177struct _format_traits {
1178 static constexpr const char* markers = "pbs";
1179 static constexpr bool has_own_unit = true;
1180
1181 static std::string own_unit(bool power) {
1182 const std::string suffix = power ? _power_suffix<Unit, Precision>() : quantity_suffix<Unit, Precision>::value();
1183 return suffix;
1184 }
1185
1186 template<typename OutputIt>
1187 static OutputIt append_own_unit(OutputIt out, const std::string& suffix) {
1188 return std::format_to(out, "{}", suffix);
1189 }
1190
1191 template<typename Q>
1192 static _display base_display(const Q& q) {
1193 return _base_unit_display(q);
1194 }
1195
1196 template<typename Q>
1197 static _display scaled_display(const Q& q) {
1198 return _scaled_display(q);
1199 }
1200
1201 template<typename OutputIt>
1202 static OutputIt append_label(OutputIt out, const _display& d) {
1203 return std::format_to(out, "{}", d.suffix);
1204 }
1205};
1206#endif
1207
1214 explicit power_form_t() = default;
1215};
1216
1232inline constexpr power_form_t power_form{};
1233
1248using quanta::base_unit;
1250
1271using quanta::scaled;
1272using quanta::scaled_t;
1273
1292template<typename Unit, typename Rep, typename Precision>
1293 requires _has_suffix<Unit, typename Precision::type>
1294inline std::string to_string(const quantity<Unit, Rep, Precision>& q) {
1296}
1297
1309template<typename Unit, typename Rep, typename Precision>
1310 requires _has_suffix<Unit, typename Precision::type>
1312 return _count_string(q.count()) + _power_suffix<Unit, typename Precision::type>();
1313}
1314
1325template<typename Unit, typename Rep, typename Precision>
1326 requires _has_suffix<Unit, typename Precision::type>
1328 const _display d = _base_unit_display(q);
1329 return _fixed_string(d.value) + d.suffix;
1330}
1331
1342template<typename Unit, typename Rep, typename Precision>
1343 requires _has_suffix<Unit, typename Precision::type>
1345 const _display d = _scaled_display(q);
1346 return _fixed_string(d.value) + d.suffix;
1347}
1348
1349} // namespace quanta::spatial
1350
1351namespace std {
1352
1353template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
1354struct common_type<
1355 quanta::spatial::quantity<Unit, Rep1, Precision1>,
1356 quanta::spatial::quantity<Unit, Rep2, Precision2>> {
1357private:
1358 using common_precision = quanta::detail::_common_precision<Precision1, Precision2>;
1359
1360public:
1362};
1363
1364#if CONFIG_QUANTA_STD_FORMAT
1365// "{}" prints the exact stored count with a precision-qualified unit
1366// (millimeters(250) -> "250mm"; floating-point counts in the shortest fixed
1367// notation that round-trips, as to_string does: length<double>(1e6) ->
1368// "1000000m", never "1e+06m"). A non-empty spec controls only how the number
1369// is rendered (as double), never the unit, so both forms use the same suffix:
1370// std::format("{:.1f}", millimeters(1500)) == "1500.0mm" and
1371// std::format("{:.1f}", feet(6)) == "6.0ft".
1372//
1373// The unit changes only when the spec opts in with a single leading marker
1374// letter; the rest of the spec is then handled as above:
1375// - 'p' (power form, see quanta::spatial::power_form) keeps the count and writes the
1376// suffix as a power of a length unit: std::format("{:p}", milliliters(24))
1377// == "24cm³" and std::format("{:p.1f}", milliliters(24)) == "24.0cm³".
1378// - 'b' (base unit, see quanta::base_unit) shows the value in m, m² or m³:
1379// std::format("{:b.1f}", millimeters(1500)) == "1.5m".
1380// - 's' (scaled, see quanta::scaled) shows a metric value in a unit suited
1381// to its magnitude: std::format("{:s}", milliliters(1500)) == "1.5L".
1382// With 'b' or 's' and nothing after the marker, the value is rendered in the
1383// shortest fixed notation that round-trips (never scientific), exactly as by
1384// to_string(q, quanta::base_unit) or to_string(q, quanta::scaled):
1385// std::format("{:b}", milliliters(24)) == "0.000024m³".
1386//
1387// A spec starting with 'p', 'b' or 's' is always a marker, so these letters
1388// cannot be the fill character of a spec that starts with a fill
1389// ("{:p>10.1f}" is the marker followed by ">10.1f").
1390template<typename Unit, typename Rep, typename Precision>
1391 requires quanta::spatial::_has_suffix<Unit, typename Precision::type>
1392struct formatter<quanta::spatial::quantity<Unit, Rep, Precision>, char>
1393 : private quanta::detail::_unit_formatter<quanta::spatial::_format_traits<Unit, typename Precision::type>> {
1394 using quanta::detail::_unit_formatter<quanta::spatial::_format_traits<Unit, typename Precision::type>>::parse;
1395
1396 template<typename FormatContext>
1397 auto format(const quanta::spatial::quantity<Unit, Rep, Precision>& q, FormatContext& ctx) const {
1398 return this->format_quantity(q, ctx);
1399 }
1400};
1401#endif
1402
1403} // namespace std
1404
1408namespace quanta {
1409inline namespace literals {
1410inline namespace spatial_literals {
1412template<char... Digits>
1413constexpr quanta::spatial::nanometers operator""_nm() {
1414 return detail::check_overflow<quanta::spatial::nanometers, Digits...>();
1415}
1416
1418template<char... Digits>
1419constexpr quanta::spatial::micrometers operator""_um() {
1420 return detail::check_overflow<quanta::spatial::micrometers, Digits...>();
1421}
1422
1423#if QUANTA_HAS_UTF8_LITERALS
1425template<char... Digits>
1426constexpr quanta::spatial::micrometers operator""_µm() {
1427 return detail::check_overflow<quanta::spatial::micrometers, Digits...>();
1428}
1429#endif
1430
1432template<char... Digits>
1433constexpr quanta::spatial::millimeters operator""_mm() {
1434 return detail::check_overflow<quanta::spatial::millimeters, Digits...>();
1435}
1436
1438template<char... Digits>
1439constexpr quanta::spatial::centimeters operator""_cm() {
1440 return detail::check_overflow<quanta::spatial::centimeters, Digits...>();
1441}
1442
1444template<char... Digits>
1445constexpr quanta::spatial::meters operator""_m() {
1446 return detail::check_overflow<quanta::spatial::meters, Digits...>();
1447}
1448
1450template<char... Digits>
1451constexpr quanta::spatial::kilometers operator""_km() {
1452 return detail::check_overflow<quanta::spatial::kilometers, Digits...>();
1453}
1454
1456template<char... Digits>
1457constexpr quanta::spatial::mils operator""_mil() {
1458 return detail::check_overflow<quanta::spatial::mils, Digits...>();
1459}
1460
1462template<char... Digits>
1463constexpr quanta::spatial::inches operator""_in() {
1464 return detail::check_overflow<quanta::spatial::inches, Digits...>();
1465}
1466
1468template<char... Digits>
1469constexpr quanta::spatial::feet operator""_ft() {
1470 return detail::check_overflow<quanta::spatial::feet, Digits...>();
1471}
1472
1474template<char... Digits>
1475constexpr quanta::spatial::yards operator""_yd() {
1476 return detail::check_overflow<quanta::spatial::yards, Digits...>();
1477}
1478
1480template<char... Digits>
1481constexpr quanta::spatial::miles operator""_mi() {
1482 return detail::check_overflow<quanta::spatial::miles, Digits...>();
1483}
1484
1486template<char... Digits>
1488 return detail::check_overflow<quanta::spatial::nautical_miles, Digits...>();
1489}
1490
1492template<char... Digits>
1494 return detail::check_overflow<quanta::spatial::square_millimeters, Digits...>();
1495}
1496
1498template<char... Digits>
1500 return detail::check_overflow<quanta::spatial::square_centimeters, Digits...>();
1501}
1502
1504template<char... Digits>
1506 return detail::check_overflow<quanta::spatial::square_meters, Digits...>();
1507}
1508
1510template<char... Digits>
1511constexpr quanta::spatial::hectares operator""_ha() {
1512 return detail::check_overflow<quanta::spatial::hectares, Digits...>();
1513}
1514
1516template<char... Digits>
1518 return detail::check_overflow<quanta::spatial::square_kilometers, Digits...>();
1519}
1520
1522template<char... Digits>
1524 return detail::check_overflow<quanta::spatial::square_inches, Digits...>();
1525}
1526
1528template<char... Digits>
1529constexpr quanta::spatial::square_feet operator""_ft2() {
1530 return detail::check_overflow<quanta::spatial::square_feet, Digits...>();
1531}
1532
1534template<char... Digits>
1536 return detail::check_overflow<quanta::spatial::square_yards, Digits...>();
1537}
1538
1540template<char... Digits>
1541constexpr quanta::spatial::acres operator""_ac() {
1542 return detail::check_overflow<quanta::spatial::acres, Digits...>();
1543}
1544
1546template<char... Digits>
1548 return detail::check_overflow<quanta::spatial::square_miles, Digits...>();
1549}
1550
1552template<char... Digits>
1553constexpr quanta::spatial::microliters operator""_uL() {
1554 return detail::check_overflow<quanta::spatial::microliters, Digits...>();
1555}
1556
1557#if QUANTA_HAS_UTF8_LITERALS
1559template<char... Digits>
1560constexpr quanta::spatial::microliters operator""_µL() {
1561 return detail::check_overflow<quanta::spatial::microliters, Digits...>();
1562}
1563#endif
1564
1566template<char... Digits>
1567constexpr quanta::spatial::milliliters operator""_mL() {
1568 return detail::check_overflow<quanta::spatial::milliliters, Digits...>();
1569}
1570
1572template<char... Digits>
1573constexpr quanta::spatial::liters operator""_L() {
1574 return detail::check_overflow<quanta::spatial::liters, Digits...>();
1575}
1576
1578template<char... Digits>
1579constexpr quanta::spatial::cubic_meters operator""_m3() {
1580 return detail::check_overflow<quanta::spatial::cubic_meters, Digits...>();
1581}
1582
1584template<char... Digits>
1586 return detail::check_overflow<quanta::spatial::cubic_millimeters, Digits...>();
1587}
1588
1590template<char... Digits>
1592 return detail::check_overflow<quanta::spatial::cubic_centimeters, Digits...>();
1593}
1594
1596template<char... Digits>
1598 return detail::check_overflow<quanta::spatial::cubic_inches, Digits...>();
1599}
1600
1602template<char... Digits>
1603constexpr quanta::spatial::cubic_feet operator""_ft3() {
1604 return detail::check_overflow<quanta::spatial::cubic_feet, Digits...>();
1605}
1606
1608template<char... Digits>
1609constexpr quanta::spatial::cubic_yards operator""_yd3() {
1610 return detail::check_overflow<quanta::spatial::cubic_yards, Digits...>();
1611}
1612
1614template<char... Digits>
1615constexpr quanta::spatial::us_gallons operator""_gal() {
1616 return detail::check_overflow<quanta::spatial::us_gallons, Digits...>();
1617}
1618
1619} // namespace spatial_literals
1620} // namespace literals
1621
1622namespace spatial {
1623using namespace literals::spatial_literals;
1624} // namespace spatial
1625} // namespace quanta
A quantity of a spatial unit with a representation and precision.
Definition spatial.hpp:231
constexpr quantity & operator%=(const rep &r)
Definition spatial.hpp:356
Rep rep
The representation type.
Definition spatial.hpp:240
constexpr rep count() const
Returns the tick count.
Definition spatial.hpp:310
constexpr quantity & operator%=(const quantity &q)
Definition spatial.hpp:363
constexpr quantity & operator++()
Definition spatial.hpp:322
quantity & operator=(const quantity &)=default
constexpr quantity(const quantity< Unit, Rep2, Precision2 > &q)
Constructs from another quantity of the same unit with different representation or precision.
Definition spatial.hpp:280
Unit unit
The unit tag type.
Definition spatial.hpp:238
static constexpr quantity zero() noexcept
Returns a zero quantity.
Definition spatial.hpp:371
typename Precision::type precision
The precision as a std::ratio.
Definition spatial.hpp:242
constexpr quantity()=default
Constructs a zero quantity.
constexpr quantity & operator+=(const quantity &q)
Definition spatial.hpp:336
constexpr quantity & operator-=(const quantity &q)
Definition spatial.hpp:341
constexpr quantity & operator/=(const rep &r)
Definition spatial.hpp:351
constexpr quantity & operator--()
Definition spatial.hpp:329
quantity(const quantity &)=default
constexpr quantity< Unit, typename std::common_type< rep >::type, precision > operator-() const
Returns the negation of this quantity.
Definition spatial.hpp:318
constexpr quantity operator--(int)
Definition spatial.hpp:334
constexpr quantity(const Rep2 &r)
Constructs from a tick count.
Definition spatial.hpp:259
constexpr quantity< Unit, typename std::common_type< rep >::type, precision > operator+() const
Returns a copy of this quantity.
Definition spatial.hpp:313
constexpr quantity(const quantity< Unit, Rep2, Precision2 > &q)
Explicit constructor for lossy conversions.
Definition spatial.hpp:303
static constexpr quantity min() noexcept
Returns the minimum representable quantity.
Definition spatial.hpp:374
constexpr quantity operator++(int)
Definition spatial.hpp:327
static constexpr quantity max() noexcept
Returns the maximum representable quantity.
Definition spatial.hpp:377
constexpr quantity & operator*=(const rep &r)
Definition spatial.hpp:346
Configuration, traits and internals shared by every quanta domain.
quantity< watt_unit, Rep, Precision > power
Power quantity with configurable representation and precision.
Definition electro.hpp:900
length< int64_t, std::ratio< 201168, 125 > > miles
Length with 1 mi (5280 ft = 1609.344 m) precision.
Definition spatial.hpp:744
area< int64_t, std::mega > square_kilometers
Area with 1 km² precision.
Definition spatial.hpp:761
area< int64_t, std::micro > square_millimeters
Area with 1 mm² precision.
Definition spatial.hpp:753
length< int64_t, std::nano > nanometers
Length with 1 nm precision.
Definition spatial.hpp:723
volume< int64_t, std::nano > microliters
Volume with 1 µL (1 mm³) precision.
Definition spatial.hpp:779
area< int64_t, std::ratio< 1, 10000 > > square_centimeters
Area with 1 cm² precision.
Definition spatial.hpp:755
area< int64_t, std::ratio< 145161, 1562500 > > square_feet
Area with 1 ft² (144 in² = 0.09290304 m²) precision.
Definition spatial.hpp:766
volume< int64_t, std::ratio< 2048383, 125000000000 > > cubic_inches
Volume with 1 in³ (16.387064 mL) precision.
Definition spatial.hpp:792
microliters cubic_millimeters
Volume with 1 mm³ precision (the same type as microliters).
Definition spatial.hpp:781
area< int64_t, std::ratio< 1306449, 1562500 > > square_yards
Area with 1 yd² (9 ft² = 0.83612736 m²) precision.
Definition spatial.hpp:768
volume< int64_t, std::ratio< 473176473, 125000000000 > > us_gallons
Volume with 1 US gallon (231 in³ = 3.785411784 L) precision.
Definition spatial.hpp:798
volume< int64_t > cubic_meters
Volume with 1 m³ precision.
Definition spatial.hpp:789
area< int64_t, std::ratio< 316160658, 78125 > > acres
Area with 1 acre (43,560 ft² = 4046.8564224 m²) precision.
Definition spatial.hpp:770
volume< int64_t, std::micro > milliliters
Volume with 1 mL (1 cm³) precision.
Definition spatial.hpp:783
area< int64_t, std::ratio< 40468564224, 15625 > > square_miles
Area with 1 mi² (640 acres = 2,589,988.110336 m²) precision.
Definition spatial.hpp:772
length< int64_t, std::ratio< 1143, 1250 > > yards
Length with 1 yd (3 ft = 0.9144 m) precision.
Definition spatial.hpp:742
volume< int64_t, std::ratio< 55306341, 1953125000 > > cubic_feet
Volume with 1 ft³ (1728 in³ = 28.316846592 L) precision.
Definition spatial.hpp:794
volume< int64_t, std::milli > liters
Volume with 1 L (1 dm³) precision.
Definition spatial.hpp:787
length< int64_t, std::ratio< 127, 5000 > > inches
Length with 1 in (25.4 mm) precision.
Definition spatial.hpp:738
length< int64_t, std::milli > millimeters
Length with 1 mm precision.
Definition spatial.hpp:727
length< int64_t, std::kilo > kilometers
Length with 1 km precision.
Definition spatial.hpp:733
milliliters cubic_centimeters
Volume with 1 cm³ precision (the same type as milliliters).
Definition spatial.hpp:785
area< int64_t > square_meters
Area with 1 m² precision.
Definition spatial.hpp:757
quantity< meter_unit, Rep, Precision > length
Length quantity with configurable representation and precision.
Definition spatial.hpp:720
quantity< cubic_meter_unit, Rep, Precision > volume
Volume quantity with configurable representation and precision (a ratio of one m³).
Definition spatial.hpp:776
area< int64_t, std::ratio< 16129, 25000000 > > square_inches
Area with 1 in² (645.16 mm²) precision.
Definition spatial.hpp:764
volume< int64_t, std::ratio< 1493271207, 1953125000 > > cubic_yards
Volume with 1 yd³ (27 ft³ = 0.764554857984 m³) precision.
Definition spatial.hpp:796
length< int64_t, std::ratio< 381, 1250 > > feet
Length with 1 ft (12 in = 0.3048 m) precision.
Definition spatial.hpp:740
quantity< square_meter_unit, Rep, Precision > area
Area quantity with configurable representation and precision (a ratio of one m²).
Definition spatial.hpp:750
length< int64_t, std::micro > micrometers
Length with 1 µm precision.
Definition spatial.hpp:725
length< int64_t, std::ratio< 1852 > > nautical_miles
Length with 1 nmi (1852 m) precision.
Definition spatial.hpp:746
length< int64_t, std::ratio< 127, 5000000 > > mils
Length with 1 mil (thou, 1/1000 in = 25.4 µm) precision.
Definition spatial.hpp:736
length< int64_t > meters
Length with 1 m precision.
Definition spatial.hpp:731
area< int64_t, std::ratio< 10000 > > hectares
Area with 1 ha (1 hm² = 10,000 m²) precision.
Definition spatial.hpp:759
length< int64_t, std::centi > centimeters
Length with 1 cm precision.
Definition spatial.hpp:729
Spatial unit types and utilities.
Definition spatial.hpp:100
constexpr bool is_quantity_v
Definition spatial.hpp:120
constexpr bool operator==(const quantity< Unit, Rep1, Precision1 > &lhs, const quantity< Unit, Rep2, Precision2 > &rhs)
Definition spatial.hpp:599
constexpr ToQuantity trunc(const quantity< Unit, Rep, Precision > &q)
Converts a quantity to the target type, rounding toward zero.
Definition spatial.hpp:482
constexpr ToQuantity quantity_cast(const quantity< Unit, Rep, Precision > &q)
Converts a quantity to a different precision or representation.
Definition spatial.hpp:407
constexpr ToQuantity ceil(const quantity< Unit, Rep, Precision > &q)
Converts a quantity to the target type, rounding toward positive infinity.
Definition spatial.hpp:459
constexpr ToQuantity round(const quantity< Unit, Rep, Precision > &q)
Converts a quantity to the target type, rounding to nearest (ties to even).
Definition spatial.hpp:506
constexpr auto operator-(const quantity< Unit, Rep1, Precision1 > &lhs, const quantity< Unit, Rep2, Precision2 > &rhs) -> std::common_type_t< quantity< Unit, Rep1, Precision1 >, quantity< Unit, Rep2, Precision2 > >
Returns the difference of two quantities of the same unit.
Definition spatial.hpp:539
std::string to_string(const quantity< Unit, Rep, Precision > &q)
Converts a quantity to a string with its unit suffix.
Definition spatial.hpp:1294
constexpr auto operator*(const quantity< Unit, Rep1, Precision > &q, const Rep2 &r) -> quantity< Unit, std::common_type_t< Rep1, Rep2 >, Precision >
Multiplies a quantity by a scalar.
Definition spatial.hpp:548
constexpr quantity< Unit, Rep, Precision > abs(const quantity< Unit, Rep, Precision > &q)
Returns the absolute value of a quantity.
Definition spatial.hpp:521
constexpr power_form_t power_form
Selects the power-form suffix in to_string().
Definition spatial.hpp:1232
constexpr ToQuantity floor(const quantity< Unit, Rep, Precision > &q)
Converts a quantity to the target type, rounding toward negative infinity.
Definition spatial.hpp:435
constexpr auto operator/(const quantity< Unit, Rep1, Precision > &q, const Rep2 &s) -> quantity< Unit, std::common_type_t< Rep1, Rep2 >, Precision >
Divides a quantity by a scalar.
Definition spatial.hpp:565
constexpr auto operator+(const quantity< Unit, Rep1, Precision1 > &lhs, const quantity< Unit, Rep2, Precision2 > &rhs) -> std::common_type_t< quantity< Unit, Rep1, Precision1 >, quantity< Unit, Rep2, Precision2 > >
Returns the sum of two quantities of the same unit.
Definition spatial.hpp:531
constexpr auto operator<=>(const quantity< Unit, Rep1, Precision1 > &lhs, const quantity< Unit, Rep2, Precision2 > &rhs)
Definition spatial.hpp:606
Type-safe units modeled after std::chrono.
Definition core.hpp:90
constexpr scaled_t scaled
Selects the scaled form in to_string().
Definition core.hpp:161
constexpr base_unit_t base_unit
Selects the base-unit form in to_string().
Definition core.hpp:140
constexpr bool treat_as_inexact_v
Definition core.hpp:119
Tag type selecting the base-unit form, see base_unit.
Definition core.hpp:124
Tag type selecting the scaled form, see scaled.
Definition core.hpp:145
Volume, measured in cubic meters.
Definition spatial.hpp:169
static constexpr const char * symbol
Definition spatial.hpp:170
Trait to detect quantity specializations.
Definition spatial.hpp:114
Length, measured in meters.
Definition spatial.hpp:159
static constexpr const char * symbol
Definition spatial.hpp:160
Tag type selecting the power-form suffix, see power_form.
Definition spatial.hpp:1213
Trait giving the display suffix for a (unit, precision) pair.
Definition spatial.hpp:909
static std::string value()
Returns the display suffix.
Definition spatial.hpp:911
Provides special values for quantity representations.
Definition spatial.hpp:132
static constexpr Rep max() noexcept
Returns the maximum representable quantity.
Definition spatial.hpp:137
static constexpr Rep zero() noexcept
Returns a zero quantity.
Definition spatial.hpp:134
static constexpr Rep min() noexcept
Returns the minimum representable quantity.
Definition spatial.hpp:140
Trait giving the display symbol for an SI precision prefix.
Definition spatial.hpp:814
Area, measured in square meters.
Definition spatial.hpp:164
static constexpr const char * symbol
Definition spatial.hpp:165
Trait to indicate floating-point-like behavior.
Definition core.hpp:116
quanta::spatial::quantity< Unit, std::common_type_t< Rep1, Rep2 >, common_precision > type
Definition spatial.hpp:1361