15#ifndef CONFIG_ELECTRO_STD_FORMAT
16#if __has_include(<format>) && defined(__cpp_lib_format)
17#define CONFIG_ELECTRO_STD_FORMAT 1
19#define CONFIG_ELECTRO_STD_FORMAT 0
23#if CONFIG_ELECTRO_STD_FORMAT
91template<
typename Unit,
typename Rep,
typename Precision = std::ratio<1>>
101template<
typename Unit,
typename Rep,
typename Precision>
108template<
typename Rep>
132template<
typename Rep>
141 static constexpr Rep min()
noexcept {
return std::numeric_limits<Rep>::lowest(); }
145struct _is_ratio : std::false_type {};
147template<std::
intmax_t Num, std::
intmax_t Denom>
148struct _is_ratio<
std::
ratio<Num, Denom>> : std::true_type {};
191template<
typename R1,
typename R2>
195 return (R1::den /
g2) * (R2::num /
g1);
198template<
typename From,
typename To>
216 static constexpr const char*
symbol =
"V";
221 static constexpr const char*
symbol =
"A";
226 static constexpr const char*
symbol =
"Ω";
231 static constexpr const char*
symbol =
"W";
236 static constexpr const char*
symbol =
"C";
241 static constexpr const char*
symbol =
"J";
246 static constexpr const char*
symbol =
"F";
251 static constexpr const char*
symbol =
"H";
285template<
typename Unit,
typename Rep,
typename Precision>
288 static_assert(_is_ratio<Precision>::value,
"precision must be a specialization of std::ratio");
289 static_assert(Precision::num > 0,
"precision must be positive");
312 template<
typename Rep2>
315 : _r(
static_cast<rep>(
r)) {}
328 template<
typename Rep2,
typename Precision2>
329 requires std::convertible_to<const Rep2&, rep> &&
341 template<
typename Rep2,
typename Precision2>
437template<
typename ToQuantity,
typename Unit,
typename Rep,
typename Precision>
440 std::is_same_v<typename ToQuantity::unit, Unit>,
"quantity_cast cannot convert between different units"
442 if constexpr (std::is_same_v<ToQuantity, quantity<Unit, Rep, Precision>>) {
445 using to_rep =
typename ToQuantity::rep;
447 using cf = std::ratio_divide<Precision, to_precision>;
450 if constexpr (std::is_integral_v<Rep> && std::is_integral_v<to_rep>) {
451#ifdef __SIZEOF_INT128__
452 using cr = std::common_type_t<to_rep, Rep, intmax_t>;
458 if constexpr (cf::den == 1 && cf::num == 1) {
460 }
else if constexpr (cf::den == 1) {
463 }
else if constexpr (cf::num == 1) {
478 using cr = std::common_type_t<to_rep, Rep, intmax_t>;
479 if constexpr (cf::den == 1 && cf::num == 1) {
481 }
else if constexpr (cf::den == 1) {
483 }
else if constexpr (cf::num == 1) {
488 static_cast<cr>(
q.count()) *
static_cast<cr>(cf::num) /
static_cast<cr>(cf::den)
513template<
typename ToQuantity,
typename Unit,
typename Rep,
typename Precision>
515 using to_rep =
typename ToQuantity::rep;
518 if constexpr (std::is_integral_v<Rep> && std::is_integral_v<to_rep>) {
544template<
typename ToQuantity,
typename Unit,
typename Rep,
typename Precision>
546 using to_rep =
typename ToQuantity::rep;
549 if constexpr (std::is_integral_v<Rep> && std::is_integral_v<to_rep>) {
575template<
typename ToQuantity,
typename Unit,
typename Rep,
typename Precision>
577 using to_rep =
typename ToQuantity::rep;
579 if constexpr (std::is_integral_v<Rep> && std::is_integral_v<to_rep>) {
609template<
typename Unit,
typename Rep,
typename Precision>
619template<
typename Unit,
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
627template<
typename Unit,
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
635template<
typename Unit,
typename Rep1,
typename Precision,
typename Rep2>
636 requires not_quantity<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>>
640 return cq(
cq(
q).count() *
r);
644template<
typename Unit,
typename Rep1,
typename Rep2,
typename Precision>
645 requires not_quantity<Rep1> && std::convertible_to<const Rep1&, std::common_type_t<Rep1, Rep2>>
652template<
typename Unit,
typename Rep1,
typename Precision,
typename Rep2>
653 requires not_quantity<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>>
657 return cq(
cq(
q).count() /
s);
661template<
typename Unit,
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
663 -> std::common_type_t<Rep1, Rep2> {
669template<
typename Unit,
typename Rep1,
typename Precision,
typename Rep2>
670 requires not_quantity<Rep2> && std::convertible_to<const Rep2&, std::common_type_t<Rep1, Rep2>> &&
675 return cq(
cq(
q).count() %
s);
679template<
typename Unit,
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
687template<
typename Unit,
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
693template<
typename Unit,
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
694 requires std::three_way_comparable<std::common_type_t<Rep1, Rep2>>
708template<
typename ToUnit,
typename U1,
typename R1,
typename P1,
typename U2,
typename R2,
typename P2>
710 using cr = std::common_type_t<R1, R2>;
717template<
typename ToUnit,
typename U1,
typename R1,
typename P1,
typename U2,
typename R2,
typename P2>
719 using cr = std::common_type_t<R1, R2>;
725template<
typename ToUnit,
typename U1,
typename R1,
typename P1, duration_like D>
727 using cr = std::common_type_t<R1, typename D::rep>;
733template<
typename ToUnit,
typename U1,
typename R1,
typename P1, duration_like D>
735 using cr = std::common_type_t<R1, typename D::rep>;
741template<
typename U1,
typename R1,
typename P1,
typename U2,
typename R2,
typename P2>
743 using cr = std::common_type_t<R1, R2>;
744 using result_t = std::chrono::duration<cr, std::ratio_divide<P1, P2>>;
749template<
typename U1,
typename R1,
typename P1,
typename U2,
typename R2,
typename P2>
751 using cr = std::common_type_t<R1, R2>;
752 using result_t = std::chrono::duration<cr, std::ratio_multiply<P1, P2>>;
769template<
typename R1,
typename P1,
typename R2,
typename P2>
775template<
typename R1,
typename P1,
typename R2,
typename P2>
781template<
typename R1,
typename P1,
typename R2,
typename P2>
787template<
typename R1,
typename P1,
typename R2,
typename P2>
793template<
typename R1,
typename P1,
typename R2,
typename P2>
799template<
typename R1,
typename P1,
typename R2,
typename P2>
805template<
typename R1,
typename P1,
typename R2,
typename P2>
811template<
typename R1,
typename P1,
typename R2,
typename P2>
823template<
typename R1,
typename P1, duration_like D>
829template<duration_like D,
typename R1,
typename P1>
835template<
typename R1,
typename P1, duration_like D>
847template<
typename R1,
typename P1,
typename R2,
typename P2>
859template<
typename R1,
typename P1, duration_like D>
865template<duration_like D,
typename R1,
typename P1>
871template<
typename R1,
typename P1, duration_like D>
877template<
typename R1,
typename P1,
typename R2,
typename P2>
889template<
typename R1,
typename P1,
typename R2,
typename P2>
895template<
typename R1,
typename P1,
typename R2,
typename P2>
901template<
typename R1,
typename P1,
typename R2,
typename P2>
907template<
typename R1,
typename P1,
typename R2,
typename P2>
913template<
typename R1,
typename P1,
typename R2,
typename P2>
919template<
typename R1,
typename P1,
typename R2,
typename P2>
931template<
typename R1,
typename P1,
typename R2,
typename P2>
937template<
typename R1,
typename P1,
typename R2,
typename P2>
949template<
typename R1,
typename P1,
typename R2,
typename P2>
970template<
typename Rep,
typename Precision = std::ratio<1>>
974template<
typename Rep,
typename Precision = std::ratio<1>>
978template<
typename Rep,
typename Precision = std::ratio<1>>
982template<
typename Rep,
typename Precision = std::ratio<1>>
986template<
typename Rep,
typename Precision = std::ratio<1>>
990template<
typename Rep,
typename Precision = std::ratio<1>>
994template<
typename Rep,
typename Precision = std::ratio<1>>
998template<
typename Rep,
typename Precision = std::ratio<1>>
1103template<
typename Precision>
1109 static constexpr const char* symbol =
"f";
1114 static constexpr const char* symbol =
"p";
1119 static constexpr const char* symbol =
"n";
1124 static constexpr const char* symbol =
"µ";
1129 static constexpr const char* symbol =
"m";
1134 static constexpr const char* symbol =
"";
1139 static constexpr const char* symbol =
"k";
1144 static constexpr const char* symbol =
"M";
1149 static constexpr const char* symbol =
"G";
1154 static constexpr const char* symbol =
"T";
1169template<
typename Unit,
typename Precision>
1181struct quantity_suffix<coulomb_unit,
std::
ratio<18, 5>> {
1182 static std::string
value() {
return "mAh"; }
1186struct quantity_suffix<coulomb_unit,
std::
ratio<3600>> {
1187 static std::string
value() {
return "Ah"; }
1191struct quantity_suffix<joule_unit,
std::
ratio<3600>> {
1192 static std::string
value() {
return "Wh"; }
1196struct quantity_suffix<joule_unit,
std::
ratio<3600000>> {
1197 static std::string
value() {
return "kWh"; }
1200template<
typename Unit,
typename Precision>
1207template<
typename Unit,
typename Precision>
1209 using scale = std::ratio<1>;
1210 static constexpr const char*
suffix = Unit::symbol;
1214 using scale = std::ratio<3600>;
1215 static constexpr const char*
suffix =
"Ah";
1219 using scale = std::ratio<3600>;
1220 static constexpr const char*
suffix =
"Wh";
1236template<
typename OutputIt>
1238 for (; *
s !=
'\0'; ++
s) {
1257template<
typename Unit,
typename Rep,
typename Precision>
1267template<
typename Unit,
typename Rep1,
typename Precision1,
typename Rep2,
typename Precision2>
1270 using common_precision = std::ratio<
1272 (Precision1::den /
electro::_gcd(Precision1::den, Precision2::den)) * Precision2::den>;
1278#if CONFIG_ELECTRO_STD_FORMAT
1284template<
typename Unit,
typename Rep,
typename Precision>
1286struct formatter<
electro::quantity<Unit, Rep, Precision>, char> {
1290 using _upc =
typename ratio_divide<typename Precision::type, typename _display::scale>::type;
1291 std::formatter<double> _num;
1292 bool _has_spec =
false;
1295 constexpr auto parse(format_parse_context& ctx) {
1296 auto it = ctx.begin();
1297 if (it == ctx.end() || *it ==
'}') {
1301 return _num.parse(ctx);
1304 template<
typename FormatContext>
1307 double value =
static_cast<double>(q.
count()) * _upc::num / _upc::den;
1308 auto out = _num.format(value, ctx);
1311 return std::format_to(
1327template<
unsigned long long Value,
unsigned long long Power>
1329 static constexpr unsigned long long value = 10 * pow10<Value, Power - 1>::value;
1332template<
unsigned long long Value>
1333struct pow10<Value, 0> {
1334 static constexpr unsigned long long value = Value;
1337template<
char... Digits>
1340template<
char D,
char... Rest>
1341struct parse_int<D, Rest...> {
1342 static_assert(D >=
'0' && D <=
'9',
"invalid digit");
1343 static constexpr unsigned long long value = pow10<D -
'0',
sizeof...(Rest)>::value + parse_int<Rest...>::value;
1347struct parse_int<D> {
1348 static_assert(D >=
'0' && D <=
'9',
"invalid digit");
1349 static constexpr unsigned long long value = D -
'0';
1352template<
typename Quantity,
char... Digits>
1353constexpr Quantity check_overflow() {
1354 using parsed = parse_int<Digits...>;
1355 constexpr typename Quantity::rep repval = parsed::value;
1357 repval >= 0 &&
static_cast<unsigned long long>(repval) == parsed::value,
1358 "literal value cannot be represented by quantity type"
1360 return Quantity(repval);
1367template<
char... Digits>
1373template<
char... Digits>
1379template<
char... Digits>
1385template<
char... Digits>
1391template<
char... Digits>
1397template<
char... Digits>
1403template<
char... Digits>
1409template<
char... Digits>
1415template<
char... Digits>
1421template<
char... Digits>
1427template<
char... Digits>
1433template<
char... Digits>
1439template<
char... Digits>
1445template<
char... Digits>
1451template<
char... Digits>
1457template<
char... Digits>
1463template<
char... Digits>
1469template<
char... Digits>
1475template<
char... Digits>
1481template<
char... Digits>
1487template<
char... Digits>
1493template<
char... Digits>
1499template<
char... Digits>
1505template<
char... Digits>
1511template<
char... Digits>
1517template<
char... Digits>
1523template<
char... Digits>
1529template<
char... Digits>
1535template<
char... Digits>
1541template<
char... Digits>
1547template<
char... Digits>
1553template<
char... Digits>
1559template<
char... Digits>
1565template<
char... Digits>
1571template<
char... Digits>
1577template<
char... Digits>
A quantity of an electrical unit with a representation and precision.
Unit unit
The unit tag type.
constexpr quantity operator--(int)
constexpr quantity & operator*=(const rep &r)
constexpr quantity operator++(int)
constexpr quantity & operator++()
constexpr quantity & operator+=(const quantity &q)
Rep rep
The representation type.
static constexpr quantity zero() noexcept
Returns a zero quantity.
constexpr quantity()=default
Constructs a zero quantity.
constexpr quantity & operator/=(const rep &r)
static constexpr quantity max() noexcept
Returns the maximum representable quantity.
constexpr quantity< Unit, typename std::common_type< rep >::type, precision > operator+() const
constexpr quantity & operator--()
constexpr quantity< Unit, typename std::common_type< rep >::type, precision > operator-() const
quantity & operator=(const quantity &)=default
quantity(const quantity &)=default
typename Precision::type precision
The precision as a std::ratio.
constexpr rep count() const
Returns the tick count.
constexpr quantity & operator-=(const quantity &q)
constexpr quantity & operator%=(const rep &r)
static constexpr quantity min() noexcept
Returns the minimum representable quantity.
constexpr quantity(const quantity< Unit, Rep2, Precision2 > &q)
Explicit constructor for lossy precision conversions.
constexpr quantity & operator%=(const quantity &q)
constexpr quantity(const Rep2 &r)
Constructs from a tick count.
capacitance< int64_t, std::pico > picofarads
Capacitance with 1 pF precision.
resistance< int64_t, std::milli > milliohms
Resistance with 1 mΩ precision.
inductance< int64_t, std::milli > millihenries
Inductance with 1 mH precision.
capacitance< int64_t > farads
Capacitance with 1 F precision.
capacitance< int64_t, std::nano > nanofarads
Capacitance with 1 nF precision.
energy< int64_t, std::ratio< 3600000 > > kilowatt_hours
Energy with 1 kWh (3,600,000 J) precision.
power< int64_t, std::mega > megawatts
Power with 1 MW precision.
inductance< int64_t, std::micro > microhenries
Inductance with 1 µH precision.
charge< int64_t, std::ratio< 18, 5 > > milliampere_hours
Charge with 1 mAh (3.6 C) precision.
voltage< int64_t, std::milli > millivolts
Voltage with 1 mV precision.
energy< int64_t, std::kilo > kilojoules
Energy with 1 kJ precision.
power< int64_t > watts
Power with 1 W precision.
energy< int64_t, std::milli > millijoules
Energy with 1 mJ precision.
voltage< int64_t, std::kilo > kilovolts
Voltage with 1 kV precision.
capacitance< int64_t, std::micro > microfarads
Capacitance with 1 µF precision.
current< int64_t, std::milli > milliamperes
Current with 1 mA precision.
current< int64_t > amperes
Current with 1 A precision.
resistance< int64_t > ohms
Resistance with 1 Ω precision.
voltage< int64_t, std::micro > microvolts
Voltage with 1 µV precision.
inductance< int64_t, std::nano > nanohenries
Inductance with 1 nH precision.
voltage< int64_t > volts
Voltage with 1 V precision.
charge< int64_t > coulombs
Charge with 1 C precision.
power< int64_t, std::kilo > kilowatts
Power with 1 kW precision.
inductance< int64_t > henries
Inductance with 1 H precision.
energy< int64_t, std::ratio< 3600 > > watt_hours
Energy with 1 Wh (3600 J) precision.
current< int64_t, std::micro > microamperes
Current with 1 µA precision.
power< int64_t, std::micro > microwatts
Power with 1 µW precision.
resistance< int64_t, std::kilo > kiloohms
Resistance with 1 kΩ precision.
energy< int64_t > joules
Energy with 1 J precision.
resistance< int64_t, std::mega > megaohms
Resistance with 1 MΩ precision.
charge< int64_t, std::ratio< 3600 > > ampere_hours
Charge with 1 Ah (3600 C) precision.
power< int64_t, std::milli > milliwatts
Power with 1 mW precision.
User-defined literals for electrical quantity types.
Electrical unit types and utilities.
constexpr quantity< Unit, Rep, Precision > abs(const quantity< Unit, Rep, Precision > &q)
Returns the absolute value of a quantity.
constexpr ToQuantity quantity_cast(const quantity< Unit, Rep, Precision > &q)
Converts a quantity to a different precision or representation.
constexpr auto operator+(const level< Reference, Rep1, Precision1 > &l, const quantity< decibel_unit, Rep2, Precision2 > &g)
Applies a gain to a level.
constexpr auto operator-(const level< Reference, Rep1, Precision1 > &l, const quantity< decibel_unit, Rep2, Precision2 > &g)
Applies a loss to a level.
constexpr auto operator<=>(const level< Reference, Rep1, Precision1 > &a, const level< Reference, Rep2, Precision2 > &b)
constexpr ToLevel ceil(const level< Reference, Rep, Precision > &l)
Converts a level to the target type, rounding toward positive infinity.
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.
constexpr bool treat_as_inexact_v
constexpr ToLevel round(const level< Reference, Rep, Precision > &l)
Converts a level to the target type, rounding to nearest (ties to even).
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.
constexpr bool is_quantity_v
constexpr ToLevel floor(const level< Reference, Rep, Precision > &l)
Converts a level to the target type, rounding toward negative infinity.
std::string to_string(const quantity< decibel_unit, Rep, Precision > &g)
Converts a gain to a string, e.g.
constexpr bool operator==(const level< Reference, Rep1, Precision1 > &a, const level< Reference, Rep2, Precision2 > &b)
Electric current, measured in amperes.
static constexpr const char * symbol
Electric charge, measured in coulombs.
static constexpr const char * symbol
Capacitance, measured in farads.
static constexpr const char * symbol
Inductance, measured in henries.
static constexpr const char * symbol
Trait to detect quantity specializations.
Energy, measured in joules.
static constexpr const char * symbol
Electrical resistance, measured in ohms.
static constexpr const char * symbol
Trait giving the display suffix for a (unit, precision) pair.
static std::string value()
Returns the display suffix.
Provides special values for quantity representations.
static constexpr Rep max() noexcept
Returns the maximum representable quantity.
static constexpr Rep min() noexcept
Returns the minimum representable quantity.
static constexpr Rep zero() noexcept
Returns a zero quantity.
Trait giving the display symbol for an SI precision prefix.
Trait to indicate floating-point-like behavior.
Voltage, measured in volts.
static constexpr const char * symbol
Power, measured in watts.
static constexpr const char * symbol