50#ifndef UNIT_LIB_DEFAULT_TYPE
51#define UNIT_LIB_DEFAULT_TYPE double
89#if defined(UNIT_LIB_DISABLE_STRING)
90#if !defined(UNIT_LIB_DISABLE_IOSTREAM)
91#define UNIT_LIB_DISABLE_IOSTREAM
93#if !defined(UNIT_LIB_DISABLE_FORMAT)
94#define UNIT_LIB_DISABLE_FORMAT
100#if !defined(UNIT_LIB_DISABLE_FORMAT) && !defined(UNIT_LIB_DISABLE_STRING) && defined(__cpp_lib_format) && __cpp_lib_format >= 201907L && \
101 (!defined(UNIT_LIB_DISABLE_IOSTREAM) || defined(UNIT_LIB_ENABLE_FORMAT))
102#if !defined(UNIT_LIB_ENABLE_FORMAT)
103#define UNIT_LIB_ENABLE_FORMAT
107#undef UNIT_LIB_ENABLE_FORMAT
112#if !defined(UNIT_LIB_DISABLE_STRING) && (!defined(UNIT_LIB_DISABLE_IOSTREAM) || defined(UNIT_LIB_ENABLE_FORMAT))
113#define UNIT_LIB_ENABLE_STRING
116#if defined(UNIT_LIB_ENABLE_STRING)
120#if defined(UNIT_LIB_ENABLE_FORMAT)
122#include <string_view>
125#if defined(UNIT_LIB_ENABLE_STRING)
132namespace units::detail
135 requires std::is_arithmetic_v<T>
137 std::string to_string(
const T& t)
139 std::string str{std::to_string(t)};
141 if constexpr (std::is_floating_point_v<T>)
143 unsigned int offset{1};
146 std::lconv* lc = std::localeconv();
147 char decimalPoint = *lc->decimal_point;
148 if (str.find_last_not_of(
'0') == str.find(decimalPoint))
152 str.erase(str.find_last_not_of(
'0') + offset, std::string::npos);
160#if !defined(UNIT_LIB_DISABLE_IOSTREAM)
176 static constexpr const char* value =
nullptr;
182 static constexpr const char* value =
nullptr;
186 inline constexpr const char* unit_name_v = unit_name<Unit>::value;
189 inline constexpr const char* unit_abbreviation_v = unit_abbreviation<Unit>::value;
193 inline constexpr UNIT_LIB_DEFAULT_TYPE PI_VAL = 3.14159265358979323846264338327950288419716939937510;
221#define UNIT_ADD_STRONG_CONVERSION_FACTOR(namespaceName, namePlural, ...) \
222 inline namespace namespaceName \
224 struct namePlural##_ : __VA_ARGS__ \
233 ::units::namespaceName::namePlural##_ strong_name(__VA_ARGS__*); \
246#define UNIT_ADD_UNIT_DEFINITION(namespaceName, namePlural, ...) \
247 inline namespace namespaceName \
249 UNIT_ADD_SCALED_UNIT_DEFINITION(namePlural, ::units::linear_scale, __VA_ARGS__) \
267#define UNIT_ADD_SCALED_UNIT_DEFINITION(unitName, scale, ...) \
270 template<class Underlying = UNIT_LIB_DEFAULT_TYPE> \
271 struct unitName : ::units::unit<traits::strong_t<__VA_ARGS__>, Underlying, scale> \
273 using base = ::units::unit<traits::strong_t<__VA_ARGS__>, Underlying, scale>; \
279 unitName() = default; \
280 unitName(const unitName&) = default; \
281 unitName(unitName&&) = default; \
282 unitName& operator=(const unitName&) = default; \
283 unitName& operator=(unitName&&) = default; \
284 constexpr unitName(const base& other) noexcept : base(other) {} \
293 template<::units::ConversionFactorType Cf, ::units::ArithmeticType Ty, ::units::NumericalScaleType<Ty> Ns> \
294 requires(::units::traits::is_same_dimension_unit_v<::units::unit<Cf, Ty, Ns>, base> && \
295 !::units::detail::is_losslessly_convertible_unit<::units::unit<Cf, Ty, Ns>, base> && \
296 (::std::is_floating_point_v<Ty> || ::std::is_integral_v<Ty>) && ::std::is_integral_v<Underlying>) \
297 consteval unitName(const ::units::unit<Cf, Ty, Ns>& rhs) : base(rhs) {} \
301 template<class Rhs> \
302 requires ::std::is_arithmetic_v<Rhs> \
303 constexpr unitName& operator=(const Rhs& rhs) noexcept \
305 base::operator=(rhs); \
310 template<class NewUnderlying> \
311 using rebind = unitName<NewUnderlying>; \
317 template<class Arg> \
318 requires ::std::is_arithmetic_v<Arg> \
319 unitName(Arg) -> unitName<Arg>; \
322 unitName() -> unitName<UNIT_LIB_DEFAULT_TYPE>; \
328 template<class OtherUnit> \
329 requires(::units::traits::is_unit<OtherUnit>::value && \
330 ::units::traits::is_same_dimension_unit_v<OtherUnit, \
331 ::units::unit<traits::strong_t<__VA_ARGS__>, typename ::units::traits::unit_traits<OtherUnit>::underlying_type, scale>>) \
332 unitName(const OtherUnit&) -> unitName<::units::detail::deduced_named_underlying_t<OtherUnit, traits::strong_t<__VA_ARGS__>, scale>>;\
336 template<class Rep, class Period> \
337 unitName(const ::std::chrono::duration<Rep, Period>&) -> unitName<UNIT_LIB_DEFAULT_TYPE>; \
348#define UNIT_ADD_NAME(namespaceName, namePlural, abbrev) \
349 template<class Underlying> \
350 struct unit_name<namespaceName::namePlural<Underlying>> \
352 static constexpr const char* value = #namePlural; \
355 template<class Underlying> \
356 struct unit_abbreviation<namespaceName::namePlural<Underlying>> \
358 static constexpr const char* value = #abbrev; \
369#define UNIT_REGISTER_NAMED_CLASS(namespaceName, namePlural) \
375 ::units::namespaceName::namePlural<UNIT_LIB_DEFAULT_TYPE> named_class_of( \
376 typename ::units::namespaceName::namePlural<>::conversion_factor*, \
377 typename ::units::namespaceName::namePlural<>::numerical_scale_type*); \
391#ifdef UNIT_NO_LITERAL_SUPPORT
392#define UNIT_ADD_LITERALS(namespaceName, namePlural, abbreviation)
394#define UNIT_ADD_LITERALS(namespaceName, namePlural, abbreviation) \
400 constexpr namespaceName::namePlural<::units::detail::floating_point_promotion_t<UNIT_LIB_DEFAULT_TYPE>> operator""_##abbreviation(long double d) noexcept \
402 return namespaceName::namePlural<::units::detail::floating_point_promotion_t<UNIT_LIB_DEFAULT_TYPE>>(static_cast<::units::detail::floating_point_promotion_t<UNIT_LIB_DEFAULT_TYPE>>(d)); \
409 constexpr namespaceName::namePlural<::units::detail::floating_point_promotion_t<UNIT_LIB_DEFAULT_TYPE>> operator""_##abbreviation(unsigned long long d) noexcept \
411 return namespaceName::namePlural<::units::detail::floating_point_promotion_t<UNIT_LIB_DEFAULT_TYPE>>(static_cast<::units::detail::floating_point_promotion_t<UNIT_LIB_DEFAULT_TYPE>>(d)); \
422#ifdef UNIT_NO_LITERAL_SUPPORT
423#define UNIT_ADD_DECIBEL_LITERALS(namespaceName, namePlural, abbreviation)
425#define UNIT_ADD_DECIBEL_LITERALS(namespaceName, namePlural, abbreviation) \
428 constexpr namespaceName::namePlural<double> operator""_##abbreviation(long double d) noexcept \
430 return namespaceName::namePlural<double>(static_cast<double>(d)); \
435#define UNIT_ADD_CONSTANT(namespaceName, namePlural, abbreviation) static constexpr namespaceName::namePlural abbreviation{1.0};
456#define UNIT_ADD(namespaceName, namePlural, abbreviation, ...) \
457 UNIT_ADD_STRONG_CONVERSION_FACTOR(namespaceName, namePlural, __VA_ARGS__) \
458 UNIT_ADD_UNIT_DEFINITION(namespaceName, namePlural, __VA_ARGS__) \
459 UNIT_ADD_NAME(namespaceName, namePlural, abbreviation) \
460 UNIT_REGISTER_NAMED_CLASS(namespaceName, namePlural) \
461 UNIT_ADD_LITERALS(namespaceName, namePlural, abbreviation) \
462 UNIT_ADD_CONSTANT(namespaceName, namePlural, abbreviation)
473#define UNIT_ADD_DECIBEL(namespaceName, namePlural, abbreviation) \
474 inline namespace namespaceName \
476 UNIT_ADD_SCALED_UNIT_DEFINITION(abbreviation, ::units::decibel_scale, typename ::units::namespaceName::namePlural<>::conversion_factor) \
478 UNIT_ADD_NAME(namespaceName, abbreviation, abbreviation) \
479 UNIT_REGISTER_NAMED_CLASS(namespaceName, abbreviation) \
480 UNIT_ADD_DECIBEL_LITERALS(namespaceName, abbreviation, abbreviation)
497#define UNIT_ADD_DIMENSION_TRAIT(unitdimension, ConceptName) \
505 template<typename T> \
506 struct is_##unitdimension##_unit : ::units::detail::has_dimension_of<std::decay_t<T>, units::dimension::unitdimension> \
509 template<typename T> \
510 inline constexpr bool is_##unitdimension##_unit_v = is_##unitdimension##_unit<T>::value; \
517 template<typename T> \
518 concept ConceptName = ::units::traits::is_##unitdimension##_unit_v<std::decay_t<T>>;
538#define UNIT_ADD_WITH_METRIC_PREFIXES(namespaceName, namePlural, abbreviation, ...) \
539 UNIT_ADD(namespaceName, namePlural, abbreviation, __VA_ARGS__) \
540 UNIT_ADD(namespaceName, femto##namePlural, f##abbreviation, femto<namePlural<>>) \
541 UNIT_ADD(namespaceName, pico##namePlural, p##abbreviation, pico<namePlural<>>) \
542 UNIT_ADD(namespaceName, nano##namePlural, n##abbreviation, nano<namePlural<>>) \
543 UNIT_ADD(namespaceName, micro##namePlural, u##abbreviation, micro<namePlural<>>) \
544 UNIT_ADD(namespaceName, milli##namePlural, m##abbreviation, milli<namePlural<>>) \
545 UNIT_ADD(namespaceName, centi##namePlural, c##abbreviation, centi<namePlural<>>) \
546 UNIT_ADD(namespaceName, deci##namePlural, d##abbreviation, deci<namePlural<>>) \
547 UNIT_ADD(namespaceName, deca##namePlural, da##abbreviation, deca<namePlural<>>) \
548 UNIT_ADD(namespaceName, hecto##namePlural, h##abbreviation, hecto<namePlural<>>) \
549 UNIT_ADD(namespaceName, kilo##namePlural, k##abbreviation, kilo<namePlural<>>) \
550 UNIT_ADD(namespaceName, mega##namePlural, M##abbreviation, mega<namePlural<>>) \
551 UNIT_ADD(namespaceName, giga##namePlural, G##abbreviation, giga<namePlural<>>) \
552 UNIT_ADD(namespaceName, tera##namePlural, T##abbreviation, tera<namePlural<>>) \
553 UNIT_ADD(namespaceName, peta##namePlural, P##abbreviation, peta<namePlural<>>)
573#define UNIT_ADD_WITH_METRIC_AND_BINARY_PREFIXES(namespaceName, namePlural, abbreviation, ...) \
574 UNIT_ADD_WITH_METRIC_PREFIXES(namespaceName, namePlural, abbreviation, __VA_ARGS__) \
575 UNIT_ADD(namespaceName, kibi##namePlural, Ki##abbreviation, kibi<namePlural<>>) \
576 UNIT_ADD(namespaceName, mebi##namePlural, Mi##abbreviation, mebi<namePlural<>>) \
577 UNIT_ADD(namespaceName, gibi##namePlural, Gi##abbreviation, gibi<namePlural<>>) \
578 UNIT_ADD(namespaceName, tebi##namePlural, Ti##abbreviation, tebi<namePlural<>>) \
579 UNIT_ADD(namespaceName, pebi##namePlural, Pi##abbreviation, pebi<namePlural<>>) \
580 UNIT_ADD(namespaceName, exbi##namePlural, Ei##abbreviation, exbi<namePlural<>>)
687 template<
class Default,
class AlwaysVoid,
template<
class...>
class Op,
class... Args>
690 using value_t = std::false_type;
691 using type = Default;
694 template<
class Default,
template<
class...>
class Op,
class... Args>
695 struct detector<Default,
std::void_t<Op<Args...>>, Op, Args...>
697 using value_t = std::true_type;
698 using type = Op<Args...>;
704 ~nonesuch() =
delete;
705 nonesuch(
const nonesuch&) =
delete;
706 void operator=(
const nonesuch&) =
delete;
709 template<
template<
class...>
class Op,
class... Args>
710 using is_detected =
typename detector<nonesuch, void, Op, Args...>::value_t;
712 template<
template<
class...>
class Op,
class... Args>
713 inline constexpr bool is_detected_v = is_detected<Op, Args...>::value;
715 template<
template<
class...>
class Op,
class... Args>
716 using detected_t =
typename detector<nonesuch, void, Op, Args...>::type;
718 template<
class Default,
template<
class...>
class Op,
class... Args>
719 using detected_or = detector<Default, void, Op, Args...>;
721 template<
class Default,
template<
class...>
class Op,
class... Args>
722 using detected_or_t =
typename detected_or<Default, Op, Args...>::type;
724 template<
class Expected,
template<
class...>
class Op,
class... Args>
725 using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
727 template<
class Expected,
template<
class...>
class Op,
class... Args>
728 inline constexpr bool is_detected_exact_v = is_detected_exact<Expected, Op, Args...>::value;
730 template<
class To,
template<
class...>
class Op,
class... Args>
731 using is_detected_convertible = std::is_convertible<detected_t<Op, Args...>, To>;
733 template<
class To,
template<
class...>
class Op,
class... Args>
734 inline constexpr bool is_detected_convertible_v = is_detected_convertible<To, Op, Args...>::value;
753 struct is_ratio_impl : std::false_type
757 template<std::
intmax_t N, std::
intmax_t D>
758 struct is_ratio_impl<
std::ratio<N, D>> : std::true_type
770 using is_ratio = detail::is_ratio_impl<T>;
773 inline constexpr bool is_ratio_v = is_ratio<T>::value;
785#ifdef FOR_DOXYGEN_PURPOSES_ONLY
794 struct conversion_factor_traits
796 typedef typename T::dimension_type dimension_type;
799 typedef typename T::conversion_ratio conversion_ratio;
801 typedef typename T::pi_exponent_ratio pi_exponent_ratio;
803 typedef typename T::translation_ratio translation_ratio;
811 template<
class T,
typename =
void>
812 struct conversion_factor_traits
814 using dimension_type = void;
815 using conversion_ratio = void;
816 using pi_exponent_ratio = void;
817 using translation_ratio = void;
821 struct conversion_factor_traits<T, std::void_t<typename T::dimension_type, typename T::conversion_ratio, typename T::pi_exponent_ratio, typename T::translation_ratio>>
823 using dimension_type =
typename T::dimension_type;
826 using conversion_ratio =
typename T::conversion_ratio;
828 using pi_exponent_ratio =
typename T::pi_exponent_ratio;
830 using translation_ratio =
typename T::translation_ratio;
845 struct _conversion_factor
861 using is_conversion_factor =
typename std::is_base_of<units::detail::_conversion_factor, T>::type;
893 template<
class T,
class =
void>
899 struct is_complete<T,
std::void_t<decltype(sizeof(T))>> : std::true_type
908 template<class T, bool = is_complete<T>::value>
914 struct is_unit_impl<T, true> : std::is_base_of<_unit, T>::type
933 template<
class ConversionFactor>
934 ConversionFactor
strong_name(ConversionFactor*, ...);
956 template<
class NumericalScale>
957 struct invocable_scale
960 requires std::is_same_v<
decltype(NumericalScale::linearize(T{})),
decltype(NumericalScale::scale(T{}))>
961 decltype(NumericalScale::scale(T{})) operator()(T)
980 template<
class T,
class Ret>
983 template<
class T,
class Ret>
1002 template<
typename T>
1009 template<
typename T>
1010 concept RatioType = traits::is_ratio_v<T>;
1016 template<
typename T>
1023 template<
typename Scale,
typename T>
1030 template<
typename T>
1031 concept UnitType = traits::is_unit_v<T>;
1037 template<
typename T>
1044 template<
typename T>
1050 template<UnitType U1, UnitType U2>
1051 struct is_same_dimension_unit;
1058 template<
typename UnitTo,
typename UnitFrom>
1082 template<ConversionFactorType T>
1083 requires std::is_same_v<T, std::remove_cv_t<T>>
1090 using type =
decltype(strong_name(
static_cast<T*
>(
nullptr)));
1094 using strong_t =
typename strong<T>::type;
1104 template<
class D,
class E>
1111 template<
class... D>
1117 static constexpr bool empty =
true;
1120 template<
class D0,
class... D>
1123 static constexpr bool empty =
false;
1128 template<
class T,
class U>
1134 constexpr int const_strcmp(
const char* lhs,
const char* rhs)
1136 return (*lhs && *rhs) ? (*lhs == *rhs ? const_strcmp(lhs + 1, rhs + 1) : (*lhs < *rhs ? -1 : 1)) : ((!*lhs && !*rhs) ? 0 : (!*lhs ? -1 : 1));
1139 template<
bool HasT,
bool HasU>
1145 template<
class T,
class U,
class...
R>
1146 using apply =
typename merge_dimensions_impl<const_strcmp(T::front::dimension::name, U::front::dimension::name)>::template apply<T, U,
R...>;
1149 template<
class T,
class U>
1152 template<
class... T,
class... U>
1161 template<
class T,
class U,
class...
R>
1168 template<
class T,
class U,
class...
R>
1175 template<
class T,
class U,
class...
R>
1179 template<
class T,
class U,
class...
R>
1185 template<
class T,
class U,
class...
R>
1186 using apply = merge_dimensions_recurse<T,
typename U::pop_front,
R...,
typename U::front>;
1192 template<
class T,
class U,
class...
R>
1193 using apply = merge_dimensions_recurse<
typename T::pop_front, U,
R...,
typename T::front>;
1196 template<
bool Cancels>
1202 template<
class T,
class U,
class X,
class...
R>
1203 using apply = merge_dimensions_recurse<T, U,
R...>;
1209 template<
class T,
class U,
class X,
class...
R>
1210 using apply = merge_dimensions_recurse<T, U,
R..., X>;
1216 template<
class T,
class U,
class...
R>
1221 template<
class T,
class U>
1222 using merge_dimensions = merge_dimensions_recurse<T, U>;
1224 template<
class T,
class E>
1227 template<
class... T,
class... E,
class R>
1233 template<
class T,
class E>
1234 using dimension_pow =
typename dimension_pow_impl<T, E>::type;
1236 template<
class T,
class E>
1237 using dimension_root = dimension_pow<T, std::ratio_divide<std::ratio<1>, E>>;
1239 template<
class T,
class U>
1240 using dimension_multiply = merge_dimensions<T, U>;
1242 template<
class T,
class U>
1243 using dimension_divide = merge_dimensions<T, dimension_pow<U, std::ratio<-1>>>;
1245 template<
class T0 =
void,
class N0 = std::ratio<1>,
class... Rest>
1248 using type = dimension_multiply<dimension_t<dim<T0, N0>>,
typename make_dimension_list<Rest...>::type>;
1251 template<
class... T,
class N0,
class... Rest>
1258 struct make_dimension_list<>
1260 using type = dimension_t<>;
1263 template<
class... T>
1280 static constexpr auto name =
"length";
1281 static constexpr auto abbreviation =
"m";
1286 static constexpr auto name =
"mass";
1287 static constexpr auto abbreviation =
"kg";
1292 static constexpr auto name =
"time";
1293 static constexpr auto abbreviation =
"s";
1298 static constexpr auto name =
"current";
1299 static constexpr auto abbreviation =
"A";
1304 static constexpr auto name =
"temperature";
1305 static constexpr auto abbreviation =
"K";
1310 static constexpr auto name =
"amount of substance";
1311 static constexpr auto abbreviation =
"mol";
1316 static constexpr auto name =
"luminous intensity";
1317 static constexpr auto abbreviation =
"cd";
1322 static constexpr auto name =
"angle";
1323 static constexpr auto abbreviation =
"rad";
1328 static constexpr auto name =
"data";
1329 static constexpr auto abbreviation =
"byte";
1333 using length = make_dimension<length_tag>;
1334 using mass = make_dimension<mass_tag>;
1335 using time = make_dimension<time_tag>;
1336 using current = make_dimension<current_tag>;
1337 using temperature = make_dimension<temperature_tag>;
1338 using substance = make_dimension<substance_tag>;
1339 using luminous_intensity = make_dimension<luminous_intensity_tag>;
1343 using angle = make_dimension<angle_tag>;
1353 using force = dimension_multiply<mass, acceleration>;
1354 using area = dimension_pow<length, std::ratio<2>>;
1355 using volume = dimension_pow<length, std::ratio<3>>;
1358 using charge = dimension_multiply<time, current>;
1359 using energy = dimension_multiply<force, length>;
1360 using power = dimension_divide<energy, time>;
1368 using illuminance = make_dimension<luminous_flux, std::ratio<1>, length, std::ratio<-2>>;
1369 using luminance = make_dimension<luminous_intensity, std::ratio<1>, length, std::ratio<-2>>;
1370 using radioactivity = make_dimension<length, std::ratio<2>, time, std::ratio<-2>>;
1373 using magnetic_field_strength = make_dimension<mass, std::ratio<1>, time, std::ratio<-2>, current, std::ratio<-1>>;
1375 using radiance = make_dimension<radiant_intensity, std::ratio<1>,
area, std::ratio<-1>>;
1378 using spectral_flux = make_dimension<power, std::ratio<1>, length, std::ratio<-1>>;
1383 using jerk = make_dimension<length, std::ratio<1>, time, std::ratio<-3>>;
1384 using torque = dimension_multiply<force, length>;
1385 using density = dimension_divide<mass, volume>;
1390 using data = make_dimension<data_tag>;
1402 template<RatioType,
class, RatioType, RatioType>
1409 using conversion_ratio = Conversion;
1410 using translation_ratio = Translation;
1411 using pi_exponent_ratio = PiExponent;
1419 template<RatioType C,
typename U, RatioType P, RatioType T>
1420 conversion_factor<C, U, P, T> conversion_factor_base_t_impl(conversion_factor<C, U, P, T>* cf)
1425 template<
typename T>
1426 using conversion_factor_base_t =
decltype(conversion_factor_base_t_impl(std::declval<T*>()));
1434 template<
class ConversionFactor>
1435 struct dimension_of_impl : dimension_of_impl<conversion_factor_base_t<ConversionFactor>>
1439 template<RatioType Conversion,
class BaseUnit, RatioType PiExponent, RatioType Translation>
1440 struct dimension_of_impl<conversion_factor<Conversion, BaseUnit, PiExponent, Translation>> : dimension_of_impl<BaseUnit>
1444 template<
class... Exponents>
1445 struct dimension_of_impl<dimension_t<Exponents...>>
1447 using type = dimension_t<Exponents...>;
1451 struct dimension_of_impl<void>
1466 using dimension_of_t =
typename units::detail::dimension_of_impl<U>::type;
1469 template<ConversionFactorType ConversionFactor, ArithmeticType T, NumericalScaleType<T> NumericalScale>
1475 template<
typename T,
class Dim,
bool IsConv = false>
1476 struct has_dimension_of_impl : std::false_type
1480 template<
typename T,
class Dim>
1481 using has_dimension_of =
typename has_dimension_of_impl<T, Dim, traits::is_conversion_factor_v<T>>::type;
1483 template<
typename Cf,
class Dim>
1484 struct has_dimension_of_impl<Cf, Dim, true> : has_dimension_of<conversion_factor_base_t<Cf>, Dim>::type
1488 template<
typename C,
typename Cf,
typename P,
typename T,
class Dim>
1489 struct has_dimension_of_impl<conversion_factor<C, Cf, P, T>, Dim, true> : std::is_same<typename conversion_factor<C, Cf, P, T>::dimension_type, Dim>::type
1493 template<
typename Cf,
typename T,
class Ns,
class Dim>
1494 struct has_dimension_of_impl<unit<Cf, T, Ns>, Dim> : std::is_same<traits::dimension_of_t<Cf>, Dim>::type
1510 template<
class,
class>
1515 template<ConversionFactorType Cf, ArithmeticType T, NumericalScaleType<T> Ns, ArithmeticType Underlying>
1521 template<
class Unit,
class Underlying>
1525 template<
class ConversionFactor,
class =
void>
1530 template<
class ConversionFactor>
1531 struct is_ratio_dimensionless_cf<ConversionFactor,
std::void_t<typename ConversionFactor::dimension_type, typename ConversionFactor::conversion_ratio>>
1532 : std::bool_constant<std::is_same_v<typename ConversionFactor::dimension_type, dimension::dimensionless> && !std::ratio_equal_v<typename ConversionFactor::conversion_ratio, std::ratio<1>>>
1536 template<
class ConversionFactor>
1537 inline constexpr bool is_ratio_dimensionless_cf_v = is_ratio_dimensionless_cf<ConversionFactor>::value;
1541 template<
typename U>
1544 template<
typename U>
1547 template<
typename U>
1548 concept IntegralUnitType = units::traits::is_unit_v<U> && std::integral<typename U::underlying_type>;
1575 template<RatioType Conversion,
class BaseUnit, RatioType PiExponent = std::ratio<0>, RatioType Translation = std::ratio<0>>
1579 using conversion_ratio = std::ratio_multiply<typename BaseUnit::conversion_ratio, Conversion>;
1580 using pi_exponent_ratio = std::ratio_add<typename BaseUnit::pi_exponent_ratio, PiExponent>;
1581 using translation_ratio = std::ratio_add<std::ratio_multiply<typename BaseUnit::conversion_ratio, Translation>,
typename BaseUnit::translation_ratio>;
1597 template<ConversionFactorType Cf1, ConversionFactorType Cf2>
1598 struct unit_multiply_impl
1602 std::ratio_add<typename Cf1::pi_exponent_ratio, typename Cf2::pi_exponent_ratio>>;
1609 template<ConversionFactorType Cf1, ConversionFactorType Cf2>
1610 using unit_multiply =
typename unit_multiply_impl<Cf1, Cf2>::type;
1618 template<ConversionFactorType Cf1, ConversionFactorType Cf2>
1619 struct unit_divide_impl
1621 using type = conversion_factor<std::ratio_divide<typename Cf1::conversion_ratio, typename Cf2::conversion_ratio>,
1622 dimension_divide<traits::dimension_of_t<typename Cf1::dimension_type>, traits::dimension_of_t<typename Cf2::dimension_type>>,
1623 std::ratio_subtract<typename Cf1::pi_exponent_ratio, typename Cf2::pi_exponent_ratio>>;
1630 template<ConversionFactorType Cf1, ConversionFactorType Cf2>
1631 using unit_divide =
typename unit_divide_impl<Cf1, Cf2>::type;
1639 template<ConversionFactorType Cf>
1642 using type = conversion_factor<std::ratio<Cf::conversion_ratio::den, Cf::conversion_ratio::num>, dimension_pow<
typename Cf::dimension_type, std::ratio<-1>>,
1643 std::ratio_multiply<
typename Cf::pi_exponent_ratio, std::ratio<-1>>>;
1654 template<ConversionFactorType Cf>
1655 using inverse =
typename detail::inverse_impl<Cf>::type;
1666 template<ConversionFactorType Cf>
1669 using Conversion =
typename Cf::conversion_ratio;
1671 std::ratio_multiply<typename Cf::pi_exponent_ratio, std::ratio<2>>, std::ratio<0>>;
1682 template<ConversionFactorType Cf>
1683 using squared =
typename detail::squared_impl<Cf>::type;
1693 template<ConversionFactorType Cf>
1696 using Conversion =
typename Cf::conversion_ratio;
1698 dimension_pow<traits::dimension_of_t<typename Cf::dimension_type>, std::ratio<3>>, std::ratio_multiply<typename Cf::pi_exponent_ratio, std::ratio<3>>, std::ratio<0>>;
1709 template<ConversionFactorType Cf>
1710 using cubed =
typename detail::cubed_impl<Cf>::type;
1720 using Zero = std::ratio<0>;
1721 using One = std::ratio<1>;
1722 template <RatioType R>
using Square = std::ratio_multiply<R, R>;
1725 template <
template <std::
intmax_t N>
class Predicate,
typename =
void>
1728 template <std::
intmax_t N>
1731 static constexpr const std::intmax_t value = 2 * N;
1732 static_assert(value > 0,
"Overflows when computing 2 * N");
1735 template <std::
intmax_t Lower, std::
intmax_t Upper,
typename Condition1 =
void,
typename Condition2 =
void>
1736 struct DoubleSidedSearch_ : DoubleSidedSearch_<Lower, Upper,
1737 std::integral_constant<bool, (Upper - Lower == 1)>,
1738 std::integral_constant<bool, ((Upper - Lower>1 && Predicate<Lower + (Upper - Lower) / 2>::value))>> {};
1740 template <std::
intmax_t Lower, std::
intmax_t Upper>
1741 struct DoubleSidedSearch_<Lower, Upper,
std::false_type, std::false_type> : DoubleSidedSearch_<Lower, Lower + (Upper - Lower) / 2> {};
1743 template <std::
intmax_t Lower, std::
intmax_t Upper,
typename Condition2>
1744 struct DoubleSidedSearch_<Lower, Upper,
std::true_type, Condition2> : std::integral_constant<std::intmax_t, Lower>{};
1746 template <std::
intmax_t Lower, std::
intmax_t Upper,
typename Condition1>
1747 struct DoubleSidedSearch_<Lower, Upper, Condition1,
std::true_type> : DoubleSidedSearch_<Lower + (Upper - Lower) / 2, Upper>{};
1749 template <std::
intmax_t Lower,
class =
void>
1750 struct SingleSidedSearch_ : SingleSidedSearch_<Lower, std::integral_constant<bool, Predicate<SafeDouble_<Lower>::value>::value>>{};
1752 template <std::
intmax_t Lower>
1753 struct SingleSidedSearch_<Lower,
std::false_type> : DoubleSidedSearch_<Lower, SafeDouble_<Lower>::value> {};
1755 template <std::
intmax_t Lower>
1756 struct SingleSidedSearch_<Lower,
std::true_type> : SingleSidedSearch_<SafeDouble_<Lower>::value>{};
1758 static constexpr std::intmax_t value = SingleSidedSearch_<1>::value;
1761 template <
template <std::
intmax_t N>
class Predicate>
1762 struct BinarySearch<Predicate,
std::enable_if_t<!Predicate<1>::value>> : std::integral_constant<std::intmax_t, 0>{};
1765 template <
typename R>
1768 template <std::
intmax_t N>
using Predicate_ = std::ratio_less_equal<std::ratio<N>, std::ratio_divide<R, std::ratio<N>>>;
1769 static constexpr const std::intmax_t value = BinarySearch<Predicate_>::value;
1772 template <
typename R>
1773 struct IsPerfectSquare
1775 static constexpr const std::intmax_t DenSqrt_ = Integer<std::ratio<R::den>>::value;
1776 static constexpr const std::intmax_t NumSqrt_ = Integer<std::ratio<R::num>>::value;
1777 static constexpr const bool value =( DenSqrt_ * DenSqrt_ == R::den && NumSqrt_ * NumSqrt_ == R::num);
1778 using Sqrt = std::ratio<NumSqrt_, DenSqrt_>;
1782 template <
typename Tp,
typename Tq>
1790 template <
typename R>
1793 using P_ =
typename R::P;
1794 using Q_ =
typename R::Q;
1795 using Den_ = std::ratio_subtract<P_, Square<Q_>>;
1796 using A_ = std::ratio_divide<Q_, Den_>;
1797 using B_ = std::ratio_divide<P_, Square<Den_>>;
1798 static constexpr const std::intmax_t I_ = (A_::num + Integer<std::ratio_multiply<B_, Square<std::ratio<A_::den>>>>::value) / A_::den;
1799 using I = std::ratio<I_>;
1800 using Rem = Remainder<B_, std::ratio_subtract<I, A_>>;
1807 template <
typename Tr, std::
intmax_t N>
1808 struct ContinuedFraction
1810 template <
typename T>
1811 using Abs_ = std::conditional_t<std::ratio_less_v<T, Zero>, std::ratio_subtract<Zero, T>, T>;
1814 using Last_ = ContinuedFraction<
R, N - 1>;
1815 using Reciprocal_ = Reciprocal<typename Last_::Rem>;
1816 using Rem =
typename Reciprocal_::Rem;
1817 using I_ =
typename Reciprocal_::I;
1818 using Den_ = std::ratio_add<typename Last_::W, I_>;
1819 using U = std::ratio_divide<typename Last_::V, Den_>;
1820 using V = std::ratio_divide<std::ratio_add<typename Last_::U, std::ratio_multiply<typename Last_::V, I_>>, Den_>;
1821 using W = std::ratio_divide<One, Den_>;
1822 using Error = Abs_<std::ratio_divide<std::ratio_subtract<U, std::ratio_multiply<V, W>>,
typename Reciprocal<Rem>::I>>;
1825 template <
typename Tr>
1826 struct ContinuedFraction<Tr, 1>
1830 using V = std::ratio<Integer<R>::value>;
1832 using Rem = Remainder<R, V>;
1833 using Error = std::ratio_divide<One, typename Reciprocal<Rem>::I>;
1836 template <
typename R,
typename Eps, std::
intmax_t N = 1,
typename =
void>
1837 struct Sqrt_ : Sqrt_<R, Eps, N + 1> {};
1839 template <
typename R,
typename Eps, std::
intmax_t N>
1840 struct Sqrt_<
R, Eps, N,
std::enable_if_t<std::ratio_less_equal_v<typename ContinuedFraction<R, N>::Error, Eps>>>
1842 using type =
typename ContinuedFraction<R, N>::V;
1845 template <
typename R,
typename,
typename =
void>
1848 static_assert(std::ratio_greater_equal_v<R, Zero>,
"R can't be negative");
1851 template <
typename R,
typename Eps>
1852 struct Sqrt<
R, Eps,
std::enable_if_t<std::ratio_greater_equal_v<R, Zero> && IsPerfectSquare<R>::value>>
1854 using type =
typename IsPerfectSquare<R>::Sqrt;
1857 template <
typename R,
typename Eps>
1858 struct Sqrt<
R, Eps,
std::enable_if_t<(std::ratio_greater_equal_v<R, Zero> && !IsPerfectSquare<R>::value)>> : Sqrt_<R, Eps>{};
1883 template<RatioType Ratio, std::
intmax_t Eps = 10000000000>
1884 using ratio_sqrt =
typename units::detail::Sqrt<Ratio, std::ratio<1, Eps>>::type;
1894 template<ConversionFactorType Unit, std::
intmax_t Eps>
1897 using Conversion =
typename Unit::conversion_ratio;
1899 std::ratio_divide<typename Unit::pi_exponent_ratio, std::ratio<2>>, std::ratio<0>>;
1925 template<ConversionFactorType Cf, std::
intmax_t Eps = 10000000000>
1926 using square_root =
typename detail::sqrt_impl<Cf, Eps>::type;
1941 struct compound_impl;
1943 template<ConversionFactorType Cf>
1944 struct compound_impl<Cf>
1950 struct compound_impl<Cf1, Cf2, Cfs...> : compound_impl<unit_multiply<Cf1, Cf2>, Cfs...>
1981 template<RatioType Ratio, ConversionFactorType ConversionFactor>
1988 template<
int N, RatioType R>
1989 struct power_of_ratio
1991 using type = std::ratio_multiply<
R,
typename power_of_ratio<N - 1,
R>::type>;
1995 template<RatioType R>
1996 struct power_of_ratio<1,
R>
2008 template<ConversionFactorType Cf>
using atto =
typename detail::prefix<std::atto,Cf>::type;
2009 template<ConversionFactorType Cf>
using femto =
typename detail::prefix<std::femto,Cf>::type;
2010 template<ConversionFactorType Cf>
using pico =
typename detail::prefix<std::pico,Cf>::type;
2011 template<ConversionFactorType Cf>
using nano =
typename detail::prefix<std::nano,Cf>::type;
2012 template<ConversionFactorType Cf>
using micro =
typename detail::prefix<std::micro,Cf>::type;
2013 template<ConversionFactorType Cf>
using milli =
typename detail::prefix<std::milli,Cf>::type;
2014 template<ConversionFactorType Cf>
using centi =
typename detail::prefix<std::centi,Cf>::type;
2015 template<ConversionFactorType Cf>
using deci =
typename detail::prefix<std::deci,Cf>::type;
2016 template<ConversionFactorType Cf>
using deca =
typename detail::prefix<std::deca,Cf>::type;
2017 template<ConversionFactorType Cf>
using hecto =
typename detail::prefix<std::hecto,Cf>::type;
2018 template<ConversionFactorType Cf>
using kilo =
typename detail::prefix<std::kilo,Cf>::type;
2019 template<ConversionFactorType Cf>
using mega =
typename detail::prefix<std::mega,Cf>::type;
2020 template<ConversionFactorType Cf>
using giga =
typename detail::prefix<std::giga,Cf>::type;
2021 template<ConversionFactorType Cf>
using tera =
typename detail::prefix<std::tera,Cf>::type;
2022 template<ConversionFactorType Cf>
using peta =
typename detail::prefix<std::peta,Cf>::type;
2023 template<ConversionFactorType Cf>
using exa =
typename detail::prefix<std::exa, Cf>::type;
2030 template<ConversionFactorType Cf>
using kibi =
typename detail::prefix<std::ratio<1024>, Cf>::type;
2031 template<ConversionFactorType Cf>
using mebi =
typename detail::prefix<std::ratio<1048576>, Cf>::type;
2032 template<ConversionFactorType Cf>
using gibi =
typename detail::prefix<std::ratio<1073741824>, Cf>::type;
2033 template<ConversionFactorType Cf>
using tebi =
typename detail::prefix<std::ratio<1099511627776>, Cf>::type;
2034 template<ConversionFactorType Cf>
using pebi =
typename detail::prefix<std::ratio<1125899906842624>, Cf>::type;
2035 template<ConversionFactorType Cf>
using exbi =
typename detail::prefix<std::ratio<1152921504606846976>, Cf>::type;
2056 template<ConversionFactorType Cf1, ConversionFactorType Cf2>
2058 : std::conjunction<std::is_same<dimension_of_t<typename conversion_factor_traits<Cf1>::dimension_type>, dimension_of_t<typename conversion_factor_traits<Cf2>::dimension_type>>>
2062 template<ConversionFactorType Cf1, ConversionFactorType Cf2>
2072 template<ConversionFactorType Cf>
2073 inline constexpr bool is_affine_conversion_factor_v = !std::ratio_equal_v<typename conversion_factor_traits<Cf>::translation_ratio, std::ratio<0>>;
2089 template<
typename T>
2090 struct floating_point_promotion : std::conditional<std::is_floating_point_v<T>, T, double>
2094 template<
typename T>
2095 using floating_point_promotion_t =
typename floating_point_promotion<T>::type;
2097 template<ConversionFactorType Cf,
typename T,
class Ns>
2098 struct floating_point_promotion<unit<Cf, T, Ns>>
2100 using type = unit<Cf, floating_point_promotion_t<T>, Ns>;
2114 template<
class To,
class From>
2115 constexpr To exact_integral_cast(From value)
2117 const To result =
static_cast<To
>(value);
2118 if (
static_cast<From
>(result) != value)
2119 throw "a floating-point unit converts to an integral unit only when its value is a whole number in range";
2126 template<std::
floating_po
int T>
2127 constexpr T sqrtNewtonRaphson(T x, T curr, T prev)
2129 return curr == prev ? curr : sqrtNewtonRaphson(x, T{0.5} * (curr + x / curr), curr);
2134 template<ArithmeticType T>
2135 constexpr detail::floating_point_promotion_t<T> sqrt(T x_)
2137 using FloatingPoint = detail::floating_point_promotion_t<T>;
2139 const FloatingPoint x(x_);
2141 return x >= 0 && x < std::numeric_limits<FloatingPoint>::infinity() ? Detail::sqrtNewtonRaphson(x, x, FloatingPoint(0)) : std::numeric_limits<FloatingPoint>::quiet_NaN();
2147 template<
unsigned long long Exp,
typename B>
2148 constexpr auto pow_acc(B acc, B
base [[maybe_unused]])
noexcept
2150 if constexpr (Exp == 0)
2152 return static_cast<B
>(acc);
2154 else if constexpr ((Exp & 1) == 0)
2156 return pow_acc<Exp / 2>(acc,
base *
base);
2160 return pow_acc<(Exp - 1) / 2>(acc *
base,
base *
base);
2166 template<
signed long long Exp, ArithmeticType B>
2167 constexpr detail::floating_point_promotion_t<B> pow(B base)
noexcept
2169 using promoted_t = detail::floating_point_promotion_t<B>;
2170 constexpr auto one =
static_cast<promoted_t
>(1);
2171 if constexpr (Exp >= 0)
2173 return detail::pow_acc<Exp>(one,
static_cast<promoted_t
>(base));
2175 constexpr auto new_exp =
static_cast<unsigned long long>(-(Exp + 1));
2176 return 1 / (
base * detail::pow_acc<new_exp>(one,
static_cast<promoted_t
>(base)));
2182 template<
typename T1,
typename T2>
2183 constexpr auto pow_acc(T1 acc, T1 x, T2 y)
noexcept
2191 return pow_acc(acc, x * x, y / 2);
2193 return pow_acc(acc * x, x * x, (y - 1) / 2);
2198 template<ArithmeticType T1, ArithmeticType T2>
2199 requires std::is_unsigned_v<T2>
2200 constexpr detail::floating_point_promotion_t<T1> pow(T1 x, T2 y)
noexcept
2202 using promoted_t = detail::floating_point_promotion_t<T1>;
2203 return detail::pow_acc(
static_cast<promoted_t
>(1.0),
static_cast<promoted_t
>(x), y);
2206 template<ArithmeticType T1, ArithmeticType T2>
2207 requires std::is_signed_v<T2>
2208 constexpr detail::floating_point_promotion_t<T1> pow(T1 x, T2 y)
noexcept
2212 return pow(x,
static_cast<unsigned long long>(y));
2214 return 1 / (x * pow(x,
static_cast<unsigned long long>(-(y + 1))));
2217 template<ArithmeticType T>
2218 constexpr T abs(T x)
2220 return x < 0 ? -x : x;
2231 struct linearized_value_t
2233 explicit linearized_value_t() =
default;
2246#if defined(__SIZEOF_INT128__)
2247 using widest_signed_int = __int128;
2248 using widest_unsigned_int =
unsigned __int128;
2249 inline constexpr bool has_builtin_int128 =
true;
2251 using widest_signed_int = std::intmax_t;
2252 using widest_unsigned_int = std::uintmax_t;
2253 inline constexpr bool has_builtin_int128 =
false;
2261 constexpr Rep widening_mul_div(Rep value, std::intmax_t num, std::intmax_t den)
noexcept
2263 if constexpr (has_builtin_int128)
2265 return static_cast<Rep
>(
static_cast<widest_signed_int
>(value) *
static_cast<widest_signed_int
>(num) /
static_cast<widest_signed_int
>(den));
2272 const bool negative = (value < 0);
2273 const std::uint64_t a = negative ?
static_cast<std::uint64_t
>(-(value + 1)) + 1u : static_cast<std::uint64_t>(value);
2274 const std::uint64_t b =
static_cast<std::uint64_t
>(num);
2275 const std::uint64_t d =
static_cast<std::uint64_t
>(den);
2278 const std::uint64_t aLo = a & 0xFFFFFFFFull, aHi = a >> 32;
2279 const std::uint64_t bLo = b & 0xFFFFFFFFull, bHi = b >> 32;
2280 const std::uint64_t ll = aLo * bLo;
2281 const std::uint64_t lh = aLo * bHi;
2282 const std::uint64_t hl = aHi * bLo;
2283 const std::uint64_t hh = aHi * bHi;
2284 const std::uint64_t cross = (ll >> 32) + (lh & 0xFFFFFFFFull) + (hl & 0xFFFFFFFFull);
2285 std::uint64_t hi = hh + (lh >> 32) + (hl >> 32) + (cross >> 32);
2286 std::uint64_t lo = (cross << 32) | (ll & 0xFFFFFFFFull);
2289 std::uint64_t quotient = 0;
2290 std::uint64_t rem = 0;
2291 for (
int bit = 127; bit >= 0; --bit)
2293 rem = (rem << 1) | ((bit >= 64 ? (hi >> (bit - 64)) : (lo >> bit)) & 1u);
2294 const bool canSubtract = (rem >= d);
2295 rem -= canSubtract ? d : 0u;
2297 quotient |= (
static_cast<std::uint64_t
>(canSubtract) << bit);
2299 const auto result =
static_cast<Rep
>(quotient);
2300 return negative ?
static_cast<Rep
>(-result) : result;
2311 constexpr bool integral_conversion_is_exact(Rep value, std::intmax_t num, std::intmax_t den)
noexcept
2313 const widest_signed_int product =
static_cast<widest_signed_int
>(value) *
static_cast<widest_signed_int
>(num);
2314 return product %
static_cast<widest_signed_int
>(den) == 0;
2329 template<
class To,
class From>
2330 constexpr To exact_integral_unit_cast(From value, std::intmax_t num, std::intmax_t den)
2332 if (!integral_conversion_is_exact(value, num, den))
2333 throw "an integral unit converts to a coarser integral unit only when the value is an exact whole number of the target unit";
2334 return static_cast<To
>(widening_mul_div(value, num, den));
2358 template<ConversionFactorType ConversionFactorFrom, ConversionFactorType ConversionFactorTo, ArithmeticType To = UNIT_LIB_DEFAULT_TYPE, ArithmeticType From>
2359 requires(traits::is_same_dimension_conversion_factor_v<ConversionFactorFrom, ConversionFactorTo>)
2360 constexpr To
convert(
const From& value)
noexcept
2362 using Ratio = std::ratio_divide<typename ConversionFactorFrom::conversion_ratio, typename ConversionFactorTo::conversion_ratio>;
2363 using PiRatio = std::ratio_subtract<typename ConversionFactorFrom::pi_exponent_ratio, typename ConversionFactorTo::pi_exponent_ratio>;
2365 std::ratio_divide<std::ratio_subtract<typename ConversionFactorFrom::translation_ratio, typename ConversionFactorTo::translation_ratio>,
typename ConversionFactorTo::conversion_ratio>;
2367 [[maybe_unused]]
constexpr auto normal_convert = []<
typename T0>(
const T0& val)
2374 [[maybe_unused]]
constexpr auto pi_convert = []<
typename T0>(
const T0& val)
2376 using ResolvedUnitFrom =
2383 if constexpr (std::same_as<ConversionFactorFrom, ConversionFactorTo>)
2385 return static_cast<To
>(value);
2388 else if constexpr (!std::same_as<std::ratio<0>, PiRatio> && std::same_as<std::ratio<0>, Translation>)
2390 using CommonUnderlying = std::common_type_t<To, From, UNIT_LIB_DEFAULT_TYPE>;
2395 constexpr long double PiRatioValue =
static_cast<long double>(PiRatio::num) /
static_cast<long double>(PiRatio::den);
2396 constexpr bool integerExponent = (PiRatio::num % PiRatio::den == 0);
2400 if constexpr (integerExponent && PiRatioValue >= 0)
2402 return static_cast<To
>(normal_convert(
static_cast<CommonUnderlying
>(value) *
static_cast<CommonUnderlying
>(pow(detail::PI_VAL, PiRatioValue))));
2404 else if constexpr (integerExponent)
2406 return static_cast<To
>(normal_convert(
static_cast<CommonUnderlying
>(value) /
static_cast<CommonUnderlying
>(pow(detail::PI_VAL, -PiRatioValue))));
2410 return static_cast<To
>(normal_convert(
static_cast<CommonUnderlying
>(value) *
static_cast<CommonUnderlying
>(std::pow(detail::PI_VAL, PiRatioValue))));
2414 else if constexpr (std::same_as<std::ratio<0>, PiRatio> && !std::same_as<std::ratio<0>, Translation>)
2416 using CommonUnderlying = std::common_type_t<To, From, UNIT_LIB_DEFAULT_TYPE>;
2418 return static_cast<To
>(normal_convert(
static_cast<CommonUnderlying
>(value)) + (
static_cast<CommonUnderlying
>(Translation::num) /
static_cast<CommonUnderlying
>(Translation::den)));
2421 else if constexpr (!std::same_as<std::ratio<0>, PiRatio> && !std::same_as<std::ratio<0>, Translation>)
2423 using CommonUnderlying = std::common_type_t<To, From, UNIT_LIB_DEFAULT_TYPE>;
2425 return static_cast<To
>(pi_convert(
static_cast<CommonUnderlying
>(value)) + (
static_cast<CommonUnderlying
>(Translation::num) /
static_cast<CommonUnderlying
>(Translation::den)));
2430 using CommonUnderlying = std::common_type_t<To, From, std::intmax_t>;
2432 if constexpr (Ratio::num == 1 && Ratio::den == 1)
2433 return static_cast<To
>(value);
2434 if constexpr (Ratio::num != 1 && Ratio::den == 1)
2435 return static_cast<To
>(
static_cast<CommonUnderlying
>(value) *
static_cast<CommonUnderlying
>(Ratio::num));
2436 if constexpr (Ratio::num == 1 && Ratio::den != 1)
2437 return static_cast<To
>(
static_cast<CommonUnderlying
>(value) /
static_cast<CommonUnderlying
>(Ratio::den));
2438 if constexpr (Ratio::num != 1 && Ratio::den != 1)
2448 if constexpr (std::is_integral_v<CommonUnderlying>)
2450 return static_cast<To
>(detail::widening_mul_div(
static_cast<CommonUnderlying
>(value), Ratio::num, Ratio::den));
2454 const CommonUnderlying v =
static_cast<CommonUnderlying
>(value);
2455 const CommonUnderlying num =
static_cast<CommonUnderlying
>(Ratio::num);
2456 const CommonUnderlying den =
static_cast<CommonUnderlying
>(Ratio::den);
2459 const CommonUnderlying limit = (std::numeric_limits<CommonUnderlying>::max)() / num;
2460 if (v > limit || v < -limit)
2461 return static_cast<To
>((v / den) * num);
2462 return static_cast<To
>((v * num) / den);
2476 template<UnitType UnitFrom, UnitType UnitTo>
2477 struct delayed_is_same_dimension_conversion_factor : std::false_type
2479 static constexpr bool value = traits::is_same_dimension_conversion_factor_v<typename UnitFrom::conversion_factor, typename UnitTo::conversion_factor>;
2496 template<UnitType UnitTo, UnitType UnitFrom>
2498 constexpr UnitTo
convert(
const UnitFrom& from)
noexcept
2509#ifdef FOR_DOXYGEN_PURPOSOES_ONLY
2516 template<
typename T>
2519 typedef typename T::numerical_scale_type numerical_scale_type;
2522 typedef typename T::underlying_type underlying_type;
2523 typedef typename T::value_type value_type;
2524 typedef typename T::conversion_factor conversion_factor;
2533 template<
typename,
typename =
void>
2536 using numerical_scale_type = void;
2537 using underlying_type = void;
2538 using value_type = void;
2539 using conversion_factor = void;
2542 template<ArithmeticType T>
2543 struct unit_traits<T, std::void_t<T>>
2545 using numerical_scale_type = void;
2546 using underlying_type = T;
2547 using value_type = void;
2548 using conversion_factor = units::conversion_factor<std::ratio<1>, dimension_t<>>;
2556 template<NonArithmeticType T>
2557 struct unit_traits<T, std::void_t<typename T::numerical_scale_type, typename T::underlying_type, typename T::value_type, typename T::conversion_factor>>
2559 using numerical_scale_type =
typename T::numerical_scale_type;
2560 using underlying_type =
typename T::underlying_type;
2561 using value_type =
typename T::value_type;
2562 using conversion_factor =
typename T::conversion_factor;
2573 template<UnitType U>
2574 inline constexpr bool is_affine_unit_v = is_affine_conversion_factor_v<typename unit_traits<U>::conversion_factor>;
2586 template<UnitType U1, UnitType U2>
2588 : std::conjunction<is_unit<U1>, is_unit<U2>, is_same_dimension_conversion_factor<typename unit_traits<U1>::conversion_factor, typename unit_traits<U2>::conversion_factor>>
2592 template<UnitType U1, UnitType U2>
2606 template<
class U,
class =
void>
2607 struct rewrap_to_named;
2609 using rewrap_to_named_t =
typename rewrap_to_named<U>::type;
2614 template<
class From,
class To>
2615 inline constexpr bool is_losslessly_convertible = std::is_arithmetic_v<From> && (std::is_floating_point_v<To> || !std::is_floating_point_v<From>);
2621 template<ConversionFactorType ConversionFactorFrom, ConversionFactorType ConversionFactorTo>
2622 struct is_non_truncated_convertible_unit : std::false_type
2624 static constexpr bool value = std::ratio_divide<typename ConversionFactorFrom::conversion_ratio, typename ConversionFactorTo::conversion_ratio>::den == 1;
2630 template<
class UnitFrom,
class UnitTo>
2631 inline constexpr bool is_losslessly_convertible_unit = std::conjunction_v<traits::is_same_dimension_unit<UnitFrom, UnitTo>,
2632 std::disjunction<std::is_floating_point<typename UnitTo::underlying_type>,
2633 std::conjunction<std::negation<std::is_floating_point<typename UnitFrom::underlying_type>>,
2634 is_non_truncated_convertible_unit<typename UnitFrom::conversion_factor, typename UnitTo::conversion_factor>>>>;
2637 template<
class L,
class R>
2638 inline constexpr bool both_floating_v = std::is_floating_point_v<typename traits::unit_traits<L>::underlying_type> &&
2639 std::is_floating_point_v<typename traits::unit_traits<R>::underlying_type>;
2647 template<
class L,
class R>
2648 using lhs_result_unit_t = std::conditional_t<is_losslessly_convertible_unit<R, L> || both_floating_v<L, R>, L, std::common_type_t<L, R>>;
2656 template<
class Source,
class StrongCf,
class Scale,
class =
void>
2657 struct deduced_named_underlying
2659 using type =
typename traits::unit_traits<Source>::underlying_type;
2661 template<
class Source,
class StrongCf,
class Scale>
2662 struct deduced_named_underlying<Source, StrongCf, Scale,
2663 std::enable_if_t<traits::is_unit_v<Source> &&
2664 traits::is_same_dimension_unit_v<Source, unit<StrongCf, typename traits::unit_traits<Source>::underlying_type, Scale>>>>
2667 using Src =
typename traits::unit_traits<Source>::underlying_type;
2670 using type = std::conditional_t<is_losslessly_convertible_unit<Source, unit<StrongCf, Src, Scale>>, Src, floating_point_promotion_t<Src>>;
2672 template<
class Source,
class StrongCf,
class Scale>
2673 using deduced_named_underlying_t =
typename deduced_named_underlying<Source, StrongCf, Scale>::type;
2675 template<RatioType Ratio>
2676 using time_conversion_factor = conversion_factor<Ratio, dimension::time>;
2681 template<ConversionFactorType ConversionFactor>
2682 inline constexpr bool is_time_conversion_factor = traits::is_same_dimension_conversion_factor_v<ConversionFactor, time_conversion_factor<std::ratio<1>>>;
2744#define MSVC_EBO __declspec(empty_bases)
2748 template<ConversionFactorType ConversionFactor, ArithmeticType T = UNIT_LIB_DEFAULT_TYPE, NumericalScaleType<T> NumericalScale = linear_scale>
2752 using numerical_scale_type = NumericalScale;
2761 constexpr unit() =
default;
2767 constexpr unit(
const unit&) =
default;
2774 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2775 requires traits::is_same_dimension_unit_v<unit<ConversionFactorRhs, Ty, NsRhs>, unit> && detail::is_losslessly_convertible_unit<unit<ConversionFactorRhs, Ty, NsRhs>, unit>
2776 constexpr unit(
const unit<ConversionFactorRhs, Ty, NsRhs>& rhs) noexcept
2793 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2794 requires(traits::is_same_dimension_unit_v<unit<ConversionFactorRhs, Ty, NsRhs>, unit> &&
2795 !detail::is_losslessly_convertible_unit<unit<ConversionFactorRhs, Ty, NsRhs>, unit> &&
2796 std::is_floating_point_v<Ty> && std::is_integral_v<T>)
2797 consteval unit(
const unit<ConversionFactorRhs, Ty, NsRhs>& rhs)
2798 :
_linearized_value(detail::exact_integral_cast<T>(unit<ConversionFactor, detail::floating_point_promotion_t<T>, NumericalScale>(rhs).
raw()))
2816 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2817 requires(traits::is_same_dimension_unit_v<unit<ConversionFactorRhs, Ty, NsRhs>, unit> &&
2818 !detail::is_losslessly_convertible_unit<unit<ConversionFactorRhs, Ty, NsRhs>, unit> &&
2819 std::is_integral_v<Ty> && std::is_integral_v<T>)
2820 consteval unit(
const unit<ConversionFactorRhs, Ty, NsRhs>& rhs)
2822 std::ratio_divide<typename ConversionFactorRhs::conversion_ratio, typename ConversionFactor::conversion_ratio>::num,
2823 std::ratio_divide<typename ConversionFactorRhs::conversion_ratio, typename ConversionFactor::conversion_ratio>::den))
2832 template<ArithmeticType Ty>
2834 explicit constexpr unit(Ty value) noexcept
2835 : _linearized_value(NumericalScale::linearize(
static_cast<T
>(value)))
2844 template<ArithmeticType Ty>
2845 requires detail::is_losslessly_convertible<Ty, T>
2847 : _linearized_value(value)
2856 template<ArithmeticType Ty>
2858 constexpr unit(Ty value) noexcept
2859 : _linearized_value(NumericalScale::linearize(
static_cast<T
>(value)))
2868 template<ArithmeticType Rep, RatioType Period>
2869 requires detail::is_time_conversion_factor<ConversionFactor> && detail::is_losslessly_convertible<Rep, T> &&
2870 detail::is_losslessly_convertible_unit<units::unit<units::conversion_factor<Period, dimension::time>, Rep>, unit>
2871 constexpr unit(
const std::chrono::duration<Rep, Period>&
value) noexcept
2881 constexpr unit&
operator=(
const unit& rhs)
noexcept =
default;
2888 template<ConversionFactorType Cf = ConversionFactor>
2892 unit<units::conversion_factor<std::ratio<1>, units::dimension::dimensionless>,
underlying_type,
linear_scale> dimensionlessRhs(rhs);
2903 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2906 return value_compare(rhs) < 0;
2915 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2918 return value_compare(rhs) <= 0;
2927 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2930 return value_compare(rhs) > 0;
2939 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2942 return value_compare(rhs) >= 0;
2952 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2953 requires(std::floating_point<T> || std::floating_point<Ty>)
2954 constexpr bool operator==(
const unit<ConversionFactorRhs, Ty, NsRhs>& rhs)
const noexcept
2956 using CommonUnit = std::common_type_t<unit, unit<ConversionFactorRhs, Ty, NsRhs>>;
2957 using CommonUnderlying =
typename CommonUnit::underlying_type;
2959 const auto common_lhs(CommonUnit(*this)._linearized_value);
2962 return abs(common_lhs - common_rhs) < std::numeric_limits<CommonUnderlying>::epsilon() * abs(common_lhs + common_rhs) ||
2963 abs(common_lhs - common_rhs) < std::numeric_limits<CommonUnderlying>::min();
2966 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2967 requires(std::integral<T> && std::integral<Ty>)
2970 return value_compare(rhs) == 0;
2980 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2981 constexpr bool operator!=(
const unit<ConversionFactorRhs, Ty, NsRhs>& rhs)
const noexcept
2983 return !(*
this == rhs);
2992 constexpr underlying_type raw() const noexcept
2994 return static_cast<underlying_type
>(NumericalScale::scale(_linearized_value));
3004 constexpr auto value() const noexcept
3006 using CfTraits = traits::conversion_factor_traits<ConversionFactor>;
3008 constexpr bool needs_fp = traits::is_ratio_dimensionless_cf_v<ConversionFactor> || !std::ratio_equal_v<typename CfTraits::pi_exponent_ratio, std::ratio<0>> ||
3009 !std::ratio_equal_v<typename CfTraits::translation_ratio, std::ratio<0>>;
3011 using normalized_value_type = std::conditional_t<needs_fp, detail::floating_point_promotion_t<underlying_type>, underlying_type>;
3017 using Under = normalized_value_type;
3027 return static_cast<normalized_value_type
>(
raw());
3035 template<ArithmeticType Ty>
3036 constexpr Ty to() const noexcept
3038 return static_cast<Ty
>(*this);
3050 template<
template<
class>
class UnitType>
3061 constexpr T to_linearized() const noexcept
3063 return _linearized_value;
3076 template<ConversionFactorType Cf, ArithmeticType Ty = T>
3077 constexpr unit<Cf, Ty>
convert() const noexcept
3079 return unit<Cf, Ty>(*
this);
3091 template<
template<
class>
class UnitType>
3102 template<ArithmeticType Ty>
3104 constexpr operator Ty() const noexcept
3108 return static_cast<Ty
>(this->value());
3115 template<ArithmeticType Ty>
3117 constexpr explicit operator Ty()
const noexcept
3119 return static_cast<Ty
>(this->value());
3126 template<ArithmeticType Rep, RatioType Period, ConversionFactorType Cf = ConversionFactor>
3127 requires detail::is_time_conversion_factor<Cf> && detail::is_losslessly_convertible<T, Rep>
3128 constexpr operator std::chrono::duration<Rep, Period>() const noexcept
3136 template<UnitType Unit = unit>
3137 [[nodiscard]]
constexpr const char* name() const noexcept
3142 constexpr const char* n = unit_name_v<detail::rewrap_to_named_t<Unit>>;
3149 template<UnitType Unit = unit>
3150 [[nodiscard]]
constexpr const char* abbreviation() const noexcept
3155 constexpr const char* a = unit_abbreviation_v<detail::rewrap_to_named_t<Unit>>;
3159 template<ConversionFactorType Cf, ArithmeticType Ty, NumericalScaleType<Ty> Ns>
3167 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
3168 constexpr auto value_compare(
const unit<ConversionFactorRhs, Ty, NsRhs>& rhs)
const noexcept
3170 using CommonUnit = std::common_type_t<unit, unit<ConversionFactorRhs, Ty, NsRhs>>;
3171 if constexpr (std::is_integral_v<T> && std::is_integral_v<Ty>)
3174 using Wide = std::conditional_t<std::is_unsigned_v<T> && std::is_unsigned_v<Ty>,
3175 detail::widest_unsigned_int, detail::widest_signed_int>;
3176 using CommonRatio =
typename traits::conversion_factor_traits<typename CommonUnit::conversion_factor>::conversion_ratio;
3177 using LhsScale = std::ratio_divide<typename traits::conversion_factor_traits<ConversionFactor>::conversion_ratio, CommonRatio>;
3178 using RhsScale = std::ratio_divide<typename traits::conversion_factor_traits<ConversionFactorRhs>::conversion_ratio, CommonRatio>;
3180 if constexpr (LhsScale::den == 1 && RhsScale::den == 1 &&
3181 (std::is_signed_v<T> == std::is_signed_v<Ty> ||
3182 (
sizeof(detail::widest_signed_int) >
sizeof(T) &&
sizeof(detail::widest_signed_int) >
sizeof(Ty))))
3184 constexpr Wide lhsMultiplier =
static_cast<Wide
>(LhsScale::num);
3185 constexpr Wide rhsMultiplier =
static_cast<Wide
>(RhsScale::num);
3186 constexpr Wide cap = std::numeric_limits<Wide>::max();
3188 const Wide lhsRaw =
static_cast<Wide
>(_linearized_value);
3192 const auto fits = [](Wide value, Wide multiplier) {
3193 const Wide bound = cap / multiplier;
3194 if constexpr (std::is_unsigned_v<Wide>)
3195 return value <= bound;
3197 return value <= bound && value >= -bound;
3200 if (fits(lhsRaw, lhsMultiplier) && fits(rhsRaw, rhsMultiplier))
3201 return lhsRaw * lhsMultiplier <=> rhsRaw * rhsMultiplier;
3204 const T lhsCommon = unit<typename CommonUnit::conversion_factor, T, NumericalScale>(*this)._linearized_value;
3205 const Ty rhsCommon = unit<typename CommonUnit::conversion_factor, Ty, NsRhs>(rhs)._linearized_value;
3206 if (std::cmp_less(lhsCommon, rhsCommon))
3207 return std::strong_ordering::less;
3208 if (std::cmp_greater(lhsCommon, rhsCommon))
3209 return std::strong_ordering::greater;
3210 return std::strong_ordering::equal;
3214 const auto lhsCommon = CommonUnit(*this)._linearized_value;
3215 const auto rhsCommon = CommonUnit(rhs)._linearized_value;
3216 return lhsCommon <=> rhsCommon;
3223 T _linearized_value;
3244 template<class T, bool = traits::is_unit<T>::value>
3249 struct is_named_unit_impl<T, true> : std::bool_constant<!std::is_same_v<T, unit_base_t<T>>>
3253 inline constexpr bool is_named_unit_v = is_named_unit_impl<T>::value;
3260 template<
class Cf1,
class Cf2>
3261 inline constexpr bool is_equivalent_conversion_factor_v =
3262 traits::is_same_dimension_conversion_factor_v<Cf1, Cf2> &&
3263 std::ratio_equal_v<typename Cf1::conversion_ratio, typename Cf2::conversion_ratio> &&
3264 std::ratio_equal_v<typename Cf1::pi_exponent_ratio, typename Cf2::pi_exponent_ratio> &&
3265 std::ratio_equal_v<typename Cf1::translation_ratio, typename Cf2::translation_ratio>;
3275 inline constexpr bool is_raw_conversion_factor_v =
3276 std::is_void_v<decltype(named_class_of(static_cast<Cf*>(
nullptr),
static_cast<linear_scale*
>(
nullptr)))>;
3282 template<
class Base,
class Named,
class =
void>
3287 template<
class Base,
class Named>
3289 std::enable_if_t<is_named_unit_v<Named> && std::is_same_v<typename Base::conversion_factor, typename Named::conversion_factor>>>
3291 using type =
typename Named::template rebind<typename Base::underlying_type>;
3297 template<
class Base,
class Named>
3299 std::enable_if_t<is_named_unit_v<Named> && !std::is_same_v<typename Base::conversion_factor, typename Named::conversion_factor> &&
3300 is_raw_conversion_factor_v<typename Base::conversion_factor> &&
3301 is_equivalent_conversion_factor_v<typename Base::conversion_factor, typename Named::conversion_factor>>>
3303 using type =
typename Named::template rebind<typename Base::underlying_type>;
3305 template<
class Base,
class Named>
3306 using rewrap_named_t =
typename rewrap_named<Base, Named>::type;
3311 template<
class ConversionFactor,
class Scale>
3312 void named_class_of(ConversionFactor*, Scale*, ...);
3320 template<
class U,
class>
3327 std::enable_if_t<traits::is_unit<U>::value &&
3328 !std::is_void_v<decltype(named_class_of(static_cast<typename U::conversion_factor*>(nullptr),
3329 static_cast<typename U::numerical_scale_type*>(nullptr)))>>>
3331 using type =
typename decltype(named_class_of(
static_cast<typename U::conversion_factor*
>(
nullptr),
3332 static_cast<typename U::numerical_scale_type*
>(
nullptr)))::template rebind<typename U::underlying_type>;
3341 template<
class Unit,
class Underlying>
3342 requires ::units::detail::is_named_unit_v<Unit>
3347 using type =
typename Unit::template rebind<Underlying>;
3353 template<
class Unit>
3354 requires is_named_unit_v<Unit>
3355 struct floating_point_promotion<Unit>
3359 using type =
typename Unit::template rebind<typename floating_point_promotion<unit_base_t<Unit>>::type::underlying_type>;
3377 template<UnitType UnitType, ArithmeticType T>
3378 requires detail::is_losslessly_convertible<T, typename UnitType::underlying_type>
3388#if defined(UNIT_LIB_ENABLE_STRING)
3402 template<
class D,
class E>
3406 if constexpr (E::num != 0)
3408 s.append(
" ").append(D::abbreviation);
3410 if constexpr (E::num != 0 && E::num != 1)
3412 s.append(
"^").append(std::to_string(E::num));
3414 if constexpr (E::den != 1)
3416 s.append(
"/").append(std::to_string(E::den));
3428 template<
class... Dims>
3466 template<label_form Form = label_form::abbreviation, ConversionFactorType ConversionFactor, ArithmeticType T, NumericalScaleType<T> NumericalScale>
3471 using NamedForm = detail::rewrap_to_named_t<unit<ConversionFactor, T, NumericalScale>>;
3474 if constexpr (Form == label_form::base)
3477 if constexpr (!DimType::empty)
3478 return dimension_to_string(DimType{});
3480 return std::string{};
3484 return std::string(
" ").append(unit_name<NamedForm>::value);
3486 else if constexpr (unit_abbreviation_v<NamedForm>)
3488 return std::string(
" ").append(unit_abbreviation<NamedForm>::value);
3493 if constexpr (!DimType::empty)
3496 return std::string{};
3512 template<ConversionFactorType ConversionFactor, ArithmeticType T, NumericalScaleType<T> NumericalScale>
3515 using NamedForm = detail::rewrap_to_named_t<unit<ConversionFactor, T, NumericalScale>>;
3516 return !
static_cast<bool>(unit_abbreviation_v<NamedForm>);
3522#if defined(UNIT_LIB_ENABLE_FORMAT)
3535 struct unit_format_options
3537 label_form form = label_form::abbreviation;
3538 bool showValue =
true;
3539 bool showUnit =
true;
3540 bool customSep =
false;
3541 std::string separator =
" ";
3547#if !defined(UNIT_LIB_DISABLE_IOSTREAM)
3553 template<
class D,
class E>
3554 std::ostream& operator<<(std::ostream& os,
const dim<D, E>&)
3556 if constexpr (E::num != 0)
3557 os <<
' ' << D::abbreviation;
3558 if constexpr (E::num != 0 && E::num != 1)
3560 os <<
"^" << E::num;
3562 if constexpr (E::den != 1)
3564 os <<
"/" << E::den;
3569 template<
class... Dims>
3572 ((os << Dims{}), ...);
3576 template<ConversionFactorType ConversionFactor, ArithmeticType T, NumericalScaleType<T> NumericalScale>
3586 using NamedForm = detail::rewrap_to_named_t<unit<ConversionFactor, T, NumericalScale>>;
3588 if constexpr (unit_abbreviation_v<NamedForm>)
3594 os << std::conditional_t<detail::is_losslessly_convertible_unit<std::decay_t<
decltype(obj)>, BaseUnit>, BaseUnit, PromotedBaseUnit>(obj).raw();
3596 os << detail::unit_label(obj);
3605 template<ConversionFactorType ConversionFactor, ArithmeticType T, NumericalScaleType<T> NumericalScale>
3615 using NamedForm = detail::rewrap_to_named_t<unit<ConversionFactor, T, NumericalScale>>;
3618 if constexpr (unit_abbreviation_v<NamedForm>)
3619 s = detail::to_string(obj.raw());
3621 s = detail::to_string(std::conditional_t<detail::is_losslessly_convertible_unit<std::decay_t<
decltype(obj)>, BaseUnit>, BaseUnit, PromotedBaseUnit>(obj).raw());
3623 s.append(detail::unit_label(obj));
3638 template<RatioType Ratio1, RatioType Ratio2>
3639 using ratio_gcd = std::ratio<std::gcd(Ratio1::num, Ratio2::num), std::lcm(Ratio1::den, Ratio2::den)>;
3647 template<RatioType Ratio1, RatioType Ratio2>
3648 using common_baggage_ratio = std::conditional_t<std::ratio_equal_v<Ratio1, Ratio2>, Ratio1, std::ratio<0>>;
3667 template<
class ConversionFactorLhs,
class Tx,
class ConversionFactorRhs,
class Ty,
class NumericalScale>
3668 struct common_type<
units::unit<ConversionFactorLhs, Tx, NumericalScale>,
units::unit<ConversionFactorRhs, Ty, NumericalScale>>
3669 : std::enable_if<units::traits::is_same_dimension_conversion_factor_v<ConversionFactorLhs, ConversionFactorRhs>,
3671 units::traits::strong_t<units::conversion_factor<units::detail::ratio_gcd<typename ConversionFactorLhs::conversion_ratio, typename ConversionFactorRhs::conversion_ratio>,
3672 units::traits::dimension_of_t<ConversionFactorLhs>, units::detail::ratio_gcd<typename ConversionFactorLhs::pi_exponent_ratio, typename ConversionFactorRhs::pi_exponent_ratio>,
3673 units::detail::common_baggage_ratio<typename ConversionFactorLhs::translation_ratio, typename ConversionFactorRhs::translation_ratio>>>,
3674 common_type_t<Tx, Ty>, NumericalScale>>
3679 template<
class UnitConversionT,
class T,
class NonLinearScale>
3680 struct common_type<
units::unit<UnitConversionT, T, NonLinearScale>,
units::unit<UnitConversionT, T, NonLinearScale>>
3690 template<
class Lhs,
class Rhs>
3692 (units::detail::is_named_unit_v<Lhs> || units::detail::is_named_unit_v<Rhs>) &&
3698 struct common_type<Lhs, Rhs>
3703 using viaLhs = units::detail::rewrap_named_t<base, Lhs>;
3706 using type = units::detail::rewrap_named_t<viaLhs, Rhs>;
3715 template<
class Named,
class Scalar>
3716 requires(units::detail::is_named_unit_v<Named> && std::is_arithmetic_v<Scalar> &&
3718 struct common_type<Named, Scalar>
3720 using type = units::detail::rewrap_named_t<common_type_t<units::detail::unit_base_t<Named>, Scalar>, Named>;
3722 template<
class Scalar,
class Named>
3723 requires(units::detail::is_named_unit_v<Named> && std::is_arithmetic_v<Scalar> &&
3725 struct common_type<Scalar, Named>
3727 using type = units::detail::rewrap_named_t<common_type_t<Scalar, units::detail::unit_base_t<Named>>, Named>;
3730 template<
class Ratio,
class T,
class NumericalScale,
class Rep,
class Period>
3731 struct common_type<
units::unit<units::detail::time_conversion_factor<Ratio>, T, NumericalScale>, chrono::duration<Rep, Period>>
3732 : std::common_type<units::unit<units::detail::time_conversion_factor<Ratio>, T, NumericalScale>, decltype(units::unit{chrono::duration<Rep, Period>{}})>
3736 template<
class ConversionFactor,
class T,
class NumericalScale,
class Rep,
class Period>
3737 struct common_type<chrono::duration<Rep, Period>,
units::unit<ConversionFactor, T, NumericalScale>>
3738 : std::common_type<units::unit<ConversionFactor, T, NumericalScale>, chrono::duration<Rep, Period>>
3742 template<
class ConversionFactor,
class Tx,
class NumericalScale,
class Ty>
3743 requires std::is_arithmetic_v<Ty>
3744 struct common_type<Ty,
units::unit<ConversionFactor, Tx, NumericalScale>>
3745 : std::enable_if<units::traits::is_dimensionless_unit<units::unit<ConversionFactor, Tx, NumericalScale>>::value,
3746 units::unit<units::conversion_factor<std::ratio<1>, units::dimension::dimensionless>, common_type_t<Tx, Ty>, NumericalScale>>
3750 template<
class ConversionFactor,
class Tx,
class NumericalScale,
class Ty>
3751 requires std::is_arithmetic_v<Ty>
3752 struct common_type<
units::unit<ConversionFactor, Tx, NumericalScale>, Ty>
3753 : std::enable_if<units::traits::is_dimensionless_unit<units::unit<ConversionFactor, Tx, NumericalScale>>::value,
3754 units::unit<units::conversion_factor<std::ratio<1>, units::dimension::dimensionless>, common_type_t<Tx, Ty>, NumericalScale>>
3762 template<
class ConversionFactorLhs,
class Tx,
class ConversionFactorRhs,
class Ty>
3763 struct common_type<
units::unit<ConversionFactorLhs, Tx, units::linear_scale>,
units::unit<ConversionFactorRhs, Ty, units::decibel_scale>>
3764 : common_type<units::unit<ConversionFactorLhs, Tx, units::linear_scale>, units::unit<ConversionFactorRhs, Ty, units::linear_scale>>
3768 template<
class ConversionFactorLhs,
class Tx,
class ConversionFactorRhs,
class Ty>
3769 struct common_type<units::unit<ConversionFactorLhs, Tx, units::decibel_scale>, units::unit<ConversionFactorRhs, Ty, units::linear_scale>>
3770 : common_type<units::unit<ConversionFactorLhs, Tx, units::linear_scale>, units::unit<ConversionFactorRhs, Ty, units::linear_scale>>
3797 template<ArithmeticType T, UnitType Unit>
3798 constexpr T
unit_cast(
const Unit& value)
noexcept
3800 return static_cast<T
>(value);
3817 template<
typename... T>
3818 struct has_linear_scale : std::conjunction<std::is_base_of<linear_scale, T>...>
3822 template<
typename... T>
3832 template<
typename... T>
3833 struct has_decibel_scale : std::conjunction<std::is_base_of<decibel_scale, T>...>
3837 template<
typename... T>
3868 static constexpr T
linearize(
const T value)
noexcept
3880 static constexpr T
scale(
const T value)
noexcept
3898 conversion_factor<std::ratio<1>, dimension::dimensionless>
strong_name(
3899 units::detail::conversion_factor_base_t<dimensionless_>*);
3906 template<
class Underlying = UNIT_LIB_DEFAULT_TYPE>
3922 struct type_identity
3928 using type_identity_t =
typename type_identity<T>::type;
3932 template<UnitType UnitTypeLhs>
3934 constexpr UnitTypeLhs&
operator+=(UnitTypeLhs& lhs,
const detail::type_identity_t<UnitTypeLhs>& rhs)
noexcept
3945 template<UnitType UnitTypeLhs>
3947 constexpr UnitTypeLhs&
operator+=(UnitTypeLhs& lhs,
const detail::type_identity_t<UnitTypeLhs>& rhs)
noexcept
3949 lhs = UnitTypeLhs(lhs.raw() + rhs.raw());
3953 template<UnitType UnitTypeLhs, ArithmeticType T>
3955 constexpr UnitTypeLhs&
operator+=(UnitTypeLhs& lhs, T rhs)
noexcept
3961 template<RatioDimensionlessUnitType U, ArithmeticType T>
3962 requires(traits::has_linear_scale_v<U>)
3963 constexpr U&
operator+=(U& lhs, T rhs)
noexcept
3965 using Underlying =
typename U::underlying_type;
3966 using R =
typename U::conversion_factor::conversion_ratio;
3970 constexpr long double points_per_one =
static_cast<long double>(R::den) /
static_cast<long double>(R::num);
3973 const long double new_points =
static_cast<long double>(lhs.raw()) + (
static_cast<long double>(rhs) * points_per_one);
3975 if constexpr (std::is_integral_v<Underlying>)
3977 lhs = U(
static_cast<Underlying
>(std::llround(new_points)));
3981 lhs = U(
static_cast<Underlying
>(new_points));
3987 template<RatioDimensionlessUnitType U, DimensionlessUnitType D>
3989 constexpr U&
operator+=(U& lhs,
const D& rhs)
noexcept
3992 return (lhs += rhs.value());
3995 template<RatioDimensionlessUnitType U, ArithmeticType T>
3996 requires(traits::has_linear_scale_v<U>)
3997 constexpr U&
operator-=(U& lhs, T rhs)
noexcept
3999 using Underlying =
typename U::underlying_type;
4000 using R =
typename U::conversion_factor::conversion_ratio;
4002 constexpr long double points_per_one =
static_cast<long double>(R::den) /
static_cast<long double>(R::num);
4004 const long double new_points =
static_cast<long double>(lhs.raw()) - (
static_cast<long double>(rhs) * points_per_one);
4006 if constexpr (std::is_integral_v<Underlying>)
4008 lhs = U(
static_cast<Underlying
>(std::llround(new_points)));
4012 lhs = U(
static_cast<Underlying
>(new_points));
4018 template<UnitType UnitTypeLhs>
4020 constexpr UnitTypeLhs&
operator-=(UnitTypeLhs& lhs,
const detail::type_identity_t<UnitTypeLhs>& rhs)
noexcept
4031 template<UnitType UnitTypeLhs>
4033 constexpr UnitTypeLhs&
operator-=(UnitTypeLhs& lhs,
const detail::type_identity_t<UnitTypeLhs>& rhs)
noexcept
4035 lhs = UnitTypeLhs(lhs.raw() - rhs.raw());
4039 template<UnitType UnitTypeLhs, ArithmeticType T>
4041 constexpr UnitTypeLhs&
operator-=(UnitTypeLhs& lhs,
const T& rhs)
noexcept
4047 template<RatioDimensionlessUnitType U, DimensionlessUnitType D>
4049 constexpr U&
operator-=(U& lhs,
const D& rhs)
noexcept
4051 return (lhs -= rhs.value());
4054 template<UnitType UnitTypeLhs, ArithmeticType T>
4056 constexpr UnitTypeLhs&
operator*=(UnitTypeLhs& lhs,
const T& rhs)
4063 typename UnitTypeLhs::underlying_type scaled = lhs.raw() * rhs;
4064 lhs = UnitTypeLhs(scaled, linearized_value);
4068 template<RatioDimensionlessUnitType U, RatioDimensionlessUnitType URhs>
4069 requires(traits::has_linear_scale_v<U, URhs>)
4070 constexpr U&
operator*=(U& lhs,
const URhs& rhs)
noexcept
4072 using LhsUnder =
typename U::underlying_type;
4073 using RhsUnder =
typename URhs::underlying_type;
4075 using Calc0 = std::common_type_t<LhsUnder, RhsUnder>;
4076 using Calc = detail::floating_point_promotion_t<Calc0>;
4079 const Calc rhs_frac =
static_cast<Calc
>(rhs.value());
4082 const Calc new_points =
static_cast<Calc
>(lhs.raw()) * rhs_frac;
4084 if constexpr (std::is_integral_v<LhsUnder>)
4087 lhs = U(
static_cast<LhsUnder
>(new_points));
4091 lhs = U(
static_cast<LhsUnder
>(new_points));
4097 template<RatioDimensionlessUnitType U>
4098 requires(units::traits::has_linear_scale_v<U>)
4099 constexpr U&
operator*=(U& lhs,
const U& rhs)
noexcept
4101 using Underlying =
typename U::underlying_type;
4102 using R =
typename U::conversion_factor::conversion_ratio;
4105 constexpr long double points_per_one =
static_cast<long double>(R::den) /
static_cast<long double>(R::num);
4107 const long double lhs_frac =
static_cast<long double>(lhs.value());
4108 const long double rhs_frac =
static_cast<long double>(rhs.value());
4110 const long double out_frac = lhs_frac * rhs_frac;
4111 const long double out_points = out_frac * points_per_one;
4113 if constexpr (std::is_integral_v<Underlying>)
4115 lhs = U(
static_cast<Underlying
>(std::llround(out_points)));
4119 lhs = U(
static_cast<Underlying
>(out_points));
4125 template<RatioDimensionlessUnitType U, units::ArithmeticType T>
4126 requires(units::traits::has_linear_scale_v<U>)
4127 constexpr U&
operator*=(U& lhs, T rhs)
noexcept
4131 using Underlying =
typename U::underlying_type;
4132 using R =
typename U::conversion_factor::conversion_ratio;
4134 constexpr long double points_per_one =
static_cast<long double>(R::den) /
static_cast<long double>(R::num);
4136 const long double lhs_frac =
static_cast<long double>(lhs.value());
4137 const long double out_frac = lhs_frac *
static_cast<long double>(rhs);
4138 const long double out_pts = out_frac * points_per_one;
4140 if constexpr (std::is_integral_v<Underlying>)
4142 lhs = U(
static_cast<Underlying
>(std::llround(out_pts)));
4146 lhs = U(
static_cast<Underlying
>(out_pts));
4151 template<RatioDimensionlessUnitType U, DimensionlessUnitType D>
4153 constexpr U&
operator*=(U& lhs,
const D& rhs)
noexcept
4156 return (lhs *= rhs.value());
4161 template<UnitType UnitTypeLhs, DimensionlessUnitType D>
4163 constexpr UnitTypeLhs&
operator*=(UnitTypeLhs& lhs,
const D& rhs)
4165 return (lhs *= rhs.value());
4168 template<UnitType UnitTypeLhs, ArithmeticType T>
4170 constexpr UnitTypeLhs&
operator/=(UnitTypeLhs& lhs,
const T& rhs)
4174 typename UnitTypeLhs::underlying_type scaled = lhs.raw() / rhs;
4175 lhs = UnitTypeLhs(scaled, linearized_value);
4179 template<UnitType UnitTypeLhs, DimensionlessUnitType D>
4181 constexpr UnitTypeLhs&
operator/=(UnitTypeLhs& lhs,
const D& rhs)
4183 return (lhs /= rhs.value());
4186 template<RatioDimensionlessUnitType U, RatioDimensionlessUnitType URhs>
4187 requires(traits::has_linear_scale_v<U, URhs>)
4188 constexpr U&
operator/=(U& lhs,
const URhs& rhs)
noexcept
4190 using Under0 = std::common_type_t<typename U::underlying_type, typename URhs::underlying_type>;
4191 using Under = detail::floating_point_promotion_t<Under0>;
4193 const Under rhs_frac =
static_cast<Under
>(rhs.value());
4195 const Under new_points =
static_cast<Under
>(lhs.raw()) / rhs_frac;
4197 lhs = U(new_points);
4201 template<RatioDimensionlessUnitType U>
4202 requires(units::traits::has_linear_scale_v<U>)
4203 constexpr U&
operator/=(U& lhs,
const U& rhs)
noexcept
4205 using Underlying =
typename U::underlying_type;
4206 using R =
typename U::conversion_factor::conversion_ratio;
4208 constexpr long double points_per_one =
static_cast<long double>(R::den) /
static_cast<long double>(R::num);
4210 const long double lhs_frac =
static_cast<long double>(lhs.value());
4211 const long double rhs_frac =
static_cast<long double>(rhs.value());
4213 const long double out_frac = lhs_frac / rhs_frac;
4214 const long double out_points = out_frac * points_per_one;
4216 if constexpr (std::is_integral_v<Underlying>)
4218 lhs = U(
static_cast<Underlying
>(std::llround(out_points)));
4222 lhs = U(
static_cast<Underlying
>(out_points));
4227 template<RatioDimensionlessUnitType U, units::ArithmeticType T>
4228 requires(units::traits::has_linear_scale_v<U>)
4229 constexpr U&
operator/=(U& lhs, T rhs)
noexcept
4231 using Underlying =
typename U::underlying_type;
4232 using R =
typename U::conversion_factor::conversion_ratio;
4234 constexpr long double points_per_one =
static_cast<long double>(R::den) /
static_cast<long double>(R::num);
4236 const long double lhs_frac =
static_cast<long double>(lhs.value());
4237 const long double out_frac = lhs_frac /
static_cast<long double>(rhs);
4238 const long double out_pts = out_frac * points_per_one;
4240 if constexpr (std::is_integral_v<Underlying>)
4242 lhs = U(
static_cast<Underlying
>(std::llround(out_pts)));
4246 lhs = U(
static_cast<Underlying
>(out_pts));
4251 template<RatioDimensionlessUnitType U, DimensionlessUnitType D>
4253 constexpr U&
operator/=(U& lhs,
const D& rhs)
noexcept
4255 return (lhs /= rhs.value());
4258 template<DimensionedUnitType UnitTypeLhs>
4260 constexpr UnitTypeLhs&
operator%=(UnitTypeLhs& lhs,
const detail::type_identity_t<UnitTypeLhs>& rhs)
noexcept
4266 template<DimensionlessUnitType UnitTypeLhs, DimensionlessUnitType UnitTypeRhs>
4268 constexpr UnitTypeLhs&
operator%=(UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4270 using CommonUnit =
decltype(lhs % rhs);
4271 lhs = CommonUnit(lhs.raw() % rhs.raw());
4275 template<UnitType UnitTypeLhs>
4277 constexpr UnitTypeLhs&
operator%=(UnitTypeLhs& lhs,
const typename UnitTypeLhs::underlying_type& rhs)
noexcept
4284 template<RatioDimensionlessUnitType U>
4286 constexpr U&
operator%=(U& lhs,
const U& rhs)
noexcept
4293 template<RatioDimensionlessUnitType U>
4295 constexpr U&
operator%=(U& lhs,
const typename U::underlying_type& rhs)
noexcept
4302 template<RatioDimensionlessUnitType U, DimensionlessUnitType D>
4304 constexpr U&
operator%=(U& lhs,
const D& rhs)
noexcept
4307 lhs = lhs %
static_cast<typename U::underlying_type
>(rhs);
4315 template<RatioDimensionlessUnitType U, RatioDimensionlessUnitType V>
4316 requires(!std::is_same_v<U, V>)
4317 constexpr std::common_type_t<U, V>
operator%(
const U&,
const V&) =
delete;
4318 template<RatioDimensionlessUnitType U, RatioDimensionlessUnitType V>
4319 requires(!std::is_same_v<U, V>)
4320 constexpr U&
operator%=(U&,
const V&) =
delete;
4327 template<UnitType UnitTypeLhs>
4328 constexpr UnitTypeLhs operator+(
const UnitTypeLhs& u)
noexcept
4334 template<UnitType UnitTypeLhs>
4335 constexpr UnitTypeLhs& operator++(UnitTypeLhs& u)
noexcept
4337 u = UnitTypeLhs(u.raw() + 1);
4342 template<UnitType UnitTypeLhs>
4343 constexpr UnitTypeLhs operator++(UnitTypeLhs& u,
int)
noexcept
4346 u = UnitTypeLhs(u.raw() + 1);
4351 template<UnitType UnitTypeLhs>
4352 constexpr UnitTypeLhs operator-(
const UnitTypeLhs& u)
noexcept
4354 return UnitTypeLhs(-u.raw());
4358 template<UnitType UnitTypeLhs>
4359 constexpr UnitTypeLhs& operator--(UnitTypeLhs& u)
noexcept
4361 u = UnitTypeLhs(u.raw() - 1);
4366 template<UnitType UnitTypeLhs>
4367 constexpr UnitTypeLhs operator--(UnitTypeLhs& u,
int)
noexcept
4370 u = UnitTypeLhs(u.raw() - 1);
4389 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
4392 constexpr auto operator+(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4398 using ResultUnit = detail::lhs_result_unit_t<UnitTypeLhs, UnitTypeRhs>;
4399 return ResultUnit(ResultUnit(lhs).raw() + ResultUnit(rhs).raw());
4403 template<RatioDimensionlessUnitType U, ArithmeticType T>
4404 requires(traits::has_linear_scale_v<U>)
4405 constexpr auto operator+(
const U& lhs, T rhs)
noexcept -> traits::replace_underlying_t<U, detail::floating_point_promotion_t<std::common_type_t<typename U::underlying_type, T>>>
4407 using Under0 = std::common_type_t<typename U::underlying_type, T>;
4408 using Under = detail::floating_point_promotion_t<Under0>;
4409 using Ret = traits::replace_underlying_t<U, Under>;
4411 using R =
typename U::conversion_factor::conversion_ratio;
4412 constexpr Under points_per_one =
static_cast<Under
>(R::den) /
static_cast<Under
>(R::num);
4415 const Under frac =
static_cast<Under
>(lhs.value()) +
static_cast<Under
>(rhs);
4416 return Ret(frac * points_per_one);
4419 template<RatioDimensionlessUnitType U, ArithmeticType T>
4420 requires(traits::has_linear_scale_v<U>)
4421 constexpr auto operator+(T lhs,
const U& rhs)
noexcept -> traits::replace_underlying_t<U, detail::floating_point_promotion_t<std::common_type_t<T, typename U::underlying_type>>>
4423 using Under0 = std::common_type_t<T, typename U::underlying_type>;
4424 using Under = detail::floating_point_promotion_t<Under0>;
4425 using Ret = traits::replace_underlying_t<U, Under>;
4427 using R =
typename U::conversion_factor::conversion_ratio;
4428 constexpr Under points_per_one =
static_cast<Under
>(R::den) /
static_cast<Under
>(R::num);
4430 const Under frac =
static_cast<Under
>(lhs) +
static_cast<Under
>(rhs.value());
4431 return Ret(frac * points_per_one);
4436 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4437 requires(traits::has_linear_scale_v<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeLhs>)
4438 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>
operator+(
const UnitTypeLhs& lhs, T rhs)
noexcept
4440 using ret = traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>;
4441 return ret(lhs.raw() +
static_cast<ret::underlying_type
>(rhs));
4446 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4447 requires(traits::has_linear_scale_v<UnitTypeRhs> && !RatioDimensionlessUnitType<UnitTypeRhs>)
4448 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<T, typename UnitTypeRhs::underlying_type>>
operator+(T lhs,
const UnitTypeRhs& rhs)
noexcept
4452 using CommonUnit =
decltype(lhs + rhs);
4453 using InverseCommonUnit =
decltype(1 / CommonUnit(1));
4454 return CommonUnit(InverseCommonUnit(lhs).value() + rhs.raw());
4461 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
4462 requires(same_dimension<UnitTypeLhs, UnitTypeRhs> && traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs> &&
4464 constexpr auto operator-(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4467 using ResultUnit = detail::lhs_result_unit_t<UnitTypeLhs, UnitTypeRhs>;
4468 return ResultUnit(ResultUnit(lhs).raw() - ResultUnit(rhs).raw());
4478 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
4481 constexpr auto operator-(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4487 using LhsCf =
typename traits::unit_traits<UnitTypeLhs>::conversion_factor;
4489 typename traits::conversion_factor_traits<LhsCf>::dimension_type,
4490 typename traits::conversion_factor_traits<LhsCf>::pi_exponent_ratio, std::ratio<0>>;
4492 return DeltaUnit(lhs.raw() - UnitTypeLhs(rhs).raw());
4497 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4498 requires(traits::has_linear_scale_v<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeLhs>)
4499 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>
operator-(
const UnitTypeLhs& lhs, T rhs)
noexcept
4503 using CommonUnit =
decltype(lhs - rhs);
4504 using InverseCommonUnit =
decltype(1 / CommonUnit(1));
4505 return CommonUnit(lhs.raw() - InverseCommonUnit(rhs).value());
4509 template<RatioDimensionlessUnitType U, ArithmeticType T>
4510 requires(traits::has_linear_scale_v<U>)
4511 constexpr auto operator-(
const U& lhs, T rhs)
noexcept -> traits::replace_underlying_t<U, detail::floating_point_promotion_t<std::common_type_t<typename U::underlying_type, T>>>
4513 using Under0 = std::common_type_t<typename U::underlying_type, T>;
4514 using Under = detail::floating_point_promotion_t<Under0>;
4515 using Ret = traits::replace_underlying_t<U, Under>;
4517 using R =
typename U::conversion_factor::conversion_ratio;
4518 constexpr Under points_per_one =
static_cast<Under
>(R::den) /
static_cast<Under
>(R::num);
4520 const Under frac =
static_cast<Under
>(lhs.value()) -
static_cast<Under
>(rhs);
4521 return Ret(frac * points_per_one);
4524 template<RatioDimensionlessUnitType U, ArithmeticType T>
4525 requires(traits::has_linear_scale_v<U>)
4526 constexpr auto operator-(T lhs,
const U& rhs)
noexcept -> traits::replace_underlying_t<U, detail::floating_point_promotion_t<std::common_type_t<T, typename U::underlying_type>>>
4528 using Under0 = std::common_type_t<T, typename U::underlying_type>;
4529 using Under = detail::floating_point_promotion_t<Under0>;
4530 using Ret = traits::replace_underlying_t<U, Under>;
4532 using R =
typename U::conversion_factor::conversion_ratio;
4533 constexpr Under points_per_one =
static_cast<Under
>(R::den) /
static_cast<Under
>(R::num);
4535 const Under frac =
static_cast<Under
>(lhs) -
static_cast<Under
>(rhs.value());
4536 return Ret(frac * points_per_one);
4541 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4542 requires(traits::has_linear_scale_v<UnitTypeRhs> && !RatioDimensionlessUnitType<UnitTypeRhs>)
4543 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<T, typename UnitTypeRhs::underlying_type>>
operator-(T lhs,
const UnitTypeRhs& rhs)
noexcept
4547 using CommonUnit =
decltype(lhs - rhs);
4548 using InverseCommonUnit =
decltype(1 / CommonUnit(1));
4549 return CommonUnit(InverseCommonUnit(lhs).value() - rhs.raw());
4554 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
4555 requires(same_dimension<UnitTypeLhs, UnitTypeRhs> && traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4556 constexpr auto operator*(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4557 -> detail::rewrap_to_named_t<unit<traits::strong_t<squared<typename traits::unit_traits<std::common_type_t<UnitTypeLhs, UnitTypeRhs>>::conversion_factor>>,
4558 typename std::common_type_t<UnitTypeLhs, UnitTypeRhs>::underlying_type>>
4560 using SquaredUnit =
decltype(lhs * rhs);
4561 using CommonUnit = std::common_type_t<UnitTypeLhs, UnitTypeRhs>;
4562 return SquaredUnit(CommonUnit(lhs).raw() * CommonUnit(rhs).raw());
4567 template<DimensionedUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4568 requires(!same_dimension<UnitTypeLhs, UnitTypeRhs> && traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4569 constexpr auto operator*(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4570 -> detail::rewrap_to_named_t<unit<traits::strong_t<compound_conversion_factor<typename traits::unit_traits<UnitTypeLhs>::conversion_factor,
typename traits::unit_traits<UnitTypeRhs>::conversion_factor>>,
4571 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>>
4573 using CompoundUnit =
decltype(lhs * rhs);
4574 using CommonUnderlying =
typename CompoundUnit::underlying_type;
4575 return CompoundUnit(
static_cast<CommonUnderlying
>(lhs) *
static_cast<CommonUnderlying
>(rhs));
4579 template<DimensionedUnitType UnitTypeLhs, OrdinaryDimensionlessUnitType UnitTypeRhs>
4580 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4581 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator*(
4582 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4584 using CommonUnit =
decltype(lhs * rhs);
4585 return CommonUnit(CommonUnit(lhs).raw() *
static_cast<typename CommonUnit::underlying_type
>(rhs));
4590 template<DimensionedUnitType UnitTypeLhs, RatioDimensionlessUnitType UnitTypeRhs>
4591 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4592 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator*(
4593 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4595 using Out =
decltype(lhs * rhs);
4596 using U0 = std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>;
4597 using U = detail::floating_point_promotion_t<U0>;
4600 return Out(
static_cast<U
>(lhs.raw()) *
static_cast<U
>(rhs.value()));
4604 template<OrdinaryDimensionlessUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4605 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4606 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator*(
4607 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4609 using CommonUnit =
decltype(lhs * rhs);
4610 return CommonUnit(
static_cast<typename CommonUnit::underlying_type
>(lhs) * CommonUnit(rhs).raw());
4614 template<RatioDimensionlessUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4615 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4616 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator*(
4617 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4619 using Out =
decltype(lhs * rhs);
4620 using U0 = std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>;
4621 using U = detail::floating_point_promotion_t<U0>;
4623 return Out(
static_cast<U
>(lhs.value()) *
static_cast<U
>(rhs.raw()));
4627 template<DimensionedUnitType UnitTypeLhs, ArithmeticType T>
4628 requires(traits::has_linear_scale_v<UnitTypeLhs>)
4629 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>
operator*(
const UnitTypeLhs& lhs, T rhs)
noexcept
4631 using CommonUnit =
decltype(lhs * rhs);
4632 return CommonUnit(CommonUnit(lhs).raw() * rhs);
4636 template<DimensionedUnitType UnitTypeRhs, ArithmeticType T>
4637 requires(traits::has_linear_scale_v<UnitTypeRhs>)
4638 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<T, typename UnitTypeRhs::underlying_type>>
operator*(T lhs,
const UnitTypeRhs& rhs)
noexcept
4640 using CommonUnit =
decltype(lhs * rhs);
4641 return CommonUnit(lhs * CommonUnit(rhs).raw());
4645 template<RatioDimensionlessUnitType U, units::ArithmeticType T>
4646 requires(units::traits::has_linear_scale_v<U>)
4647 constexpr units::dimensionless<units::detail::floating_point_promotion_t<std::common_type_t<T, typename U::underlying_type>>>
operator*(T lhs,
const U& rhs)
noexcept
4649 using Under0 = std::common_type_t<T, typename U::underlying_type>;
4650 using Under = units::detail::floating_point_promotion_t<Under0>;
4653 return units::dimensionless<Under>(
static_cast<Under
>(lhs) *
static_cast<Under
>(rhs));
4657 template<RatioDimensionlessUnitType U, units::ArithmeticType T>
4658 requires(units::traits::has_linear_scale_v<U>)
4659 constexpr units::dimensionless<units::detail::floating_point_promotion_t<std::common_type_t<typename U::underlying_type, T>>>
operator*(
const U& lhs, T rhs)
noexcept
4661 using Under0 = std::common_type_t<typename U::underlying_type, T>;
4662 using Under = units::detail::floating_point_promotion_t<Under0>;
4664 return units::dimensionless<Under>(
static_cast<Under
>(lhs) *
static_cast<Under
>(rhs));
4668 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4669 requires(traits::has_linear_scale_v<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeLhs>)
4670 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>
operator*(
const UnitTypeLhs& lhs, T rhs)
noexcept
4672 using CommonUnit =
decltype(lhs * rhs);
4673 return CommonUnit(lhs.raw() * rhs);
4677 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4678 requires(traits::has_linear_scale_v<UnitTypeRhs> && !RatioDimensionlessUnitType<UnitTypeRhs>)
4679 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<T, typename UnitTypeRhs::underlying_type>>
operator*(T lhs,
const UnitTypeRhs& rhs)
noexcept
4681 using CommonUnit =
decltype(lhs * rhs);
4682 return CommonUnit(lhs * rhs.raw());
4687 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
4689 same_dimension<UnitTypeLhs, UnitTypeRhs> && traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs> && !RatioDimensionlessUnitType<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeRhs>)
4690 constexpr dimensionless<std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator/(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4692 using CommonUnit = std::common_type_t<UnitTypeLhs, UnitTypeRhs>;
4693 return CommonUnit(lhs).raw() / CommonUnit(rhs).raw();
4698 template<DimensionedUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4699 requires(!same_dimension<UnitTypeLhs, UnitTypeRhs> && traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4700 constexpr auto operator/(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4701 -> detail::rewrap_to_named_t<unit<traits::strong_t<compound_conversion_factor<typename traits::unit_traits<UnitTypeLhs>::conversion_factor, inverse<typename traits::unit_traits<UnitTypeRhs>::conversion_factor>>>,
4702 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>>
4704 using CompoundUnit =
decltype(lhs / rhs);
4705 using CommonUnderlying =
typename CompoundUnit::underlying_type;
4706 return CompoundUnit(
static_cast<CommonUnderlying
>(lhs) /
static_cast<CommonUnderlying
>(rhs));
4710 template<DimensionedUnitType UnitTypeLhs, OrdinaryDimensionlessUnitType UnitTypeRhs>
4711 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4712 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator/(
4713 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4715 using CommonUnit =
decltype(lhs / rhs);
4716 using CommonUnderlying =
typename CommonUnit::underlying_type;
4719 return CommonUnit(CommonUnit(lhs).raw() /
static_cast<CommonUnderlying
>(rhs));
4724 template<DimensionedUnitType UnitTypeLhs, RatioDimensionlessUnitType UnitTypeRhs>
4725 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4726 constexpr traits::replace_underlying_t<
4728 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>
4730 operator/(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4732 using Out =
decltype(lhs / rhs);
4733 using U0 = std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>;
4734 using U = detail::floating_point_promotion_t<U0>;
4736 return Out(
static_cast<U
>(lhs.raw()) /
static_cast<U
>(rhs.value()));
4741 template<OrdinaryDimensionlessUnitType UnitTypeLhs, RatioDimensionlessUnitType UnitTypeRhs>
4742 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4743 constexpr auto operator/(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept -> detail::rewrap_to_named_t<unit<traits::strong_t<inverse<typename traits::unit_traits<UnitTypeRhs>::conversion_factor>>,
4744 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>>
4746 using Out =
decltype(lhs / rhs);
4747 using CommonUnderlying =
typename Out::underlying_type;
4750 return Out(
static_cast<CommonUnderlying
>(lhs) /
static_cast<CommonUnderlying
>(rhs.raw()));
4754 template<OrdinaryDimensionlessUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4755 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs> && traits::is_dimensionless_unit_v<UnitTypeLhs>)
4756 constexpr auto operator/(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept -> detail::rewrap_to_named_t<unit<traits::strong_t<inverse<typename traits::unit_traits<UnitTypeRhs>::conversion_factor>>,
4757 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>>
4759 using CommonUnit =
decltype(lhs / rhs);
4760 using CommonUnderlying =
typename CommonUnit::underlying_type;
4761 return CommonUnit(
static_cast<CommonUnderlying
>(lhs) /
static_cast<CommonUnderlying
>(rhs));
4766 template<RatioDimensionlessUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4767 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4768 constexpr auto operator/(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4772 typename traits::unit_traits<UnitTypeLhs>::conversion_factor,
4773 inverse<typename traits::unit_traits<UnitTypeRhs>::conversion_factor>
4776 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>
4779 using Out =
decltype(lhs / rhs);
4780 using CommonUnderlying =
typename Out::underlying_type;
4785 static_cast<CommonUnderlying
>(lhs.raw()) /
static_cast<CommonUnderlying
>(rhs.raw()),
4791 template<UnitType UnitTypeLhs, ArithmeticType T>
4792 requires(traits::has_linear_scale_v<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeLhs>)
4793 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>
operator/(
const UnitTypeLhs& lhs, T rhs)
noexcept
4795 using CommonUnit =
decltype(lhs / rhs);
4796 return CommonUnit(CommonUnit(lhs).raw() / rhs);
4800 template<UnitType UnitTypeRhs, ArithmeticType T>
4801 requires(traits::has_linear_scale_v<UnitTypeRhs> && !RatioDimensionlessUnitType<UnitTypeRhs>)
4802 constexpr auto operator/(T lhs,
const UnitTypeRhs& rhs)
noexcept
4803 -> detail::rewrap_to_named_t<unit<traits::strong_t<inverse<typename traits::unit_traits<UnitTypeRhs>::conversion_factor>>, std::common_type_t<T, typename UnitTypeRhs::underlying_type>>>
4805 using InverseUnit =
decltype(lhs / rhs);
4806 using UnitConversion =
typename traits::unit_traits<UnitTypeRhs>::conversion_factor;
4807 using CommonUnderlying = std::common_type_t<T, typename UnitTypeRhs::underlying_type>;
4809 return InverseUnit(lhs / CommonUnit(rhs).raw());
4814 template<RatioDimensionlessUnitType U, ArithmeticType T>
4815 requires(traits::has_linear_scale_v<U>)
4816 constexpr traits::replace_underlying_t<U, std::common_type_t<typename U::underlying_type, T>>
operator/(
const U& lhs, T rhs)
noexcept
4818 using Out = traits::replace_underlying_t<U, std::common_type_t<typename U::underlying_type, T>>;
4819 return Out(Out(lhs).raw() / rhs);
4823 template<RatioDimensionlessUnitType U, ArithmeticType T>
4824 requires(traits::has_linear_scale_v<U>)
4825 constexpr units::dimensionless<detail::floating_point_promotion_t<std::common_type_t<T, typename U::underlying_type>>>
operator/(T lhs,
const U& rhs)
noexcept
4827 using CommonType = std::common_type_t<T, typename U::underlying_type>;
4828 using PromotedType = detail::floating_point_promotion_t<CommonType>;
4831 return units::dimensionless<PromotedType>(
static_cast<PromotedType
>(lhs) /
static_cast<PromotedType
>(rhs.value()));
4835 template<RatioDimensionlessUnitType U1, RatioDimensionlessUnitType U2>
4836 requires(traits::has_linear_scale_v<U1, U2>)
4837 constexpr dimensionless<detail::floating_point_promotion_t<std::common_type_t<typename U1::underlying_type, typename U2::underlying_type>>>
operator/(
const U1& lhs,
const U2& rhs)
noexcept
4839 using Under0 = std::common_type_t<typename U1::underlying_type, typename U2::underlying_type>;
4840 using Under = detail::floating_point_promotion_t<Under0>;
4841 return dimensionless<Under>(
static_cast<Under
>(lhs.value()) /
static_cast<Under
>(rhs.value()));
4851 template<DimensionedUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4854 constexpr std::common_type_t<UnitTypeLhs, UnitTypeRhs>
operator%(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4856 using CommonUnit = std::common_type_t<UnitTypeLhs, UnitTypeRhs>;
4857 return CommonUnit(CommonUnit(lhs).raw() % CommonUnit(rhs).raw());
4861 template<DimensionedUnitType UnitTypeLhs, DimensionlessUnitType UnitTypeRhs>
4862 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs> && IntegralUnitType<UnitTypeLhs> && IntegralUnitType<UnitTypeRhs>)
4863 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator%(
4864 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4866 using CommonUnit =
decltype(lhs % rhs);
4867 using CommonUnderlying =
typename CommonUnit::underlying_type;
4868 return CommonUnit(CommonUnit(lhs).raw() %
static_cast<CommonUnderlying
>(rhs));
4881 template<DimensionlessUnitType UnitTypeLhs, DimensionlessUnitType UnitTypeRhs>
4885 constexpr traits::replace_underlying_t<UnitTypeLhs,
typename std::common_type_t<UnitTypeLhs, UnitTypeRhs>::underlying_type>
operator%(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4887 using CommonUnit =
decltype(lhs % rhs);
4888 return CommonUnit(lhs.raw() % rhs.raw());
4892 template<UnitType UnitTypeLhs, ArithmeticType T>
4893 requires(traits::has_linear_scale_v<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeLhs> && IntegralUnitType<UnitTypeLhs> && std::integral<T>)
4894 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>
operator%(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
4896 using CommonUnit =
decltype(lhs % rhs);
4897 return CommonUnit(CommonUnit(lhs).raw() % rhs);
4901 template<RatioDimensionlessUnitType U>
4903 constexpr U
operator%(
const U& lhs,
const U& rhs)
noexcept
4905 return U(lhs.raw() % rhs.raw());
4908 template<RatioDimensionlessUnitType U, ArithmeticType T>
4910 constexpr U
operator%(
const U& lhs, T rhs)
noexcept
4912 return U(lhs.raw() % rhs);
4915 template<RatioDimensionlessUnitType U, ArithmeticType T>
4917 constexpr U
operator%(T lhs,
const U& rhs)
noexcept
4919 using Under = detail::floating_point_promotion_t<std::common_type_t<T, typename U::underlying_type>>;
4921 if constexpr (std::is_integral_v<T> && std::is_integral_v<typename U::underlying_type>)
4922 return U(lhs % rhs.raw());
4924 return U(
static_cast<Under
>(std::fmod(
static_cast<Under
>(lhs),
static_cast<Under
>(rhs.raw()))));
4931 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4932 constexpr bool operator==(
const T& lhs,
const UnitTypeRhs& rhs)
noexcept
4934 using CommonUnderlying = std::common_type_t<T, typename UnitTypeRhs::underlying_type>;
4936 const auto common_lhs =
static_cast<CommonUnderlying
>(lhs);
4937 const auto common_rhs =
static_cast<CommonUnderlying
>(rhs);
4939 if constexpr (std::is_integral_v<CommonUnderlying>)
4941 return common_lhs == common_rhs;
4945 return abs(common_lhs - common_rhs) < std::numeric_limits<CommonUnderlying>::epsilon() * abs(common_lhs + common_rhs) ||
4946 abs(common_lhs - common_rhs) < std::numeric_limits<CommonUnderlying>::min();
4950 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4951 constexpr bool operator==(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
4956 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4957 requires(traits::is_dimensionless_unit_v<UnitTypeRhs> && std::is_arithmetic_v<T>)
4958 constexpr bool operator!=(
const T& lhs,
const UnitTypeRhs& rhs)
noexcept
4960 return !(lhs == rhs);
4963 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4964 constexpr bool operator!=(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
4966 return !(lhs == rhs);
4969 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4970 requires(traits::is_dimensionless_unit_v<UnitTypeRhs> && std::is_arithmetic_v<T>)
4971 constexpr bool operator>=(
const T& lhs,
const UnitTypeRhs& rhs)
noexcept
4973 using CommonUnderlying = std::common_type_t<T, typename UnitTypeRhs::underlying_type>;
4974 return lhs >=
static_cast<CommonUnderlying
>(rhs);
4977 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4978 constexpr bool operator>=(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
4980 using CommonUnderlying = std::common_type_t<typename UnitTypeLhs::underlying_type, T>;
4981 return static_cast<CommonUnderlying
>(lhs) >= rhs;
4984 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4985 constexpr bool operator>(
const T& lhs,
const UnitTypeRhs& rhs)
noexcept
4987 using CommonUnderlying = std::common_type_t<T, typename UnitTypeRhs::underlying_type>;
4988 return lhs >
static_cast<CommonUnderlying
>(rhs);
4991 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4992 constexpr bool operator>(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
4994 using CommonUnderlying = std::common_type_t<typename UnitTypeLhs::underlying_type, T>;
4995 return static_cast<CommonUnderlying
>(lhs) > rhs;
4998 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4999 constexpr bool operator<=(
const T& lhs,
const UnitTypeRhs& rhs)
noexcept
5001 using CommonUnderlying = std::common_type_t<T, typename UnitTypeRhs::underlying_type>;
5002 return lhs <= static_cast<CommonUnderlying>(rhs);
5005 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
5006 constexpr bool operator<=(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
5008 using CommonUnderlying = std::common_type_t<typename UnitTypeLhs::underlying_type, T>;
5009 return static_cast<CommonUnderlying
>(lhs) <= rhs;
5012 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
5013 constexpr bool operator<(
const T& lhs,
const UnitTypeRhs& rhs)
noexcept
5015 using CommonUnderlying = std::common_type_t<T, typename UnitTypeRhs::underlying_type>;
5016 return lhs < static_cast<CommonUnderlying>(rhs);
5019 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
5020 constexpr bool operator<(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
5022 using CommonUnderlying = std::common_type_t<typename UnitTypeLhs::underlying_type, T>;
5023 return static_cast<CommonUnderlying
>(lhs) < rhs;
5034 template<
int N,
class U>
5035 struct power_of_unit
5037 template<
bool isPos,
int V>
5038 struct power_of_unit_impl;
5041 struct power_of_unit_impl<true, V>
5043 typedef unit_multiply<U,
typename power_of_unit<N - 1, U>::type> type;
5047 struct power_of_unit_impl<false, V>
5049 typedef inverse<
typename power_of_unit<-N, U>::type> type;
5052 typedef typename power_of_unit_impl<(N > 0), N>::type type;
5057 struct power_of_unit<1, U>
5063 struct power_of_unit<0, U>
5065 typedef dimensionless_ type;
5078 template<
int power, UnitType UnitType>
5079 requires(traits::has_linear_scale_v<UnitType>)
5080 constexpr auto pow(
const UnitType& value)
noexcept -> detail::rewrap_to_named_t<unit<traits::strong_t<typename units::detail::power_of_unit<power, typename units::traits::unit_traits<UnitType>::conversion_factor>::type>,
5081 detail::floating_point_promotion_t<typename units::traits::unit_traits<UnitType>::underlying_type>,
linear_scale>>
5083 return decltype(units::pow<power>(value))(pow<power>(value.raw()));
5104 static T
linearize(
const T value)
noexcept
5110 static_assert(std::is_floating_point_v<T>,
5111 "a decibel-scale unit requires a floating-point underlying type (an integral type cannot represent a logarithmic value)");
5112 return static_cast<T
>(std::pow(10, value / 10));
5122 static T
scale(
const T value)
noexcept
5124 return static_cast<T
>(10 * std::log10(value));
5137#if !defined(UNIT_LIB_DISABLE_IOSTREAM)
5138 template<
class Underlying>
5139 std::ostream& operator<<(std::ostream& os,
const decibels<Underlying>& obj)
5141 os << obj.
raw() <<
" dB";
5145 template<
class Underlying>
5152 template<
class Underlying>
5155 static constexpr const char* value =
"decibels";
5158 template<
class Underlying>
5161 static constexpr const char* value =
"dB";
5167 typename ::units::decibels<>::conversion_factor*, typename ::units::decibels<>::numerical_scale_type*);
5170#ifndef UNIT_NO_LITERAL_SUPPORT
5191 template<DimensionedUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
5193 auto operator+(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept =
delete;
5197 template<DimensionlessUnitType UnitTypeLhs, DimensionlessUnitType UnitTypeRhs>
5198 requires(traits::has_decibel_scale_v<UnitTypeLhs, UnitTypeRhs>)
5199 constexpr std::common_type_t<UnitTypeLhs, UnitTypeRhs>
operator+(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
5201 using CommonUnit = std::common_type_t<UnitTypeLhs, UnitTypeRhs>;
5202 return CommonUnit(CommonUnit(lhs).to_linearized() * CommonUnit(rhs).to_linearized(), linearized_value);
5206 template<DimensionedUnitType UnitTypeLhs, DimensionlessUnitType UnitTypeRhs>
5207 requires(traits::has_decibel_scale_v<UnitTypeLhs, UnitTypeRhs>)
5208 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator+(
5209 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
5211 using CommonUnit =
decltype(lhs + rhs);
5212 return CommonUnit(lhs.to_linearized() * rhs.to_linearized(), linearized_value);
5216 template<DimensionlessUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
5217 requires(traits::has_decibel_scale_v<UnitTypeLhs, UnitTypeRhs>)
5218 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator+(
5219 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
5221 using CommonUnit =
decltype(lhs + rhs);
5222 return CommonUnit(lhs.to_linearized() * rhs.to_linearized(), linearized_value);
5226 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5227 requires(same_dimension<UnitTypeLhs, UnitTypeRhs> && traits::has_decibel_scale_v<UnitTypeLhs, UnitTypeRhs>)
5228 constexpr auto operator-(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept -> decibels<typename std::common_type_t<UnitTypeLhs, UnitTypeRhs>::underlying_type>
5231 using CommonUnit = std::common_type_t<UnitTypeLhs, UnitTypeRhs>;
5233 return Dimensionless(CommonUnit(lhs).to_linearized() / CommonUnit(rhs).to_linearized(), linearized_value);
5237 template<DimensionedUnitType UnitTypeLhs, DimensionlessUnitType UnitTypeRhs>
5238 requires(traits::has_decibel_scale_v<UnitTypeLhs, UnitTypeRhs>)
5239 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator-(
5240 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
5242 using CommonUnit =
decltype(lhs - rhs);
5243 return CommonUnit(lhs.to_linearized() / rhs.to_linearized(), linearized_value);
5247 template<DimensionlessUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
5248 requires(traits::has_decibel_scale_v<UnitTypeLhs, UnitTypeRhs>)
5249 constexpr auto operator-(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept -> detail::rewrap_to_named_t<unit<traits::strong_t<inverse<typename traits::unit_traits<UnitTypeRhs>::conversion_factor>>,
5250 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>, decibel_scale>>
5252 using InverseUnit =
decltype(lhs - rhs);
5253 return InverseUnit(lhs.to_linearized() / rhs.to_linearized(), linearized_value);
5264 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5266 constexpr auto min(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
5272 using ResultUnit = detail::lhs_result_unit_t<UnitTypeLhs, UnitTypeRhs>;
5273 return (lhs < rhs ? ResultUnit(lhs) : ResultUnit(rhs));
5276 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5278 constexpr auto max(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
5280 using ResultUnit = detail::lhs_result_unit_t<UnitTypeLhs, UnitTypeRhs>;
5281 return (lhs > rhs ? ResultUnit(lhs) : ResultUnit(rhs));
5286 template<UnitType UnitTypeValue, UnitType UnitTypeLo, UnitType UnitTypeHi>
5287 requires(same_dimension<UnitTypeValue, UnitTypeLo> && same_dimension<UnitTypeValue, UnitTypeHi>)
5288 constexpr auto clamp(
const UnitTypeValue& value,
const UnitTypeLo& lo,
const UnitTypeHi& hi)
5292 using ResultUnit = detail::lhs_result_unit_t<UnitTypeValue, std::common_type_t<UnitTypeLo, UnitTypeHi>>;
5293 return (value < lo ? ResultUnit(lo) : (hi < value ? ResultUnit(hi) : ResultUnit(value)));
5313 template<DimensionlessUnitType UnitType>
5314 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
exp(
const UnitType x)
noexcept
5316 return std::exp(x.value());
5328 template<DimensionlessUnitType UnitType>
5329 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
log(
const UnitType x)
noexcept
5331 return std::log(x.value());
5342 template<DimensionlessUnitType UnitType>
5343 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
log10(
const UnitType x)
noexcept
5345 return std::log10(x.value());
5359 template<DimensionlessUnitType UnitType>
5360 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
modf(
const UnitType x,
UnitType* intpart)
noexcept
5362 using promoted = detail::floating_point_promotion_t<typename UnitType::underlying_type>;
5369 promoted fracpart = std::modf(x.template to<promoted>(), &intp);
5370 *intpart = dimensionless<promoted>{intp};
5371 return dimensionless<promoted>{fracpart};
5381 template<DimensionlessUnitType UnitType>
5382 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
exp2(
const UnitType x)
noexcept
5384 return std::exp2(x.value());
5395 template<DimensionlessUnitType UnitType>
5396 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
expm1(
const UnitType x)
noexcept
5398 return std::expm1(x.value());
5410 template<DimensionlessUnitType UnitType>
5411 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
log1p(
const UnitType x)
noexcept
5413 return std::log1p(x.value());
5424 template<DimensionlessUnitType UnitType>
5425 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
log2(
const UnitType x)
noexcept
5427 return std::log2(x.value());
5448 template<UnitType UnitType>
5449 requires(traits::has_linear_scale_v<UnitType>)
5450 constexpr auto sqrt(
const UnitType& value)
noexcept
5451 -> detail::rewrap_to_named_t<unit<traits::strong_t<square_root<typename traits::unit_traits<UnitType>::conversion_factor>>, detail::floating_point_promotion_t<typename traits::unit_traits<UnitType>::underlying_type>>>
5453 return decltype(units::sqrt(value))(sqrt(value.raw()));
5466 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5468 constexpr auto hypot(
const UnitTypeLhs& x,
const UnitTypeRhs& y)
5473 using Result = detail::floating_point_promotion_t<detail::lhs_result_unit_t<UnitTypeLhs, UnitTypeRhs>>;
5474 return Result(std::hypot(Result(x).raw(), Result(y).raw()));
5488 template<UnitType Unit>
5489 constexpr detail::floating_point_promotion_t<Unit>
ceil(
const Unit x)
noexcept
5491 return detail::floating_point_promotion_t<Unit>(std::ceil(x.raw()));
5501 template<UnitType Unit>
5502 constexpr detail::floating_point_promotion_t<Unit>
floor(
const Unit x)
noexcept
5504 return detail::floating_point_promotion_t<Unit>(std::floor(x.raw()));
5516 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5518 constexpr auto fmod(
const UnitTypeLhs numer,
const UnitTypeRhs denom)
noexcept
5520 using Result = detail::floating_point_promotion_t<detail::lhs_result_unit_t<UnitTypeLhs, UnitTypeRhs>>;
5521 return Result(std::fmod(Result(numer).raw(), Result(denom).raw()));
5532 template<UnitType UnitType>
5533 constexpr detail::floating_point_promotion_t<UnitType>
trunc(
const UnitType x)
noexcept
5535 return detail::floating_point_promotion_t<UnitType>(std::trunc(x.raw()));
5546 template<UnitType UnitType>
5547 constexpr detail::floating_point_promotion_t<UnitType>
round(
const UnitType x)
noexcept
5549 return detail::floating_point_promotion_t<UnitType>(std::round(x.raw()));
5556 enum class rounding_mode
5558 toward_neg_infinity,
5559 toward_pos_infinity,
5571 constexpr Int apply_integer_rounding(Int q, Int r, Int den, rounding_mode mode)
noexcept
5577 case rounding_mode::toward_zero:
5579 case rounding_mode::toward_neg_infinity:
5580 return r < 0 ? q - 1 : q;
5581 case rounding_mode::toward_pos_infinity:
5582 return r > 0 ? q + 1 : q;
5583 case rounding_mode::nearest_half_away:
5586 const Int twiceRemainder = (r < 0 ? -r : r) * 2;
5587 if (twiceRemainder >= den)
5588 return r < 0 ? q - 1 : q + 1;
5603 template<
class To,
class From>
5604 constexpr To rounded_unit_cast(
const From& x, rounding_mode mode)
noexcept
5606 using ToRep =
typename To::underlying_type;
5607 using FromRep =
typename From::underlying_type;
5609 if constexpr (std::is_integral_v<FromRep>)
5618 using Ratio = std::ratio_divide<typename From::conversion_factor::conversion_ratio, typename To::conversion_factor::conversion_ratio>;
5619 using Intermediate = std::conditional_t<std::is_unsigned_v<FromRep> && std::is_unsigned_v<ToRep>, widest_unsigned_int, widest_signed_int>;
5620 const Intermediate value =
static_cast<Intermediate
>(x.raw());
5621 const Intermediate product = value *
static_cast<Intermediate
>(Ratio::num);
5622 const Intermediate den =
static_cast<Intermediate
>(Ratio::den);
5623 const Intermediate quotient = product / den;
5624 const Intermediate remainder = product % den;
5625 const Intermediate rounded = apply_integer_rounding(quotient, remainder, den, mode);
5626 return To(
static_cast<ToRep
>(rounded), linearized_value);
5631 using Promoted = unit<typename To::conversion_factor, floating_point_promotion_t<ToRep>,
typename To::numerical_scale_type>;
5632 const auto inTarget = Promoted(x).to_linearized();
5633 const auto rounded = mode == rounding_mode::toward_neg_infinity ? std::floor(inTarget)
5634 : mode == rounding_mode::toward_pos_infinity ? std::
ceil(inTarget)
5635 : mode == rounding_mode::nearest_half_away ? std::
round(inTarget)
5636 : std::
trunc(inTarget);
5637 return To(
static_cast<ToRep
>(rounded), linearized_value);
5645 template<
class To,
class From>
5646 inline constexpr bool is_roundable_unit_conversion =
5647 traits::is_unit_v<To> && traits::is_unit_v<From> && same_dimension<From, To> &&
5648 std::is_integral_v<typename To::underlying_type> && !is_losslessly_convertible_unit<From, To>;
5664 template<
class To, UnitType From>
5665 requires detail::is_roundable_unit_conversion<To, From>
5666 constexpr To
floor(
const From& x)
noexcept
5668 return detail::rounded_unit_cast<To>(x, detail::rounding_mode::toward_neg_infinity);
5680 template<
class To, UnitType From>
5681 requires detail::is_roundable_unit_conversion<To, From>
5682 constexpr To
ceil(
const From& x)
noexcept
5684 return detail::rounded_unit_cast<To>(x, detail::rounding_mode::toward_pos_infinity);
5696 template<
class To, UnitType From>
5697 requires detail::is_roundable_unit_conversion<To, From>
5698 constexpr To
round(
const From& x)
noexcept
5700 return detail::rounded_unit_cast<To>(x, detail::rounding_mode::nearest_half_away);
5712 template<
class To, UnitType From>
5713 requires detail::is_roundable_unit_conversion<To, From>
5714 constexpr To
trunc(
const From& x)
noexcept
5716 return detail::rounded_unit_cast<To>(x, detail::rounding_mode::toward_zero);
5732 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5733 constexpr detail::floating_point_promotion_t<UnitTypeLhs>
copysign(
const UnitTypeLhs x,
const UnitTypeRhs y)
noexcept
5735 return detail::floating_point_promotion_t<UnitTypeLhs>(std::copysign(x.raw(), y.raw()));
5739 template<UnitType UnitTypeLhs, ArithmeticType T>
5740 constexpr detail::floating_point_promotion_t<UnitTypeLhs>
copysign(
const UnitTypeLhs x,
const T& y)
noexcept
5742 return detail::floating_point_promotion_t<UnitTypeLhs>(std::copysign(x.raw(), y));
5758 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5760 constexpr auto fdim(
const UnitTypeLhs x,
const UnitTypeRhs y)
noexcept
5762 using Result = detail::floating_point_promotion_t<detail::lhs_result_unit_t<UnitTypeLhs, UnitTypeRhs>>;
5763 return Result(std::fdim(Result(x).raw(), Result(y).raw()));
5775 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5777 constexpr auto fmax(
const UnitTypeLhs x,
const UnitTypeRhs y)
noexcept
5779 using Result = detail::floating_point_promotion_t<detail::lhs_result_unit_t<UnitTypeLhs, UnitTypeRhs>>;
5780 return Result(std::fmax(Result(x).raw(), Result(y).raw()));
5792 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5794 constexpr auto fmin(
const UnitTypeLhs x,
const UnitTypeRhs y)
noexcept
5796 using Result = detail::floating_point_promotion_t<detail::lhs_result_unit_t<UnitTypeLhs, UnitTypeRhs>>;
5797 return Result(std::fmin(Result(x).raw(), Result(y).raw()));
5811 template<UnitType UnitType>
5812 constexpr detail::floating_point_promotion_t<UnitType>
fabs(
const UnitType x)
noexcept
5814 return detail::floating_point_promotion_t<UnitType>(std::fabs(x.raw()));
5824 template<UnitType UnitType>
5827 return UnitType(std::abs(x.raw()));
5844 template<UnitType UnitTypeLhs, UnitType UnitMultiply, UnitType UnitAdd>
5845 requires(traits::is_same_dimension_conversion_factor_v<
5847 typename traits::unit_traits<UnitAdd>::conversion_factor>)
5848 constexpr auto fma(
const UnitTypeLhs x,
const UnitMultiply y,
const UnitAdd z)
noexcept
5849 -> std::common_type_t<decltype(detail::floating_point_promotion_t<UnitTypeLhs>(x) * detail::floating_point_promotion_t<UnitMultiply>(y)), UnitAdd>
5851 using CommonUnit =
decltype(
units::fma(x, y, z));
5852 using ProductUnit =
decltype(detail::floating_point_promotion_t<UnitTypeLhs>(x) * detail::floating_point_promotion_t<UnitMultiply>(y));
5858 constexpr auto scale = CommonUnit(ProductUnit(1)).raw();
5859 return CommonUnit(std::fma(x.raw(), y.raw() * scale, CommonUnit(z).raw()));
5866 template<UnitType UnitType>
5867 constexpr bool isnan(
const UnitType& x)
noexcept
5869 return std::isnan(x.raw());
5872 template<UnitType UnitType>
5873 constexpr bool isinf(
const UnitType& x)
noexcept
5875 return std::isinf(x.raw());
5878 template<UnitType UnitType>
5879 constexpr bool isfinite(
const UnitType& x)
noexcept
5881 return std::isfinite(x.raw());
5884 template<UnitType UnitType>
5885 constexpr bool isnormal(
const UnitType& x)
noexcept
5887 return std::isnormal(x.raw());
5890 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5892 constexpr bool isunordered(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
5894 return std::isunordered(lhs.raw(), rhs.raw());
5906template<
class ConversionFactor,
typename T,
class NumericalScale>
5907struct std::hash<
units::unit<ConversionFactor, T, NumericalScale>>
5909 template<
typename U = T>
5912 if constexpr (std::is_integral_v<U>)
5918 return static_cast<std::size_t
>(hash<T>()(x.
to_linearized()));
5926template<
class Named>
5927 requires units::detail::is_named_unit_v<Named>
5928struct std::hash<Named> : std::hash<units::detail::unit_base_t<Named>>
5938 template<units::ConversionFactorType ConversionFactor, units::ArithmeticType T, units::NumericalScaleType<T> NonLinearScale>
5939 struct numeric_limits<
units::unit<ConversionFactor, T, NonLinearScale>>
5986 static constexpr bool is_specialized = std::numeric_limits<T>::is_specialized;
5987 static constexpr bool is_signed = std::numeric_limits<T>::is_signed;
5988 static constexpr bool is_integer = std::numeric_limits<T>::is_integer;
5989 static constexpr bool is_exact = std::numeric_limits<T>::is_exact;
5990 static constexpr bool has_infinity = std::numeric_limits<T>::has_infinity;
5991 static constexpr bool has_quiet_NaN = std::numeric_limits<T>::has_quiet_NaN;
5992 static constexpr bool has_signaling_NaN = std::numeric_limits<T>::has_signaling_NaN;
5999 template<
class Named>
6000 requires units::detail::is_named_unit_v<Named>
6001 struct numeric_limits<Named> : numeric_limits<units::detail::unit_base_t<Named>>
6004 using Base = numeric_limits<units::detail::unit_base_t<Named>>;
6010 static constexpr Named min() {
return Named(Base::min()); }
6011 static constexpr Named max() {
return Named(Base::max()); }
6012 static constexpr Named lowest() {
return Named(Base::lowest()); }
6013 static constexpr Named epsilon() {
return Named(Base::epsilon()); }
6014 static constexpr Named round_error() {
return Named(Base::round_error()); }
6015 static constexpr Named denorm_min() {
return Named(Base::denorm_min()); }
6016 static constexpr Named infinity() {
return Named(Base::infinity()); }
6017 static constexpr Named quiet_NaN() {
return Named(Base::quiet_NaN()); }
6018 static constexpr Named signaling_NaN() {
return Named(Base::signaling_NaN()); }
6027 template<units::UnitType U>
6028 constexpr bool isnan(U x)
6030 return std::isnan(x.raw());
6033 template<units::UnitType U>
6034 constexpr bool isinf(U x)
6036 return std::isinf(x.raw());
6039 template<units::UnitType U>
6040 constexpr bool isfinite(U x)
6042 return std::isfinite(x.raw());
6045 template<units::UnitType U>
6046 constexpr bool signbit(U x)
6048 return std::signbit(x.raw());
6061 concept PureDimensionlessCF = std::is_same_v<typename Cf::dimension_type, dimension::dimensionless> && std::ratio_equal_v<typename Cf::conversion_ratio, std::ratio<1>> &&
6062 std::ratio_equal_v<typename Cf::pi_exponent_ratio, std::ratio<0>> && std::ratio_equal_v<typename Cf::translation_ratio, std::ratio<0>>;
6065 template<ArithmeticType Rep, RatioType Period>
6070 template<ArithmeticType SourceTy, ConversionFactorType SourceCf>
6077 template<ArithmeticType SourceTy, ConversionFactorType SourceCf, ConversionFactorType TargetCf = SourceCf>
6078 requires(traits::is_unit_v<unit<SourceCf, SourceTy>> && traits::is_conversion_factor_v<TargetCf> && traits::is_same_dimension_conversion_factor_v<SourceCf, TargetCf> &&
6079 !std::is_same_v<SourceCf, TargetCf> && detail::is_losslessly_convertible_unit<unit<SourceCf, SourceTy>,
unit<TargetCf, SourceTy>>)
6085 template<ArithmeticType SourceTy, ConversionFactorType SourceCf, ConversionFactorType TargetCf = SourceCf>
6086 requires(traits::is_unit_v<unit<SourceCf, SourceTy>> && traits::is_conversion_factor_v<TargetCf> && traits::is_same_dimension_conversion_factor_v<SourceCf, TargetCf> &&
6087 !std::is_same_v<SourceCf, TargetCf> && !detail::is_losslessly_convertible_unit<unit<SourceCf, SourceTy>,
unit<TargetCf, SourceTy>>)
6092 template<ConversionFactorType TargetCf, ArithmeticType SourceTy>
6093 requires traits::is_unit_v<unit<TargetCf, SourceTy>>
6097 template<
typename T,
typename Cf = dimension::dimensionless,
typename = std::enable_if_t<std::is_arithmetic_v<T>>>
6105#if defined(UNIT_LIB_ENABLE_FORMAT)
6127template<units::UnitType U>
6128struct std::formatter<U, char>
6130 using conversion_factor =
typename units::traits::unit_traits<U>::conversion_factor;
6131 using value_type =
typename units::traits::unit_traits<U>::underlying_type;
6132 using scale_type =
typename units::traits::unit_traits<U>::numerical_scale_type;
6133 using promoted_value_type = units::detail::floating_point_promotion_t<value_type>;
6139 using formatted_value_type = std::conditional_t<renders_in_base_unit, promoted_value_type, value_type>;
6143 std::formatter<formatted_value_type, char> m_valueFormatter;
6144 std::formatter<promoted_value_type, char> m_baseFormatter;
6145 units::detail::unit_format_options m_options;
6146 bool m_usesBaseFormatter =
false;
6156 constexpr auto parse(std::format_parse_context& ctx)
6158 auto it = ctx.begin();
6159 auto end = ctx.end();
6162 auto valueSpecEnd = it;
6163 for (
auto scan = it; scan != end && *scan !=
'}'; ++scan)
6167 valueSpecEnd = scan + 1;
6176 m_usesBaseFormatter =
false;
6177 for (
auto scan = valueSpecEnd; scan != end && *scan !=
'}';)
6181 for (++scan; scan != end && *scan !=
'}' && *scan !=
'\''; ++scan)
6183 if (*scan ==
'\\' && scan + 1 != end && *(scan + 1) !=
'}')
6186 if (scan != end && *scan ==
'\'')
6189 else if (*scan ==
'b')
6191 m_usesBaseFormatter =
true;
6202 if (valueSpecEnd != it)
6204 std::string_view valueSpec(it, valueSpecEnd);
6205 if (m_usesBaseFormatter)
6207 std::format_parse_context baseCtx(valueSpec);
6208 if (m_baseFormatter.parse(baseCtx) != valueSpec.end())
6209 throw std::format_error(
"units: invalid value format-spec");
6213 std::format_parse_context valueCtx(valueSpec);
6214 if (m_valueFormatter.parse(valueCtx) != valueSpec.end())
6215 throw std::format_error(
"units: invalid value format-spec");
6222 if (it != end && *it ==
'%')
6225 bool sawForm =
false;
6226 bool sawShow =
false;
6227 while (it != end && *it !=
'}')
6230 if (c ==
'a' || c ==
'n' || c ==
'b')
6233 throw std::format_error(
"units: duplicate label-form flag");
6235 m_options.form = (
c ==
'a') ? units::detail::label_form::abbreviation
6240 else if (c ==
'v' || c ==
'u')
6243 throw std::format_error(
"units: duplicate show flag");
6245 m_options.showValue = (
c ==
'v');
6246 m_options.showUnit = (
c ==
'u');
6253 bool closed =
false;
6254 while (it != end && *it !=
'}')
6259 if (it == end || *it ==
'}')
6260 throw std::format_error(
"units: dangling escape in separator");
6263 case 't': sep.push_back(
'\t');
break;
6264 case 'n': sep.push_back(
'\n');
break;
6265 case '\\': sep.push_back(
'\\');
break;
6266 case '\'': sep.push_back(
'\'');
break;
6267 default: sep.push_back(*it);
break;
6271 else if (*it ==
'\'')
6284 throw std::format_error(
"units: unterminated separator literal");
6285 m_options.separator = std::move(sep);
6286 m_options.customSep =
true;
6290 throw std::format_error(
"units: unknown unit-format flag");
6307 template<
class FormatContext>
6308 auto format(
const U& obj, FormatContext& ctx)
const
6310 using base_unit_type = units::unit<units::conversion_factor<std::ratio<1>,
typename conversion_factor::dimension_type>, promoted_value_type, scale_type>;
6315 formatted_value_type value{};
6316 promoted_value_type baseValue{};
6317 if constexpr (renders_in_base_unit)
6318 value = base_unit_type(obj).
raw();
6320 value =
static_cast<formatted_value_type
>(obj.raw());
6321 if (m_options.form == units::detail::label_form::base)
6322 baseValue = base_unit_type(obj).raw();
6325 if (m_options.showUnit)
6327 switch (m_options.form)
6329 case units::detail::label_form::name: label = units::detail::unit_label<units::detail::label_form::name>(obj);
break;
6330 case units::detail::label_form::base: label = units::detail::unit_label<units::detail::label_form::base>(obj);
break;
6331 case units::detail::label_form::abbreviation:
6332 default: label = units::detail::unit_label<units::detail::label_form::abbreviation>(obj);
break;
6336 auto out = ctx.out();
6338 if (m_options.showValue)
6340 if (m_usesBaseFormatter)
6344 const promoted_value_type emitted = renders_in_base_unit ?
static_cast<promoted_value_type
>(value) : baseValue;
6345 out = m_baseFormatter.format(emitted, ctx);
6349 out = m_valueFormatter.format(value, ctx);
6353 if (m_options.showUnit && !label.empty())
6358 std::string_view labelView(label);
6359 const bool hasLeadingSpace = !labelView.empty() && labelView.front() ==
' ';
6361 if (m_options.showValue)
6363 if (m_options.customSep)
6365 if (hasLeadingSpace)
6366 labelView.remove_prefix(1);
6367 for (
char ch : m_options.separator)
6373 if (hasLeadingSpace)
6374 labelView.remove_prefix(1);
6377 for (
char ch : labelView)
6391#if defined __has_include
6392#if __has_include(<nlohmann/json.hpp>)
6393#include <nlohmann/json.hpp>
6396 template<
class UnitType>
6397 requires(units::traits::is_unit_v<UnitType>)
6398 void from_json(
const nlohmann::json& j,
UnitType& u)
6400 using underlying =
typename units::traits::unit_traits<UnitType>::underlying_type;
6406 template<
class UnitType>
6407 requires(units::traits::is_unit_v<UnitType>)
6408 void to_json(nlohmann::json& j,
const UnitType& u)
ConversionFactor conversion_factor
Definition core.h:2746
constexpr auto value() const noexcept
Definition core.h:2995
constexpr T to_linearized() const noexcept
linearized unit value
Definition core.h:3052
T value_type
Definition core.h:2745
constexpr unit(const unit< ConversionFactorRhs, Ty, NsRhs > &rhs) noexcept
converting constructor
Definition core.h:2767
constexpr unit< Cf, Ty > convert() const noexcept
Definition core.h:3068
constexpr bool operator!=(const unit< ConversionFactorRhs, Ty, NsRhs > &rhs) const noexcept
Definition core.h:2972
constexpr underlying_type raw() const noexcept
Definition core.h:2983
T _linearized_value
Definition core.h:3214
constexpr unit & operator=(const underlying_type &rhs) noexcept
assignment
Definition core.h:2881
constexpr unit & operator=(const unit &rhs) noexcept=default
constexpr Ty to() const noexcept
Definition core.h:3027
T underlying_type
Definition core.h:2744
Concept for types which represent arithmetic types.
Definition core.h:987
Concept for types which represent conversion factors.
Definition core.h:1008
Concept for types which represent units with a dimension (i.e.
Definition core.h:1029
Concept satisfied by any unit whose SI dimension is dimensionless; being dimension-keyed it.
Definition core.h:3900
Concept for types which represent units without a dimension (dimensionless).
Definition core.h:1036
Concept for types which represent non-arithmetic types.
Definition core.h:994
Concept for types which represent numerical scales.
Definition core.h:1015
Concept for types which represent std::ratios.
Definition core.h:1001
Concept for types which represent units.
Definition core.h:1022
Concept for types which represent units of the same dimensionality.
Definition core.h:1050
unit, dimensional analysis, generic cmath functions, traits (not dimension-specific),...
#define UNIT_ADD_SCALED_UNIT_DEFINITION(unitName, scale,...)
Macro for generating the boilerplate code for the scaled unit template definition.
Definition core.h:267
label_form
Builds the unit-label suffix for a unit — the text that follows its numeric value.
Definition core.h:3451
@ base
the SI base-dimension list (" m s^-1"); pairs with a base-converted value.
Definition core.h:3454
@ name
the unit's own full name ("meters", "feet"); base-dimension list if unnamed.
Definition core.h:3453
@ abbreviation
the unit's own abbreviation ("m", "ft"), the default; base-dimension list if unnamed.
Definition core.h:3452
constexpr bool label_uses_base_unit()
Whether a unit's label is its dimension list rather than a named abbreviation.
Definition core.h:3504
std::string dimension_to_string(const dim< D, E > &)
Renders a single dimension term (base dimension + exponent) as text.
Definition core.h:3394
#define UNIT_ADD_DIMENSION_TRAIT(unitdimension, ConceptName)
Macro to create the is_dimension_unit type trait and the ConceptName concept.
Definition core.h:488
ConversionFactor strong_name(ConversionFactor *,...)
ADL customization point that maps a conversion_factor to its friendly strong type.
unit< typename T::conversion_factor, typename T::underlying_type, typename T::numerical_scale_type > unit_base_t
Maps any unit type to the canonical unit<Cf, Underlying, Scale> it represents.
Definition core.h:3229
typename detail::prefix< std::ratio< 1152921504606846976 >, Cf >::type exbi
< Represents the type of class Cf with the binary 'pebi' prefix appended.
Definition core.h:2026
typename detail::prefix< std::ratio< 1125899906842624 >, Cf >::type pebi
< Represents the type of class Cf with the binary 'tebi' prefix appended.
Definition core.h:2025
typename detail::prefix< std::ratio< 1073741824 >, Cf >::type gibi
< Represents the type of class Cf with the binary 'mibi' prefix appended.
Definition core.h:2023
typename detail::prefix< std::ratio< 1048576 >, Cf >::type mebi
< Represents the type of class Cf with the binary 'kibi' prefix appended.
Definition core.h:2022
typename detail::prefix< std::ratio< 1099511627776 >, Cf >::type tebi
< Represents the type of class Cf with the binary 'gibi' prefix appended.
Definition core.h:2024
typename detail::prefix< std::ratio< 1024 >, Cf >::type kibi
< Represents the type of class Cf with the metric 'exa' prefix appended.
Definition core.h:2021
constexpr unit()=default
< Type of conversion_factor the unit represents (e.g. meters)
typename detail::compound_impl< Cf, Cfs... >::type compound_conversion_factor
Represents a conversion factor made up from other conversion factors.
Definition core.h:1959
constexpr T unit_cast(const Unit &value) noexcept
Casts an unit to an arithmetic type.
Definition core.h:3789
constexpr To convert(const From &value) noexcept
converts a value from an unit to another.
Definition core.h:2351
typename detail::prefix< std::deci, Cf >::type deci
< Represents the type of class Cf with the metric 'centi' prefix appended.
Definition core.h:2006
typename detail::prefix< std::centi, Cf >::type centi
< Represents the type of class Cf with the metric 'milli' prefix appended.
Definition core.h:2005
typename detail::prefix< std::giga, Cf >::type giga
< Represents the type of class Cf with the metric 'mega' prefix appended.
Definition core.h:2011
typename detail::prefix< std::micro, Cf >::type micro
< Represents the type of class Cf with the metric 'nano' prefix appended.
Definition core.h:2003
typename detail::prefix< std::mega, Cf >::type mega
< Represents the type of class Cf with the metric 'kilo' prefix appended.
Definition core.h:2010
typename detail::prefix< std::exa, Cf >::type exa
< Represents the type of class Cf with the metric 'peta' prefix appended.
Definition core.h:2014
typename detail::prefix< std::femto, Cf >::type femto
< Represents the type of class Cf with the metric 'atto' prefix appended.
Definition core.h:2000
typename detail::prefix< std::pico, Cf >::type pico
< Represents the type of class Cf with the metric 'femto' prefix appended.
Definition core.h:2001
typename detail::prefix< std::kilo, Cf >::type kilo
< Represents the type of class Cf with the metric 'hecto' prefix appended.
Definition core.h:2009
typename detail::prefix< std::milli, Cf >::type milli
< Represents the type of class Cf with the metric 'micro' prefix appended.
Definition core.h:2004
typename detail::prefix< std::peta, Cf >::type peta
< Represents the type of class Cf with the metric 'tera' prefix appended.
Definition core.h:2013
typename detail::prefix< std::nano, Cf >::type nano
< Represents the type of class Cf with the metric 'pico' prefix appended.
Definition core.h:2002
typename detail::prefix< std::tera, Cf >::type tera
< Represents the type of class Cf with the metric 'giga' prefix appended.
Definition core.h:2012
typename detail::prefix< std::deca, Cf >::type deca
< Represents the type of class Cf with the metric 'deci' prefix appended.
Definition core.h:2007
typename detail::prefix< std::hecto, Cf >::type hecto
< Represents the type of class Cf with the metric 'deca' prefix appended.
Definition core.h:2008
std::is_invocable_r< Ret, detail::invocable_scale< T >, Ret > is_numerical_scale
Trait which tests whether T meets the requirements for a numerical scale.
Definition core.h:972
typename units::detail::Sqrt< Ratio, std::ratio< 1, Eps > >::type ratio_sqrt
Calculate square root of a ratio at compile-time.
Definition core.h:1875
typename detail::sqrt_impl< Cf, Eps >::type square_root
represents the square root of type class U.
Definition core.h:1917
typename detail::cubed_impl< Cf >::type cubed
represents the type of class U cubed.
Definition core.h:1701
typename detail::squared_impl< Cf >::type squared
represents the unit type of class U squared
Definition core.h:1674
typename detail::inverse_impl< Cf >::type inverse
represents the inverse unit type of class U.
Definition core.h:1646
constexpr detail::floating_point_promotion_t< UnitType > trunc(const UnitType x) noexcept
Truncate value.
Definition core.h:5524
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > modf(const UnitType x, UnitType *intpart) noexcept
Break into fractional and integral parts.
Definition core.h:5351
constexpr auto fmod(const UnitTypeLhs numer, const UnitTypeRhs denom) noexcept
Compute remainder of division.
Definition core.h:5509
constexpr auto hypot(const UnitTypeLhs &x, const UnitTypeRhs &y)
Computes the square root of the sum-of-squares of x and y.
Definition core.h:5459
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > log1p(const UnitType x) noexcept
Compute logarithm plus one.
Definition core.h:5402
constexpr detail::floating_point_promotion_t< UnitType > fabs(const UnitType x) noexcept
Compute absolute value.
Definition core.h:5803
constexpr auto fmin(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
Minimum value.
Definition core.h:5785
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > log2(const UnitType x) noexcept
Compute binary logarithm.
Definition core.h:5416
constexpr auto fmax(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
Maximum value.
Definition core.h:5768
constexpr auto fma(const UnitTypeLhs x, const UnitMultiply y, const UnitAdd z) noexcept -> std::common_type_t< decltype(detail::floating_point_promotion_t< UnitTypeLhs >(x) *detail::floating_point_promotion_t< UnitMultiply >(y)), UnitAdd >
Multiply-add.
Definition core.h:5839
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > exp(const UnitType x) noexcept
Compute exponential function.
Definition core.h:5305
constexpr detail::floating_point_promotion_t< UnitType > round(const UnitType x) noexcept
Round to nearest.
Definition core.h:5538
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > exp2(const UnitType x) noexcept
Compute binary exponential function.
Definition core.h:5373
constexpr detail::floating_point_promotion_t< Unit > ceil(const Unit x) noexcept
Round up value.
Definition core.h:5480
constexpr detail::floating_point_promotion_t< UnitTypeLhs > copysign(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
Copy sign.
Definition core.h:5724
constexpr detail::floating_point_promotion_t< Unit > floor(const Unit x) noexcept
Round down value.
Definition core.h:5493
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > log(const UnitType x) noexcept
Compute natural logarithm.
Definition core.h:5320
constexpr auto fdim(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
Positive difference.
Definition core.h:5751
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > log10(const UnitType x) noexcept
Compute common logarithm.
Definition core.h:5334
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > expm1(const UnitType x) noexcept
Compute exponential minus one.
Definition core.h:5387
#define MSVC_EBO
Describes objects that represent quantities of a given unit.
Definition core.h:2737
constexpr UnitType make_unit(const T value) noexcept
Constructs a unit container from an arithmetic type.
Definition core.h:3370
constexpr unit< compound_conversion_factor< joules_, inverse< kelvin_ >, inverse< mols_ > > > R(8.314462618)
Gas constant.
constexpr meters_per_second c(299792458.0)
Speed of light in vacuum.
namespace representing the implemented base and derived unit types.
Definition core.h:1267
make_dimension< length, std::ratio< 2 >, time, std::ratio<-2 > > radioactivity
< Represents an SI derived unit of luminance
Definition core.h:1361
dimension_multiply< pressure, time > dynamic_viscosity
< Represents an SI derived unit of density
Definition core.h:1377
dimension_divide< mass, volume > density
< Represents an SI derived unit of torque
Definition core.h:1376
make_dimension< luminous_intensity, std::ratio< 1 >, length, std::ratio<-2 > > luminance
< Represents an SI derived unit of illuminance
Definition core.h:1360
dimension_pow< angle, std::ratio< 2 > > solid_angle
< Represents a quantity of angle
Definition core.h:1337
dimension_divide< current, voltage > conductance
< Represents an SI derived unit of impedance
Definition core.h:1355
make_dimension< power, std::ratio< 1 >, length, std::ratio<-1 > > spectral_flux
< Represents an SI derived unit of spectral intensity
Definition core.h:1369
dimension_divide< mass, substance > substance_mass
< Represents an SI derived unit of radioactivity
Definition core.h:1362
make_dimension< radiant_intensity, std::ratio< 1 >, area, std::ratio<-1 > > radiance
< Represents an SI derived unit of radiant intensity
Definition core.h:1366
dimension_divide< voltage, current > impedance
< Represents an SI derived unit of capacitance
Definition core.h:1354
dimension_divide< substance, mass > substance_concentration
< Represents an SI derived unit of substance mass
Definition core.h:1363
dimension_divide< energy, time > power
< Represents an SI derived unit of energy
Definition core.h:1351
dimension_multiply< impedance, time > inductance
< Represents an SI derived unit of magnetic flux
Definition core.h:1357
dimension_pow< length, std::ratio< 3 > > volume
< Represents an SI derived unit of area
Definition core.h:1346
dimension_divide< area, time > kinematic_viscosity
< Represents an SI derived unit of dynamic (absolute) viscosity
Definition core.h:1378
make_dimension< angle_tag > angle
< Represents a quantity with no dimension.
Definition core.h:1334
dimension_divide< velocity, time > acceleration
< Represents an SI derived unit of angular velocity
Definition core.h:1341
dimension_multiply< mass, acceleration > force
< Represents an SI derived unit of angular jerk
Definition core.h:1344
make_dimension< power, std::ratio< 1 >, solid_angle, std::ratio<-1 > > radiant_intensity
< Represents an SI derived unit of magnetic field strength
Definition core.h:1365
dimension_divide< angular_velocity, time > angular_acceleration
< Represents an SI derived unit of acceleration
Definition core.h:1342
dimension_divide< force, area > pressure
< Represents an SI derived unit of volumetric flow rate
Definition core.h:1348
make_dimension< radiant_intensity, std::ratio< 1 >, length, std::ratio<-1 > > spectral_intensity
< Represents an SI derived unit of irradiance
Definition core.h:1368
dimension_divide< power, current > voltage
< Represents an SI derived unit of power
Definition core.h:1352
dimension_divide< charge, voltage > capacitance
< Represents an SI derived unit of voltage
Definition core.h:1353
dimension_multiply< time, current > charge
< Represents an SI derived unit of pressure
Definition core.h:1349
make_dimension< mass, std::ratio< 1 >, time, std::ratio<-2 >, current, std::ratio<-1 > > magnetic_field_strength
< Represents an SI derived unit of substance concentration
Definition core.h:1364
dimension_divide< energy, current > magnetic_flux
< Represents an SI derived unit of conductance
Definition core.h:1356
dimension_multiply< force, length > energy
< Represents an SI derived unit of charge
Definition core.h:1350
make_dimension< power, std::ratio< 1 >, volume, std::ratio<-1 > > spectral_irradiance
< Represents an SI derived unit of spectral intensity
Definition core.h:1371
make_dimension< volume, std::ratio<-1 > > concentration
< Represents an SI derived unit of energy density
Definition core.h:1380
make_dimension< data_tag > data
< Represents a unit of concentration
Definition core.h:1381
dimension_multiply< solid_angle, luminous_intensity > luminous_flux
< Represents an SI derived unit of inductance
Definition core.h:1358
dimension_divide< length, time > velocity
< Represents an SI derived unit of frequency
Definition core.h:1339
dimension_divide< data, time > data_transfer_rate
< Represents a unit of data size
Definition core.h:1382
dimension_pow< length, std::ratio< 2 > > area
< Represents an SI derived unit of force
Definition core.h:1345
make_dimension< radiant_intensity, std::ratio< 1 >, volume, std::ratio<-1 > > spectral_radiance
< Represents an SI derived unit of spectral flux
Definition core.h:1370
make_dimension< luminous_flux, std::ratio< 1 >, length, std::ratio<-2 > > illuminance
< Represents an SI derived unit of luminous flux
Definition core.h:1359
make_dimension< time, std::ratio<-1 > > frequency
< Represents an SI derived unit of solid angle
Definition core.h:1338
make_dimension< power, std::ratio< 1 >, area, std::ratio<-1 > > irradiance
< Represents an SI derived unit of radiance
Definition core.h:1367
dimension_divide< angle, time > angular_velocity
< Represents an SI derived unit of velocity
Definition core.h:1340
make_dimension< energy, std::ratio< 1 >, volume, std::ratio<-1 > > energy_density
< Represents an SI derived unit of kinematic viscosity
Definition core.h:1379
make_dimension< length, std::ratio< 1 >, time, std::ratio<-3 > > jerk
< Represents an SI derived unit of spectral irradiance
Definition core.h:1374
dimension_divide< volume, time > volume_flow_rate
< Represents an SI derived unit of volume
Definition core.h:1347
dimension_divide< angular_acceleration, time > angular_jerk
< Represents an SI derived unit of angular acceleration
Definition core.h:1343
dimension_multiply< force, length > torque
< Represents an SI derived unit of jerk
Definition core.h:1375
namespace for unit literal definitions of all categories.
namespace representing type traits which can access the properties of types provided by the units lib...
Definition core.h:197
constexpr bool is_affine_conversion_factor_v
true when a conversion factor carries a non-zero datum offset — i.e.
Definition core.h:2064
typename std::is_base_of< units::detail::_conversion_factor, T >::type is_conversion_factor
Definition core.h:852
detail::is_ratio_impl< T > is_ratio
UnaryTypeTrait for querying whether T represents a specialization of std::ratio.
Definition core.h:761
typename units::detail::dimension_of_impl< U >::type dimension_of_t
Names the dimension_t of a conversion_factor.
Definition core.h:1457
constexpr bool is_affine_unit_v
true when a unit type is affine — its conversion factor carries a non-zero datum offset (e....
Definition core.h:2565
Unit Conversion Library namespace.
Definition units.h:108
decibels() -> decibels< double >
Nullary guide so bare default-construction decibels{} / decibels() deduces decibels<default> — again ...
constexpr auto clamp(const UnitTypeValue &value, const UnitTypeLo &lo, const UnitTypeHi &hi)
Clamps a value to the range [lo, hi], in the value's own unit when that is lossless (matching min/max...
Definition core.h:5279
Type representing an arbitrary conversion factor between units.
Definition core.h:1568
numerical scale which is decibel
Definition core.h:5087
static T linearize(const T value) noexcept
linearizes value
Definition core.h:5095
static T scale(const T value) noexcept
returns value in dB
Definition core.h:5113
dimensionless unit with decibel scale
Definition core.h:5127
helper type to identify units.
Definition core.h:871
Whether T is a complete type, decided by SFINAE on sizeof(T) without instantiating any other trait.
Definition core.h:886
is_unit implementation: an incomplete or non-class type is never a unit, decided WITHOUT instantiatin...
Definition core.h:901
numerical scale which is linear
Definition core.h:3851
static constexpr T scale(const T value) noexcept
scales value
Definition core.h:3871
static constexpr T linearize(const T value) noexcept
linearizes value
Definition core.h:3859
Tag for unit constructors.
Definition core.h:2223
Trait which tests whether a type is inherited from a decibel scale.
Definition core.h:3825
Trait which tests whether a type is inherited from a linear scale.
Definition core.h:3810
BinaryTypeTrait for querying whether Cf1 and Cf2 are conversion factors to the same dimension.
Definition core.h:2050
BinaryTypeTrait for querying whether U1 and U2 are units of the same dimension.
Definition core.h:2580
Traits which tests if a class is a unit.
Definition core.h:938
SFINAE-able trait which replaces the underlying type of Unit with Underlying.
Definition core.h:1503
SFINAE-able trait that maps a conversion_factor to its strengthened type.
Definition core.h:1076