quanta 0.1.0
Type-safe units for temperature, frequency, electrical and spatial quantities, modeled after std::chrono
Loading...
Searching...
No Matches
electro.hpp
Go to the documentation of this file.
1#pragma once
2
8#include <assert.h>
9#include <charconv>
10#include <chrono>
11#include <cmath>
12#include <compare>
13#include <concepts>
14#include <cstddef>
15#include <cstdint>
16#include <limits>
17#include <quanta/core.hpp>
18#include <ratio>
19#include <string>
20#include <system_error>
21#include <type_traits>
22
101namespace quanta::electro {
102
103// The shared trait, re-exported for convenience; specialize quanta::treat_as_inexact.
106
107template<typename Unit, typename Rep, typename Precision = std::ratio<1>>
108class quantity;
109
114template<typename T>
115struct is_quantity : std::false_type {};
116
117template<typename Unit, typename Rep, typename Precision>
118struct is_quantity<quantity<Unit, Rep, Precision>> : std::true_type {};
119
120template<typename T>
121inline constexpr bool is_quantity_v = is_quantity<T>::value;
122
124template<typename Rep>
125concept not_quantity = !is_quantity_v<Rep>;
126
127template<typename T>
128struct _is_chrono_duration : std::false_type {};
129
130template<typename Rep, typename Period>
131struct _is_chrono_duration<std::chrono::duration<Rep, Period>> : std::true_type {};
132
141template<typename T>
142concept duration_like = _is_chrono_duration<std::remove_cvref_t<T>>::value;
149template<typename Rep>
152 static constexpr Rep zero() noexcept { return Rep(0); }
153
155 static constexpr Rep max() noexcept { return std::numeric_limits<Rep>::max(); }
156
158 static constexpr Rep min() noexcept { return std::numeric_limits<Rep>::lowest(); }
159};
160
161// ============================================================================
162// Units
163// ============================================================================
164
174struct volt_unit {
175 static constexpr const char* symbol = "V";
176};
177
180 static constexpr const char* symbol = "A";
181};
182
184struct ohm_unit {
185 static constexpr const char* symbol = "Ω";
186};
187
189struct watt_unit {
190 static constexpr const char* symbol = "W";
191};
192
195 static constexpr const char* symbol = "C";
196};
197
200 static constexpr const char* symbol = "J";
201};
202
205 static constexpr const char* symbol = "F";
206};
207
210 static constexpr const char* symbol = "H";
211};
212
// end of ElectroUnits group
214
244template<typename Unit, typename Rep, typename Precision>
245class quantity {
246 static_assert(!is_quantity_v<Rep>, "rep cannot be an quanta::electro::quantity");
247 static_assert(_is_ratio<Precision>::value, "precision must be a specialization of std::ratio");
248 static_assert(Precision::num > 0, "precision must be positive");
249
250public:
252 using unit = Unit;
254 using rep = Rep;
256 using precision = typename Precision::type;
257
259 constexpr quantity() = default;
260 quantity(const quantity&) = default;
261
271 template<typename Rep2>
272 requires std::convertible_to<const Rep2&, rep> && (treat_as_inexact_v<rep> || !treat_as_inexact_v<Rep2>)
273 constexpr explicit quantity(const Rep2& r)
274 : _r(static_cast<rep>(r)) {}
275
290 template<typename Rep2, typename Precision2>
291 requires std::convertible_to<const Rep2&, rep> &&
292 detail::_lossless_conversion<Rep2, Precision2, rep, precision> &&
293 detail::_quantity_castable<quantity<Unit, Rep2, Precision2>, quantity>
296
313 template<typename Rep2, typename Precision2>
314 requires(!detail::_lossless_conversion<Rep2, Precision2, rep, precision> ||
315 !std::convertible_to<const Rep2&, rep>) &&
316 detail::_quantity_castable<quantity<Unit, Rep2, Precision2>, quantity>
317 constexpr explicit quantity(const quantity<Unit, Rep2, Precision2>& q)
318 : _r(quantity_cast<quantity>(q).count()) {}
319
320 ~quantity() = default;
321 quantity& operator=(const quantity&) = default;
322
324 constexpr rep count() const { return _r; }
325
329
333
334 constexpr quantity& operator++() {
335 ++_r;
336 return *this;
337 }
338
339 constexpr quantity operator++(int) { return quantity(_r++); }
340
341 constexpr quantity& operator--() {
342 --_r;
343 return *this;
344 }
345
346 constexpr quantity operator--(int) { return quantity(_r--); }
347
348 constexpr quantity& operator+=(const quantity& q) {
349 _r += q.count();
350 return *this;
351 }
352
353 constexpr quantity& operator-=(const quantity& q) {
354 _r -= q.count();
355 return *this;
356 }
357
358 constexpr quantity& operator*=(const rep& r) {
359 _r *= r;
360 return *this;
361 }
362
363 constexpr quantity& operator/=(const rep& r) {
364 _r /= r;
365 return *this;
366 }
367
368 constexpr quantity& operator%=(const rep& r)
369 requires(!treat_as_inexact_v<rep>)
370 {
371 _r %= r;
372 return *this;
373 }
374
375 constexpr quantity& operator%=(const quantity& q)
376 requires(!treat_as_inexact_v<rep>)
377 {
378 _r %= q.count();
379 return *this;
380 }
381
383 static constexpr quantity zero() noexcept { return quantity(quantity_values<rep>::zero()); }
384
386 static constexpr quantity min() noexcept { return quantity(quantity_values<rep>::min()); }
387
389 static constexpr quantity max() noexcept { return quantity(quantity_values<rep>::max()); }
390
391private:
392 rep _r{};
393};
394
410template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
411 requires(!std::is_same_v<typename ToQuantity::unit, Unit>) ||
412 detail::_quantity_cast_requirements<quantity<Unit, Rep, Precision>, ToQuantity>
413constexpr ToQuantity quantity_cast(const quantity<Unit, Rep, Precision>& q) {
414 // The constraint admits a cast between units, so that this reports it.
415 static_assert(
416 std::is_same_v<typename ToQuantity::unit, Unit>, "quantity_cast cannot convert between different units"
417 );
418 return detail::_quantity_cast<ToQuantity>(q);
419}
420
440template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
441constexpr ToQuantity floor(const quantity<Unit, Rep, Precision>& q) {
442 return detail::_floor_cast(quantity_cast<ToQuantity>(q), q);
443}
444
464template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
465constexpr ToQuantity ceil(const quantity<Unit, Rep, Precision>& q) {
466 return detail::_ceil_cast(quantity_cast<ToQuantity>(q), q);
467}
468
487template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
488constexpr ToQuantity trunc(const quantity<Unit, Rep, Precision>& q) {
489 return quantity_cast<ToQuantity>(q);
490}
491
511template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
512constexpr ToQuantity round(const quantity<Unit, Rep, Precision>& q) {
513 return detail::_round_cast<ToQuantity>(q, [&q] { return floor<ToQuantity>(q); });
514}
515
526template<typename Unit, typename Rep, typename Precision>
528 return detail::_abs(q);
529}
530
531// ============================================================================
532// Same-unit arithmetic
533// ============================================================================
534
536template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
538 -> std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>> {
539 using cq = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
540 return cq(cq(lhs).count() + cq(rhs).count());
541}
542
544template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
546 -> std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>> {
547 using cq = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
548 return cq(cq(lhs).count() - cq(rhs).count());
549}
550
552template<typename Unit, typename Rep1, typename Precision, typename Rep2>
553 requires not_quantity<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>>
554constexpr auto operator*(const quantity<Unit, Rep1, Precision>& q, const Rep2& r)
557 return cq(cq(q).count() * r);
558}
559
561template<typename Unit, typename Rep1, typename Rep2, typename Precision>
562 requires not_quantity<Rep1> && std::convertible_to<const Rep1&, std::common_type_t<Rep1, Rep2>>
563constexpr auto operator*(const Rep1& r, const quantity<Unit, Rep2, Precision>& q)
565 return q * r;
566}
567
569template<typename Unit, typename Rep1, typename Precision, typename Rep2>
570 requires not_quantity<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>>
571constexpr auto operator/(const quantity<Unit, Rep1, Precision>& q, const Rep2& s)
574 return cq(cq(q).count() / s);
575}
576
578template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
580 -> std::common_type_t<Rep1, Rep2> {
581 using cq = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
582 return cq(lhs).count() / cq(rhs).count();
583}
584
586template<typename Unit, typename Rep1, typename Precision, typename Rep2>
587 requires not_quantity<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>> &&
588 (!treat_as_inexact_v<Rep1> && !treat_as_inexact_v<Rep2>)
589constexpr auto operator%(const quantity<Unit, Rep1, Precision>& q, const Rep2& s)
592 return cq(cq(q).count() % s);
593}
594
596template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
597 requires(!treat_as_inexact_v<Rep1> && !treat_as_inexact_v<Rep2>)
598constexpr auto operator%(const quantity<Unit, Rep1, Precision1>& lhs, const quantity<Unit, Rep2, Precision2>& rhs)
599 -> std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>> {
600 using cq = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
601 return cq(cq(lhs).count() % cq(rhs).count());
602}
603
604template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
606 using ct = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
607 return ct(lhs).count() == ct(rhs).count();
608}
609
610template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
611 requires std::three_way_comparable<std::common_type_t<Rep1, Rep2>>
613 using ct = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
614 return ct(lhs).count() <=> ct(rhs).count();
615}
616
617// ============================================================================
618// Cross-unit arithmetic
619// ============================================================================
620
622// Product of two quantities, in the given result unit. Counts multiply and
623// precisions multiply, so no conversion factor is needed and the result is
624// exact for integer representations.
625template<typename ToUnit, typename U1, typename R1, typename P1, typename U2, typename R2, typename P2>
626constexpr auto _product(const quantity<U1, R1, P1>& lhs, const quantity<U2, R2, P2>& rhs) {
627 using cr = std::common_type_t<R1, R2>;
628 using result_t = quantity<ToUnit, cr, std::ratio_multiply<P1, P2>>;
629 return result_t(static_cast<cr>(lhs.count()) * static_cast<cr>(rhs.count()));
630}
631
632// Quotient of two quantities, in the given result unit. Counts divide and
633// precisions divide; for integer representations the count division truncates.
634template<typename ToUnit, typename U1, typename R1, typename P1, typename U2, typename R2, typename P2>
635constexpr auto _quotient(const quantity<U1, R1, P1>& lhs, const quantity<U2, R2, P2>& rhs) {
636 using cr = std::common_type_t<R1, R2>;
637 using result_t = quantity<ToUnit, cr, std::ratio_divide<P1, P2>>;
638 return result_t(static_cast<cr>(lhs.count()) / static_cast<cr>(rhs.count()));
639}
640
641// Product of a quantity and a duration, in the given result unit.
642template<typename ToUnit, typename U1, typename R1, typename P1, duration_like D>
643constexpr auto _duration_product(const quantity<U1, R1, P1>& lhs, const D& rhs) {
644 using cr = std::common_type_t<R1, typename D::rep>;
645 using result_t = quantity<ToUnit, cr, std::ratio_multiply<P1, typename D::period>>;
646 return result_t(static_cast<cr>(lhs.count()) * static_cast<cr>(rhs.count()));
647}
648
649// Quotient of a quantity and a duration, in the given result unit.
650template<typename ToUnit, typename U1, typename R1, typename P1, duration_like D>
651constexpr auto _duration_quotient(const quantity<U1, R1, P1>& lhs, const D& rhs) {
652 using cr = std::common_type_t<R1, typename D::rep>;
653 using result_t = quantity<ToUnit, cr, std::ratio_divide<P1, typename D::period>>;
654 return result_t(static_cast<cr>(lhs.count()) / static_cast<cr>(rhs.count()));
655}
656
657// Quotient of two quantities yielding a std::chrono::duration.
658template<typename U1, typename R1, typename P1, typename U2, typename R2, typename P2>
659constexpr auto _quotient_duration(const quantity<U1, R1, P1>& lhs, const quantity<U2, R2, P2>& rhs) {
660 using cr = std::common_type_t<R1, R2>;
661 using result_t = std::chrono::duration<cr, std::ratio_divide<P1, P2>>;
662 return result_t(static_cast<cr>(lhs.count()) / static_cast<cr>(rhs.count()));
663}
664
665// Product of two quantities yielding a std::chrono::duration.
666template<typename U1, typename R1, typename P1, typename U2, typename R2, typename P2>
667constexpr auto _product_duration(const quantity<U1, R1, P1>& lhs, const quantity<U2, R2, P2>& rhs) {
668 using cr = std::common_type_t<R1, R2>;
669 using result_t = std::chrono::duration<cr, std::ratio_multiply<P1, P2>>;
670 return result_t(static_cast<cr>(lhs.count()) * static_cast<cr>(rhs.count()));
671}
686template<typename R1, typename P1, typename R2, typename P2>
688 return _product<volt_unit>(i, r);
689}
690
692template<typename R1, typename P1, typename R2, typename P2>
694 return _product<volt_unit>(r, i);
695}
696
698template<typename R1, typename P1, typename R2, typename P2>
700 return _quotient<ampere_unit>(v, r);
701}
702
704template<typename R1, typename P1, typename R2, typename P2>
706 return _quotient<ohm_unit>(v, i);
707}
708
710template<typename R1, typename P1, typename R2, typename P2>
712 return _product<watt_unit>(v, i);
713}
714
716template<typename R1, typename P1, typename R2, typename P2>
718 return _product<watt_unit>(i, v);
719}
720
722template<typename R1, typename P1, typename R2, typename P2>
724 return _quotient<ampere_unit>(p, v);
725}
726
728template<typename R1, typename P1, typename R2, typename P2>
730 return _quotient<volt_unit>(p, i);
731}
732
740template<typename R1, typename P1, duration_like D>
741constexpr auto operator*(const quantity<ampere_unit, R1, P1>& i, const D& t) {
742 return _duration_product<coulomb_unit>(i, t);
743}
744
746template<duration_like D, typename R1, typename P1>
747constexpr auto operator*(const D& t, const quantity<ampere_unit, R1, P1>& i) {
748 return _duration_product<coulomb_unit>(i, t);
749}
750
752template<typename R1, typename P1, duration_like D>
753constexpr auto operator/(const quantity<coulomb_unit, R1, P1>& q, const D& t) {
754 return _duration_quotient<ampere_unit>(q, t);
755}
756
764template<typename R1, typename P1, typename R2, typename P2>
766 return _quotient_duration(q, i);
767}
768
776template<typename R1, typename P1, duration_like D>
777constexpr auto operator*(const quantity<watt_unit, R1, P1>& p, const D& t) {
778 return _duration_product<joule_unit>(p, t);
779}
780
782template<duration_like D, typename R1, typename P1>
783constexpr auto operator*(const D& t, const quantity<watt_unit, R1, P1>& p) {
784 return _duration_product<joule_unit>(p, t);
785}
786
788template<typename R1, typename P1, duration_like D>
789constexpr auto operator/(const quantity<joule_unit, R1, P1>& e, const D& t) {
790 return _duration_quotient<watt_unit>(e, t);
791}
792
794template<typename R1, typename P1, typename R2, typename P2>
796 return _quotient_duration(e, p);
797}
798
806template<typename R1, typename P1, typename R2, typename P2>
808 return _quotient<coulomb_unit>(e, v);
809}
810
812template<typename R1, typename P1, typename R2, typename P2>
814 return _quotient<volt_unit>(e, q);
815}
816
818template<typename R1, typename P1, typename R2, typename P2>
820 return _product<coulomb_unit>(c, v);
821}
822
824template<typename R1, typename P1, typename R2, typename P2>
826 return _product<coulomb_unit>(v, c);
827}
828
830template<typename R1, typename P1, typename R2, typename P2>
832 return _quotient<farad_unit>(q, v);
833}
834
836template<typename R1, typename P1, typename R2, typename P2>
838 return _quotient<volt_unit>(q, c);
839}
840
848template<typename R1, typename P1, typename R2, typename P2>
850 return _product_duration(r, c);
851}
852
854template<typename R1, typename P1, typename R2, typename P2>
856 return _product_duration(c, r);
857}
858
866template<typename R1, typename P1, typename R2, typename P2>
868 return _quotient_duration(l, r);
869}
870
// end of ElectroCrossUnit group
872
873// ============================================================================
874// Type aliases
875// ============================================================================
876
887template<typename Rep, typename Precision = std::ratio<1>>
889
891template<typename Rep, typename Precision = std::ratio<1>>
893
895template<typename Rep, typename Precision = std::ratio<1>>
897
899template<typename Rep, typename Precision = std::ratio<1>>
901
903template<typename Rep, typename Precision = std::ratio<1>>
905
907template<typename Rep, typename Precision = std::ratio<1>>
909
911template<typename Rep, typename Precision = std::ratio<1>>
913
915template<typename Rep, typename Precision = std::ratio<1>>
917
926
938using amps = amperes;
939
950
963
974
987
998
1007
// end of ElectroQuantityTypes group
1009
1010// ============================================================================
1011// String conversion and formatting
1012// ============================================================================
1013
1020template<typename Precision>
1022
1024template<>
1025struct si_prefix<std::femto> {
1026 static constexpr const char* symbol = "f";
1027};
1028
1029template<>
1030struct si_prefix<std::pico> {
1031 static constexpr const char* symbol = "p";
1032};
1033
1034template<>
1035struct si_prefix<std::nano> {
1036 static constexpr const char* symbol = "n";
1037};
1038
1039template<>
1040struct si_prefix<std::micro> {
1041 static constexpr const char* symbol = "µ";
1042};
1043
1044template<>
1045struct si_prefix<std::milli> {
1046 static constexpr const char* symbol = "m";
1047};
1048
1049template<>
1050struct si_prefix<std::ratio<1>> {
1051 static constexpr const char* symbol = "";
1052};
1053
1054template<>
1055struct si_prefix<std::kilo> {
1056 static constexpr const char* symbol = "k";
1057};
1058
1059template<>
1060struct si_prefix<std::mega> {
1061 static constexpr const char* symbol = "M";
1062};
1063
1064template<>
1065struct si_prefix<std::giga> {
1066 static constexpr const char* symbol = "G";
1067};
1068
1069template<>
1070struct si_prefix<std::tera> {
1071 static constexpr const char* symbol = "T";
1072};
1086template<typename Unit, typename Precision>
1089 static std::string value()
1090 requires requires { si_prefix<Precision>::symbol; }
1091 {
1092 return std::string(si_prefix<Precision>::symbol) + Unit::symbol;
1093 }
1094};
1095
1097template<>
1098struct quantity_suffix<coulomb_unit, std::ratio<18, 5>> {
1099 static std::string value() { return "mAh"; }
1100};
1101
1102template<>
1103struct quantity_suffix<coulomb_unit, std::ratio<3600>> {
1104 static std::string value() { return "Ah"; }
1105};
1106
1107template<>
1108struct quantity_suffix<joule_unit, std::ratio<3600>> {
1109 static std::string value() { return "Wh"; }
1110};
1111
1112template<>
1113struct quantity_suffix<joule_unit, std::ratio<3600000>> {
1114 static std::string value() { return "kWh"; }
1115};
1116
1117template<typename Unit, typename Precision>
1118concept _has_suffix = requires { quantity_suffix<Unit, Precision>::value(); };
1119
1120// The unit the base-unit form (the `b` format marker, to_string(q,
1121// base_unit)) renders in, as `scale`-sized units labeled `suffix`. SI-prefixed
1122// precisions render in the unprefixed unit ("3.3V"); the hour-based charge and
1123// energy precisions render in Ah and Wh ("0.2Ah", never "720C").
1124template<typename Unit, typename Precision>
1125struct _base_display_unit {
1126 using scale = std::ratio<1>;
1127 static constexpr const char* suffix = Unit::symbol;
1128};
1129
1130struct _ampere_hour_display_unit {
1131 using scale = std::ratio<3600>;
1132 static constexpr const char* suffix = "Ah";
1133};
1134
1135struct _watt_hour_display_unit {
1136 using scale = std::ratio<3600>;
1137 static constexpr const char* suffix = "Wh";
1138};
1139
1140template<>
1141struct _base_display_unit<coulomb_unit, std::ratio<18, 5>> : _ampere_hour_display_unit {};
1142
1143template<>
1144struct _base_display_unit<coulomb_unit, std::ratio<3600>> : _ampere_hour_display_unit {};
1145
1146template<>
1147struct _base_display_unit<joule_unit, std::ratio<3600>> : _watt_hour_display_unit {};
1148
1149template<>
1150struct _base_display_unit<joule_unit, std::ratio<3600000>> : _watt_hour_display_unit {};
1151
1152// A value and suffix to display, for the base-unit and scaled forms.
1153struct _display {
1154 double value;
1155 std::string suffix;
1156};
1157
1158// The quantity in its base unit (see _base_display_unit), as a double.
1159template<typename Unit, typename Rep, typename Precision>
1160_display _base_unit_display(const quantity<Unit, Rep, Precision>& q) {
1161 using display = _base_display_unit<Unit, typename Precision::type>;
1162 // display units per count
1163 using upc = typename std::ratio_divide<typename Precision::type, typename display::scale>::type;
1164 return {detail::_ratio_value<upc>(q.count()), display::suffix};
1165}
1166
1167// Precisions that are SI prefixes (see si_prefix) of the unit.
1168template<typename Precision>
1169concept _si_precision = requires { si_prefix<Precision>::symbol; } && detail::_power_of_ten_precision<Precision>;
1170
1171// The quantity with the largest SI prefix for which its magnitude is at least
1172// 1, else the smallest; zero (keeping its sign) and non-finite values are
1173// shown in the unprefixed unit. Each candidate's value is computed from the
1174// count with a single scaling by a power of ten, so values that land exactly
1175// on a prefix (1000 mV) are exactly 1 in it. Precisions that are not SI
1176// prefixes (mAh, Ah, Wh, kWh) are shown in their own unit.
1177template<typename Unit, typename Rep, typename Precision>
1178_display _scaled_display(const quantity<Unit, Rep, Precision>& q) {
1179 using p = typename Precision::type;
1180 const double count = static_cast<double>(q.count());
1181 if constexpr (_si_precision<p>) {
1182 if (count == 0 || !std::isfinite(count)) {
1183 return _base_unit_display(q);
1184 }
1185 // The si_prefix set, femto to tera
1186 const detail::_scaled s = detail::_pick_scale(count, _precision_exponent<p>, detail::_si_scale);
1187 return {s.value, std::string(s.label) + Unit::symbol};
1188 } else {
1189 return {count, quantity_suffix<Unit, p>::value()};
1190 }
1191}
1192
1193#if CONFIG_QUANTA_STD_FORMAT
1194// How std::format renders a quantity of the given unit and (reduced)
1195// precision; see detail::_unit_formatter.
1196template<typename Unit, typename Precision>
1197struct _format_traits {
1198 static constexpr const char* markers = "bs";
1199 static constexpr bool has_own_unit = true;
1200
1201 static std::string own_unit(bool) {
1202 const std::string suffix = quantity_suffix<Unit, Precision>::value();
1203 return suffix;
1204 }
1205
1206 template<typename OutputIt>
1207 static OutputIt append_own_unit(OutputIt out, const std::string& suffix) {
1208 return std::format_to(out, "{}", suffix);
1209 }
1210
1211 template<typename Q>
1212 static _display base_display(const Q& q) {
1213 return _base_unit_display(q);
1214 }
1215
1216 template<typename Q>
1217 static _display scaled_display(const Q& q) {
1218 return _scaled_display(q);
1219 }
1220
1221 template<typename OutputIt>
1222 static OutputIt append_label(OutputIt out, const _display& d) {
1223 return std::format_to(out, "{}", d.suffix);
1224 }
1225};
1226#endif
1227
1246using quanta::base_unit;
1248
1267using quanta::scaled;
1268using quanta::scaled_t;
1269
1285template<typename Unit, typename Rep, typename Precision>
1286 requires _has_suffix<Unit, typename Precision::type>
1287inline std::string to_string(const quantity<Unit, Rep, Precision>& q) {
1289}
1290
1301template<typename Unit, typename Rep, typename Precision>
1302 requires _has_suffix<Unit, typename Precision::type>
1304 const _display d = _base_unit_display(q);
1305 return _fixed_string(d.value) + d.suffix;
1306}
1307
1318template<typename Unit, typename Rep, typename Precision>
1319 requires _has_suffix<Unit, typename Precision::type>
1321 const _display d = _scaled_display(q);
1322 return _fixed_string(d.value) + d.suffix;
1323}
1324
1325} // namespace quanta::electro
1326
1327namespace std {
1328
1329template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
1330struct common_type<
1331 quanta::electro::quantity<Unit, Rep1, Precision1>,
1332 quanta::electro::quantity<Unit, Rep2, Precision2>> {
1333private:
1334 using common_precision = quanta::detail::_common_precision<Precision1, Precision2>;
1335
1336public:
1338};
1339
1340#if CONFIG_QUANTA_STD_FORMAT
1341// "{}" prints the exact stored count with a precision-qualified unit
1342// (millivolts(3300) -> "3300mV"; floating-point counts in the shortest fixed
1343// notation that round-trips, as to_string does: voltage<double>(1e6) ->
1344// "1000000V", never "1e+06V"). A non-empty spec controls only how the number
1345// is rendered (as double), never the unit, so both forms use the same suffix:
1346// std::format("{:.1f}", millivolts(3300)) == "3300.0mV" and
1347// std::format("{:.1f}", milliampere_hours(200)) == "200.0mAh".
1348//
1349// The unit changes only when the spec opts in with a single leading marker
1350// letter; the rest of the spec is then handled as above:
1351// - 'b' (base unit, see quanta::base_unit) shows the value in the unprefixed
1352// unit, or in Ah/Wh for the hour-based precisions:
1353// std::format("{:b.1f}", millivolts(3300)) == "3.3V".
1354// - 's' (scaled, see quanta::scaled) shows the value with an SI prefix
1355// suited to its magnitude: std::format("{:s}", ohms(4700)) == "4.7kΩ".
1356// With 'b' or 's' and nothing after the marker, the value is rendered in the
1357// shortest fixed notation that round-trips (never scientific), exactly as by
1358// to_string(q, quanta::base_unit) or to_string(q, quanta::scaled):
1359// std::format("{:b}", millivolts(24)) == "0.024V".
1360//
1361// A spec starting with 'b' or 's' is always a marker, so these letters cannot
1362// be the fill character of a spec that starts with a fill ("{:b>8.1f}" is the
1363// marker followed by ">8.1f").
1364template<typename Unit, typename Rep, typename Precision>
1365 requires quanta::electro::_has_suffix<Unit, typename Precision::type>
1366struct formatter<quanta::electro::quantity<Unit, Rep, Precision>, char>
1367 : private quanta::detail::_unit_formatter<quanta::electro::_format_traits<Unit, typename Precision::type>> {
1368 using quanta::detail::_unit_formatter<quanta::electro::_format_traits<Unit, typename Precision::type>>::parse;
1369
1370 template<typename FormatContext>
1371 auto format(const quanta::electro::quantity<Unit, Rep, Precision>& q, FormatContext& ctx) const {
1372 return this->format_quantity(q, ctx);
1373 }
1374};
1375#endif
1376
1377} // namespace std
1378
1382namespace quanta {
1383inline namespace literals {
1384inline namespace electro_literals {
1386template<char... Digits>
1387constexpr quanta::electro::microvolts operator""_uV() {
1388 return detail::check_overflow<quanta::electro::microvolts, Digits...>();
1389}
1390
1392template<char... Digits>
1393constexpr quanta::electro::millivolts operator""_mV() {
1394 return detail::check_overflow<quanta::electro::millivolts, Digits...>();
1395}
1396
1398template<char... Digits>
1399constexpr quanta::electro::volts operator""_V() {
1400 return detail::check_overflow<quanta::electro::volts, Digits...>();
1401}
1402
1404template<char... Digits>
1405constexpr quanta::electro::kilovolts operator""_kV() {
1406 return detail::check_overflow<quanta::electro::kilovolts, Digits...>();
1407}
1408
1410template<char... Digits>
1411constexpr quanta::electro::microamperes operator""_uA() {
1412 return detail::check_overflow<quanta::electro::microamperes, Digits...>();
1413}
1414
1416template<char... Digits>
1417constexpr quanta::electro::milliamperes operator""_mA() {
1418 return detail::check_overflow<quanta::electro::milliamperes, Digits...>();
1419}
1420
1422template<char... Digits>
1423constexpr quanta::electro::amperes operator""_A() {
1424 return detail::check_overflow<quanta::electro::amperes, Digits...>();
1425}
1426
1428template<char... Digits>
1429constexpr quanta::electro::milliohms operator""_mOhm() {
1430 return detail::check_overflow<quanta::electro::milliohms, Digits...>();
1431}
1432
1434template<char... Digits>
1435constexpr quanta::electro::ohms operator""_Ohm() {
1436 return detail::check_overflow<quanta::electro::ohms, Digits...>();
1437}
1438
1440template<char... Digits>
1441constexpr quanta::electro::kiloohms operator""_kOhm() {
1442 return detail::check_overflow<quanta::electro::kiloohms, Digits...>();
1443}
1444
1446template<char... Digits>
1447constexpr quanta::electro::megaohms operator""_MOhm() {
1448 return detail::check_overflow<quanta::electro::megaohms, Digits...>();
1449}
1450
1451#if QUANTA_HAS_UTF8_LITERALS
1453template<char... Digits>
1454constexpr quanta::electro::milliohms operator""_mΩ() {
1455 return detail::check_overflow<quanta::electro::milliohms, Digits...>();
1456}
1457
1459template<char... Digits>
1460constexpr quanta::electro::ohms operator""_Ω() {
1461 return detail::check_overflow<quanta::electro::ohms, Digits...>();
1462}
1463
1465template<char... Digits>
1466constexpr quanta::electro::kiloohms operator""_kΩ() {
1467 return detail::check_overflow<quanta::electro::kiloohms, Digits...>();
1468}
1469
1471template<char... Digits>
1472constexpr quanta::electro::megaohms operator""_MΩ() {
1473 return detail::check_overflow<quanta::electro::megaohms, Digits...>();
1474}
1475#endif
1476
1478template<char... Digits>
1479constexpr quanta::electro::microwatts operator""_uW() {
1480 return detail::check_overflow<quanta::electro::microwatts, Digits...>();
1481}
1482
1484template<char... Digits>
1485constexpr quanta::electro::milliwatts operator""_mW() {
1486 return detail::check_overflow<quanta::electro::milliwatts, Digits...>();
1487}
1488
1490template<char... Digits>
1491constexpr quanta::electro::watts operator""_W() {
1492 return detail::check_overflow<quanta::electro::watts, Digits...>();
1493}
1494
1496template<char... Digits>
1497constexpr quanta::electro::kilowatts operator""_kW() {
1498 return detail::check_overflow<quanta::electro::kilowatts, Digits...>();
1499}
1500
1502template<char... Digits>
1503constexpr quanta::electro::megawatts operator""_MW() {
1504 return detail::check_overflow<quanta::electro::megawatts, Digits...>();
1505}
1506
1508template<char... Digits>
1509constexpr quanta::electro::coulombs operator""_C() {
1510 return detail::check_overflow<quanta::electro::coulombs, Digits...>();
1511}
1512
1514template<char... Digits>
1516 return detail::check_overflow<quanta::electro::milliampere_hours, Digits...>();
1517}
1518
1520template<char... Digits>
1521constexpr quanta::electro::ampere_hours operator""_Ah() {
1522 return detail::check_overflow<quanta::electro::ampere_hours, Digits...>();
1523}
1524
1526template<char... Digits>
1527constexpr quanta::electro::millijoules operator""_mJ() {
1528 return detail::check_overflow<quanta::electro::millijoules, Digits...>();
1529}
1530
1532template<char... Digits>
1533constexpr quanta::electro::joules operator""_J() {
1534 return detail::check_overflow<quanta::electro::joules, Digits...>();
1535}
1536
1538template<char... Digits>
1539constexpr quanta::electro::kilojoules operator""_kJ() {
1540 return detail::check_overflow<quanta::electro::kilojoules, Digits...>();
1541}
1542
1544template<char... Digits>
1545constexpr quanta::electro::watt_hours operator""_Wh() {
1546 return detail::check_overflow<quanta::electro::watt_hours, Digits...>();
1547}
1548
1550template<char... Digits>
1552 return detail::check_overflow<quanta::electro::kilowatt_hours, Digits...>();
1553}
1554
1556template<char... Digits>
1557constexpr quanta::electro::picofarads operator""_pF() {
1558 return detail::check_overflow<quanta::electro::picofarads, Digits...>();
1559}
1560
1562template<char... Digits>
1563constexpr quanta::electro::nanofarads operator""_nF() {
1564 return detail::check_overflow<quanta::electro::nanofarads, Digits...>();
1565}
1566
1568template<char... Digits>
1569constexpr quanta::electro::microfarads operator""_uF() {
1570 return detail::check_overflow<quanta::electro::microfarads, Digits...>();
1571}
1572
1574template<char... Digits>
1575constexpr quanta::electro::farads operator""_F() {
1576 return detail::check_overflow<quanta::electro::farads, Digits...>();
1577}
1578
1580template<char... Digits>
1581constexpr quanta::electro::nanohenries operator""_nH() {
1582 return detail::check_overflow<quanta::electro::nanohenries, Digits...>();
1583}
1584
1586template<char... Digits>
1587constexpr quanta::electro::microhenries operator""_uH() {
1588 return detail::check_overflow<quanta::electro::microhenries, Digits...>();
1589}
1590
1592template<char... Digits>
1593constexpr quanta::electro::millihenries operator""_mH() {
1594 return detail::check_overflow<quanta::electro::millihenries, Digits...>();
1595}
1596
1598template<char... Digits>
1599constexpr quanta::electro::henries operator""_H() {
1600 return detail::check_overflow<quanta::electro::henries, Digits...>();
1601}
1602
1603} // namespace electro_literals
1604} // namespace literals
1605
1606namespace electro {
1607using namespace literals::electro_literals;
1608} // namespace electro
1609} // namespace quanta
A quantity of an electrical unit with a representation and precision.
Definition electro.hpp:245
constexpr quantity operator--(int)
Definition electro.hpp:346
static constexpr quantity zero() noexcept
Returns a zero quantity.
Definition electro.hpp:383
static constexpr quantity min() noexcept
Returns the minimum representable quantity.
Definition electro.hpp:386
constexpr quantity operator++(int)
Definition electro.hpp:339
Rep rep
The representation type.
Definition electro.hpp:254
constexpr quantity(const Rep2 &r)
Constructs from a tick count.
Definition electro.hpp:273
constexpr quantity & operator%=(const quantity &q)
Definition electro.hpp:375
static constexpr quantity max() noexcept
Returns the maximum representable quantity.
Definition electro.hpp:389
typename Precision::type precision
The precision as a std::ratio.
Definition electro.hpp:256
constexpr quantity & operator--()
Definition electro.hpp:341
constexpr quantity< Unit, typename std::common_type< rep >::type, precision > operator+() const
Definition electro.hpp:326
constexpr quantity< Unit, typename std::common_type< rep >::type, precision > operator-() const
Definition electro.hpp:330
quantity & operator=(const quantity &)=default
constexpr quantity()=default
Constructs a zero quantity.
quantity(const quantity &)=default
constexpr rep count() const
Returns the tick count.
Definition electro.hpp:324
constexpr quantity & operator*=(const rep &r)
Definition electro.hpp:358
constexpr quantity & operator-=(const quantity &q)
Definition electro.hpp:353
constexpr quantity & operator/=(const rep &r)
Definition electro.hpp:363
Unit unit
The unit tag type.
Definition electro.hpp:252
constexpr quantity & operator%=(const rep &r)
Definition electro.hpp:368
constexpr quantity & operator+=(const quantity &q)
Definition electro.hpp:348
constexpr quantity(const quantity< Unit, Rep2, Precision2 > &q)
Constructs from another quantity of the same unit with different representation or precision.
Definition electro.hpp:294
constexpr quantity(const quantity< Unit, Rep2, Precision2 > &q)
Explicit constructor for lossy conversions.
Definition electro.hpp:317
constexpr quantity & operator++()
Definition electro.hpp:334
Configuration, traits and internals shared by every quanta domain.
quantity< joule_unit, Rep, Precision > energy
Energy quantity with configurable representation and precision.
Definition electro.hpp:908
capacitance< int64_t, std::nano > nanofarads
Capacitance with 1 nF precision.
Definition electro.hpp:991
microamperes microamps
Shorthand for microamperes.
Definition electro.hpp:934
power< int64_t, std::giga > gigawatts
Power with 1 GW precision.
Definition electro.hpp:962
power< int64_t, std::mega > megawatts
Power with 1 MW precision.
Definition electro.hpp:960
capacitance< int64_t, std::pico > picofarads
Capacitance with 1 pF precision.
Definition electro.hpp:989
quantity< coulomb_unit, Rep, Precision > charge
Charge quantity with configurable representation and precision.
Definition electro.hpp:904
energy< int64_t, std::ratio< 3600 > > watt_hours
Energy with 1 Wh (3600 J) precision.
Definition electro.hpp:984
inductance< int64_t, std::nano > nanohenries
Inductance with 1 nH precision.
Definition electro.hpp:1000
power< int64_t, std::kilo > kilowatts
Power with 1 kW precision.
Definition electro.hpp:958
quantity< henry_unit, Rep, Precision > inductance
Inductance quantity with configurable representation and precision.
Definition electro.hpp:916
energy< int64_t, std::milli > millijoules
Energy with 1 mJ precision.
Definition electro.hpp:976
voltage< int64_t > volts
Voltage with 1 V precision.
Definition electro.hpp:923
amperes amps
Shorthand for amperes.
Definition electro.hpp:938
charge< int64_t, std::milli > millicoulombs
Charge with 1 mC precision.
Definition electro.hpp:967
quantity< volt_unit, Rep, Precision > voltage
Voltage quantity with configurable representation and precision.
Definition electro.hpp:888
power< int64_t > watts
Power with 1 W precision.
Definition electro.hpp:956
power< int64_t, std::milli > milliwatts
Power with 1 mW precision.
Definition electro.hpp:954
energy< int64_t > joules
Energy with 1 J precision.
Definition electro.hpp:978
quantity< ohm_unit, Rep, Precision > resistance
Resistance quantity with configurable representation and precision.
Definition electro.hpp:896
voltage< int64_t, std::micro > microvolts
Voltage with 1 µV precision.
Definition electro.hpp:919
current< int64_t, std::milli > milliamperes
Current with 1 mA precision.
Definition electro.hpp:930
capacitance< int64_t, std::micro > microfarads
Capacitance with 1 µF precision.
Definition electro.hpp:993
inductance< int64_t, std::milli > millihenries
Inductance with 1 mH precision.
Definition electro.hpp:1004
quantity< farad_unit, Rep, Precision > capacitance
Capacitance quantity with configurable representation and precision.
Definition electro.hpp:912
energy< int64_t, std::mega > megajoules
Energy with 1 MJ precision.
Definition electro.hpp:982
charge< int64_t, std::ratio< 18, 5 > > milliampere_hours
Charge with 1 mAh (3.6 C) precision.
Definition electro.hpp:971
charge< int64_t, std::ratio< 3600 > > ampere_hours
Charge with 1 Ah (3600 C) precision.
Definition electro.hpp:973
resistance< int64_t, std::giga > gigaohms
Resistance with 1 GΩ precision.
Definition electro.hpp:949
voltage< int64_t, std::kilo > kilovolts
Voltage with 1 kV precision.
Definition electro.hpp:925
quantity< watt_unit, Rep, Precision > power
Power quantity with configurable representation and precision.
Definition electro.hpp:900
energy< int64_t, std::kilo > kilojoules
Energy with 1 kJ precision.
Definition electro.hpp:980
current< int64_t, std::micro > microamperes
Current with 1 µA precision.
Definition electro.hpp:928
voltage< int64_t, std::milli > millivolts
Voltage with 1 mV precision.
Definition electro.hpp:921
inductance< int64_t, std::micro > microhenries
Inductance with 1 µH precision.
Definition electro.hpp:1002
resistance< int64_t, std::kilo > kiloohms
Resistance with 1 kΩ precision.
Definition electro.hpp:945
charge< int64_t, std::micro > microcoulombs
Charge with 1 µC precision.
Definition electro.hpp:965
power< int64_t, std::micro > microwatts
Power with 1 µW precision.
Definition electro.hpp:952
capacitance< int64_t, std::milli > millifarads
Capacitance with 1 mF precision.
Definition electro.hpp:995
resistance< int64_t, std::milli > milliohms
Resistance with 1 mΩ precision.
Definition electro.hpp:941
current< int64_t > amperes
Current with 1 A precision.
Definition electro.hpp:932
milliamperes milliamps
Shorthand for milliamperes.
Definition electro.hpp:936
energy< int64_t, std::ratio< 3600000 > > kilowatt_hours
Energy with 1 kWh (3,600,000 J) precision.
Definition electro.hpp:986
charge< int64_t > coulombs
Charge with 1 C precision.
Definition electro.hpp:969
capacitance< int64_t > farads
Capacitance with 1 F precision.
Definition electro.hpp:997
inductance< int64_t > henries
Inductance with 1 H precision.
Definition electro.hpp:1006
resistance< int64_t > ohms
Resistance with 1 Ω precision.
Definition electro.hpp:943
resistance< int64_t, std::mega > megaohms
Resistance with 1 MΩ precision.
Definition electro.hpp:947
quantity< ampere_unit, Rep, Precision > current
Current quantity with configurable representation and precision.
Definition electro.hpp:892
Electrical unit types and utilities.
Definition decibel.hpp:61
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 electro.hpp:554
constexpr ToLevel ceil(const level< Reference, Rep, Precision > &l)
Converts a level to the target type, rounding toward positive infinity.
Definition decibel.hpp:340
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 electro.hpp:571
constexpr bool is_quantity_v
Definition electro.hpp:121
constexpr auto operator-(const level< Reference, Rep1, Precision1 > &l, const quantity< decibel_unit, Rep2, Precision2 > &g)
Applies a loss to a level.
Definition decibel.hpp:391
constexpr ToQuantity quantity_cast(const quantity< Unit, Rep, Precision > &q)
Converts a quantity to a different precision or representation.
Definition electro.hpp:413
constexpr ToLevel round(const level< Reference, Rep, Precision > &l)
Converts a level to the target type, rounding to nearest (ties to even).
Definition decibel.hpp:358
constexpr ToLevel trunc(const level< Reference, Rep, Precision > &l)
Converts a level to the target type, rounding toward zero (as level_cast does).
Definition decibel.hpp:347
std::string to_string(const quantity< decibel_unit, Rep, Precision > &g)
Converts a gain to a string, e.g.
Definition decibel.hpp:733
constexpr quantity< Unit, Rep, Precision > abs(const quantity< Unit, Rep, Precision > &q)
Returns the absolute value of a quantity.
Definition electro.hpp:527
constexpr auto operator<=>(const level< Reference, Rep1, Precision1 > &a, const level< Reference, Rep2, Precision2 > &b)
Definition decibel.hpp:416
constexpr bool operator==(const level< Reference, Rep1, Precision1 > &a, const level< Reference, Rep2, Precision2 > &b)
Definition decibel.hpp:410
constexpr auto operator+(const level< Reference, Rep1, Precision1 > &l, const quantity< decibel_unit, Rep2, Precision2 > &g)
Applies a gain to a level.
Definition decibel.hpp:375
constexpr ToLevel floor(const level< Reference, Rep, Precision > &l)
Converts a level to the target type, rounding toward negative infinity.
Definition decibel.hpp:329
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
Electric current, measured in amperes.
Definition electro.hpp:179
static constexpr const char * symbol
Definition electro.hpp:180
Electric charge, measured in coulombs.
Definition electro.hpp:194
static constexpr const char * symbol
Definition electro.hpp:195
Capacitance, measured in farads.
Definition electro.hpp:204
static constexpr const char * symbol
Definition electro.hpp:205
Inductance, measured in henries.
Definition electro.hpp:209
static constexpr const char * symbol
Definition electro.hpp:210
Trait to detect quantity specializations.
Definition electro.hpp:115
Energy, measured in joules.
Definition electro.hpp:199
static constexpr const char * symbol
Definition electro.hpp:200
Electrical resistance, measured in ohms.
Definition electro.hpp:184
static constexpr const char * symbol
Definition electro.hpp:185
Trait giving the display suffix for a (unit, precision) pair.
Definition electro.hpp:1087
static std::string value()
Returns the display suffix.
Definition electro.hpp:1089
Provides special values for quantity representations.
Definition electro.hpp:150
static constexpr Rep max() noexcept
Returns the maximum representable quantity.
Definition electro.hpp:155
static constexpr Rep zero() noexcept
Returns a zero quantity.
Definition electro.hpp:152
static constexpr Rep min() noexcept
Returns the minimum representable quantity.
Definition electro.hpp:158
Trait giving the display symbol for an SI precision prefix.
Definition electro.hpp:1021
Voltage, measured in volts.
Definition electro.hpp:174
static constexpr const char * symbol
Definition electro.hpp:175
Power, measured in watts.
Definition electro.hpp:189
static constexpr const char * symbol
Definition electro.hpp:190
Tag type selecting the scaled form, see scaled.
Definition core.hpp:145
Trait to indicate floating-point-like behavior.
Definition core.hpp:116
quanta::electro::quantity< Unit, std::common_type_t< Rep1, Rep2 >, common_precision > type
Definition electro.hpp:1337