electro 0.4.1
Type-safe electrical units library modeled after std::chrono
Loading...
Searching...
No Matches
electro.hpp
Go to the documentation of this file.
1#pragma once
2
8#include <charconv>
9#include <chrono>
10#include <cmath>
11#include <compare>
12#include <concepts>
13#include <cstddef>
14#include <cstdint>
15#include <limits>
16#include <ratio>
17#include <string>
18#include <system_error>
19#include <type_traits>
20#include <version> // pulls in __cpp_lib_format so the detection below works in non-IDF builds
21#ifndef CONFIG_ELECTRO_STD_FORMAT
22#if __has_include(<format>) && defined(__cpp_lib_format)
23#define CONFIG_ELECTRO_STD_FORMAT 1
24#else
25#define CONFIG_ELECTRO_STD_FORMAT 0
26#endif
27#endif
28
29#if CONFIG_ELECTRO_STD_FORMAT
30#include <format>
31#endif
32#include <assert.h>
33
42#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 14
43#define ELECTRO_HAS_UTF8_LITERALS 1
44#else
45#define ELECTRO_HAS_UTF8_LITERALS 0
46#endif
47
126namespace electro {
127
128template<typename Unit, typename Rep, typename Precision = std::ratio<1>>
129class quantity;
130
135template<typename T>
136struct is_quantity : std::false_type {};
137
138template<typename Unit, typename Rep, typename Precision>
139struct is_quantity<quantity<Unit, Rep, Precision>> : std::true_type {};
140
141template<typename T>
142inline constexpr bool is_quantity_v = is_quantity<T>::value;
143
145template<typename Rep>
147
148template<typename T>
149struct _is_chrono_duration : std::false_type {};
150
151template<typename Rep, typename Period>
152struct _is_chrono_duration<std::chrono::duration<Rep, Period>> : std::true_type {};
153
162template<typename T>
170template<typename Rep>
173 static constexpr Rep zero() noexcept { return Rep(0); }
174
176 static constexpr Rep max() noexcept { return std::numeric_limits<Rep>::max(); }
177
179 static constexpr Rep min() noexcept { return std::numeric_limits<Rep>::lowest(); }
180};
181
182template<typename T>
183struct _is_ratio : std::false_type {};
184
185template<std::intmax_t Num, std::intmax_t Denom>
186struct _is_ratio<std::ratio<Num, Denom>> : std::true_type {};
187
196template<typename T>
197struct treat_as_inexact : std::bool_constant<std::floating_point<T>> {};
198
199template<typename T>
201
203consteval intmax_t _gcd(intmax_t m, intmax_t n) noexcept {
204 while (n != 0) {
205 intmax_t rem = m % n;
206 m = n;
207 n = rem;
208 }
209 return m;
210}
211
212// Runtime GCD for integer types (using Euclidean algorithm)
213template<typename T>
214constexpr T _runtime_gcd(T m, T n) noexcept {
215 if (m < 0) {
216 m = -m;
217 }
218 if (n < 0) {
219 n = -n;
220 }
221 while (n != 0) {
222 T rem = m % n;
223 m = n;
224 n = rem;
225 }
226 return m;
227}
228
229template<typename R1, typename R2>
230inline constexpr intmax_t _safe_ratio_divide_den = [] {
231 constexpr intmax_t g1 = _gcd(R1::num, R2::num);
232 constexpr intmax_t g2 = _gcd(R1::den, R2::den);
233 return (R1::den / g2) * (R2::num / g1);
234}();
235
236template<typename From, typename To>
240// ============================================================================
241// Units
242// ============================================================================
243
253struct volt_unit {
254 static constexpr const char* symbol = "V";
255};
256
259 static constexpr const char* symbol = "A";
260};
261
263struct ohm_unit {
264 static constexpr const char* symbol = "Ω";
265};
266
268struct watt_unit {
269 static constexpr const char* symbol = "W";
270};
271
274 static constexpr const char* symbol = "C";
275};
276
279 static constexpr const char* symbol = "J";
280};
281
284 static constexpr const char* symbol = "F";
285};
286
289 static constexpr const char* symbol = "H";
290};
291
// end of Units group
293
323template<typename Unit, typename Rep, typename Precision>
324class quantity {
325 static_assert(!is_quantity_v<Rep>, "rep cannot be an electro::quantity");
326 static_assert(_is_ratio<Precision>::value, "precision must be a specialization of std::ratio");
327 static_assert(Precision::num > 0, "precision must be positive");
328
329public:
331 using unit = Unit;
333 using rep = Rep;
335 using precision = typename Precision::type;
336
338 constexpr quantity() = default;
339 quantity(const quantity&) = default;
340
350 template<typename Rep2>
351 requires std::convertible_to<const Rep2&, rep> && (treat_as_inexact_v<rep> || !treat_as_inexact_v<Rep2>)
352 constexpr explicit quantity(const Rep2& r)
353 : _r(static_cast<rep>(r)) {}
354
366 template<typename Rep2, typename Precision2>
367 requires std::convertible_to<const Rep2&, rep> &&
371
379 template<typename Rep2, typename Precision2>
380 requires(!std::is_same_v<quantity, quantity<Unit, Rep2, Precision2>>) && (!treat_as_inexact_v<rep>) &&
382 constexpr explicit quantity(const quantity<Unit, Rep2, Precision2>& q)
384
385 ~quantity() = default;
386 quantity& operator=(const quantity&) = default;
387
389 constexpr rep count() const { return _r; }
390
394
398
399 constexpr quantity& operator++() {
400 ++_r;
401 return *this;
402 }
403
404 constexpr quantity operator++(int) { return quantity(_r++); }
405
406 constexpr quantity& operator--() {
407 --_r;
408 return *this;
409 }
410
411 constexpr quantity operator--(int) { return quantity(_r--); }
412
413 constexpr quantity& operator+=(const quantity& q) {
414 _r += q.count();
415 return *this;
416 }
417
418 constexpr quantity& operator-=(const quantity& q) {
419 _r -= q.count();
420 return *this;
421 }
422
423 constexpr quantity& operator*=(const rep& r) {
424 _r *= r;
425 return *this;
426 }
427
428 constexpr quantity& operator/=(const rep& r) {
429 _r /= r;
430 return *this;
431 }
432
433 constexpr quantity& operator%=(const rep& r)
434 requires(!treat_as_inexact_v<rep>)
435 {
436 _r %= r;
437 return *this;
438 }
439
440 constexpr quantity& operator%=(const quantity& q)
441 requires(!treat_as_inexact_v<rep>)
442 {
443 _r %= q.count();
444 return *this;
445 }
446
448 static constexpr quantity zero() noexcept { return quantity(quantity_values<rep>::zero()); }
449
451 static constexpr quantity min() noexcept { return quantity(quantity_values<rep>::min()); }
452
454 static constexpr quantity max() noexcept { return quantity(quantity_values<rep>::max()); }
455
456private:
457 rep _r{};
458};
459
475template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
477 static_assert(
478 std::is_same_v<typename ToQuantity::unit, Unit>, "quantity_cast cannot convert between different units"
479 );
480 if constexpr (std::is_same_v<ToQuantity, quantity<Unit, Rep, Precision>>) {
481 return q;
482 } else {
483 using to_rep = typename ToQuantity::rep;
484 using to_precision = typename ToQuantity::precision;
485 using cf = std::ratio_divide<Precision, to_precision>;
486
487 // Use wider intermediate type for integer-to-integer conversions
488 if constexpr (std::is_integral_v<Rep> && std::is_integral_v<to_rep>) {
489#ifdef __SIZEOF_INT128__
490 using cr = std::common_type_t<to_rep, Rep, intmax_t>;
491 using wider_t = std::conditional_t<std::is_signed_v<cr>, __int128, unsigned __int128>;
492#else
493 using wider_t = intmax_t;
494#endif
495
496 if constexpr (cf::den == 1 && cf::num == 1) {
497 return ToQuantity(static_cast<to_rep>(q.count()));
498 } else if constexpr (cf::den == 1) {
499 wider_t result = static_cast<wider_t>(q.count()) * static_cast<wider_t>(cf::num);
500 return ToQuantity(static_cast<to_rep>(result));
501 } else if constexpr (cf::num == 1) {
502 wider_t result = static_cast<wider_t>(q.count()) / static_cast<wider_t>(cf::den);
503 return ToQuantity(static_cast<to_rep>(result));
504 } else {
505 // Use GCD to reduce operands: count * num / den
506 wider_t count = static_cast<wider_t>(q.count());
507 wider_t den = static_cast<wider_t>(cf::den);
508 wider_t g = _runtime_gcd(count, den);
509 wider_t reduced_count = count / g;
511 wider_t result = reduced_count * static_cast<wider_t>(cf::num) / reduced_den;
512 return ToQuantity(static_cast<to_rep>(result));
513 }
514 } else {
515 // Floating-point path
516 using cr = std::common_type_t<to_rep, Rep, intmax_t>;
517 if constexpr (cf::den == 1 && cf::num == 1) {
518 return ToQuantity(static_cast<to_rep>(q.count()));
519 } else if constexpr (cf::den == 1) {
520 return ToQuantity(static_cast<to_rep>(static_cast<cr>(q.count()) * static_cast<cr>(cf::num)));
521 } else if constexpr (cf::num == 1) {
522 return ToQuantity(static_cast<to_rep>(static_cast<cr>(q.count()) / static_cast<cr>(cf::den)));
523 } else {
524 return ToQuantity(
525 static_cast<to_rep>(
526 static_cast<cr>(q.count()) * static_cast<cr>(cf::num) / static_cast<cr>(cf::den)
527 )
528 );
529 }
530 }
531 }
532}
533
551template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
553 using to_rep = typename ToQuantity::rep;
555
556 if constexpr (std::is_integral_v<Rep> && std::is_integral_v<to_rep>) {
557 if (result > q) {
558 return ToQuantity(result.count() - to_rep(1));
559 }
560 }
561
562 return result;
563}
564
582template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
584 using to_rep = typename ToQuantity::rep;
586
587 if constexpr (std::is_integral_v<Rep> && std::is_integral_v<to_rep>) {
588 if (result < q) {
589 return ToQuantity(result.count() + to_rep(1));
590 }
591 }
592
593 return result;
594}
595
613template<typename ToQuantity, typename Unit, typename Rep, typename Precision>
615 using to_rep = typename ToQuantity::rep;
616
617 if constexpr (std::is_integral_v<Rep> && std::is_integral_v<to_rep>) {
620
621 auto diff_lower = q - lower;
622 auto diff_upper = upper - q;
623
624 if (diff_lower < diff_upper) {
625 return lower;
626 } else if (diff_lower > diff_upper) {
627 return upper;
628 } else {
629 // Tie: round to even
630 return (lower.count() % to_rep(2) == to_rep(0)) ? lower : upper;
631 }
632 } else {
634 }
635}
636
647template<typename Unit, typename Rep, typename Precision>
651
652// ============================================================================
653// Same-unit arithmetic
654// ============================================================================
655
657template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
659 -> std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>> {
660 using cq = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
661 return cq(cq(lhs).count() + cq(rhs).count());
662}
663
665template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
667 -> std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>> {
668 using cq = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
669 return cq(cq(lhs).count() - cq(rhs).count());
670}
671
673template<typename Unit, typename Rep1, typename Precision, typename Rep2>
674 requires not_quantity<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>>
680
682template<typename Unit, typename Rep1, typename Rep2, typename Precision>
683 requires not_quantity<Rep1> && std::convertible_to<const Rep1&, std::common_type_t<Rep1, Rep2>>
688
690template<typename Unit, typename Rep1, typename Precision, typename Rep2>
691 requires not_quantity<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>>
697
699template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
701 -> std::common_type_t<Rep1, Rep2> {
702 using cq = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
703 return cq(lhs).count() / cq(rhs).count();
704}
705
707template<typename Unit, typename Rep1, typename Precision, typename Rep2>
708 requires not_quantity<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>> &&
710constexpr auto operator%(const quantity<Unit, Rep1, Precision>& q, const Rep2& s)
713 return cq(cq(q).count() % s);
714}
715
717template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
720 -> std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>> {
721 using cq = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
722 return cq(cq(lhs).count() % cq(rhs).count());
723}
724
725template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
727 using ct = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
728 return ct(lhs).count() == ct(rhs).count();
729}
730
731template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
732 requires std::three_way_comparable<std::common_type_t<Rep1, Rep2>>
734 using ct = std::common_type_t<quantity<Unit, Rep1, Precision1>, quantity<Unit, Rep2, Precision2>>;
735 return ct(lhs).count() <=> ct(rhs).count();
736}
737
738// ============================================================================
739// Cross-unit arithmetic
740// ============================================================================
741
743// Product of two quantities, in the given result unit. Counts multiply and
744// precisions multiply, so no conversion factor is needed and the result is
745// exact for integer representations.
746template<typename ToUnit, typename U1, typename R1, typename P1, typename U2, typename R2, typename P2>
747constexpr auto _product(const quantity<U1, R1, P1>& lhs, const quantity<U2, R2, P2>& rhs) {
748 using cr = std::common_type_t<R1, R2>;
750 return result_t(static_cast<cr>(lhs.count()) * static_cast<cr>(rhs.count()));
751}
752
753// Quotient of two quantities, in the given result unit. Counts divide and
754// precisions divide; for integer representations the count division truncates.
755template<typename ToUnit, typename U1, typename R1, typename P1, typename U2, typename R2, typename P2>
756constexpr auto _quotient(const quantity<U1, R1, P1>& lhs, const quantity<U2, R2, P2>& rhs) {
757 using cr = std::common_type_t<R1, R2>;
759 return result_t(static_cast<cr>(lhs.count()) / static_cast<cr>(rhs.count()));
760}
761
762// Product of a quantity and a duration, in the given result unit.
763template<typename ToUnit, typename U1, typename R1, typename P1, duration_like D>
764constexpr auto _duration_product(const quantity<U1, R1, P1>& lhs, const D& rhs) {
765 using cr = std::common_type_t<R1, typename D::rep>;
767 return result_t(static_cast<cr>(lhs.count()) * static_cast<cr>(rhs.count()));
768}
769
770// Quotient of a quantity and a duration, in the given result unit.
771template<typename ToUnit, typename U1, typename R1, typename P1, duration_like D>
772constexpr auto _duration_quotient(const quantity<U1, R1, P1>& lhs, const D& rhs) {
773 using cr = std::common_type_t<R1, typename D::rep>;
775 return result_t(static_cast<cr>(lhs.count()) / static_cast<cr>(rhs.count()));
776}
777
778// Quotient of two quantities yielding a std::chrono::duration.
779template<typename U1, typename R1, typename P1, typename U2, typename R2, typename P2>
781 using cr = std::common_type_t<R1, R2>;
782 using result_t = std::chrono::duration<cr, std::ratio_divide<P1, P2>>;
783 return result_t(static_cast<cr>(lhs.count()) / static_cast<cr>(rhs.count()));
784}
785
786// Product of two quantities yielding a std::chrono::duration.
787template<typename U1, typename R1, typename P1, typename U2, typename R2, typename P2>
789 using cr = std::common_type_t<R1, R2>;
790 using result_t = std::chrono::duration<cr, std::ratio_multiply<P1, P2>>;
791 return result_t(static_cast<cr>(lhs.count()) * static_cast<cr>(rhs.count()));
792}
807template<typename R1, typename P1, typename R2, typename P2>
811
813template<typename R1, typename P1, typename R2, typename P2>
817
819template<typename R1, typename P1, typename R2, typename P2>
823
825template<typename R1, typename P1, typename R2, typename P2>
829
831template<typename R1, typename P1, typename R2, typename P2>
835
837template<typename R1, typename P1, typename R2, typename P2>
841
843template<typename R1, typename P1, typename R2, typename P2>
847
849template<typename R1, typename P1, typename R2, typename P2>
853
861template<typename R1, typename P1, duration_like D>
862constexpr auto operator*(const quantity<ampere_unit, R1, P1>& i, const D& t) {
864}
865
867template<duration_like D, typename R1, typename P1>
868constexpr auto operator*(const D& t, const quantity<ampere_unit, R1, P1>& i) {
870}
871
873template<typename R1, typename P1, duration_like D>
874constexpr auto operator/(const quantity<coulomb_unit, R1, P1>& q, const D& t) {
876}
877
885template<typename R1, typename P1, typename R2, typename P2>
889
897template<typename R1, typename P1, duration_like D>
898constexpr auto operator*(const quantity<watt_unit, R1, P1>& p, const D& t) {
900}
901
903template<duration_like D, typename R1, typename P1>
904constexpr auto operator*(const D& t, const quantity<watt_unit, R1, P1>& p) {
906}
907
909template<typename R1, typename P1, duration_like D>
910constexpr auto operator/(const quantity<joule_unit, R1, P1>& e, const D& t) {
912}
913
915template<typename R1, typename P1, typename R2, typename P2>
917 return _quotient_duration(e, p);
918}
919
927template<typename R1, typename P1, typename R2, typename P2>
931
933template<typename R1, typename P1, typename R2, typename P2>
937
939template<typename R1, typename P1, typename R2, typename P2>
943
945template<typename R1, typename P1, typename R2, typename P2>
949
951template<typename R1, typename P1, typename R2, typename P2>
955
957template<typename R1, typename P1, typename R2, typename P2>
961
969template<typename R1, typename P1, typename R2, typename P2>
971 return _product_duration(r, c);
972}
973
975template<typename R1, typename P1, typename R2, typename P2>
977 return _product_duration(c, r);
978}
979
987template<typename R1, typename P1, typename R2, typename P2>
989 return _quotient_duration(l, r);
990}
991
// end of CrossUnit group
993
994// ============================================================================
995// Type aliases
996// ============================================================================
997
1008template<typename Rep, typename Precision = std::ratio<1>>
1010
1012template<typename Rep, typename Precision = std::ratio<1>>
1014
1016template<typename Rep, typename Precision = std::ratio<1>>
1018
1020template<typename Rep, typename Precision = std::ratio<1>>
1022
1024template<typename Rep, typename Precision = std::ratio<1>>
1026
1028template<typename Rep, typename Precision = std::ratio<1>>
1030
1032template<typename Rep, typename Precision = std::ratio<1>>
1034
1036template<typename Rep, typename Precision = std::ratio<1>>
1038
1047
1060
1071
1084
1095
1108
1119
1128
// end of QuantityTypes group
1130
1131// ============================================================================
1132// String conversion and formatting
1133// ============================================================================
1134
1141template<typename Precision>
1143
1145template<>
1146struct si_prefix<std::femto> {
1147 static constexpr const char* symbol = "f";
1148};
1149
1150template<>
1151struct si_prefix<std::pico> {
1152 static constexpr const char* symbol = "p";
1153};
1154
1155template<>
1156struct si_prefix<std::nano> {
1157 static constexpr const char* symbol = "n";
1158};
1159
1160template<>
1161struct si_prefix<std::micro> {
1162 static constexpr const char* symbol = "µ";
1163};
1164
1165template<>
1166struct si_prefix<std::milli> {
1167 static constexpr const char* symbol = "m";
1168};
1169
1170template<>
1171struct si_prefix<std::ratio<1>> {
1172 static constexpr const char* symbol = "";
1173};
1174
1175template<>
1176struct si_prefix<std::kilo> {
1177 static constexpr const char* symbol = "k";
1178};
1179
1180template<>
1181struct si_prefix<std::mega> {
1182 static constexpr const char* symbol = "M";
1183};
1184
1185template<>
1186struct si_prefix<std::giga> {
1187 static constexpr const char* symbol = "G";
1188};
1189
1190template<>
1191struct si_prefix<std::tera> {
1192 static constexpr const char* symbol = "T";
1193};
1207template<typename Unit, typename Precision>
1210 static std::string value()
1211 requires requires { si_prefix<Precision>::symbol; }
1212 {
1213 return std::string(si_prefix<Precision>::symbol) + Unit::symbol;
1214 }
1215};
1216
1218template<>
1219struct quantity_suffix<coulomb_unit, std::ratio<18, 5>> {
1220 static std::string value() { return "mAh"; }
1221};
1222
1223template<>
1224struct quantity_suffix<coulomb_unit, std::ratio<3600>> {
1225 static std::string value() { return "Ah"; }
1226};
1227
1228template<>
1229struct quantity_suffix<joule_unit, std::ratio<3600>> {
1230 static std::string value() { return "Wh"; }
1231};
1232
1233template<>
1234struct quantity_suffix<joule_unit, std::ratio<3600000>> {
1235 static std::string value() { return "kWh"; }
1236};
1237
1238template<typename Unit, typename Precision>
1240
1241// The unit the base-unit form (the `b` format marker, to_string(q,
1242// base_unit)) renders in, as `scale`-sized units labeled `suffix`. SI-prefixed
1243// precisions render in the unprefixed unit ("3.3V"); the hour-based charge and
1244// energy precisions render in Ah and Wh ("0.2Ah", never "720C").
1245template<typename Unit, typename Precision>
1246struct _base_display_unit {
1247 using scale = std::ratio<1>;
1248 static constexpr const char* suffix = Unit::symbol;
1249};
1250
1252 using scale = std::ratio<3600>;
1253 static constexpr const char* suffix = "Ah";
1254};
1255
1257 using scale = std::ratio<3600>;
1258 static constexpr const char* suffix = "Wh";
1259};
1260
1261template<>
1262struct _base_display_unit<coulomb_unit, std::ratio<18, 5>> : _ampere_hour_display_unit {};
1263
1264template<>
1265struct _base_display_unit<coulomb_unit, std::ratio<3600>> : _ampere_hour_display_unit {};
1266
1267template<>
1268struct _base_display_unit<joule_unit, std::ratio<3600>> : _watt_hour_display_unit {};
1269
1270template<>
1271struct _base_display_unit<joule_unit, std::ratio<3600000>> : _watt_hour_display_unit {};
1272
1273// A value and suffix to display, for the base-unit and scaled forms.
1274struct _display {
1275 double value;
1276 std::string suffix;
1277};
1278
1279// The quantity in its base unit (see _base_display_unit), as a double.
1280template<typename Unit, typename Rep, typename Precision>
1283 // display units per count
1284 using upc = typename std::ratio_divide<typename Precision::type, typename display::scale>::type;
1285 double v = static_cast<double>(q.count());
1286 if constexpr (upc::num != 1) {
1287 v *= static_cast<double>(upc::num);
1288 }
1289 if constexpr (upc::den != 1) {
1290 v /= static_cast<double>(upc::den);
1291 }
1292 return {v, display::suffix};
1293}
1294
1295consteval bool _is_power_of_ten(intmax_t n) {
1296 while (n >= 10 && n % 10 == 0) {
1297 n /= 10;
1298 }
1299 return n == 1;
1300}
1301
1302consteval int _log10(intmax_t n) {
1303 int e = 0;
1304 while (n >= 10) {
1305 n /= 10;
1306 ++e;
1307 }
1308 return e;
1309}
1310
1311// Precisions that are SI prefixes (see si_prefix) of the unit.
1312template<typename Precision>
1313concept _si_precision =
1314 requires { si_prefix<Precision>::symbol; } && _is_power_of_ten(Precision::num) && _is_power_of_ten(Precision::den);
1315
1316template<typename Precision>
1317inline constexpr int _precision_exponent = _log10(Precision::num) - _log10(Precision::den);
1318
1319// 10^k as a double, exact for |k| <= 22.
1320constexpr double _pow10(int k) {
1321 double r = 1.0;
1322 for (int i = 0; i < (k < 0 ? -k : k); ++i) {
1323 r *= 10.0;
1324 }
1325 return r;
1326}
1327
1328// v x 10^k with a single rounding (exact power of ten for |k| <= 22).
1329constexpr double _scale_pow10(double v, int k) {
1330 return k >= 0 ? v * _pow10(k) : v / _pow10(-k);
1331}
1332
1333// The prefixes the scaled form chooses between: the si_prefix set, by
1334// power-of-ten exponent, in ascending order.
1335struct _scale_prefix {
1336 int exponent;
1337 const char* symbol;
1338};
1339
1340inline constexpr _scale_prefix _scale_prefixes[] = {
1341 {-15, si_prefix<std::femto>::symbol},
1342 {-12, si_prefix<std::pico>::symbol},
1343 {-9, si_prefix<std::nano>::symbol},
1344 {-6, si_prefix<std::micro>::symbol},
1345 {-3, si_prefix<std::milli>::symbol},
1346 {0, si_prefix<std::ratio<1>>::symbol},
1347 {3, si_prefix<std::kilo>::symbol},
1348 {6, si_prefix<std::mega>::symbol},
1349 {9, si_prefix<std::giga>::symbol},
1350 {12, si_prefix<std::tera>::symbol},
1351};
1352
1353// The quantity with the largest SI prefix for which its magnitude is at least
1354// 1, else the smallest; zero (keeping its sign) and non-finite values are
1355// shown in the unprefixed unit. Each candidate's value is computed from the
1356// count with a single scaling by a power of ten, so values that land exactly
1357// on a prefix (1000 mV) are exactly 1 in it. Precisions that are not SI
1358// prefixes (mAh, Ah, Wh, kWh) are shown in their own unit.
1359template<typename Unit, typename Rep, typename Precision>
1361 using p = typename Precision::type;
1362 const double count = static_cast<double>(q.count());
1363 if constexpr (_si_precision<p>) {
1364 if (count == 0 || !std::isfinite(count)) {
1365 return _base_unit_display(q);
1366 }
1367 constexpr std::size_t n = std::extent_v<decltype(_scale_prefixes)>;
1368 for (std::size_t i = n; i-- > 1;) {
1370 if (v >= 1.0 || v <= -1.0) {
1371 return {v, std::string(_scale_prefixes[i].symbol) + Unit::symbol};
1372 }
1373 }
1374 return {
1376 std::string(_scale_prefixes[0].symbol) + Unit::symbol
1377 };
1378 } else {
1379 return {count, quantity_suffix<Unit, p>::value()};
1380 }
1381}
1382
1383// The shortest fixed-notation representation of v that round-trips: never
1384// scientific notation, and no trailing zeros (2.5 -> "2.5", 1e6 -> "1000000",
1385// 1e-15 -> "0.000000000000001"). Used wherever a floating-point value is
1386// rendered without a format spec, so to_string and std::format agree.
1387template<std::floating_point T>
1388std::string _fixed_string(T v) {
1389 std::string s(32, '\0');
1390 for (;;) {
1391 const auto result = std::to_chars(s.data(), s.data() + s.size(), v, std::chars_format::fixed);
1392 if (result.ec == std::errc()) {
1393 s.resize(static_cast<std::size_t>(result.ptr - s.data()));
1394 return s;
1395 }
1396 s.resize(s.size() * 2);
1397 }
1398}
1399
1400// A count rendered without a format spec: integers exactly, floating-point
1401// counts in shortest round-trip fixed notation.
1402template<typename Rep>
1403std::string _count_string(const Rep& r) {
1404 if constexpr (std::floating_point<Rep>) {
1405 return _fixed_string(r);
1406 } else {
1407 return std::to_string(r);
1408 }
1409}
1410
1411// Appends a NUL-terminated string to a format output iterator.
1412template<typename OutputIt>
1413constexpr OutputIt _format_append(OutputIt out, const char* s) {
1414 for (; *s != '\0'; ++s) {
1415 *out++ = *s;
1416 }
1417 return out;
1418}
1425 explicit base_unit_t() = default;
1426};
1427
1444inline constexpr base_unit_t base_unit{};
1445
1449struct scaled_t {
1450 explicit scaled_t() = default;
1451};
1452
1471inline constexpr scaled_t scaled{};
1472
1488template<typename Unit, typename Rep, typename Precision>
1493
1504template<typename Unit, typename Rep, typename Precision>
1507 const _display d = _base_unit_display(q);
1508 return _fixed_string(d.value) + d.suffix;
1509}
1510
1521template<typename Unit, typename Rep, typename Precision>
1524 const _display d = _scaled_display(q);
1525 return _fixed_string(d.value) + d.suffix;
1526}
1527
1528} // namespace electro
1529
1530namespace std {
1531
1532template<typename Unit, typename Rep1, typename Precision1, typename Rep2, typename Precision2>
1533struct common_type<electro::quantity<Unit, Rep1, Precision1>, electro::quantity<Unit, Rep2, Precision2>> {
1534private:
1535 using common_precision = std::ratio<
1536 electro::_gcd(Precision1::num, Precision2::num),
1537 (Precision1::den / electro::_gcd(Precision1::den, Precision2::den)) * Precision2::den>;
1538
1539public:
1541};
1542
1543#if CONFIG_ELECTRO_STD_FORMAT
1544// "{}" prints the exact stored count with a precision-qualified unit
1545// (millivolts(3300) -> "3300mV"; floating-point counts in the shortest fixed
1546// notation that round-trips, as to_string does: voltage<double>(1e6) ->
1547// "1000000V", never "1e+06V"). A non-empty spec controls only how the number
1548// is rendered (as double), never the unit, so both forms use the same suffix:
1549// std::format("{:.1f}", millivolts(3300)) == "3300.0mV" and
1550// std::format("{:.1f}", milliampere_hours(200)) == "200.0mAh".
1551//
1552// The unit changes only when the spec opts in with a single leading marker
1553// letter; the rest of the spec is then handled as above:
1554// - 'b' (base unit, see electro::base_unit) shows the value in the unprefixed
1555// unit, or in Ah/Wh for the hour-based precisions:
1556// std::format("{:b.1f}", millivolts(3300)) == "3.3V".
1557// - 's' (scaled, see electro::scaled) shows the value with an SI prefix
1558// suited to its magnitude: std::format("{:s}", ohms(4700)) == "4.7kΩ".
1559// With 'b' or 's' and nothing after the marker, the value is rendered in the
1560// shortest fixed notation that round-trips (never scientific), exactly as by
1561// to_string(q, electro::base_unit) or to_string(q, electro::scaled):
1562// std::format("{:b}", millivolts(24)) == "0.024V".
1563//
1564// A spec starting with 'b' or 's' is always a marker, so these letters cannot
1565// be the fill character of a spec that starts with a fill ("{:b>8.1f}" is the
1566// marker followed by ">8.1f").
1567template<typename Unit, typename Rep, typename Precision>
1569struct formatter<electro::quantity<Unit, Rep, Precision>, char> {
1570private:
1571 enum class _unit_form { own, base, scaled };
1572
1573 std::formatter<double> _num;
1574 bool _has_spec = false;
1575 _unit_form _form = _unit_form::own;
1576
1577public:
1578 constexpr auto parse(format_parse_context& ctx) {
1579 auto it = ctx.begin();
1580 if (it != ctx.end() && (*it == 'b' || *it == 's')) {
1581 _form = *it == 'b' ? _unit_form::base : _unit_form::scaled;
1582 ctx.advance_to(++it);
1583 }
1584 if (it == ctx.end() || *it == '}') {
1585 return it;
1586 }
1587 _has_spec = true;
1588 return _num.parse(ctx);
1589 }
1590
1591 template<typename FormatContext>
1592 auto format(const electro::quantity<Unit, Rep, Precision>& q, FormatContext& ctx) const {
1593 if (_form != _unit_form::own) {
1594 const electro::_display d =
1595 _form == _unit_form::base ? electro::_base_unit_display(q) : electro::_scaled_display(q);
1596 auto out = _has_spec ? _num.format(d.value, ctx)
1597 : std::format_to(ctx.out(), "{}", electro::_fixed_string(d.value));
1598 return std::format_to(out, "{}", d.suffix);
1599 }
1601 if (_has_spec) {
1602 auto out = _num.format(static_cast<double>(q.count()), ctx);
1603 return std::format_to(out, "{}", suffix);
1604 }
1605 if constexpr (std::floating_point<Rep>) {
1606 return std::format_to(ctx.out(), "{}{}", electro::_fixed_string(q.count()), suffix);
1607 } else {
1608 return std::format_to(ctx.out(), "{}{}", q.count(), suffix);
1609 }
1610 }
1611};
1612#endif
1613
1614} // namespace std
1615
1619namespace electro_literals {
1621namespace detail {
1622
1623template<unsigned long long Value, unsigned long long Power>
1624struct pow10 {
1625 static constexpr unsigned long long value = 10 * pow10<Value, Power - 1>::value;
1626};
1627
1628template<unsigned long long Value>
1629struct pow10<Value, 0> {
1630 static constexpr unsigned long long value = Value;
1631};
1632
1633template<char... Digits>
1634struct parse_int;
1635
1636template<char D, char... Rest>
1637struct parse_int<D, Rest...> {
1638 static_assert(D >= '0' && D <= '9', "invalid digit");
1639 static constexpr unsigned long long value = pow10<D - '0', sizeof...(Rest)>::value + parse_int<Rest...>::value;
1640};
1641
1642template<char D>
1643struct parse_int<D> {
1644 static_assert(D >= '0' && D <= '9', "invalid digit");
1645 static constexpr unsigned long long value = D - '0';
1646};
1647
1648template<typename Quantity, char... Digits>
1649constexpr Quantity check_overflow() {
1650 using parsed = parse_int<Digits...>;
1651 constexpr typename Quantity::rep repval = parsed::value;
1652 static_assert(
1653 repval >= 0 && static_cast<unsigned long long>(repval) == parsed::value,
1654 "literal value cannot be represented by quantity type"
1655 );
1656 return Quantity(repval);
1657}
1658
1659} // namespace detail
1663template<char... Digits>
1664constexpr electro::microvolts operator""_uV() {
1665 return detail::check_overflow<electro::microvolts, Digits...>();
1666}
1667
1669template<char... Digits>
1670constexpr electro::millivolts operator""_mV() {
1671 return detail::check_overflow<electro::millivolts, Digits...>();
1672}
1673
1675template<char... Digits>
1676constexpr electro::volts operator""_V() {
1677 return detail::check_overflow<electro::volts, Digits...>();
1678}
1679
1681template<char... Digits>
1682constexpr electro::kilovolts operator""_kV() {
1683 return detail::check_overflow<electro::kilovolts, Digits...>();
1684}
1685
1687template<char... Digits>
1688constexpr electro::microamperes operator""_uA() {
1689 return detail::check_overflow<electro::microamperes, Digits...>();
1690}
1691
1693template<char... Digits>
1694constexpr electro::milliamperes operator""_mA() {
1695 return detail::check_overflow<electro::milliamperes, Digits...>();
1696}
1697
1699template<char... Digits>
1700constexpr electro::amperes operator""_A() {
1701 return detail::check_overflow<electro::amperes, Digits...>();
1702}
1703
1705template<char... Digits>
1706constexpr electro::milliohms operator""_mOhm() {
1707 return detail::check_overflow<electro::milliohms, Digits...>();
1708}
1709
1711template<char... Digits>
1712constexpr electro::ohms operator""_Ohm() {
1713 return detail::check_overflow<electro::ohms, Digits...>();
1714}
1715
1717template<char... Digits>
1718constexpr electro::kiloohms operator""_kOhm() {
1719 return detail::check_overflow<electro::kiloohms, Digits...>();
1720}
1721
1723template<char... Digits>
1724constexpr electro::megaohms operator""_MOhm() {
1725 return detail::check_overflow<electro::megaohms, Digits...>();
1726}
1727
1728#if ELECTRO_HAS_UTF8_LITERALS
1730template<char... Digits>
1731constexpr electro::milliohms operator""_mΩ() {
1732 return detail::check_overflow<electro::milliohms, Digits...>();
1733}
1734
1736template<char... Digits>
1737constexpr electro::ohms operator""_Ω() {
1738 return detail::check_overflow<electro::ohms, Digits...>();
1739}
1740
1742template<char... Digits>
1743constexpr electro::kiloohms operator""_kΩ() {
1744 return detail::check_overflow<electro::kiloohms, Digits...>();
1745}
1746
1748template<char... Digits>
1749constexpr electro::megaohms operator""_MΩ() {
1750 return detail::check_overflow<electro::megaohms, Digits...>();
1751}
1752#endif
1753
1755template<char... Digits>
1756constexpr electro::microwatts operator""_uW() {
1757 return detail::check_overflow<electro::microwatts, Digits...>();
1758}
1759
1761template<char... Digits>
1762constexpr electro::milliwatts operator""_mW() {
1763 return detail::check_overflow<electro::milliwatts, Digits...>();
1764}
1765
1767template<char... Digits>
1768constexpr electro::watts operator""_W() {
1769 return detail::check_overflow<electro::watts, Digits...>();
1770}
1771
1773template<char... Digits>
1774constexpr electro::kilowatts operator""_kW() {
1775 return detail::check_overflow<electro::kilowatts, Digits...>();
1776}
1777
1779template<char... Digits>
1780constexpr electro::megawatts operator""_MW() {
1781 return detail::check_overflow<electro::megawatts, Digits...>();
1782}
1783
1785template<char... Digits>
1786constexpr electro::coulombs operator""_C() {
1787 return detail::check_overflow<electro::coulombs, Digits...>();
1788}
1789
1791template<char... Digits>
1792constexpr electro::milliampere_hours operator""_mAh() {
1793 return detail::check_overflow<electro::milliampere_hours, Digits...>();
1794}
1795
1797template<char... Digits>
1798constexpr electro::ampere_hours operator""_Ah() {
1799 return detail::check_overflow<electro::ampere_hours, Digits...>();
1800}
1801
1803template<char... Digits>
1804constexpr electro::millijoules operator""_mJ() {
1805 return detail::check_overflow<electro::millijoules, Digits...>();
1806}
1807
1809template<char... Digits>
1810constexpr electro::joules operator""_J() {
1811 return detail::check_overflow<electro::joules, Digits...>();
1812}
1813
1815template<char... Digits>
1816constexpr electro::kilojoules operator""_kJ() {
1817 return detail::check_overflow<electro::kilojoules, Digits...>();
1818}
1819
1821template<char... Digits>
1822constexpr electro::watt_hours operator""_Wh() {
1823 return detail::check_overflow<electro::watt_hours, Digits...>();
1824}
1825
1827template<char... Digits>
1828constexpr electro::kilowatt_hours operator""_kWh() {
1829 return detail::check_overflow<electro::kilowatt_hours, Digits...>();
1830}
1831
1833template<char... Digits>
1834constexpr electro::picofarads operator""_pF() {
1835 return detail::check_overflow<electro::picofarads, Digits...>();
1836}
1837
1839template<char... Digits>
1840constexpr electro::nanofarads operator""_nF() {
1841 return detail::check_overflow<electro::nanofarads, Digits...>();
1842}
1843
1845template<char... Digits>
1846constexpr electro::microfarads operator""_uF() {
1847 return detail::check_overflow<electro::microfarads, Digits...>();
1848}
1849
1851template<char... Digits>
1852constexpr electro::farads operator""_F() {
1853 return detail::check_overflow<electro::farads, Digits...>();
1854}
1855
1857template<char... Digits>
1858constexpr electro::nanohenries operator""_nH() {
1859 return detail::check_overflow<electro::nanohenries, Digits...>();
1860}
1861
1863template<char... Digits>
1864constexpr electro::microhenries operator""_uH() {
1865 return detail::check_overflow<electro::microhenries, Digits...>();
1866}
1867
1869template<char... Digits>
1870constexpr electro::millihenries operator""_mH() {
1871 return detail::check_overflow<electro::millihenries, Digits...>();
1872}
1873
1875template<char... Digits>
1876constexpr electro::henries operator""_H() {
1877 return detail::check_overflow<electro::henries, Digits...>();
1878}
1879
1880} // namespace electro_literals
A quantity of an electrical unit with a representation and precision.
Definition electro.hpp:324
Unit unit
The unit tag type.
Definition electro.hpp:331
constexpr quantity operator--(int)
Definition electro.hpp:411
constexpr quantity & operator*=(const rep &r)
Definition electro.hpp:423
constexpr quantity operator++(int)
Definition electro.hpp:404
constexpr quantity & operator++()
Definition electro.hpp:399
constexpr quantity & operator+=(const quantity &q)
Definition electro.hpp:413
Rep rep
The representation type.
Definition electro.hpp:333
static constexpr quantity zero() noexcept
Returns a zero quantity.
Definition electro.hpp:448
constexpr quantity()=default
Constructs a zero quantity.
constexpr quantity & operator/=(const rep &r)
Definition electro.hpp:428
static constexpr quantity max() noexcept
Returns the maximum representable quantity.
Definition electro.hpp:454
constexpr quantity< Unit, typename std::common_type< rep >::type, precision > operator+() const
Definition electro.hpp:391
constexpr quantity & operator--()
Definition electro.hpp:406
constexpr quantity< Unit, typename std::common_type< rep >::type, precision > operator-() const
Definition electro.hpp:395
quantity & operator=(const quantity &)=default
quantity(const quantity &)=default
~quantity()=default
typename Precision::type precision
The precision as a std::ratio.
Definition electro.hpp:335
constexpr rep count() const
Returns the tick count.
Definition electro.hpp:389
constexpr quantity & operator-=(const quantity &q)
Definition electro.hpp:418
constexpr quantity & operator%=(const rep &r)
Definition electro.hpp:433
static constexpr quantity min() noexcept
Returns the minimum representable quantity.
Definition electro.hpp:451
constexpr quantity(const quantity< Unit, Rep2, Precision2 > &q)
Explicit constructor for lossy precision conversions.
Definition electro.hpp:382
constexpr quantity & operator%=(const quantity &q)
Definition electro.hpp:440
constexpr quantity(const Rep2 &r)
Constructs from a tick count.
Definition electro.hpp:352
capacitance< int64_t, std::pico > picofarads
Capacitance with 1 pF precision.
Definition electro.hpp:1110
resistance< int64_t, std::milli > milliohms
Resistance with 1 mΩ precision.
Definition electro.hpp:1062
inductance< int64_t, std::milli > millihenries
Inductance with 1 mH precision.
Definition electro.hpp:1125
capacitance< int64_t > farads
Capacitance with 1 F precision.
Definition electro.hpp:1118
capacitance< int64_t, std::nano > nanofarads
Capacitance with 1 nF precision.
Definition electro.hpp:1112
energy< int64_t, std::ratio< 3600000 > > kilowatt_hours
Energy with 1 kWh (3,600,000 J) precision.
Definition electro.hpp:1107
power< int64_t, std::mega > megawatts
Power with 1 MW precision.
Definition electro.hpp:1081
inductance< int64_t, std::micro > microhenries
Inductance with 1 µH precision.
Definition electro.hpp:1123
charge< int64_t, std::ratio< 18, 5 > > milliampere_hours
Charge with 1 mAh (3.6 C) precision.
Definition electro.hpp:1092
voltage< int64_t, std::milli > millivolts
Voltage with 1 mV precision.
Definition electro.hpp:1042
energy< int64_t, std::kilo > kilojoules
Energy with 1 kJ precision.
Definition electro.hpp:1101
power< int64_t > watts
Power with 1 W precision.
Definition electro.hpp:1077
energy< int64_t, std::milli > millijoules
Energy with 1 mJ precision.
Definition electro.hpp:1097
voltage< int64_t, std::kilo > kilovolts
Voltage with 1 kV precision.
Definition electro.hpp:1046
capacitance< int64_t, std::micro > microfarads
Capacitance with 1 µF precision.
Definition electro.hpp:1114
current< int64_t, std::milli > milliamperes
Current with 1 mA precision.
Definition electro.hpp:1051
current< int64_t > amperes
Current with 1 A precision.
Definition electro.hpp:1053
resistance< int64_t > ohms
Resistance with 1 Ω precision.
Definition electro.hpp:1064
voltage< int64_t, std::micro > microvolts
Voltage with 1 µV precision.
Definition electro.hpp:1040
inductance< int64_t, std::nano > nanohenries
Inductance with 1 nH precision.
Definition electro.hpp:1121
voltage< int64_t > volts
Voltage with 1 V precision.
Definition electro.hpp:1044
charge< int64_t > coulombs
Charge with 1 C precision.
Definition electro.hpp:1090
power< int64_t, std::kilo > kilowatts
Power with 1 kW precision.
Definition electro.hpp:1079
inductance< int64_t > henries
Inductance with 1 H precision.
Definition electro.hpp:1127
energy< int64_t, std::ratio< 3600 > > watt_hours
Energy with 1 Wh (3600 J) precision.
Definition electro.hpp:1105
current< int64_t, std::micro > microamperes
Current with 1 µA precision.
Definition electro.hpp:1049
power< int64_t, std::micro > microwatts
Power with 1 µW precision.
Definition electro.hpp:1073
resistance< int64_t, std::kilo > kiloohms
Resistance with 1 kΩ precision.
Definition electro.hpp:1066
energy< int64_t > joules
Energy with 1 J precision.
Definition electro.hpp:1099
resistance< int64_t, std::mega > megaohms
Resistance with 1 MΩ precision.
Definition electro.hpp:1068
charge< int64_t, std::ratio< 3600 > > ampere_hours
Charge with 1 Ah (3600 C) precision.
Definition electro.hpp:1094
power< int64_t, std::milli > milliwatts
Power with 1 mW precision.
Definition electro.hpp:1075
User-defined literals for electrical quantity types.
Definition decibel.hpp:834
Electrical unit types and utilities.
Definition decibel.hpp:61
constexpr quantity< Unit, Rep, Precision > abs(const quantity< Unit, Rep, Precision > &q)
Returns the absolute value of a quantity.
Definition electro.hpp:648
constexpr ToQuantity quantity_cast(const quantity< Unit, Rep, Precision > &q)
Converts a quantity to a different precision or representation.
Definition electro.hpp:476
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:353
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:369
constexpr auto operator<=>(const level< Reference, Rep1, Precision1 > &a, const level< Reference, Rep2, Precision2 > &b)
Definition decibel.hpp:394
constexpr base_unit_t base_unit
Selects the base-unit form in to_string().
Definition electro.hpp:1444
constexpr ToLevel ceil(const level< Reference, Rep, Precision > &l)
Converts a level to the target type, rounding toward positive infinity.
Definition decibel.hpp:329
constexpr scaled_t scaled
Selects the scaled (engineering) form in to_string().
Definition electro.hpp:1471
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:675
constexpr bool treat_as_inexact_v
Definition electro.hpp:200
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:336
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:692
constexpr bool is_quantity_v
Definition electro.hpp:142
constexpr ToLevel floor(const level< Reference, Rep, Precision > &l)
Converts a level to the target type, rounding toward negative infinity.
Definition decibel.hpp:322
std::string to_string(const quantity< decibel_unit, Rep, Precision > &g)
Converts a gain to a string, e.g.
Definition decibel.hpp:679
constexpr bool operator==(const level< Reference, Rep1, Precision1 > &a, const level< Reference, Rep2, Precision2 > &b)
Definition decibel.hpp:388
Electric current, measured in amperes.
Definition electro.hpp:258
static constexpr const char * symbol
Definition electro.hpp:259
Tag type selecting the base-unit form, see base_unit.
Definition electro.hpp:1424
Electric charge, measured in coulombs.
Definition electro.hpp:273
static constexpr const char * symbol
Definition electro.hpp:274
Capacitance, measured in farads.
Definition electro.hpp:283
static constexpr const char * symbol
Definition electro.hpp:284
Inductance, measured in henries.
Definition electro.hpp:288
static constexpr const char * symbol
Definition electro.hpp:289
Trait to detect quantity specializations.
Definition electro.hpp:136
Energy, measured in joules.
Definition electro.hpp:278
static constexpr const char * symbol
Definition electro.hpp:279
Electrical resistance, measured in ohms.
Definition electro.hpp:263
static constexpr const char * symbol
Definition electro.hpp:264
Trait giving the display suffix for a (unit, precision) pair.
Definition electro.hpp:1208
static std::string value()
Returns the display suffix.
Definition electro.hpp:1210
Provides special values for quantity representations.
Definition electro.hpp:171
static constexpr Rep max() noexcept
Returns the maximum representable quantity.
Definition electro.hpp:176
static constexpr Rep min() noexcept
Returns the minimum representable quantity.
Definition electro.hpp:179
static constexpr Rep zero() noexcept
Returns a zero quantity.
Definition electro.hpp:173
Tag type selecting the scaled form, see scaled.
Definition electro.hpp:1449
scaled_t()=default
Trait giving the display symbol for an SI precision prefix.
Definition electro.hpp:1142
Trait to indicate floating-point-like behavior.
Definition electro.hpp:197
Voltage, measured in volts.
Definition electro.hpp:253
static constexpr const char * symbol
Definition electro.hpp:254
Power, measured in watts.
Definition electro.hpp:268
static constexpr const char * symbol
Definition electro.hpp:269