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>;
1351 using force = dimension_multiply<mass, acceleration>;
1352 using area = dimension_pow<length, std::ratio<2>>;
1353 using volume = dimension_pow<length, std::ratio<3>>;
1356 using charge = dimension_multiply<time, current>;
1357 using energy = dimension_multiply<force, length>;
1358 using power = dimension_divide<energy, time>;
1366 using illuminance = make_dimension<luminous_flux, std::ratio<1>, length, std::ratio<-2>>;
1367 using luminance = make_dimension<luminous_intensity, std::ratio<1>, length, std::ratio<-2>>;
1368 using radioactivity = make_dimension<length, std::ratio<2>, time, std::ratio<-2>>;
1371 using magnetic_field_strength = make_dimension<mass, std::ratio<1>, time, std::ratio<-2>, current, std::ratio<-1>>;
1373 using radiance = make_dimension<radiant_intensity, std::ratio<1>,
area, std::ratio<-1>>;
1376 using spectral_flux = make_dimension<power, std::ratio<1>, length, std::ratio<-1>>;
1381 using jerk = make_dimension<length, std::ratio<1>, time, std::ratio<-3>>;
1382 using torque = dimension_multiply<force, length>;
1383 using density = dimension_divide<mass, volume>;
1388 using data = make_dimension<data_tag>;
1400 template<RatioType,
class, RatioType, RatioType>
1407 using conversion_ratio = Conversion;
1408 using translation_ratio = Translation;
1409 using pi_exponent_ratio = PiExponent;
1417 template<RatioType C,
typename U, RatioType P, RatioType T>
1418 conversion_factor<C, U, P, T> conversion_factor_base_t_impl(conversion_factor<C, U, P, T>* cf)
1423 template<
typename T>
1424 using conversion_factor_base_t =
decltype(conversion_factor_base_t_impl(std::declval<T*>()));
1432 template<
class ConversionFactor>
1433 struct dimension_of_impl : dimension_of_impl<conversion_factor_base_t<ConversionFactor>>
1437 template<RatioType Conversion,
class BaseUnit, RatioType PiExponent, RatioType Translation>
1438 struct dimension_of_impl<conversion_factor<Conversion, BaseUnit, PiExponent, Translation>> : dimension_of_impl<BaseUnit>
1442 template<
class... Exponents>
1443 struct dimension_of_impl<dimension_t<Exponents...>>
1445 using type = dimension_t<Exponents...>;
1449 struct dimension_of_impl<void>
1464 using dimension_of_t =
typename units::detail::dimension_of_impl<U>::type;
1467 template<ConversionFactorType ConversionFactor, ArithmeticType T, NumericalScaleType<T> NumericalScale>
1473 template<
typename T,
class Dim,
bool IsConv = false>
1474 struct has_dimension_of_impl : std::false_type
1478 template<
typename T,
class Dim>
1479 using has_dimension_of =
typename has_dimension_of_impl<T, Dim, traits::is_conversion_factor_v<T>>::type;
1481 template<
typename Cf,
class Dim>
1482 struct has_dimension_of_impl<Cf, Dim, true> : has_dimension_of<conversion_factor_base_t<Cf>, Dim>::type
1486 template<
typename C,
typename Cf,
typename P,
typename T,
class Dim>
1487 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
1491 template<
typename Cf,
typename T,
class Ns,
class Dim>
1492 struct has_dimension_of_impl<unit<Cf, T, Ns>, Dim> : std::is_same<traits::dimension_of_t<Cf>, Dim>::type
1508 template<
class,
class>
1513 template<ConversionFactorType Cf, ArithmeticType T, NumericalScaleType<T> Ns, ArithmeticType Underlying>
1519 template<
class Unit,
class Underlying>
1523 template<
class ConversionFactor,
class =
void>
1528 template<
class ConversionFactor>
1529 struct is_ratio_dimensionless_cf<ConversionFactor,
std::void_t<typename ConversionFactor::dimension_type, typename ConversionFactor::conversion_ratio>>
1530 : std::bool_constant<std::is_same_v<typename ConversionFactor::dimension_type, dimension::dimensionless> && !std::ratio_equal_v<typename ConversionFactor::conversion_ratio, std::ratio<1>>>
1534 template<
class ConversionFactor>
1535 inline constexpr bool is_ratio_dimensionless_cf_v = is_ratio_dimensionless_cf<ConversionFactor>::value;
1539 template<
typename U>
1542 template<
typename U>
1570 template<RatioType Conversion,
class BaseUnit, RatioType PiExponent = std::ratio<0>, RatioType Translation = std::ratio<0>>
1574 using conversion_ratio = std::ratio_multiply<typename BaseUnit::conversion_ratio, Conversion>;
1575 using pi_exponent_ratio = std::ratio_add<typename BaseUnit::pi_exponent_ratio, PiExponent>;
1576 using translation_ratio = std::ratio_add<std::ratio_multiply<typename BaseUnit::conversion_ratio, Translation>,
typename BaseUnit::translation_ratio>;
1592 template<ConversionFactorType Cf1, ConversionFactorType Cf2>
1593 struct unit_multiply_impl
1597 std::ratio_add<typename Cf1::pi_exponent_ratio, typename Cf2::pi_exponent_ratio>>;
1604 template<ConversionFactorType Cf1, ConversionFactorType Cf2>
1605 using unit_multiply =
typename unit_multiply_impl<Cf1, Cf2>::type;
1613 template<ConversionFactorType Cf1, ConversionFactorType Cf2>
1614 struct unit_divide_impl
1616 using type = conversion_factor<std::ratio_divide<typename Cf1::conversion_ratio, typename Cf2::conversion_ratio>,
1617 dimension_divide<traits::dimension_of_t<typename Cf1::dimension_type>, traits::dimension_of_t<typename Cf2::dimension_type>>,
1618 std::ratio_subtract<typename Cf1::pi_exponent_ratio, typename Cf2::pi_exponent_ratio>>;
1625 template<ConversionFactorType Cf1, ConversionFactorType Cf2>
1626 using unit_divide =
typename unit_divide_impl<Cf1, Cf2>::type;
1634 template<ConversionFactorType Cf>
1637 using type = conversion_factor<std::ratio<Cf::conversion_ratio::den, Cf::conversion_ratio::num>, dimension_pow<
typename Cf::dimension_type, std::ratio<-1>>,
1638 std::ratio_multiply<
typename Cf::pi_exponent_ratio, std::ratio<-1>>>;
1649 template<ConversionFactorType Cf>
1650 using inverse =
typename detail::inverse_impl<Cf>::type;
1660 template<ConversionFactorType Cf>
1663 using Conversion =
typename Cf::conversion_ratio;
1665 std::ratio_multiply<typename Cf::pi_exponent_ratio, std::ratio<2>>,
typename Cf::translation_ratio>;
1676 template<ConversionFactorType Cf>
1677 using squared =
typename detail::squared_impl<Cf>::type;
1687 template<ConversionFactorType Cf>
1690 using Conversion =
typename Cf::conversion_ratio;
1692 dimension_pow<traits::dimension_of_t<typename Cf::dimension_type>, std::ratio<3>>, std::ratio_multiply<typename Cf::pi_exponent_ratio, std::ratio<3>>,
typename Cf::translation_ratio>;
1703 template<ConversionFactorType Cf>
1704 using cubed =
typename detail::cubed_impl<Cf>::type;
1714 using Zero = std::ratio<0>;
1715 using One = std::ratio<1>;
1716 template <RatioType R>
using Square = std::ratio_multiply<R, R>;
1719 template <
template <std::
intmax_t N>
class Predicate,
typename =
void>
1722 template <std::
intmax_t N>
1725 static constexpr const std::intmax_t value = 2 * N;
1726 static_assert(value > 0,
"Overflows when computing 2 * N");
1729 template <std::
intmax_t Lower, std::
intmax_t Upper,
typename Condition1 =
void,
typename Condition2 =
void>
1730 struct DoubleSidedSearch_ : DoubleSidedSearch_<Lower, Upper,
1731 std::integral_constant<bool, (Upper - Lower == 1)>,
1732 std::integral_constant<bool, ((Upper - Lower>1 && Predicate<Lower + (Upper - Lower) / 2>::value))>> {};
1734 template <std::
intmax_t Lower, std::
intmax_t Upper>
1735 struct DoubleSidedSearch_<Lower, Upper,
std::false_type, std::false_type> : DoubleSidedSearch_<Lower, Lower + (Upper - Lower) / 2> {};
1737 template <std::
intmax_t Lower, std::
intmax_t Upper,
typename Condition2>
1738 struct DoubleSidedSearch_<Lower, Upper,
std::true_type, Condition2> : std::integral_constant<std::intmax_t, Lower>{};
1740 template <std::
intmax_t Lower, std::
intmax_t Upper,
typename Condition1>
1741 struct DoubleSidedSearch_<Lower, Upper, Condition1,
std::true_type> : DoubleSidedSearch_<Lower + (Upper - Lower) / 2, Upper>{};
1743 template <std::
intmax_t Lower,
class =
void>
1744 struct SingleSidedSearch_ : SingleSidedSearch_<Lower, std::integral_constant<bool, Predicate<SafeDouble_<Lower>::value>::value>>{};
1746 template <std::
intmax_t Lower>
1747 struct SingleSidedSearch_<Lower,
std::false_type> : DoubleSidedSearch_<Lower, SafeDouble_<Lower>::value> {};
1749 template <std::
intmax_t Lower>
1750 struct SingleSidedSearch_<Lower,
std::true_type> : SingleSidedSearch_<SafeDouble_<Lower>::value>{};
1752 static constexpr std::intmax_t value = SingleSidedSearch_<1>::value;
1755 template <
template <std::
intmax_t N>
class Predicate>
1756 struct BinarySearch<Predicate,
std::enable_if_t<!Predicate<1>::value>> : std::integral_constant<std::intmax_t, 0>{};
1759 template <
typename R>
1762 template <std::
intmax_t N>
using Predicate_ = std::ratio_less_equal<std::ratio<N>, std::ratio_divide<R, std::ratio<N>>>;
1763 static constexpr const std::intmax_t value = BinarySearch<Predicate_>::value;
1766 template <
typename R>
1767 struct IsPerfectSquare
1769 static constexpr const std::intmax_t DenSqrt_ = Integer<std::ratio<R::den>>::value;
1770 static constexpr const std::intmax_t NumSqrt_ = Integer<std::ratio<R::num>>::value;
1771 static constexpr const bool value =( DenSqrt_ * DenSqrt_ == R::den && NumSqrt_ * NumSqrt_ == R::num);
1772 using Sqrt = std::ratio<NumSqrt_, DenSqrt_>;
1776 template <
typename Tp,
typename Tq>
1784 template <
typename R>
1787 using P_ =
typename R::P;
1788 using Q_ =
typename R::Q;
1789 using Den_ = std::ratio_subtract<P_, Square<Q_>>;
1790 using A_ = std::ratio_divide<Q_, Den_>;
1791 using B_ = std::ratio_divide<P_, Square<Den_>>;
1792 static constexpr const std::intmax_t I_ = (A_::num + Integer<std::ratio_multiply<B_, Square<std::ratio<A_::den>>>>::value) / A_::den;
1793 using I = std::ratio<I_>;
1794 using Rem = Remainder<B_, std::ratio_subtract<I, A_>>;
1801 template <
typename Tr, std::
intmax_t N>
1802 struct ContinuedFraction
1804 template <
typename T>
1805 using Abs_ = std::conditional_t<std::ratio_less_v<T, Zero>, std::ratio_subtract<Zero, T>, T>;
1808 using Last_ = ContinuedFraction<
R, N - 1>;
1809 using Reciprocal_ = Reciprocal<typename Last_::Rem>;
1810 using Rem =
typename Reciprocal_::Rem;
1811 using I_ =
typename Reciprocal_::I;
1812 using Den_ = std::ratio_add<typename Last_::W, I_>;
1813 using U = std::ratio_divide<typename Last_::V, Den_>;
1814 using V = std::ratio_divide<std::ratio_add<typename Last_::U, std::ratio_multiply<typename Last_::V, I_>>, Den_>;
1815 using W = std::ratio_divide<One, Den_>;
1816 using Error = Abs_<std::ratio_divide<std::ratio_subtract<U, std::ratio_multiply<V, W>>,
typename Reciprocal<Rem>::I>>;
1819 template <
typename Tr>
1820 struct ContinuedFraction<Tr, 1>
1824 using V = std::ratio<Integer<R>::value>;
1826 using Rem = Remainder<R, V>;
1827 using Error = std::ratio_divide<One, typename Reciprocal<Rem>::I>;
1830 template <
typename R,
typename Eps, std::
intmax_t N = 1,
typename =
void>
1831 struct Sqrt_ : Sqrt_<R, Eps, N + 1> {};
1833 template <
typename R,
typename Eps, std::
intmax_t N>
1834 struct Sqrt_<
R, Eps, N,
std::enable_if_t<std::ratio_less_equal_v<typename ContinuedFraction<R, N>::Error, Eps>>>
1836 using type =
typename ContinuedFraction<R, N>::V;
1839 template <
typename R,
typename,
typename =
void>
1842 static_assert(std::ratio_greater_equal_v<R, Zero>,
"R can't be negative");
1845 template <
typename R,
typename Eps>
1846 struct Sqrt<
R, Eps,
std::enable_if_t<std::ratio_greater_equal_v<R, Zero> && IsPerfectSquare<R>::value>>
1848 using type =
typename IsPerfectSquare<R>::Sqrt;
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)>> : Sqrt_<R, Eps>{};
1877 template<RatioType Ratio, std::
intmax_t Eps = 10000000000>
1878 using ratio_sqrt =
typename units::detail::Sqrt<Ratio, std::ratio<1, Eps>>::type;
1888 template<ConversionFactorType Unit, std::
intmax_t Eps>
1891 using Conversion =
typename Unit::conversion_ratio;
1893 std::ratio_divide<typename Unit::pi_exponent_ratio, std::ratio<2>>,
typename Unit::translation_ratio>;
1919 template<ConversionFactorType Cf, std::
intmax_t Eps = 10000000000>
1920 using square_root =
typename detail::sqrt_impl<Cf, Eps>::type;
1935 struct compound_impl;
1937 template<ConversionFactorType Cf>
1938 struct compound_impl<Cf>
1944 struct compound_impl<Cf1, Cf2, Cfs...> : compound_impl<unit_multiply<Cf1, Cf2>, Cfs...>
1975 template<RatioType Ratio, ConversionFactorType ConversionFactor>
1982 template<
int N, RatioType R>
1983 struct power_of_ratio
1985 using type = std::ratio_multiply<
R,
typename power_of_ratio<N - 1,
R>::type>;
1989 template<RatioType R>
1990 struct power_of_ratio<1,
R>
2002 template<ConversionFactorType Cf>
using atto =
typename detail::prefix<std::atto,Cf>::type;
2003 template<ConversionFactorType Cf>
using femto =
typename detail::prefix<std::femto,Cf>::type;
2004 template<ConversionFactorType Cf>
using pico =
typename detail::prefix<std::pico,Cf>::type;
2005 template<ConversionFactorType Cf>
using nano =
typename detail::prefix<std::nano,Cf>::type;
2006 template<ConversionFactorType Cf>
using micro =
typename detail::prefix<std::micro,Cf>::type;
2007 template<ConversionFactorType Cf>
using milli =
typename detail::prefix<std::milli,Cf>::type;
2008 template<ConversionFactorType Cf>
using centi =
typename detail::prefix<std::centi,Cf>::type;
2009 template<ConversionFactorType Cf>
using deci =
typename detail::prefix<std::deci,Cf>::type;
2010 template<ConversionFactorType Cf>
using deca =
typename detail::prefix<std::deca,Cf>::type;
2011 template<ConversionFactorType Cf>
using hecto =
typename detail::prefix<std::hecto,Cf>::type;
2012 template<ConversionFactorType Cf>
using kilo =
typename detail::prefix<std::kilo,Cf>::type;
2013 template<ConversionFactorType Cf>
using mega =
typename detail::prefix<std::mega,Cf>::type;
2014 template<ConversionFactorType Cf>
using giga =
typename detail::prefix<std::giga,Cf>::type;
2015 template<ConversionFactorType Cf>
using tera =
typename detail::prefix<std::tera,Cf>::type;
2016 template<ConversionFactorType Cf>
using peta =
typename detail::prefix<std::peta,Cf>::type;
2017 template<ConversionFactorType Cf>
using exa =
typename detail::prefix<std::exa, Cf>::type;
2024 template<ConversionFactorType Cf>
using kibi =
typename detail::prefix<std::ratio<1024>, Cf>::type;
2025 template<ConversionFactorType Cf>
using mebi =
typename detail::prefix<std::ratio<1048576>, Cf>::type;
2026 template<ConversionFactorType Cf>
using gibi =
typename detail::prefix<std::ratio<1073741824>, Cf>::type;
2027 template<ConversionFactorType Cf>
using tebi =
typename detail::prefix<std::ratio<1099511627776>, Cf>::type;
2028 template<ConversionFactorType Cf>
using pebi =
typename detail::prefix<std::ratio<1125899906842624>, Cf>::type;
2029 template<ConversionFactorType Cf>
using exbi =
typename detail::prefix<std::ratio<1152921504606846976>, Cf>::type;
2050 template<ConversionFactorType Cf1, ConversionFactorType Cf2>
2052 : 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>>>
2056 template<ConversionFactorType Cf1, ConversionFactorType Cf2>
2066 template<ConversionFactorType Cf>
2067 inline constexpr bool is_affine_conversion_factor_v = !std::ratio_equal_v<typename conversion_factor_traits<Cf>::translation_ratio, std::ratio<0>>;
2083 template<
typename T>
2084 struct floating_point_promotion : std::conditional<std::is_floating_point_v<T>, T, double>
2088 template<
typename T>
2089 using floating_point_promotion_t =
typename floating_point_promotion<T>::type;
2091 template<ConversionFactorType Cf,
typename T,
class Ns>
2092 struct floating_point_promotion<unit<Cf, T, Ns>>
2094 using type = unit<Cf, floating_point_promotion_t<T>, Ns>;
2108 template<
class To,
class From>
2109 constexpr To exact_integral_cast(From value)
2111 const To result =
static_cast<To
>(value);
2112 if (
static_cast<From
>(result) != value)
2113 throw "a floating-point unit converts to an integral unit only when its value is a whole number in range";
2120 template<std::
floating_po
int T>
2121 constexpr T sqrtNewtonRaphson(T x, T curr, T prev)
2123 return curr == prev ? curr : sqrtNewtonRaphson(x, T{0.5} * (curr + x / curr), curr);
2128 template<ArithmeticType T>
2129 constexpr detail::floating_point_promotion_t<T> sqrt(T x_)
2131 using FloatingPoint = detail::floating_point_promotion_t<T>;
2133 const FloatingPoint x(x_);
2135 return x >= 0 && x < std::numeric_limits<FloatingPoint>::infinity() ? Detail::sqrtNewtonRaphson(x, x, FloatingPoint(0)) : std::numeric_limits<FloatingPoint>::quiet_NaN();
2141 template<
unsigned long long Exp,
typename B>
2142 constexpr auto pow_acc(B acc, B
base [[maybe_unused]])
noexcept
2144 if constexpr (Exp == 0)
2146 return static_cast<B
>(acc);
2148 else if constexpr ((Exp & 1) == 0)
2150 return pow_acc<Exp / 2>(acc,
base *
base);
2154 return pow_acc<(Exp - 1) / 2>(acc *
base,
base *
base);
2160 template<
signed long long Exp, ArithmeticType B>
2161 constexpr detail::floating_point_promotion_t<B> pow(B base)
noexcept
2163 using promoted_t = detail::floating_point_promotion_t<B>;
2164 constexpr auto one =
static_cast<promoted_t
>(1);
2165 if constexpr (Exp >= 0)
2167 return detail::pow_acc<Exp>(one,
static_cast<promoted_t
>(base));
2169 constexpr auto new_exp =
static_cast<unsigned long long>(-(Exp + 1));
2170 return 1 / (
base * detail::pow_acc<new_exp>(one,
static_cast<promoted_t
>(base)));
2176 template<
typename T1,
typename T2>
2177 constexpr auto pow_acc(T1 acc, T1 x, T2 y)
noexcept
2185 return pow_acc(acc, x * x, y / 2);
2187 return pow_acc(acc * x, x * x, (y - 1) / 2);
2192 template<ArithmeticType T1, ArithmeticType T2>
2193 requires std::is_unsigned_v<T2>
2194 constexpr detail::floating_point_promotion_t<T1> pow(T1 x, T2 y)
noexcept
2196 using promoted_t = detail::floating_point_promotion_t<T1>;
2197 return detail::pow_acc(
static_cast<promoted_t
>(1.0),
static_cast<promoted_t
>(x), y);
2200 template<ArithmeticType T1, ArithmeticType T2>
2201 requires std::is_signed_v<T2>
2202 constexpr detail::floating_point_promotion_t<T1> pow(T1 x, T2 y)
noexcept
2206 return pow(x,
static_cast<unsigned long long>(y));
2208 return 1 / (x * pow(x,
static_cast<unsigned long long>(-(y + 1))));
2211 template<ArithmeticType T>
2212 constexpr T abs(T x)
2214 return x < 0 ? -x : x;
2225 struct linearized_value_t
2227 explicit linearized_value_t() =
default;
2240#if defined(__SIZEOF_INT128__)
2241 using widest_signed_int = __int128;
2242 using widest_unsigned_int =
unsigned __int128;
2243 inline constexpr bool has_builtin_int128 =
true;
2245 using widest_signed_int = std::intmax_t;
2246 using widest_unsigned_int = std::uintmax_t;
2247 inline constexpr bool has_builtin_int128 =
false;
2255 constexpr Rep widening_mul_div(Rep value, std::intmax_t num, std::intmax_t den)
noexcept
2257 if constexpr (has_builtin_int128)
2259 return static_cast<Rep
>(
static_cast<widest_signed_int
>(value) *
static_cast<widest_signed_int
>(num) /
static_cast<widest_signed_int
>(den));
2266 const bool negative = (value < 0);
2267 const std::uint64_t a = negative ?
static_cast<std::uint64_t
>(-(value + 1)) + 1u : static_cast<std::uint64_t>(value);
2268 const std::uint64_t b =
static_cast<std::uint64_t
>(num);
2269 const std::uint64_t d =
static_cast<std::uint64_t
>(den);
2272 const std::uint64_t aLo = a & 0xFFFFFFFFull, aHi = a >> 32;
2273 const std::uint64_t bLo = b & 0xFFFFFFFFull, bHi = b >> 32;
2274 const std::uint64_t ll = aLo * bLo;
2275 const std::uint64_t lh = aLo * bHi;
2276 const std::uint64_t hl = aHi * bLo;
2277 const std::uint64_t hh = aHi * bHi;
2278 const std::uint64_t cross = (ll >> 32) + (lh & 0xFFFFFFFFull) + (hl & 0xFFFFFFFFull);
2279 std::uint64_t hi = hh + (lh >> 32) + (hl >> 32) + (cross >> 32);
2280 std::uint64_t lo = (cross << 32) | (ll & 0xFFFFFFFFull);
2283 std::uint64_t quotient = 0;
2284 std::uint64_t rem = 0;
2285 for (
int bit = 127; bit >= 0; --bit)
2287 rem = (rem << 1) | ((bit >= 64 ? (hi >> (bit - 64)) : (lo >> bit)) & 1u);
2288 const bool canSubtract = (rem >= d);
2289 rem -= canSubtract ? d : 0u;
2291 quotient |= (
static_cast<std::uint64_t
>(canSubtract) << bit);
2293 const auto result =
static_cast<Rep
>(quotient);
2294 return negative ?
static_cast<Rep
>(-result) : result;
2305 constexpr bool integral_conversion_is_exact(Rep value, std::intmax_t num, std::intmax_t den)
noexcept
2307 const widest_signed_int product =
static_cast<widest_signed_int
>(value) *
static_cast<widest_signed_int
>(num);
2308 return product %
static_cast<widest_signed_int
>(den) == 0;
2323 template<
class To,
class From>
2324 constexpr To exact_integral_unit_cast(From value, std::intmax_t num, std::intmax_t den)
2326 if (!integral_conversion_is_exact(value, num, den))
2327 throw "an integral unit converts to a coarser integral unit only when the value is an exact whole number of the target unit";
2328 return static_cast<To
>(widening_mul_div(value, num, den));
2352 template<ConversionFactorType ConversionFactorFrom, ConversionFactorType ConversionFactorTo, ArithmeticType To = UNIT_LIB_DEFAULT_TYPE, ArithmeticType From>
2353 requires(traits::is_same_dimension_conversion_factor_v<ConversionFactorFrom, ConversionFactorTo>)
2354 constexpr To
convert(
const From& value)
noexcept
2356 using Ratio = std::ratio_divide<typename ConversionFactorFrom::conversion_ratio, typename ConversionFactorTo::conversion_ratio>;
2357 using PiRatio = std::ratio_subtract<typename ConversionFactorFrom::pi_exponent_ratio, typename ConversionFactorTo::pi_exponent_ratio>;
2359 std::ratio_divide<std::ratio_subtract<typename ConversionFactorFrom::translation_ratio, typename ConversionFactorTo::translation_ratio>,
typename ConversionFactorTo::conversion_ratio>;
2361 [[maybe_unused]]
constexpr auto normal_convert = []<
typename T0>(
const T0& val)
2368 [[maybe_unused]]
constexpr auto pi_convert = []<
typename T0>(
const T0& val)
2370 using ResolvedUnitFrom =
2377 if constexpr (std::same_as<ConversionFactorFrom, ConversionFactorTo>)
2379 return static_cast<To
>(value);
2382 else if constexpr (!std::same_as<std::ratio<0>, PiRatio> && std::same_as<std::ratio<0>, Translation>)
2384 using CommonUnderlying = std::common_type_t<To, From, UNIT_LIB_DEFAULT_TYPE>;
2389 constexpr long double PiRatioValue =
static_cast<long double>(PiRatio::num) /
static_cast<long double>(PiRatio::den);
2390 constexpr bool integerExponent = (PiRatio::num % PiRatio::den == 0);
2394 if constexpr (integerExponent && PiRatioValue >= 0)
2396 return static_cast<To
>(normal_convert(
static_cast<CommonUnderlying
>(value) *
static_cast<CommonUnderlying
>(pow(detail::PI_VAL, PiRatioValue))));
2398 else if constexpr (integerExponent)
2400 return static_cast<To
>(normal_convert(
static_cast<CommonUnderlying
>(value) /
static_cast<CommonUnderlying
>(pow(detail::PI_VAL, -PiRatioValue))));
2404 return static_cast<To
>(normal_convert(
static_cast<CommonUnderlying
>(value) *
static_cast<CommonUnderlying
>(std::pow(detail::PI_VAL, PiRatioValue))));
2408 else if constexpr (std::same_as<std::ratio<0>, PiRatio> && !std::same_as<std::ratio<0>, Translation>)
2410 using CommonUnderlying = std::common_type_t<To, From, UNIT_LIB_DEFAULT_TYPE>;
2412 return static_cast<To
>(normal_convert(
static_cast<CommonUnderlying
>(value)) + (
static_cast<CommonUnderlying
>(Translation::num) /
static_cast<CommonUnderlying
>(Translation::den)));
2415 else if constexpr (!std::same_as<std::ratio<0>, PiRatio> && !std::same_as<std::ratio<0>, Translation>)
2417 using CommonUnderlying = std::common_type_t<To, From, UNIT_LIB_DEFAULT_TYPE>;
2419 return static_cast<To
>(pi_convert(
static_cast<CommonUnderlying
>(value)) + (
static_cast<CommonUnderlying
>(Translation::num) /
static_cast<CommonUnderlying
>(Translation::den)));
2424 using CommonUnderlying = std::common_type_t<To, From, std::intmax_t>;
2426 if constexpr (Ratio::num == 1 && Ratio::den == 1)
2427 return static_cast<To
>(value);
2428 if constexpr (Ratio::num != 1 && Ratio::den == 1)
2429 return static_cast<To
>(
static_cast<CommonUnderlying
>(value) *
static_cast<CommonUnderlying
>(Ratio::num));
2430 if constexpr (Ratio::num == 1 && Ratio::den != 1)
2431 return static_cast<To
>(
static_cast<CommonUnderlying
>(value) /
static_cast<CommonUnderlying
>(Ratio::den));
2432 if constexpr (Ratio::num != 1 && Ratio::den != 1)
2442 if constexpr (std::is_integral_v<CommonUnderlying>)
2444 return static_cast<To
>(detail::widening_mul_div(
static_cast<CommonUnderlying
>(value), Ratio::num, Ratio::den));
2448 const CommonUnderlying v =
static_cast<CommonUnderlying
>(value);
2449 const CommonUnderlying num =
static_cast<CommonUnderlying
>(Ratio::num);
2450 const CommonUnderlying den =
static_cast<CommonUnderlying
>(Ratio::den);
2453 const CommonUnderlying limit = (std::numeric_limits<CommonUnderlying>::max)() / num;
2454 if (v > limit || v < -limit)
2455 return static_cast<To
>((v / den) * num);
2456 return static_cast<To
>((v * num) / den);
2470 template<UnitType UnitFrom, UnitType UnitTo>
2471 struct delayed_is_same_dimension_conversion_factor : std::false_type
2473 static constexpr bool value = traits::is_same_dimension_conversion_factor_v<typename UnitFrom::conversion_factor, typename UnitTo::conversion_factor>;
2490 template<UnitType UnitTo, UnitType UnitFrom>
2492 constexpr UnitTo
convert(
const UnitFrom& from)
noexcept
2503#ifdef FOR_DOXYGEN_PURPOSOES_ONLY
2510 template<
typename T>
2513 typedef typename T::numerical_scale_type numerical_scale_type;
2516 typedef typename T::underlying_type underlying_type;
2517 typedef typename T::value_type value_type;
2518 typedef typename T::conversion_factor conversion_factor;
2527 template<
typename,
typename =
void>
2530 using numerical_scale_type = void;
2531 using underlying_type = void;
2532 using value_type = void;
2533 using conversion_factor = void;
2536 template<ArithmeticType T>
2537 struct unit_traits<T, std::void_t<T>>
2539 using numerical_scale_type = void;
2540 using underlying_type = T;
2541 using value_type = void;
2542 using conversion_factor = units::conversion_factor<std::ratio<1>, dimension_t<>>;
2550 template<NonArithmeticType T>
2551 struct unit_traits<T, std::void_t<typename T::numerical_scale_type, typename T::underlying_type, typename T::value_type, typename T::conversion_factor>>
2553 using numerical_scale_type =
typename T::numerical_scale_type;
2554 using underlying_type =
typename T::underlying_type;
2555 using value_type =
typename T::value_type;
2556 using conversion_factor =
typename T::conversion_factor;
2567 template<UnitType U>
2568 inline constexpr bool is_affine_unit_v = is_affine_conversion_factor_v<typename unit_traits<U>::conversion_factor>;
2580 template<UnitType U1, UnitType U2>
2582 : 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>>
2586 template<UnitType U1, UnitType U2>
2600 template<
class U,
class =
void>
2601 struct rewrap_to_named;
2603 using rewrap_to_named_t =
typename rewrap_to_named<U>::type;
2608 template<
class From,
class To>
2609 inline constexpr bool is_losslessly_convertible = std::is_arithmetic_v<From> && (std::is_floating_point_v<To> || !std::is_floating_point_v<From>);
2615 template<ConversionFactorType ConversionFactorFrom, ConversionFactorType ConversionFactorTo>
2616 struct is_non_truncated_convertible_unit : std::false_type
2618 static constexpr bool value = std::ratio_divide<typename ConversionFactorFrom::conversion_ratio, typename ConversionFactorTo::conversion_ratio>::den == 1;
2624 template<
class UnitFrom,
class UnitTo>
2625 inline constexpr bool is_losslessly_convertible_unit = std::conjunction_v<traits::is_same_dimension_unit<UnitFrom, UnitTo>,
2626 std::disjunction<std::is_floating_point<typename UnitTo::underlying_type>,
2627 std::conjunction<std::negation<std::is_floating_point<typename UnitFrom::underlying_type>>,
2628 is_non_truncated_convertible_unit<typename UnitFrom::conversion_factor, typename UnitTo::conversion_factor>>>>;
2631 template<
class L,
class R>
2632 inline constexpr bool both_floating_v = std::is_floating_point_v<typename traits::unit_traits<L>::underlying_type> &&
2633 std::is_floating_point_v<typename traits::unit_traits<R>::underlying_type>;
2641 template<
class L,
class R>
2642 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>>;
2650 template<
class Source,
class StrongCf,
class Scale,
class =
void>
2651 struct deduced_named_underlying
2653 using type =
typename traits::unit_traits<Source>::underlying_type;
2655 template<
class Source,
class StrongCf,
class Scale>
2656 struct deduced_named_underlying<Source, StrongCf, Scale,
2657 std::enable_if_t<traits::is_unit_v<Source> &&
2658 traits::is_same_dimension_unit_v<Source, unit<StrongCf, typename traits::unit_traits<Source>::underlying_type, Scale>>>>
2661 using Src =
typename traits::unit_traits<Source>::underlying_type;
2664 using type = std::conditional_t<is_losslessly_convertible_unit<Source, unit<StrongCf, Src, Scale>>, Src, floating_point_promotion_t<Src>>;
2666 template<
class Source,
class StrongCf,
class Scale>
2667 using deduced_named_underlying_t =
typename deduced_named_underlying<Source, StrongCf, Scale>::type;
2669 template<RatioType Ratio>
2670 using time_conversion_factor = conversion_factor<Ratio, dimension::time>;
2675 template<ConversionFactorType ConversionFactor>
2676 inline constexpr bool is_time_conversion_factor = traits::is_same_dimension_conversion_factor_v<ConversionFactor, time_conversion_factor<std::ratio<1>>>;
2738#define MSVC_EBO __declspec(empty_bases)
2742 template<ConversionFactorType ConversionFactor, ArithmeticType T = UNIT_LIB_DEFAULT_TYPE, NumericalScaleType<T> NumericalScale = linear_scale>
2746 using numerical_scale_type = NumericalScale;
2755 constexpr unit() =
default;
2761 constexpr unit(
const unit&) =
default;
2768 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2769 requires traits::is_same_dimension_unit_v<unit<ConversionFactorRhs, Ty, NsRhs>, unit> && detail::is_losslessly_convertible_unit<unit<ConversionFactorRhs, Ty, NsRhs>, unit>
2770 constexpr unit(
const unit<ConversionFactorRhs, Ty, NsRhs>& rhs) noexcept
2787 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2788 requires(traits::is_same_dimension_unit_v<unit<ConversionFactorRhs, Ty, NsRhs>, unit> &&
2789 !detail::is_losslessly_convertible_unit<unit<ConversionFactorRhs, Ty, NsRhs>, unit> &&
2790 std::is_floating_point_v<Ty> && std::is_integral_v<T>)
2791 consteval unit(
const unit<ConversionFactorRhs, Ty, NsRhs>& rhs)
2792 :
_linearized_value(detail::exact_integral_cast<T>(unit<ConversionFactor, detail::floating_point_promotion_t<T>, NumericalScale>(rhs).
raw()))
2810 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2811 requires(traits::is_same_dimension_unit_v<unit<ConversionFactorRhs, Ty, NsRhs>, unit> &&
2812 !detail::is_losslessly_convertible_unit<unit<ConversionFactorRhs, Ty, NsRhs>, unit> &&
2813 std::is_integral_v<Ty> && std::is_integral_v<T>)
2814 consteval unit(
const unit<ConversionFactorRhs, Ty, NsRhs>& rhs)
2816 std::ratio_divide<typename ConversionFactorRhs::conversion_ratio, typename ConversionFactor::conversion_ratio>::num,
2817 std::ratio_divide<typename ConversionFactorRhs::conversion_ratio, typename ConversionFactor::conversion_ratio>::den))
2826 template<ArithmeticType Ty>
2828 explicit constexpr unit(Ty value) noexcept
2829 : _linearized_value(NumericalScale::linearize(
static_cast<T
>(value)))
2838 template<ArithmeticType Ty>
2839 requires detail::is_losslessly_convertible<Ty, T>
2841 : _linearized_value(value)
2850 template<ArithmeticType Ty>
2852 constexpr unit(Ty value) noexcept
2853 : _linearized_value(NumericalScale::linearize(
static_cast<T
>(value)))
2862 template<ArithmeticType Rep, RatioType Period>
2863 requires detail::is_time_conversion_factor<ConversionFactor> && detail::is_losslessly_convertible<Rep, T> &&
2864 detail::is_losslessly_convertible_unit<units::unit<units::conversion_factor<Period, dimension::time>, Rep>, unit>
2865 constexpr unit(
const std::chrono::duration<Rep, Period>&
value) noexcept
2875 constexpr unit&
operator=(
const unit& rhs)
noexcept =
default;
2882 template<ConversionFactorType Cf = ConversionFactor>
2886 unit<units::conversion_factor<std::ratio<1>, units::dimension::dimensionless>,
underlying_type,
linear_scale> dimensionlessRhs(rhs);
2897 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2900 return value_compare(rhs) < 0;
2909 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2912 return value_compare(rhs) <= 0;
2921 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2924 return value_compare(rhs) > 0;
2933 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2936 return value_compare(rhs) >= 0;
2946 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2947 requires(std::floating_point<T> || std::floating_point<Ty>)
2948 constexpr bool operator==(
const unit<ConversionFactorRhs, Ty, NsRhs>& rhs)
const noexcept
2950 using CommonUnit = std::common_type_t<unit, unit<ConversionFactorRhs, Ty, NsRhs>>;
2951 using CommonUnderlying =
typename CommonUnit::underlying_type;
2953 const auto common_lhs(CommonUnit(*this)._linearized_value);
2956 return abs(common_lhs - common_rhs) < std::numeric_limits<CommonUnderlying>::epsilon() * abs(common_lhs + common_rhs) ||
2957 abs(common_lhs - common_rhs) < std::numeric_limits<CommonUnderlying>::min();
2960 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2961 requires(std::integral<T> && std::integral<Ty>)
2964 return value_compare(rhs) == 0;
2974 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
2975 constexpr bool operator!=(
const unit<ConversionFactorRhs, Ty, NsRhs>& rhs)
const noexcept
2977 return !(*
this == rhs);
2986 constexpr underlying_type raw() const noexcept
2988 return static_cast<underlying_type
>(NumericalScale::scale(_linearized_value));
2998 constexpr auto value() const noexcept
3000 using CfTraits = traits::conversion_factor_traits<ConversionFactor>;
3002 constexpr bool needs_fp = traits::is_ratio_dimensionless_cf_v<ConversionFactor> || !std::ratio_equal_v<typename CfTraits::pi_exponent_ratio, std::ratio<0>> ||
3003 !std::ratio_equal_v<typename CfTraits::translation_ratio, std::ratio<0>>;
3005 using normalized_value_type = std::conditional_t<needs_fp, detail::floating_point_promotion_t<underlying_type>, underlying_type>;
3011 using Under = normalized_value_type;
3021 return static_cast<normalized_value_type
>(
raw());
3029 template<ArithmeticType Ty>
3030 constexpr Ty to() const noexcept
3032 return static_cast<Ty
>(*this);
3044 template<
template<
class>
class UnitType>
3055 constexpr T to_linearized() const noexcept
3057 return _linearized_value;
3070 template<ConversionFactorType Cf, ArithmeticType Ty = T>
3071 constexpr unit<Cf, Ty>
convert() const noexcept
3073 return unit<Cf, Ty>(*
this);
3085 template<
template<
class>
class UnitType>
3096 template<ArithmeticType Ty>
3098 constexpr operator Ty() const noexcept
3102 return static_cast<Ty
>(this->value());
3109 template<ArithmeticType Ty>
3111 constexpr explicit operator Ty()
const noexcept
3113 return static_cast<Ty
>(this->value());
3120 template<ArithmeticType Rep, RatioType Period, ConversionFactorType Cf = ConversionFactor>
3121 requires detail::is_time_conversion_factor<Cf> && detail::is_losslessly_convertible<T, Rep>
3122 constexpr operator std::chrono::duration<Rep, Period>() const noexcept
3130 template<UnitType Unit = unit>
3131 [[nodiscard]]
constexpr const char* name() const noexcept
3136 constexpr const char* n = unit_name_v<detail::rewrap_to_named_t<Unit>>;
3143 template<UnitType Unit = unit>
3144 [[nodiscard]]
constexpr const char* abbreviation() const noexcept
3149 constexpr const char* a = unit_abbreviation_v<detail::rewrap_to_named_t<Unit>>;
3153 template<ConversionFactorType Cf, ArithmeticType Ty, NumericalScaleType<Ty> Ns>
3161 template<ConversionFactorType ConversionFactorRhs, ArithmeticType Ty, NumericalScaleType<Ty> NsRhs>
3162 constexpr auto value_compare(
const unit<ConversionFactorRhs, Ty, NsRhs>& rhs)
const noexcept
3164 using CommonUnit = std::common_type_t<unit, unit<ConversionFactorRhs, Ty, NsRhs>>;
3165 if constexpr (std::is_integral_v<T> && std::is_integral_v<Ty>)
3169 const T lhsCommon = unit<typename CommonUnit::conversion_factor, T, NumericalScale>(*this)._linearized_value;
3170 const Ty rhsCommon = unit<typename CommonUnit::conversion_factor, Ty, NsRhs>(rhs)._linearized_value;
3171 if (std::cmp_less(lhsCommon, rhsCommon))
3172 return std::strong_ordering::less;
3173 if (std::cmp_greater(lhsCommon, rhsCommon))
3174 return std::strong_ordering::greater;
3175 return std::strong_ordering::equal;
3179 const auto lhsCommon = CommonUnit(*this)._linearized_value;
3180 const auto rhsCommon = CommonUnit(rhs)._linearized_value;
3181 return lhsCommon <=> rhsCommon;
3188 T _linearized_value;
3209 template<class T, bool = traits::is_unit<T>::value>
3214 struct is_named_unit_impl<T, true> : std::bool_constant<!std::is_same_v<T, unit_base_t<T>>>
3218 inline constexpr bool is_named_unit_v = is_named_unit_impl<T>::value;
3225 template<
class Cf1,
class Cf2>
3226 inline constexpr bool is_equivalent_conversion_factor_v =
3227 traits::is_same_dimension_conversion_factor_v<Cf1, Cf2> &&
3228 std::ratio_equal_v<typename Cf1::conversion_ratio, typename Cf2::conversion_ratio> &&
3229 std::ratio_equal_v<typename Cf1::pi_exponent_ratio, typename Cf2::pi_exponent_ratio> &&
3230 std::ratio_equal_v<typename Cf1::translation_ratio, typename Cf2::translation_ratio>;
3240 inline constexpr bool is_raw_conversion_factor_v =
3241 std::is_void_v<decltype(named_class_of(static_cast<Cf*>(
nullptr),
static_cast<linear_scale*
>(
nullptr)))>;
3247 template<
class Base,
class Named,
class =
void>
3252 template<
class Base,
class Named>
3254 std::enable_if_t<is_named_unit_v<Named> && std::is_same_v<typename Base::conversion_factor, typename Named::conversion_factor>>>
3256 using type =
typename Named::template rebind<typename Base::underlying_type>;
3262 template<
class Base,
class Named>
3264 std::enable_if_t<is_named_unit_v<Named> && !std::is_same_v<typename Base::conversion_factor, typename Named::conversion_factor> &&
3265 is_raw_conversion_factor_v<typename Base::conversion_factor> &&
3266 is_equivalent_conversion_factor_v<typename Base::conversion_factor, typename Named::conversion_factor>>>
3268 using type =
typename Named::template rebind<typename Base::underlying_type>;
3270 template<
class Base,
class Named>
3271 using rewrap_named_t =
typename rewrap_named<Base, Named>::type;
3276 template<
class ConversionFactor,
class Scale>
3277 void named_class_of(ConversionFactor*, Scale*, ...);
3285 template<
class U,
class>
3292 std::enable_if_t<traits::is_unit<U>::value &&
3293 !std::is_void_v<decltype(named_class_of(static_cast<typename U::conversion_factor*>(nullptr),
3294 static_cast<typename U::numerical_scale_type*>(nullptr)))>>>
3296 using type =
typename decltype(named_class_of(
static_cast<typename U::conversion_factor*
>(
nullptr),
3297 static_cast<typename U::numerical_scale_type*
>(
nullptr)))::template rebind<typename U::underlying_type>;
3306 template<
class Unit,
class Underlying>
3307 requires ::units::detail::is_named_unit_v<Unit>
3312 using type =
typename Unit::template rebind<Underlying>;
3318 template<
class Unit>
3319 requires is_named_unit_v<Unit>
3320 struct floating_point_promotion<Unit>
3324 using type =
typename Unit::template rebind<typename floating_point_promotion<unit_base_t<Unit>>::type::underlying_type>;
3342 template<UnitType UnitType, ArithmeticType T>
3343 requires detail::is_losslessly_convertible<T, typename UnitType::underlying_type>
3353#if defined(UNIT_LIB_ENABLE_STRING)
3367 template<
class D,
class E>
3371 if constexpr (E::num != 0)
3373 s.append(
" ").append(D::abbreviation);
3375 if constexpr (E::num != 0 && E::num != 1)
3377 s.append(
"^").append(std::to_string(E::num));
3379 if constexpr (E::den != 1)
3381 s.append(
"/").append(std::to_string(E::den));
3393 template<
class... Dims>
3431 template<label_form Form = label_form::abbreviation, ConversionFactorType ConversionFactor, ArithmeticType T, NumericalScaleType<T> NumericalScale>
3436 using NamedForm = detail::rewrap_to_named_t<unit<ConversionFactor, T, NumericalScale>>;
3439 if constexpr (Form == label_form::base)
3442 if constexpr (!DimType::empty)
3443 return dimension_to_string(DimType{});
3445 return std::string{};
3449 return std::string(
" ").append(unit_name<NamedForm>::value);
3451 else if constexpr (unit_abbreviation_v<NamedForm>)
3453 return std::string(
" ").append(unit_abbreviation<NamedForm>::value);
3458 if constexpr (!DimType::empty)
3461 return std::string{};
3477 template<ConversionFactorType ConversionFactor, ArithmeticType T, NumericalScaleType<T> NumericalScale>
3480 using NamedForm = detail::rewrap_to_named_t<unit<ConversionFactor, T, NumericalScale>>;
3481 return !
static_cast<bool>(unit_abbreviation_v<NamedForm>);
3487#if defined(UNIT_LIB_ENABLE_FORMAT)
3500 struct unit_format_options
3502 label_form form = label_form::abbreviation;
3503 bool showValue =
true;
3504 bool showUnit =
true;
3505 bool customSep =
false;
3506 std::string separator =
" ";
3512#if !defined(UNIT_LIB_DISABLE_IOSTREAM)
3518 template<
class D,
class E>
3519 std::ostream& operator<<(std::ostream& os,
const dim<D, E>&)
3521 if constexpr (E::num != 0)
3522 os <<
' ' << D::abbreviation;
3523 if constexpr (E::num != 0 && E::num != 1)
3525 os <<
"^" << E::num;
3527 if constexpr (E::den != 1)
3529 os <<
"/" << E::den;
3534 template<
class... Dims>
3537 ((os << Dims{}), ...);
3541 template<ConversionFactorType ConversionFactor, ArithmeticType T, NumericalScaleType<T> NumericalScale>
3551 using NamedForm = detail::rewrap_to_named_t<unit<ConversionFactor, T, NumericalScale>>;
3553 if constexpr (unit_abbreviation_v<NamedForm>)
3559 os << std::conditional_t<detail::is_losslessly_convertible_unit<std::decay_t<
decltype(obj)>, BaseUnit>, BaseUnit, PromotedBaseUnit>(obj).raw();
3561 os << detail::unit_label(obj);
3570 template<ConversionFactorType ConversionFactor, ArithmeticType T, NumericalScaleType<T> NumericalScale>
3580 using NamedForm = detail::rewrap_to_named_t<unit<ConversionFactor, T, NumericalScale>>;
3583 if constexpr (unit_abbreviation_v<NamedForm>)
3584 s = detail::to_string(obj.raw());
3586 s = detail::to_string(std::conditional_t<detail::is_losslessly_convertible_unit<std::decay_t<
decltype(obj)>, BaseUnit>, BaseUnit, PromotedBaseUnit>(obj).raw());
3588 s.append(detail::unit_label(obj));
3603 template<RatioType Ratio1, RatioType Ratio2>
3604 using ratio_gcd = std::ratio<std::gcd(Ratio1::num, Ratio2::num), std::lcm(Ratio1::den, Ratio2::den)>;
3612 template<RatioType Ratio1, RatioType Ratio2>
3613 using common_baggage_ratio = std::conditional_t<std::ratio_equal_v<Ratio1, Ratio2>, Ratio1, std::ratio<0>>;
3632 template<
class ConversionFactorLhs,
class Tx,
class ConversionFactorRhs,
class Ty,
class NumericalScale>
3633 struct common_type<
units::unit<ConversionFactorLhs, Tx, NumericalScale>,
units::unit<ConversionFactorRhs, Ty, NumericalScale>>
3634 : std::enable_if<units::traits::is_same_dimension_conversion_factor_v<ConversionFactorLhs, ConversionFactorRhs>,
3636 units::traits::strong_t<units::conversion_factor<units::detail::ratio_gcd<typename ConversionFactorLhs::conversion_ratio, typename ConversionFactorRhs::conversion_ratio>,
3637 units::traits::dimension_of_t<ConversionFactorLhs>, units::detail::ratio_gcd<typename ConversionFactorLhs::pi_exponent_ratio, typename ConversionFactorRhs::pi_exponent_ratio>,
3638 units::detail::common_baggage_ratio<typename ConversionFactorLhs::translation_ratio, typename ConversionFactorRhs::translation_ratio>>>,
3639 common_type_t<Tx, Ty>, NumericalScale>>
3644 template<
class UnitConversionT,
class T,
class NonLinearScale>
3645 struct common_type<
units::unit<UnitConversionT, T, NonLinearScale>,
units::unit<UnitConversionT, T, NonLinearScale>>
3655 template<
class Lhs,
class Rhs>
3657 (units::detail::is_named_unit_v<Lhs> || units::detail::is_named_unit_v<Rhs>) &&
3663 struct common_type<Lhs, Rhs>
3668 using viaLhs = units::detail::rewrap_named_t<base, Lhs>;
3671 using type = units::detail::rewrap_named_t<viaLhs, Rhs>;
3680 template<
class Named,
class Scalar>
3681 requires(units::detail::is_named_unit_v<Named> && std::is_arithmetic_v<Scalar> &&
3683 struct common_type<Named, Scalar>
3685 using type = units::detail::rewrap_named_t<common_type_t<units::detail::unit_base_t<Named>, Scalar>, Named>;
3687 template<
class Scalar,
class Named>
3688 requires(units::detail::is_named_unit_v<Named> && std::is_arithmetic_v<Scalar> &&
3690 struct common_type<Scalar, Named>
3692 using type = units::detail::rewrap_named_t<common_type_t<Scalar, units::detail::unit_base_t<Named>>, Named>;
3695 template<
class Ratio,
class T,
class NumericalScale,
class Rep,
class Period>
3696 struct common_type<
units::unit<units::detail::time_conversion_factor<Ratio>, T, NumericalScale>, chrono::duration<Rep, Period>>
3697 : std::common_type<units::unit<units::detail::time_conversion_factor<Ratio>, T, NumericalScale>, decltype(units::unit{chrono::duration<Rep, Period>{}})>
3701 template<
class ConversionFactor,
class T,
class NumericalScale,
class Rep,
class Period>
3702 struct common_type<chrono::duration<Rep, Period>,
units::unit<ConversionFactor, T, NumericalScale>>
3703 : std::common_type<units::unit<ConversionFactor, T, NumericalScale>, chrono::duration<Rep, Period>>
3707 template<
class ConversionFactor,
class Tx,
class NumericalScale,
class Ty>
3708 requires std::is_arithmetic_v<Ty>
3709 struct common_type<Ty,
units::unit<ConversionFactor, Tx, NumericalScale>>
3710 : std::enable_if<units::traits::is_dimensionless_unit<units::unit<ConversionFactor, Tx, NumericalScale>>::value,
3711 units::unit<units::conversion_factor<std::ratio<1>, units::dimension::dimensionless>, common_type_t<Tx, Ty>, NumericalScale>>
3715 template<
class ConversionFactor,
class Tx,
class NumericalScale,
class Ty>
3716 requires std::is_arithmetic_v<Ty>
3717 struct common_type<
units::unit<ConversionFactor, Tx, NumericalScale>, Ty>
3718 : std::enable_if<units::traits::is_dimensionless_unit<units::unit<ConversionFactor, Tx, NumericalScale>>::value,
3719 units::unit<units::conversion_factor<std::ratio<1>, units::dimension::dimensionless>, common_type_t<Tx, Ty>, NumericalScale>>
3727 template<
class ConversionFactorLhs,
class Tx,
class ConversionFactorRhs,
class Ty>
3728 struct common_type<
units::unit<ConversionFactorLhs, Tx, units::linear_scale>,
units::unit<ConversionFactorRhs, Ty, units::decibel_scale>>
3729 : common_type<units::unit<ConversionFactorLhs, Tx, units::linear_scale>, units::unit<ConversionFactorRhs, Ty, units::linear_scale>>
3733 template<
class ConversionFactorLhs,
class Tx,
class ConversionFactorRhs,
class Ty>
3734 struct common_type<units::unit<ConversionFactorLhs, Tx, units::decibel_scale>, units::unit<ConversionFactorRhs, Ty, units::linear_scale>>
3735 : common_type<units::unit<ConversionFactorLhs, Tx, units::linear_scale>, units::unit<ConversionFactorRhs, Ty, units::linear_scale>>
3762 template<ArithmeticType T, UnitType Unit>
3763 constexpr T
unit_cast(
const Unit& value)
noexcept
3765 return static_cast<T
>(value);
3782 template<
typename... T>
3783 struct has_linear_scale : std::conjunction<std::is_base_of<linear_scale, T>...>
3787 template<
typename... T>
3797 template<
typename... T>
3798 struct has_decibel_scale : std::conjunction<std::is_base_of<decibel_scale, T>...>
3802 template<
typename... T>
3833 static constexpr T
linearize(
const T value)
noexcept
3845 static constexpr T
scale(
const T value)
noexcept
3863 conversion_factor<std::ratio<1>, dimension::dimensionless>
strong_name(
3864 units::detail::conversion_factor_base_t<dimensionless_>*);
3871 template<
class Underlying = UNIT_LIB_DEFAULT_TYPE>
3887 struct type_identity
3893 using type_identity_t =
typename type_identity<T>::type;
3897 template<UnitType UnitTypeLhs>
3899 constexpr UnitTypeLhs&
operator+=(UnitTypeLhs& lhs,
const detail::type_identity_t<UnitTypeLhs>& rhs)
noexcept
3910 template<UnitType UnitTypeLhs>
3912 constexpr UnitTypeLhs&
operator+=(UnitTypeLhs& lhs,
const detail::type_identity_t<UnitTypeLhs>& rhs)
noexcept
3914 lhs = UnitTypeLhs(lhs.raw() + rhs.raw());
3918 template<UnitType UnitTypeLhs, ArithmeticType T>
3920 constexpr UnitTypeLhs&
operator+=(UnitTypeLhs& lhs, T rhs)
noexcept
3926 template<RatioDimensionlessUnitType U, ArithmeticType T>
3927 requires(traits::has_linear_scale_v<U>)
3928 constexpr U&
operator+=(U& lhs, T rhs)
noexcept
3930 using Underlying =
typename U::underlying_type;
3931 using R =
typename U::conversion_factor::conversion_ratio;
3935 constexpr long double points_per_one =
static_cast<long double>(R::den) /
static_cast<long double>(R::num);
3938 const long double new_points =
static_cast<long double>(lhs.raw()) + (
static_cast<long double>(rhs) * points_per_one);
3940 if constexpr (std::is_integral_v<Underlying>)
3942 lhs = U(
static_cast<Underlying
>(std::llround(new_points)));
3946 lhs = U(
static_cast<Underlying
>(new_points));
3952 template<RatioDimensionlessUnitType U, DimensionlessUnitType D>
3954 constexpr U&
operator+=(U& lhs,
const D& rhs)
noexcept
3957 return (lhs += rhs.value());
3960 template<RatioDimensionlessUnitType U, ArithmeticType T>
3961 requires(traits::has_linear_scale_v<U>)
3962 constexpr U&
operator-=(U& lhs, T rhs)
noexcept
3964 using Underlying =
typename U::underlying_type;
3965 using R =
typename U::conversion_factor::conversion_ratio;
3967 constexpr long double points_per_one =
static_cast<long double>(R::den) /
static_cast<long double>(R::num);
3969 const long double new_points =
static_cast<long double>(lhs.raw()) - (
static_cast<long double>(rhs) * points_per_one);
3971 if constexpr (std::is_integral_v<Underlying>)
3973 lhs = U(
static_cast<Underlying
>(std::llround(new_points)));
3977 lhs = U(
static_cast<Underlying
>(new_points));
3983 template<UnitType UnitTypeLhs>
3985 constexpr UnitTypeLhs&
operator-=(UnitTypeLhs& lhs,
const detail::type_identity_t<UnitTypeLhs>& rhs)
noexcept
3996 template<UnitType UnitTypeLhs>
3998 constexpr UnitTypeLhs&
operator-=(UnitTypeLhs& lhs,
const detail::type_identity_t<UnitTypeLhs>& rhs)
noexcept
4000 lhs = UnitTypeLhs(lhs.raw() - rhs.raw());
4004 template<UnitType UnitTypeLhs, ArithmeticType T>
4006 constexpr UnitTypeLhs&
operator-=(UnitTypeLhs& lhs,
const T& rhs)
noexcept
4012 template<RatioDimensionlessUnitType U, DimensionlessUnitType D>
4014 constexpr U&
operator-=(U& lhs,
const D& rhs)
noexcept
4016 return (lhs -= rhs.value());
4019 template<UnitType UnitTypeLhs, ArithmeticType T>
4021 constexpr UnitTypeLhs&
operator*=(UnitTypeLhs& lhs,
const T& rhs)
4028 typename UnitTypeLhs::underlying_type scaled = lhs.raw() * rhs;
4029 lhs = UnitTypeLhs(scaled, linearized_value);
4033 template<RatioDimensionlessUnitType U, RatioDimensionlessUnitType URhs>
4034 requires(traits::has_linear_scale_v<U, URhs>)
4035 constexpr U&
operator*=(U& lhs,
const URhs& rhs)
noexcept
4037 using LhsUnder =
typename U::underlying_type;
4038 using RhsUnder =
typename URhs::underlying_type;
4040 using Calc0 = std::common_type_t<LhsUnder, RhsUnder>;
4041 using Calc = detail::floating_point_promotion_t<Calc0>;
4044 const Calc rhs_frac =
static_cast<Calc
>(rhs.value());
4047 const Calc new_points =
static_cast<Calc
>(lhs.raw()) * rhs_frac;
4049 if constexpr (std::is_integral_v<LhsUnder>)
4052 lhs = U(
static_cast<LhsUnder
>(new_points));
4056 lhs = U(
static_cast<LhsUnder
>(new_points));
4062 template<RatioDimensionlessUnitType U>
4063 requires(units::traits::has_linear_scale_v<U>)
4064 constexpr U&
operator*=(U& lhs,
const U& rhs)
noexcept
4066 using Underlying =
typename U::underlying_type;
4067 using R =
typename U::conversion_factor::conversion_ratio;
4070 constexpr long double points_per_one =
static_cast<long double>(R::den) /
static_cast<long double>(R::num);
4072 const long double lhs_frac =
static_cast<long double>(lhs.value());
4073 const long double rhs_frac =
static_cast<long double>(rhs.value());
4075 const long double out_frac = lhs_frac * rhs_frac;
4076 const long double out_points = out_frac * points_per_one;
4078 if constexpr (std::is_integral_v<Underlying>)
4080 lhs = U(
static_cast<Underlying
>(std::llround(out_points)));
4084 lhs = U(
static_cast<Underlying
>(out_points));
4090 template<RatioDimensionlessUnitType U, units::ArithmeticType T>
4091 requires(units::traits::has_linear_scale_v<U>)
4092 constexpr U&
operator*=(U& lhs, T rhs)
noexcept
4096 using Underlying =
typename U::underlying_type;
4097 using R =
typename U::conversion_factor::conversion_ratio;
4099 constexpr long double points_per_one =
static_cast<long double>(R::den) /
static_cast<long double>(R::num);
4101 const long double lhs_frac =
static_cast<long double>(lhs.value());
4102 const long double out_frac = lhs_frac *
static_cast<long double>(rhs);
4103 const long double out_pts = out_frac * points_per_one;
4105 if constexpr (std::is_integral_v<Underlying>)
4107 lhs = U(
static_cast<Underlying
>(std::llround(out_pts)));
4111 lhs = U(
static_cast<Underlying
>(out_pts));
4116 template<RatioDimensionlessUnitType U, DimensionlessUnitType D>
4118 constexpr U&
operator*=(U& lhs,
const D& rhs)
noexcept
4121 return (lhs *= rhs.value());
4126 template<UnitType UnitTypeLhs, DimensionlessUnitType D>
4128 constexpr UnitTypeLhs&
operator*=(UnitTypeLhs& lhs,
const D& rhs)
4130 return (lhs *= rhs.value());
4133 template<UnitType UnitTypeLhs, ArithmeticType T>
4135 constexpr UnitTypeLhs&
operator/=(UnitTypeLhs& lhs,
const T& rhs)
4139 typename UnitTypeLhs::underlying_type scaled = lhs.raw() / rhs;
4140 lhs = UnitTypeLhs(scaled, linearized_value);
4144 template<UnitType UnitTypeLhs, DimensionlessUnitType D>
4146 constexpr UnitTypeLhs&
operator/=(UnitTypeLhs& lhs,
const D& rhs)
4148 return (lhs /= rhs.value());
4151 template<RatioDimensionlessUnitType U, RatioDimensionlessUnitType URhs>
4152 requires(traits::has_linear_scale_v<U, URhs>)
4153 constexpr U&
operator/=(U& lhs,
const URhs& rhs)
noexcept
4155 using Under0 = std::common_type_t<typename U::underlying_type, typename URhs::underlying_type>;
4156 using Under = detail::floating_point_promotion_t<Under0>;
4158 const Under rhs_frac =
static_cast<Under
>(rhs.value());
4160 const Under new_points =
static_cast<Under
>(lhs.raw()) / rhs_frac;
4162 lhs = U(new_points);
4166 template<RatioDimensionlessUnitType U>
4167 requires(units::traits::has_linear_scale_v<U>)
4168 constexpr U&
operator/=(U& lhs,
const U& rhs)
noexcept
4170 using Underlying =
typename U::underlying_type;
4171 using R =
typename U::conversion_factor::conversion_ratio;
4173 constexpr long double points_per_one =
static_cast<long double>(R::den) /
static_cast<long double>(R::num);
4175 const long double lhs_frac =
static_cast<long double>(lhs.value());
4176 const long double rhs_frac =
static_cast<long double>(rhs.value());
4178 const long double out_frac = lhs_frac / rhs_frac;
4179 const long double out_points = out_frac * points_per_one;
4181 if constexpr (std::is_integral_v<Underlying>)
4183 lhs = U(
static_cast<Underlying
>(std::llround(out_points)));
4187 lhs = U(
static_cast<Underlying
>(out_points));
4192 template<RatioDimensionlessUnitType U, units::ArithmeticType T>
4193 requires(units::traits::has_linear_scale_v<U>)
4194 constexpr U&
operator/=(U& lhs, T rhs)
noexcept
4196 using Underlying =
typename U::underlying_type;
4197 using R =
typename U::conversion_factor::conversion_ratio;
4199 constexpr long double points_per_one =
static_cast<long double>(R::den) /
static_cast<long double>(R::num);
4201 const long double lhs_frac =
static_cast<long double>(lhs.value());
4202 const long double out_frac = lhs_frac /
static_cast<long double>(rhs);
4203 const long double out_pts = out_frac * points_per_one;
4205 if constexpr (std::is_integral_v<Underlying>)
4207 lhs = U(
static_cast<Underlying
>(std::llround(out_pts)));
4211 lhs = U(
static_cast<Underlying
>(out_pts));
4216 template<RatioDimensionlessUnitType U, DimensionlessUnitType D>
4218 constexpr U&
operator/=(U& lhs,
const D& rhs)
noexcept
4220 return (lhs /= rhs.value());
4223 template<DimensionedUnitType UnitTypeLhs>
4225 constexpr UnitTypeLhs&
operator%=(UnitTypeLhs& lhs,
const detail::type_identity_t<UnitTypeLhs>& rhs)
noexcept
4231 template<DimensionlessUnitType UnitTypeLhs, DimensionlessUnitType UnitTypeRhs>
4233 constexpr UnitTypeLhs&
operator%=(UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4235 using CommonUnit =
decltype(lhs % rhs);
4236 lhs = CommonUnit(lhs.raw() % rhs.raw());
4240 template<UnitType UnitTypeLhs>
4242 constexpr UnitTypeLhs&
operator%=(UnitTypeLhs& lhs,
const typename UnitTypeLhs::underlying_type& rhs)
noexcept
4249 template<RatioDimensionlessUnitType U>
4250 requires(traits::has_linear_scale_v<U>)
4251 constexpr U&
operator%=(U& lhs,
const U& rhs)
noexcept
4258 template<RatioDimensionlessUnitType U>
4259 requires(traits::has_linear_scale_v<U>)
4260 constexpr U&
operator%=(U& lhs,
const typename U::underlying_type& rhs)
noexcept
4267 template<RatioDimensionlessUnitType U, DimensionlessUnitType D>
4269 constexpr U&
operator%=(U& lhs,
const D& rhs)
noexcept
4272 lhs = lhs %
static_cast<typename U::underlying_type
>(rhs);
4281 template<UnitType UnitTypeLhs>
4282 constexpr UnitTypeLhs operator+(
const UnitTypeLhs& u)
noexcept
4288 template<UnitType UnitTypeLhs>
4289 constexpr UnitTypeLhs& operator++(UnitTypeLhs& u)
noexcept
4291 u = UnitTypeLhs(u.raw() + 1);
4296 template<UnitType UnitTypeLhs>
4297 constexpr UnitTypeLhs operator++(UnitTypeLhs& u,
int)
noexcept
4300 u = UnitTypeLhs(u.raw() + 1);
4305 template<UnitType UnitTypeLhs>
4306 constexpr UnitTypeLhs operator-(
const UnitTypeLhs& u)
noexcept
4308 return UnitTypeLhs(-u.raw());
4312 template<UnitType UnitTypeLhs>
4313 constexpr UnitTypeLhs& operator--(UnitTypeLhs& u)
noexcept
4315 u = UnitTypeLhs(u.raw() - 1);
4320 template<UnitType UnitTypeLhs>
4321 constexpr UnitTypeLhs operator--(UnitTypeLhs& u,
int)
noexcept
4324 u = UnitTypeLhs(u.raw() - 1);
4343 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
4346 constexpr auto operator+(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4352 using ResultUnit = detail::lhs_result_unit_t<UnitTypeLhs, UnitTypeRhs>;
4353 return ResultUnit(ResultUnit(lhs).raw() + ResultUnit(rhs).raw());
4357 template<RatioDimensionlessUnitType U, ArithmeticType T>
4358 requires(traits::has_linear_scale_v<U>)
4359 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>>>
4361 using Under0 = std::common_type_t<typename U::underlying_type, T>;
4362 using Under = detail::floating_point_promotion_t<Under0>;
4363 using Ret = traits::replace_underlying_t<U, Under>;
4365 using R =
typename U::conversion_factor::conversion_ratio;
4366 constexpr Under points_per_one =
static_cast<Under
>(R::den) /
static_cast<Under
>(R::num);
4369 const Under frac =
static_cast<Under
>(lhs.value()) +
static_cast<Under
>(rhs);
4370 return Ret(frac * points_per_one);
4373 template<RatioDimensionlessUnitType U, ArithmeticType T>
4374 requires(traits::has_linear_scale_v<U>)
4375 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>>>
4377 using Under0 = std::common_type_t<T, typename U::underlying_type>;
4378 using Under = detail::floating_point_promotion_t<Under0>;
4379 using Ret = traits::replace_underlying_t<U, Under>;
4381 using R =
typename U::conversion_factor::conversion_ratio;
4382 constexpr Under points_per_one =
static_cast<Under
>(R::den) /
static_cast<Under
>(R::num);
4384 const Under frac =
static_cast<Under
>(lhs) +
static_cast<Under
>(rhs.value());
4385 return Ret(frac * points_per_one);
4390 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4391 requires(traits::has_linear_scale_v<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeLhs>)
4392 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>
operator+(
const UnitTypeLhs& lhs, T rhs)
noexcept
4394 using ret = traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>;
4395 return ret(lhs.raw() +
static_cast<ret::underlying_type
>(rhs));
4400 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4401 requires(traits::has_linear_scale_v<UnitTypeRhs> && !RatioDimensionlessUnitType<UnitTypeRhs>)
4402 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<T, typename UnitTypeRhs::underlying_type>>
operator+(T lhs,
const UnitTypeRhs& rhs)
noexcept
4406 using CommonUnit =
decltype(lhs + rhs);
4407 using InverseCommonUnit =
decltype(1 / CommonUnit(1));
4408 return CommonUnit(InverseCommonUnit(lhs).value() + rhs.raw());
4415 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
4416 requires(same_dimension<UnitTypeLhs, UnitTypeRhs> && traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs> &&
4418 constexpr auto operator-(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4421 using ResultUnit = detail::lhs_result_unit_t<UnitTypeLhs, UnitTypeRhs>;
4422 return ResultUnit(ResultUnit(lhs).raw() - ResultUnit(rhs).raw());
4432 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
4435 constexpr auto operator-(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4441 using LhsCf =
typename traits::unit_traits<UnitTypeLhs>::conversion_factor;
4443 typename traits::conversion_factor_traits<LhsCf>::dimension_type,
4444 typename traits::conversion_factor_traits<LhsCf>::pi_exponent_ratio, std::ratio<0>>;
4446 return DeltaUnit(lhs.raw() - UnitTypeLhs(rhs).raw());
4451 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4452 requires(traits::has_linear_scale_v<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeLhs>)
4453 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>
operator-(
const UnitTypeLhs& lhs, T rhs)
noexcept
4457 using CommonUnit =
decltype(lhs - rhs);
4458 using InverseCommonUnit =
decltype(1 / CommonUnit(1));
4459 return CommonUnit(lhs.raw() - InverseCommonUnit(rhs).value());
4463 template<RatioDimensionlessUnitType U, ArithmeticType T>
4464 requires(traits::has_linear_scale_v<U>)
4465 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>>>
4467 using Under0 = std::common_type_t<typename U::underlying_type, T>;
4468 using Under = detail::floating_point_promotion_t<Under0>;
4469 using Ret = traits::replace_underlying_t<U, Under>;
4471 using R =
typename U::conversion_factor::conversion_ratio;
4472 constexpr Under points_per_one =
static_cast<Under
>(R::den) /
static_cast<Under
>(R::num);
4474 const Under frac =
static_cast<Under
>(lhs.value()) -
static_cast<Under
>(rhs);
4475 return Ret(frac * points_per_one);
4478 template<RatioDimensionlessUnitType U, ArithmeticType T>
4479 requires(traits::has_linear_scale_v<U>)
4480 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>>>
4482 using Under0 = std::common_type_t<T, typename U::underlying_type>;
4483 using Under = detail::floating_point_promotion_t<Under0>;
4484 using Ret = traits::replace_underlying_t<U, Under>;
4486 using R =
typename U::conversion_factor::conversion_ratio;
4487 constexpr Under points_per_one =
static_cast<Under
>(R::den) /
static_cast<Under
>(R::num);
4489 const Under frac =
static_cast<Under
>(lhs) -
static_cast<Under
>(rhs.value());
4490 return Ret(frac * points_per_one);
4495 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4496 requires(traits::has_linear_scale_v<UnitTypeRhs> && !RatioDimensionlessUnitType<UnitTypeRhs>)
4497 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<T, typename UnitTypeRhs::underlying_type>>
operator-(T lhs,
const UnitTypeRhs& rhs)
noexcept
4501 using CommonUnit =
decltype(lhs - rhs);
4502 using InverseCommonUnit =
decltype(1 / CommonUnit(1));
4503 return CommonUnit(InverseCommonUnit(lhs).value() - rhs.raw());
4508 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
4509 requires(same_dimension<UnitTypeLhs, UnitTypeRhs> && traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4510 constexpr auto operator*(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4511 -> detail::rewrap_to_named_t<unit<traits::strong_t<squared<typename traits::unit_traits<std::common_type_t<UnitTypeLhs, UnitTypeRhs>>::conversion_factor>>,
4512 typename std::common_type_t<UnitTypeLhs, UnitTypeRhs>::underlying_type>>
4514 using SquaredUnit =
decltype(lhs * rhs);
4515 using CommonUnit = std::common_type_t<UnitTypeLhs, UnitTypeRhs>;
4516 return SquaredUnit(CommonUnit(lhs).raw() * CommonUnit(rhs).raw());
4521 template<DimensionedUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4522 requires(!same_dimension<UnitTypeLhs, UnitTypeRhs> && traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4523 constexpr auto operator*(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4524 -> 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>>,
4525 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>>
4527 using CompoundUnit =
decltype(lhs * rhs);
4528 using CommonUnderlying =
typename CompoundUnit::underlying_type;
4529 return CompoundUnit(
static_cast<CommonUnderlying
>(lhs) *
static_cast<CommonUnderlying
>(rhs));
4533 template<DimensionedUnitType UnitTypeLhs, OrdinaryDimensionlessUnitType UnitTypeRhs>
4534 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4535 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator*(
4536 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4538 using CommonUnit =
decltype(lhs * rhs);
4539 return CommonUnit(CommonUnit(lhs).raw() *
static_cast<typename CommonUnit::underlying_type
>(rhs));
4544 template<DimensionedUnitType UnitTypeLhs, RatioDimensionlessUnitType UnitTypeRhs>
4545 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4546 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator*(
4547 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4549 using Out =
decltype(lhs * rhs);
4550 using U0 = std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>;
4551 using U = detail::floating_point_promotion_t<U0>;
4554 return Out(
static_cast<U
>(lhs.raw()) *
static_cast<U
>(rhs.value()));
4558 template<OrdinaryDimensionlessUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4559 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4560 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator*(
4561 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4563 using CommonUnit =
decltype(lhs * rhs);
4564 return CommonUnit(
static_cast<typename CommonUnit::underlying_type
>(lhs) * CommonUnit(rhs).raw());
4568 template<RatioDimensionlessUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4569 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4570 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator*(
4571 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4573 using Out =
decltype(lhs * rhs);
4574 using U0 = std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>;
4575 using U = detail::floating_point_promotion_t<U0>;
4577 return Out(
static_cast<U
>(lhs.value()) *
static_cast<U
>(rhs.raw()));
4581 template<DimensionedUnitType UnitTypeLhs, ArithmeticType T>
4582 requires(traits::has_linear_scale_v<UnitTypeLhs>)
4583 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>
operator*(
const UnitTypeLhs& lhs, T rhs)
noexcept
4585 using CommonUnit =
decltype(lhs * rhs);
4586 return CommonUnit(CommonUnit(lhs).raw() * rhs);
4590 template<DimensionedUnitType UnitTypeRhs, ArithmeticType T>
4591 requires(traits::has_linear_scale_v<UnitTypeRhs>)
4592 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<T, typename UnitTypeRhs::underlying_type>>
operator*(T lhs,
const UnitTypeRhs& rhs)
noexcept
4594 using CommonUnit =
decltype(lhs * rhs);
4595 return CommonUnit(lhs * CommonUnit(rhs).raw());
4599 template<RatioDimensionlessUnitType U, units::ArithmeticType T>
4600 requires(units::traits::has_linear_scale_v<U>)
4601 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
4603 using Under0 = std::common_type_t<T, typename U::underlying_type>;
4604 using Under = units::detail::floating_point_promotion_t<Under0>;
4607 return units::dimensionless<Under>(
static_cast<Under
>(lhs) *
static_cast<Under
>(rhs));
4611 template<RatioDimensionlessUnitType U, units::ArithmeticType T>
4612 requires(units::traits::has_linear_scale_v<U>)
4613 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
4615 using Under0 = std::common_type_t<typename U::underlying_type, T>;
4616 using Under = units::detail::floating_point_promotion_t<Under0>;
4618 return units::dimensionless<Under>(
static_cast<Under
>(lhs) *
static_cast<Under
>(rhs));
4622 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4623 requires(traits::has_linear_scale_v<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeLhs>)
4624 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>
operator*(
const UnitTypeLhs& lhs, T rhs)
noexcept
4626 using CommonUnit =
decltype(lhs * rhs);
4627 return CommonUnit(lhs.raw() * rhs);
4631 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4632 requires(traits::has_linear_scale_v<UnitTypeRhs> && !RatioDimensionlessUnitType<UnitTypeRhs>)
4633 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<T, typename UnitTypeRhs::underlying_type>>
operator*(T lhs,
const UnitTypeRhs& rhs)
noexcept
4635 using CommonUnit =
decltype(lhs * rhs);
4636 return CommonUnit(lhs * rhs.raw());
4641 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
4643 same_dimension<UnitTypeLhs, UnitTypeRhs> && traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs> && !RatioDimensionlessUnitType<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeRhs>)
4644 constexpr dimensionless<std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator/(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4646 using CommonUnit = std::common_type_t<UnitTypeLhs, UnitTypeRhs>;
4647 return CommonUnit(lhs).raw() / CommonUnit(rhs).raw();
4652 template<DimensionedUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4653 requires(!same_dimension<UnitTypeLhs, UnitTypeRhs> && traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4654 constexpr auto operator/(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4655 -> 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>>>,
4656 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>>
4658 using CompoundUnit =
decltype(lhs / rhs);
4659 using CommonUnderlying =
typename CompoundUnit::underlying_type;
4660 return CompoundUnit(
static_cast<CommonUnderlying
>(lhs) /
static_cast<CommonUnderlying
>(rhs));
4664 template<DimensionedUnitType UnitTypeLhs, OrdinaryDimensionlessUnitType UnitTypeRhs>
4665 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4666 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator/(
4667 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4669 using CommonUnit =
decltype(lhs / rhs);
4670 using CommonUnderlying =
typename CommonUnit::underlying_type;
4673 return CommonUnit(CommonUnit(lhs).raw() /
static_cast<CommonUnderlying
>(rhs));
4678 template<DimensionedUnitType UnitTypeLhs, RatioDimensionlessUnitType UnitTypeRhs>
4679 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4680 constexpr traits::replace_underlying_t<
4682 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>
4684 operator/(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4686 using Out =
decltype(lhs / rhs);
4687 using U0 = std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>;
4688 using U = detail::floating_point_promotion_t<U0>;
4690 return Out(
static_cast<U
>(lhs.raw()) /
static_cast<U
>(rhs.value()));
4695 template<OrdinaryDimensionlessUnitType UnitTypeLhs, RatioDimensionlessUnitType UnitTypeRhs>
4696 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4697 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>>,
4698 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>>
4700 using Out =
decltype(lhs / rhs);
4701 using CommonUnderlying =
typename Out::underlying_type;
4704 return Out(
static_cast<CommonUnderlying
>(lhs) /
static_cast<CommonUnderlying
>(rhs.raw()));
4708 template<OrdinaryDimensionlessUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4709 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs> && traits::is_dimensionless_unit_v<UnitTypeLhs>)
4710 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>>,
4711 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>>
4713 using CommonUnit =
decltype(lhs / rhs);
4714 using CommonUnderlying =
typename CommonUnit::underlying_type;
4715 return CommonUnit(
static_cast<CommonUnderlying
>(lhs) /
static_cast<CommonUnderlying
>(rhs));
4720 template<RatioDimensionlessUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4721 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4722 constexpr auto operator/(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4726 typename traits::unit_traits<UnitTypeLhs>::conversion_factor,
4727 inverse<typename traits::unit_traits<UnitTypeRhs>::conversion_factor>
4730 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>
4733 using Out =
decltype(lhs / rhs);
4734 using CommonUnderlying =
typename Out::underlying_type;
4739 static_cast<CommonUnderlying
>(lhs.raw()) /
static_cast<CommonUnderlying
>(rhs.raw()),
4745 template<UnitType UnitTypeLhs, ArithmeticType T>
4746 requires(traits::has_linear_scale_v<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeLhs>)
4747 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>
operator/(
const UnitTypeLhs& lhs, T rhs)
noexcept
4749 using CommonUnit =
decltype(lhs / rhs);
4750 return CommonUnit(CommonUnit(lhs).raw() / rhs);
4754 template<UnitType UnitTypeRhs, ArithmeticType T>
4755 requires(traits::has_linear_scale_v<UnitTypeRhs> && !RatioDimensionlessUnitType<UnitTypeRhs>)
4756 constexpr auto operator/(T lhs,
const UnitTypeRhs& rhs)
noexcept
4757 -> 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>>>
4759 using InverseUnit =
decltype(lhs / rhs);
4760 using UnitConversion =
typename traits::unit_traits<UnitTypeRhs>::conversion_factor;
4761 using CommonUnderlying = std::common_type_t<T, typename UnitTypeRhs::underlying_type>;
4763 return InverseUnit(lhs / CommonUnit(rhs).raw());
4768 template<RatioDimensionlessUnitType U, ArithmeticType T>
4769 requires(traits::has_linear_scale_v<U>)
4770 constexpr traits::replace_underlying_t<U, std::common_type_t<typename U::underlying_type, T>>
operator/(
const U& lhs, T rhs)
noexcept
4772 using Out = traits::replace_underlying_t<U, std::common_type_t<typename U::underlying_type, T>>;
4773 return Out(Out(lhs).raw() / rhs);
4777 template<RatioDimensionlessUnitType U, ArithmeticType T>
4778 requires(traits::has_linear_scale_v<U>)
4779 constexpr units::dimensionless<detail::floating_point_promotion_t<std::common_type_t<T, typename U::underlying_type>>>
operator/(T lhs,
const U& rhs)
noexcept
4781 using CommonType = std::common_type_t<T, typename U::underlying_type>;
4782 using PromotedType = detail::floating_point_promotion_t<CommonType>;
4785 return units::dimensionless<PromotedType>(
static_cast<PromotedType
>(lhs) /
static_cast<PromotedType
>(rhs.value()));
4789 template<RatioDimensionlessUnitType U1, RatioDimensionlessUnitType U2>
4790 requires(traits::has_linear_scale_v<U1, U2>)
4791 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
4793 using Under0 = std::common_type_t<typename U1::underlying_type, typename U2::underlying_type>;
4794 using Under = detail::floating_point_promotion_t<Under0>;
4795 return dimensionless<Under>(
static_cast<Under
>(lhs.value()) /
static_cast<Under
>(rhs.value()));
4805 template<DimensionedUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
4807 constexpr std::common_type_t<UnitTypeLhs, UnitTypeRhs>
operator%(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4809 using CommonUnit = std::common_type_t<UnitTypeLhs, UnitTypeRhs>;
4810 return CommonUnit(CommonUnit(lhs).raw() % CommonUnit(rhs).raw());
4814 template<DimensionedUnitType UnitTypeLhs, DimensionlessUnitType UnitTypeRhs>
4815 requires(traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4816 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator%(
4817 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4819 using CommonUnit =
decltype(lhs % rhs);
4820 using CommonUnderlying =
typename CommonUnit::underlying_type;
4821 return CommonUnit(CommonUnit(lhs).raw() %
static_cast<CommonUnderlying
>(rhs));
4826 template<DimensionlessUnitType UnitTypeLhs, DimensionlessUnitType UnitTypeRhs>
4827 requires(same_dimension<UnitTypeLhs, UnitTypeRhs> && traits::has_linear_scale_v<UnitTypeLhs, UnitTypeRhs>)
4828 constexpr traits::replace_underlying_t<UnitTypeLhs,
typename std::common_type_t<UnitTypeLhs, UnitTypeRhs>::underlying_type>
operator%(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
4830 using CommonUnit =
decltype(lhs % rhs);
4831 return CommonUnit(lhs.raw() % rhs.raw());
4835 template<UnitType UnitTypeLhs, ArithmeticType T>
4836 requires(traits::has_linear_scale_v<UnitTypeLhs> && !RatioDimensionlessUnitType<UnitTypeLhs>)
4837 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, T>>
operator%(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
4839 using CommonUnit =
decltype(lhs % rhs);
4840 return CommonUnit(CommonUnit(lhs).raw() % rhs);
4844 template<RatioDimensionlessUnitType U>
4845 requires(traits::has_linear_scale_v<U>)
4846 constexpr U
operator%(
const U& lhs,
const U& rhs)
noexcept
4848 return U(lhs.raw() % rhs.raw());
4851 template<RatioDimensionlessUnitType U, ArithmeticType T>
4852 requires(traits::has_linear_scale_v<U>)
4853 constexpr U
operator%(
const U& lhs, T rhs)
noexcept
4855 return U(lhs.raw() % rhs);
4858 template<RatioDimensionlessUnitType U, ArithmeticType T>
4859 requires(traits::has_linear_scale_v<U>)
4860 constexpr U
operator%(T lhs,
const U& rhs)
noexcept
4862 using Under = detail::floating_point_promotion_t<std::common_type_t<T, typename U::underlying_type>>;
4864 if constexpr (std::is_integral_v<T> && std::is_integral_v<typename U::underlying_type>)
4865 return U(lhs % rhs.raw());
4867 return U(
static_cast<Under
>(std::fmod(
static_cast<Under
>(lhs),
static_cast<Under
>(rhs.raw()))));
4874 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4875 constexpr bool operator==(
const T& lhs,
const UnitTypeRhs& rhs)
noexcept
4877 using CommonUnderlying = std::common_type_t<T, typename UnitTypeRhs::underlying_type>;
4879 const auto common_lhs =
static_cast<CommonUnderlying
>(lhs);
4880 const auto common_rhs =
static_cast<CommonUnderlying
>(rhs);
4882 if constexpr (std::is_integral_v<CommonUnderlying>)
4884 return common_lhs == common_rhs;
4888 return abs(common_lhs - common_rhs) < std::numeric_limits<CommonUnderlying>::epsilon() * abs(common_lhs + common_rhs) ||
4889 abs(common_lhs - common_rhs) < std::numeric_limits<CommonUnderlying>::min();
4893 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4894 constexpr bool operator==(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
4899 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4900 requires(traits::is_dimensionless_unit_v<UnitTypeRhs> && std::is_arithmetic_v<T>)
4901 constexpr bool operator!=(
const T& lhs,
const UnitTypeRhs& rhs)
noexcept
4903 return !(lhs == rhs);
4906 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4907 constexpr bool operator!=(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
4909 return !(lhs == rhs);
4912 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4913 requires(traits::is_dimensionless_unit_v<UnitTypeRhs> && std::is_arithmetic_v<T>)
4914 constexpr bool operator>=(
const T& lhs,
const UnitTypeRhs& rhs)
noexcept
4916 using CommonUnderlying = std::common_type_t<T, typename UnitTypeRhs::underlying_type>;
4917 return lhs >=
static_cast<CommonUnderlying
>(rhs);
4920 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4921 constexpr bool operator>=(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
4923 using CommonUnderlying = std::common_type_t<typename UnitTypeLhs::underlying_type, T>;
4924 return static_cast<CommonUnderlying
>(lhs) >= rhs;
4927 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4928 constexpr bool operator>(
const T& lhs,
const UnitTypeRhs& rhs)
noexcept
4930 using CommonUnderlying = std::common_type_t<T, typename UnitTypeRhs::underlying_type>;
4931 return lhs >
static_cast<CommonUnderlying
>(rhs);
4934 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4935 constexpr bool operator>(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
4937 using CommonUnderlying = std::common_type_t<typename UnitTypeLhs::underlying_type, T>;
4938 return static_cast<CommonUnderlying
>(lhs) > rhs;
4941 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4942 constexpr bool operator<=(
const T& lhs,
const UnitTypeRhs& rhs)
noexcept
4944 using CommonUnderlying = std::common_type_t<T, typename UnitTypeRhs::underlying_type>;
4945 return lhs <= static_cast<CommonUnderlying>(rhs);
4948 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4949 constexpr bool operator<=(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
4951 using CommonUnderlying = std::common_type_t<typename UnitTypeLhs::underlying_type, T>;
4952 return static_cast<CommonUnderlying
>(lhs) <= rhs;
4955 template<DimensionlessUnitType UnitTypeRhs, ArithmeticType T>
4956 constexpr bool operator<(
const T& lhs,
const UnitTypeRhs& rhs)
noexcept
4958 using CommonUnderlying = std::common_type_t<T, typename UnitTypeRhs::underlying_type>;
4959 return lhs < static_cast<CommonUnderlying>(rhs);
4962 template<DimensionlessUnitType UnitTypeLhs, ArithmeticType T>
4963 constexpr bool operator<(
const UnitTypeLhs& lhs,
const T& rhs)
noexcept
4965 using CommonUnderlying = std::common_type_t<typename UnitTypeLhs::underlying_type, T>;
4966 return static_cast<CommonUnderlying
>(lhs) < rhs;
4977 template<
int N,
class U>
4978 struct power_of_unit
4980 template<
bool isPos,
int V>
4981 struct power_of_unit_impl;
4984 struct power_of_unit_impl<true, V>
4986 typedef unit_multiply<U,
typename power_of_unit<N - 1, U>::type> type;
4990 struct power_of_unit_impl<false, V>
4992 typedef inverse<
typename power_of_unit<-N, U>::type> type;
4995 typedef typename power_of_unit_impl<(N > 0), N>::type type;
5000 struct power_of_unit<1, U>
5006 struct power_of_unit<0, U>
5008 typedef dimensionless_ type;
5021 template<
int power, UnitType UnitType>
5022 requires(traits::has_linear_scale_v<UnitType>)
5023 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>,
5024 detail::floating_point_promotion_t<typename units::traits::unit_traits<UnitType>::underlying_type>,
linear_scale>>
5026 return decltype(units::pow<power>(value))(pow<power>(value.raw()));
5047 static T
linearize(
const T value)
noexcept
5053 static_assert(std::is_floating_point_v<T>,
5054 "a decibel-scale unit requires a floating-point underlying type (an integral type cannot represent a logarithmic value)");
5055 return static_cast<T
>(std::pow(10, value / 10));
5065 static T
scale(
const T value)
noexcept
5067 return static_cast<T
>(10 * std::log10(value));
5080#if !defined(UNIT_LIB_DISABLE_IOSTREAM)
5081 template<
class Underlying>
5082 std::ostream& operator<<(std::ostream& os,
const decibels<Underlying>& obj)
5084 os << obj.
raw() <<
" dB";
5088 template<
class Underlying>
5095 template<
class Underlying>
5098 static constexpr const char* value =
"decibels";
5101 template<
class Underlying>
5104 static constexpr const char* value =
"dB";
5110 typename ::units::decibels<>::conversion_factor*, typename ::units::decibels<>::numerical_scale_type*);
5113#ifndef UNIT_NO_LITERAL_SUPPORT
5134 template<DimensionedUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
5136 auto operator+(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept =
delete;
5140 template<DimensionlessUnitType UnitTypeLhs, DimensionlessUnitType UnitTypeRhs>
5141 requires(traits::has_decibel_scale_v<UnitTypeLhs, UnitTypeRhs>)
5142 constexpr std::common_type_t<UnitTypeLhs, UnitTypeRhs>
operator+(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
5144 using CommonUnit = std::common_type_t<UnitTypeLhs, UnitTypeRhs>;
5145 return CommonUnit(CommonUnit(lhs).to_linearized() * CommonUnit(rhs).to_linearized(), linearized_value);
5149 template<DimensionedUnitType UnitTypeLhs, DimensionlessUnitType UnitTypeRhs>
5150 requires(traits::has_decibel_scale_v<UnitTypeLhs, UnitTypeRhs>)
5151 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator+(
5152 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
5154 using CommonUnit =
decltype(lhs + rhs);
5155 return CommonUnit(lhs.to_linearized() * rhs.to_linearized(), linearized_value);
5159 template<DimensionlessUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
5160 requires(traits::has_decibel_scale_v<UnitTypeLhs, UnitTypeRhs>)
5161 constexpr traits::replace_underlying_t<UnitTypeRhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator+(
5162 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
5164 using CommonUnit =
decltype(lhs + rhs);
5165 return CommonUnit(lhs.to_linearized() * rhs.to_linearized(), linearized_value);
5169 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5170 requires(same_dimension<UnitTypeLhs, UnitTypeRhs> && traits::has_decibel_scale_v<UnitTypeLhs, UnitTypeRhs>)
5171 constexpr auto operator-(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept -> decibels<typename std::common_type_t<UnitTypeLhs, UnitTypeRhs>::underlying_type>
5174 using CommonUnit = std::common_type_t<UnitTypeLhs, UnitTypeRhs>;
5176 return Dimensionless(CommonUnit(lhs).to_linearized() / CommonUnit(rhs).to_linearized(), linearized_value);
5180 template<DimensionedUnitType UnitTypeLhs, DimensionlessUnitType UnitTypeRhs>
5181 requires(traits::has_decibel_scale_v<UnitTypeLhs, UnitTypeRhs>)
5182 constexpr traits::replace_underlying_t<UnitTypeLhs, std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>>
operator-(
5183 const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
5185 using CommonUnit =
decltype(lhs - rhs);
5186 return CommonUnit(lhs.to_linearized() / rhs.to_linearized(), linearized_value);
5190 template<DimensionlessUnitType UnitTypeLhs, DimensionedUnitType UnitTypeRhs>
5191 requires(traits::has_decibel_scale_v<UnitTypeLhs, UnitTypeRhs>)
5192 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>>,
5193 std::common_type_t<typename UnitTypeLhs::underlying_type, typename UnitTypeRhs::underlying_type>, decibel_scale>>
5195 using InverseUnit =
decltype(lhs - rhs);
5196 return InverseUnit(lhs.to_linearized() / rhs.to_linearized(), linearized_value);
5207 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5209 constexpr std::common_type_t<UnitTypeLhs, UnitTypeRhs> min(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
5211 using CommonUnit =
decltype(units::min(lhs, rhs));
5212 return (lhs < rhs ? CommonUnit(lhs) : CommonUnit(rhs));
5215 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5217 constexpr std::common_type_t<UnitTypeLhs, UnitTypeRhs> max(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
5219 using CommonUnit =
decltype(units::max(lhs, rhs));
5220 return (lhs > rhs ? CommonUnit(lhs) : CommonUnit(rhs));
5240 template<DimensionlessUnitType UnitType>
5241 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
exp(
const UnitType x)
noexcept
5243 return std::exp(x.value());
5255 template<DimensionlessUnitType UnitType>
5256 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
log(
const UnitType x)
noexcept
5258 return std::log(x.value());
5269 template<DimensionlessUnitType UnitType>
5270 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
log10(
const UnitType x)
noexcept
5272 return std::log10(x.value());
5286 template<DimensionlessUnitType UnitType>
5287 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
modf(
const UnitType x,
UnitType* intpart)
noexcept
5289 using promoted = detail::floating_point_promotion_t<typename UnitType::underlying_type>;
5296 promoted fracpart = std::modf(x.template to<promoted>(), &intp);
5297 *intpart = dimensionless<promoted>{intp};
5298 return dimensionless<promoted>{fracpart};
5308 template<DimensionlessUnitType UnitType>
5309 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
exp2(
const UnitType x)
noexcept
5311 return std::exp2(x.value());
5322 template<DimensionlessUnitType UnitType>
5323 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
expm1(
const UnitType x)
noexcept
5325 return std::expm1(x.value());
5337 template<DimensionlessUnitType UnitType>
5338 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
log1p(
const UnitType x)
noexcept
5340 return std::log1p(x.value());
5351 template<DimensionlessUnitType UnitType>
5352 constexpr dimensionless<detail::floating_point_promotion_t<typename UnitType::underlying_type>>
log2(
const UnitType x)
noexcept
5354 return std::log2(x.value());
5375 template<UnitType UnitType>
5376 requires(traits::has_linear_scale_v<UnitType>)
5377 constexpr auto sqrt(
const UnitType& value)
noexcept
5378 -> 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>>>
5380 return decltype(units::sqrt(value))(sqrt(value.raw()));
5392 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5394 constexpr detail::floating_point_promotion_t<std::common_type_t<UnitTypeLhs, UnitTypeRhs>>
hypot(
const UnitTypeLhs& x,
const UnitTypeRhs& y)
5397 return CommonUnit(std::hypot(CommonUnit(x).raw(), CommonUnit(y).raw()));
5411 template<UnitType Unit>
5412 constexpr detail::floating_point_promotion_t<Unit>
ceil(
const Unit x)
noexcept
5414 return detail::floating_point_promotion_t<Unit>(std::ceil(x.raw()));
5424 template<UnitType Unit>
5425 constexpr detail::floating_point_promotion_t<Unit>
floor(
const Unit x)
noexcept
5427 return detail::floating_point_promotion_t<Unit>(std::floor(x.raw()));
5438 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5440 constexpr detail::floating_point_promotion_t<std::common_type_t<UnitTypeLhs, UnitTypeRhs>>
fmod(
const UnitTypeLhs numer,
const UnitTypeRhs denom)
noexcept
5442 using CommonUnit =
decltype(
units::fmod(numer, denom));
5443 return CommonUnit(std::fmod(CommonUnit(numer).raw(), CommonUnit(denom).raw()));
5454 template<UnitType UnitType>
5455 constexpr detail::floating_point_promotion_t<UnitType>
trunc(
const UnitType x)
noexcept
5457 return detail::floating_point_promotion_t<UnitType>(std::trunc(x.raw()));
5468 template<UnitType UnitType>
5469 constexpr detail::floating_point_promotion_t<UnitType>
round(
const UnitType x)
noexcept
5471 return detail::floating_point_promotion_t<UnitType>(std::round(x.raw()));
5478 enum class rounding_mode
5480 toward_neg_infinity,
5481 toward_pos_infinity,
5493 constexpr Int apply_integer_rounding(Int q, Int r, Int den, rounding_mode mode)
noexcept
5499 case rounding_mode::toward_zero:
5501 case rounding_mode::toward_neg_infinity:
5502 return r < 0 ? q - 1 : q;
5503 case rounding_mode::toward_pos_infinity:
5504 return r > 0 ? q + 1 : q;
5505 case rounding_mode::nearest_half_away:
5508 const Int twiceRemainder = (r < 0 ? -r : r) * 2;
5509 if (twiceRemainder >= den)
5510 return r < 0 ? q - 1 : q + 1;
5525 template<
class To,
class From>
5526 constexpr To rounded_unit_cast(
const From& x, rounding_mode mode)
noexcept
5528 using ToRep =
typename To::underlying_type;
5529 using FromRep =
typename From::underlying_type;
5531 if constexpr (std::is_integral_v<FromRep>)
5534 using Ratio = std::ratio_divide<typename From::conversion_factor::conversion_ratio, typename To::conversion_factor::conversion_ratio>;
5535 const widest_signed_int value =
static_cast<widest_signed_int
>(x.raw());
5536 const widest_signed_int product = value *
static_cast<widest_signed_int
>(Ratio::num);
5537 const widest_signed_int den =
static_cast<widest_signed_int
>(Ratio::den);
5538 const widest_signed_int quotient = product / den;
5539 const widest_signed_int remainder = product % den;
5540 const widest_signed_int rounded = apply_integer_rounding(quotient, remainder, den, mode);
5541 return To(
static_cast<ToRep
>(rounded), linearized_value);
5546 using Promoted = unit<typename To::conversion_factor, floating_point_promotion_t<ToRep>,
typename To::numerical_scale_type>;
5547 const auto inTarget = Promoted(x).to_linearized();
5548 const auto rounded = mode == rounding_mode::toward_neg_infinity ? std::floor(inTarget)
5549 : mode == rounding_mode::toward_pos_infinity ? std::
ceil(inTarget)
5550 : mode == rounding_mode::nearest_half_away ? std::
round(inTarget)
5551 : std::
trunc(inTarget);
5552 return To(
static_cast<ToRep
>(rounded), linearized_value);
5560 template<
class To,
class From>
5561 inline constexpr bool is_roundable_unit_conversion =
5562 traits::is_unit_v<To> && traits::is_unit_v<From> && same_dimension<From, To> &&
5563 std::is_integral_v<typename To::underlying_type> && !is_losslessly_convertible_unit<From, To>;
5579 template<
class To, UnitType From>
5580 requires detail::is_roundable_unit_conversion<To, From>
5581 constexpr To
floor(
const From& x)
noexcept
5583 return detail::rounded_unit_cast<To>(x, detail::rounding_mode::toward_neg_infinity);
5595 template<
class To, UnitType From>
5596 requires detail::is_roundable_unit_conversion<To, From>
5597 constexpr To
ceil(
const From& x)
noexcept
5599 return detail::rounded_unit_cast<To>(x, detail::rounding_mode::toward_pos_infinity);
5611 template<
class To, UnitType From>
5612 requires detail::is_roundable_unit_conversion<To, From>
5613 constexpr To
round(
const From& x)
noexcept
5615 return detail::rounded_unit_cast<To>(x, detail::rounding_mode::nearest_half_away);
5627 template<
class To, UnitType From>
5628 requires detail::is_roundable_unit_conversion<To, From>
5629 constexpr To
trunc(
const From& x)
noexcept
5631 return detail::rounded_unit_cast<To>(x, detail::rounding_mode::toward_zero);
5647 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5648 constexpr detail::floating_point_promotion_t<UnitTypeLhs>
copysign(
const UnitTypeLhs x,
const UnitTypeRhs y)
noexcept
5650 return detail::floating_point_promotion_t<UnitTypeLhs>(std::copysign(x.raw(), y.raw()));
5654 template<UnitType UnitTypeLhs, ArithmeticType T>
5655 constexpr detail::floating_point_promotion_t<UnitTypeLhs>
copysign(
const UnitTypeLhs x,
const T& y)
noexcept
5657 return detail::floating_point_promotion_t<UnitTypeLhs>(std::copysign(x.raw(), y));
5672 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5674 constexpr detail::floating_point_promotion_t<std::common_type_t<UnitTypeLhs, UnitTypeRhs>>
fdim(
const UnitTypeLhs x,
const UnitTypeRhs y)
noexcept
5677 return CommonUnit(std::fdim(CommonUnit(x).raw(), CommonUnit(y).raw()));
5688 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5690 constexpr detail::floating_point_promotion_t<std::common_type_t<UnitTypeLhs, UnitTypeRhs>>
fmax(
const UnitTypeLhs x,
const UnitTypeRhs y)
noexcept
5693 return CommonUnit(std::fmax(CommonUnit(x).raw(), CommonUnit(y).raw()));
5705 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5707 constexpr detail::floating_point_promotion_t<std::common_type_t<UnitTypeLhs, UnitTypeRhs>>
fmin(
const UnitTypeLhs x,
const UnitTypeRhs y)
noexcept
5710 return CommonUnit(std::fmin(CommonUnit(x).raw(), CommonUnit(y).raw()));
5724 template<UnitType UnitType>
5725 constexpr detail::floating_point_promotion_t<UnitType>
fabs(
const UnitType x)
noexcept
5727 return detail::floating_point_promotion_t<UnitType>(std::fabs(x.raw()));
5737 template<UnitType UnitType>
5740 return UnitType(std::abs(x.raw()));
5757 template<UnitType UnitTypeLhs, UnitType UnitMultiply, UnitType UnitAdd>
5758 requires(traits::is_same_dimension_conversion_factor_v<
5760 typename traits::unit_traits<UnitAdd>::conversion_factor>)
5761 constexpr auto fma(
const UnitTypeLhs x,
const UnitMultiply y,
const UnitAdd z)
noexcept
5762 -> std::common_type_t<decltype(detail::floating_point_promotion_t<UnitTypeLhs>(x) * detail::floating_point_promotion_t<UnitMultiply>(y)), UnitAdd>
5764 using CommonUnit =
decltype(
units::fma(x, y, z));
5765 using ProductUnit =
decltype(detail::floating_point_promotion_t<UnitTypeLhs>(x) * detail::floating_point_promotion_t<UnitMultiply>(y));
5771 constexpr auto scale = CommonUnit(ProductUnit(1)).raw();
5772 return CommonUnit(std::fma(x.raw(), y.raw() * scale, CommonUnit(z).raw()));
5779 template<UnitType UnitType>
5780 constexpr bool isnan(
const UnitType& x)
noexcept
5782 return std::isnan(x.raw());
5785 template<UnitType UnitType>
5786 constexpr bool isinf(
const UnitType& x)
noexcept
5788 return std::isinf(x.raw());
5791 template<UnitType UnitType>
5792 constexpr bool isfinite(
const UnitType& x)
noexcept
5794 return std::isfinite(x.raw());
5797 template<UnitType UnitType>
5798 constexpr bool isnormal(
const UnitType& x)
noexcept
5800 return std::isnormal(x.raw());
5803 template<UnitType UnitTypeLhs, UnitType UnitTypeRhs>
5805 constexpr bool isunordered(
const UnitTypeLhs& lhs,
const UnitTypeRhs& rhs)
noexcept
5807 return std::isunordered(lhs.raw(), rhs.raw());
5819template<
class ConversionFactor,
typename T,
class NumericalScale>
5820struct std::hash<
units::unit<ConversionFactor, T, NumericalScale>>
5822 template<
typename U = T>
5825 if constexpr (std::is_integral_v<U>)
5831 return static_cast<std::size_t
>(hash<T>()(x.
to_linearized()));
5839template<
class Named>
5840 requires units::detail::is_named_unit_v<Named>
5841struct std::hash<Named> : std::hash<units::detail::unit_base_t<Named>>
5851 template<units::ConversionFactorType ConversionFactor, units::ArithmeticType T, units::NumericalScaleType<T> NonLinearScale>
5852 struct numeric_limits<
units::unit<ConversionFactor, T, NonLinearScale>>
5899 static constexpr bool is_specialized = std::numeric_limits<T>::is_specialized;
5900 static constexpr bool is_signed = std::numeric_limits<T>::is_signed;
5901 static constexpr bool is_integer = std::numeric_limits<T>::is_integer;
5902 static constexpr bool is_exact = std::numeric_limits<T>::is_exact;
5903 static constexpr bool has_infinity = std::numeric_limits<T>::has_infinity;
5904 static constexpr bool has_quiet_NaN = std::numeric_limits<T>::has_quiet_NaN;
5905 static constexpr bool has_signaling_NaN = std::numeric_limits<T>::has_signaling_NaN;
5912 template<
class Named>
5913 requires units::detail::is_named_unit_v<Named>
5914 struct numeric_limits<Named> : numeric_limits<units::detail::unit_base_t<Named>>
5917 using Base = numeric_limits<units::detail::unit_base_t<Named>>;
5923 static constexpr Named min() {
return Named(Base::min()); }
5924 static constexpr Named max() {
return Named(Base::max()); }
5925 static constexpr Named lowest() {
return Named(Base::lowest()); }
5926 static constexpr Named epsilon() {
return Named(Base::epsilon()); }
5927 static constexpr Named round_error() {
return Named(Base::round_error()); }
5928 static constexpr Named denorm_min() {
return Named(Base::denorm_min()); }
5929 static constexpr Named infinity() {
return Named(Base::infinity()); }
5930 static constexpr Named quiet_NaN() {
return Named(Base::quiet_NaN()); }
5931 static constexpr Named signaling_NaN() {
return Named(Base::signaling_NaN()); }
5940 template<units::UnitType U>
5941 constexpr bool isnan(U x)
5943 return std::isnan(x.raw());
5946 template<units::UnitType U>
5947 constexpr bool isinf(U x)
5949 return std::isinf(x.raw());
5952 template<units::UnitType U>
5953 constexpr bool isfinite(U x)
5955 return std::isfinite(x.raw());
5958 template<units::UnitType U>
5959 constexpr bool signbit(U x)
5961 return std::signbit(x.raw());
5974 concept PureDimensionlessCF = std::is_same_v<typename Cf::dimension_type, dimension::dimensionless> && std::ratio_equal_v<typename Cf::conversion_ratio, std::ratio<1>> &&
5975 std::ratio_equal_v<typename Cf::pi_exponent_ratio, std::ratio<0>> && std::ratio_equal_v<typename Cf::translation_ratio, std::ratio<0>>;
5978 template<ArithmeticType Rep, RatioType Period>
5983 template<ArithmeticType SourceTy, ConversionFactorType SourceCf>
5990 template<ArithmeticType SourceTy, ConversionFactorType SourceCf, ConversionFactorType TargetCf = SourceCf>
5991 requires(traits::is_unit_v<unit<SourceCf, SourceTy>> && traits::is_conversion_factor_v<TargetCf> && traits::is_same_dimension_conversion_factor_v<SourceCf, TargetCf> &&
5992 !std::is_same_v<SourceCf, TargetCf> && detail::is_losslessly_convertible_unit<unit<SourceCf, SourceTy>,
unit<TargetCf, SourceTy>>)
5998 template<ArithmeticType SourceTy, ConversionFactorType SourceCf, ConversionFactorType TargetCf = SourceCf>
5999 requires(traits::is_unit_v<unit<SourceCf, SourceTy>> && traits::is_conversion_factor_v<TargetCf> && traits::is_same_dimension_conversion_factor_v<SourceCf, TargetCf> &&
6000 !std::is_same_v<SourceCf, TargetCf> && !detail::is_losslessly_convertible_unit<unit<SourceCf, SourceTy>,
unit<TargetCf, SourceTy>>)
6005 template<ConversionFactorType TargetCf, ArithmeticType SourceTy>
6006 requires traits::is_unit_v<unit<TargetCf, SourceTy>>
6010 template<
typename T,
typename Cf = dimension::dimensionless,
typename = std::enable_if_t<std::is_arithmetic_v<T>>>
6018#if defined(UNIT_LIB_ENABLE_FORMAT)
6040template<units::UnitType U>
6041struct std::formatter<U, char>
6043 using conversion_factor =
typename units::traits::unit_traits<U>::conversion_factor;
6044 using value_type =
typename units::traits::unit_traits<U>::underlying_type;
6045 using scale_type =
typename units::traits::unit_traits<U>::numerical_scale_type;
6046 using promoted_value_type = units::detail::floating_point_promotion_t<value_type>;
6052 using formatted_value_type = std::conditional_t<renders_in_base_unit, promoted_value_type, value_type>;
6056 std::formatter<formatted_value_type, char> m_valueFormatter;
6057 std::formatter<promoted_value_type, char> m_baseFormatter;
6058 units::detail::unit_format_options m_options;
6059 bool m_usesBaseFormatter =
false;
6069 constexpr auto parse(std::format_parse_context& ctx)
6071 auto it = ctx.begin();
6072 auto end = ctx.end();
6075 auto valueSpecEnd = it;
6076 for (
auto scan = it; scan != end && *scan !=
'}'; ++scan)
6080 valueSpecEnd = scan + 1;
6087 m_usesBaseFormatter =
false;
6088 for (
auto scan = valueSpecEnd; scan != end && *scan !=
'}'; ++scan)
6092 m_usesBaseFormatter =
true;
6099 if (valueSpecEnd != it)
6101 std::string_view valueSpec(it, valueSpecEnd);
6102 if (m_usesBaseFormatter)
6104 std::format_parse_context baseCtx(valueSpec);
6105 if (m_baseFormatter.parse(baseCtx) != valueSpec.end())
6106 throw std::format_error(
"units: invalid value format-spec");
6110 std::format_parse_context valueCtx(valueSpec);
6111 if (m_valueFormatter.parse(valueCtx) != valueSpec.end())
6112 throw std::format_error(
"units: invalid value format-spec");
6119 if (it != end && *it ==
'%')
6122 bool sawForm =
false;
6123 bool sawShow =
false;
6124 while (it != end && *it !=
'}')
6127 if (c ==
'a' || c ==
'n' || c ==
'b')
6130 throw std::format_error(
"units: duplicate label-form flag");
6132 m_options.form = (
c ==
'a') ? units::detail::label_form::abbreviation
6137 else if (c ==
'v' || c ==
'u')
6140 throw std::format_error(
"units: duplicate show flag");
6142 m_options.showValue = (
c ==
'v');
6143 m_options.showUnit = (
c ==
'u');
6150 bool closed =
false;
6151 while (it != end && *it !=
'}')
6156 if (it == end || *it ==
'}')
6157 throw std::format_error(
"units: dangling escape in separator");
6160 case 't': sep.push_back(
'\t');
break;
6161 case 'n': sep.push_back(
'\n');
break;
6162 case '\\': sep.push_back(
'\\');
break;
6163 case '\'': sep.push_back(
'\'');
break;
6164 default: sep.push_back(*it);
break;
6168 else if (*it ==
'\'')
6181 throw std::format_error(
"units: unterminated separator literal");
6182 m_options.separator = std::move(sep);
6183 m_options.customSep =
true;
6187 throw std::format_error(
"units: unknown unit-format flag");
6204 template<
class FormatContext>
6205 auto format(
const U& obj, FormatContext& ctx)
const
6207 using base_unit_type = units::unit<units::conversion_factor<std::ratio<1>,
typename conversion_factor::dimension_type>, promoted_value_type, scale_type>;
6212 formatted_value_type value{};
6213 promoted_value_type baseValue{};
6214 if constexpr (renders_in_base_unit)
6215 value = base_unit_type(obj).
raw();
6217 value =
static_cast<formatted_value_type
>(obj.raw());
6218 if (m_options.form == units::detail::label_form::base)
6219 baseValue = base_unit_type(obj).raw();
6222 if (m_options.showUnit)
6224 switch (m_options.form)
6226 case units::detail::label_form::name: label = units::detail::unit_label<units::detail::label_form::name>(obj);
break;
6227 case units::detail::label_form::base: label = units::detail::unit_label<units::detail::label_form::base>(obj);
break;
6228 case units::detail::label_form::abbreviation:
6229 default: label = units::detail::unit_label<units::detail::label_form::abbreviation>(obj);
break;
6233 auto out = ctx.out();
6235 if (m_options.showValue)
6237 if (m_usesBaseFormatter)
6241 const promoted_value_type emitted = renders_in_base_unit ?
static_cast<promoted_value_type
>(value) : baseValue;
6242 out = m_baseFormatter.format(emitted, ctx);
6246 out = m_valueFormatter.format(value, ctx);
6250 if (m_options.showUnit && !label.empty())
6255 std::string_view labelView(label);
6256 const bool hasLeadingSpace = !labelView.empty() && labelView.front() ==
' ';
6258 if (m_options.showValue)
6260 if (m_options.customSep)
6262 if (hasLeadingSpace)
6263 labelView.remove_prefix(1);
6264 for (
char ch : m_options.separator)
6270 if (hasLeadingSpace)
6271 labelView.remove_prefix(1);
6274 for (
char ch : labelView)
6288#if defined __has_include
6289#if __has_include(<nlohmann/json.hpp>)
6290#include <nlohmann/json.hpp>
6293 template<
class UnitType>
6294 requires(units::traits::is_unit_v<UnitType>)
6295 void from_json(
const nlohmann::json& j,
UnitType& u)
6297 using underlying =
typename units::traits::unit_traits<UnitType>::underlying_type;
6303 template<
class UnitType>
6304 requires(units::traits::is_unit_v<UnitType>)
6305 void to_json(nlohmann::json& j,
const UnitType& u)
ConversionFactor conversion_factor
Definition core.h:2740
constexpr auto value() const noexcept
Definition core.h:2989
constexpr T to_linearized() const noexcept
linearized unit value
Definition core.h:3046
T value_type
Definition core.h:2739
constexpr unit(const unit< ConversionFactorRhs, Ty, NsRhs > &rhs) noexcept
converting constructor
Definition core.h:2761
constexpr unit< Cf, Ty > convert() const noexcept
Definition core.h:3062
constexpr bool operator!=(const unit< ConversionFactorRhs, Ty, NsRhs > &rhs) const noexcept
Definition core.h:2966
constexpr underlying_type raw() const noexcept
Definition core.h:2977
T _linearized_value
Definition core.h:3179
constexpr unit & operator=(const underlying_type &rhs) noexcept
assignment
Definition core.h:2875
constexpr unit & operator=(const unit &rhs) noexcept=default
constexpr Ty to() const noexcept
Definition core.h:3021
T underlying_type
Definition core.h:2738
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:3865
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:3416
@ base
the SI base-dimension list (" m s^-1"); pairs with a base-converted value.
Definition core.h:3419
@ name
the unit's own full name ("meters", "feet"); base-dimension list if unnamed.
Definition core.h:3418
@ abbreviation
the unit's own abbreviation ("m", "ft"), the default; base-dimension list if unnamed.
Definition core.h:3417
constexpr bool label_uses_base_unit()
Whether a unit's label is its dimension list rather than a named abbreviation.
Definition core.h:3469
std::string dimension_to_string(const dim< D, E > &)
Renders a single dimension term (base dimension + exponent) as text.
Definition core.h:3359
#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:3194
typename detail::prefix< std::ratio< 1152921504606846976 >, Cf >::type exbi
< Represents the type of class Cf with the binary 'pebi' prefix appended.
Definition core.h:2020
typename detail::prefix< std::ratio< 1125899906842624 >, Cf >::type pebi
< Represents the type of class Cf with the binary 'tebi' prefix appended.
Definition core.h:2019
typename detail::prefix< std::ratio< 1073741824 >, Cf >::type gibi
< Represents the type of class Cf with the binary 'mibi' prefix appended.
Definition core.h:2017
typename detail::prefix< std::ratio< 1048576 >, Cf >::type mebi
< Represents the type of class Cf with the binary 'kibi' prefix appended.
Definition core.h:2016
typename detail::prefix< std::ratio< 1099511627776 >, Cf >::type tebi
< Represents the type of class Cf with the binary 'gibi' prefix appended.
Definition core.h:2018
typename detail::prefix< std::ratio< 1024 >, Cf >::type kibi
< Represents the type of class Cf with the metric 'exa' prefix appended.
Definition core.h:2015
typename detail::compound_impl< Cf, Cfs... >::type compound_conversion_factor
Represents a conversion factor made up from other conversion factors.
Definition core.h:1953
constexpr T unit_cast(const Unit &value) noexcept
Casts an unit to an arithmetic type.
Definition core.h:3754
constexpr To convert(const From &value) noexcept
converts a value from an unit to another.
Definition core.h:2345
typename detail::prefix< std::deci, Cf >::type deci
< Represents the type of class Cf with the metric 'centi' prefix appended.
Definition core.h:2000
typename detail::prefix< std::centi, Cf >::type centi
< Represents the type of class Cf with the metric 'milli' prefix appended.
Definition core.h:1999
typename detail::prefix< std::giga, Cf >::type giga
< Represents the type of class Cf with the metric 'mega' prefix appended.
Definition core.h:2005
typename detail::prefix< std::micro, Cf >::type micro
< Represents the type of class Cf with the metric 'nano' prefix appended.
Definition core.h:1997
typename detail::prefix< std::mega, Cf >::type mega
< Represents the type of class Cf with the metric 'kilo' prefix appended.
Definition core.h:2004
typename detail::prefix< std::exa, Cf >::type exa
< Represents the type of class Cf with the metric 'peta' prefix appended.
Definition core.h:2008
typename detail::prefix< std::femto, Cf >::type femto
< Represents the type of class Cf with the metric 'atto' prefix appended.
Definition core.h:1994
typename detail::prefix< std::pico, Cf >::type pico
< Represents the type of class Cf with the metric 'femto' prefix appended.
Definition core.h:1995
typename detail::prefix< std::kilo, Cf >::type kilo
< Represents the type of class Cf with the metric 'hecto' prefix appended.
Definition core.h:2003
typename detail::prefix< std::milli, Cf >::type milli
< Represents the type of class Cf with the metric 'micro' prefix appended.
Definition core.h:1998
typename detail::prefix< std::peta, Cf >::type peta
< Represents the type of class Cf with the metric 'tera' prefix appended.
Definition core.h:2007
typename detail::prefix< std::nano, Cf >::type nano
< Represents the type of class Cf with the metric 'pico' prefix appended.
Definition core.h:1996
typename detail::prefix< std::tera, Cf >::type tera
< Represents the type of class Cf with the metric 'giga' prefix appended.
Definition core.h:2006
typename detail::prefix< std::deca, Cf >::type deca
< Represents the type of class Cf with the metric 'deci' prefix appended.
Definition core.h:2001
typename detail::prefix< std::hecto, Cf >::type hecto
< Represents the type of class Cf with the metric 'deca' prefix appended.
Definition core.h:2002
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:1869
typename detail::sqrt_impl< Cf, Eps >::type square_root
represents the square root of type class U.
Definition core.h:1911
typename detail::cubed_impl< Cf >::type cubed
represents the type of class U cubed.
Definition core.h:1695
typename detail::squared_impl< Cf >::type squared
represents the unit type of class U squared
Definition core.h:1668
typename detail::inverse_impl< Cf >::type inverse
represents the inverse unit type of class U.
Definition core.h:1641
constexpr detail::floating_point_promotion_t< UnitType > trunc(const UnitType x) noexcept
Truncate value.
Definition core.h:5446
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:5278
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > log1p(const UnitType x) noexcept
Compute logarithm plus one.
Definition core.h:5329
constexpr detail::floating_point_promotion_t< std::common_type_t< UnitTypeLhs, UnitTypeRhs > > fmax(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
Maximum value.
Definition core.h:5681
constexpr detail::floating_point_promotion_t< UnitType > fabs(const UnitType x) noexcept
Compute absolute value.
Definition core.h:5716
constexpr detail::floating_point_promotion_t< std::common_type_t< UnitTypeLhs, UnitTypeRhs > > fmin(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
Minimum value.
Definition core.h:5698
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > log2(const UnitType x) noexcept
Compute binary logarithm.
Definition core.h:5343
constexpr detail::floating_point_promotion_t< std::common_type_t< UnitTypeLhs, UnitTypeRhs > > hypot(const UnitTypeLhs &x, const UnitTypeRhs &y)
Computes the square root of the sum-of-squares of x and y.
Definition core.h:5385
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:5752
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > exp(const UnitType x) noexcept
Compute exponential function.
Definition core.h:5232
constexpr detail::floating_point_promotion_t< UnitType > round(const UnitType x) noexcept
Round to nearest.
Definition core.h:5460
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > exp2(const UnitType x) noexcept
Compute binary exponential function.
Definition core.h:5300
constexpr detail::floating_point_promotion_t< Unit > ceil(const Unit x) noexcept
Round up value.
Definition core.h:5403
constexpr detail::floating_point_promotion_t< UnitTypeLhs > copysign(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
Copy sign.
Definition core.h:5639
constexpr detail::floating_point_promotion_t< std::common_type_t< UnitTypeLhs, UnitTypeRhs > > fdim(const UnitTypeLhs x, const UnitTypeRhs y) noexcept
Positive difference.
Definition core.h:5665
constexpr detail::floating_point_promotion_t< Unit > floor(const Unit x) noexcept
Round down value.
Definition core.h:5416
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > log(const UnitType x) noexcept
Compute natural logarithm.
Definition core.h:5247
constexpr detail::floating_point_promotion_t< std::common_type_t< UnitTypeLhs, UnitTypeRhs > > fmod(const UnitTypeLhs numer, const UnitTypeRhs denom) noexcept
Compute remainder of division.
Definition core.h:5431
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > log10(const UnitType x) noexcept
Compute common logarithm.
Definition core.h:5261
constexpr dimensionless< detail::floating_point_promotion_t< typename UnitType::underlying_type > > expm1(const UnitType x) noexcept
Compute exponential minus one.
Definition core.h:5314
#define MSVC_EBO
Describes objects that represent quantities of a given unit.
Definition core.h:2731
constexpr UnitType make_unit(const T value) noexcept
Constructs a unit container from an arithmetic type.
Definition core.h:3335
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:1359
dimension_multiply< pressure, time > dynamic_viscosity
< Represents an SI derived unit of density
Definition core.h:1375
dimension_divide< mass, volume > density
< Represents an SI derived unit of torque
Definition core.h:1374
make_dimension< luminous_intensity, std::ratio< 1 >, length, std::ratio<-2 > > luminance
< Represents an SI derived unit of illuminance
Definition core.h:1358
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:1353
make_dimension< power, std::ratio< 1 >, length, std::ratio<-1 > > spectral_flux
< Represents an SI derived unit of spectral intensity
Definition core.h:1367
dimension_divide< mass, substance > substance_mass
< Represents an SI derived unit of radioactivity
Definition core.h:1360
make_dimension< radiant_intensity, std::ratio< 1 >, area, std::ratio<-1 > > radiance
< Represents an SI derived unit of radiant intensity
Definition core.h:1364
dimension_divide< voltage, current > impedance
< Represents an SI derived unit of capacitance
Definition core.h:1352
dimension_divide< substance, mass > substance_concentration
< Represents an SI derived unit of substance mass
Definition core.h:1361
dimension_divide< energy, time > power
< Represents an SI derived unit of energy
Definition core.h:1349
dimension_multiply< impedance, time > inductance
< Represents an SI derived unit of magnetic flux
Definition core.h:1355
dimension_pow< length, std::ratio< 3 > > volume
< Represents an SI derived unit of area
Definition core.h:1344
dimension_divide< area, time > kinematic_viscosity
< Represents an SI derived unit of dynamic (absolute) viscosity
Definition core.h:1376
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 acceleration
Definition core.h:1342
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:1363
dimension_divide< force, area > pressure
< Represents an SI derived unit of volumetric flow rate
Definition core.h:1346
make_dimension< radiant_intensity, std::ratio< 1 >, length, std::ratio<-1 > > spectral_intensity
< Represents an SI derived unit of irradiance
Definition core.h:1366
dimension_divide< power, current > voltage
< Represents an SI derived unit of power
Definition core.h:1350
dimension_divide< charge, voltage > capacitance
< Represents an SI derived unit of voltage
Definition core.h:1351
dimension_multiply< time, current > charge
< Represents an SI derived unit of pressure
Definition core.h:1347
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:1362
dimension_divide< energy, current > magnetic_flux
< Represents an SI derived unit of conductance
Definition core.h:1354
dimension_multiply< force, length > energy
< Represents an SI derived unit of charge
Definition core.h:1348
make_dimension< power, std::ratio< 1 >, volume, std::ratio<-1 > > spectral_irradiance
< Represents an SI derived unit of spectral intensity
Definition core.h:1369
make_dimension< volume, std::ratio<-1 > > concentration
< Represents an SI derived unit of energy density
Definition core.h:1378
make_dimension< data_tag > data
< Represents a unit of concentration
Definition core.h:1379
dimension_multiply< solid_angle, luminous_intensity > luminous_flux
< Represents an SI derived unit of inductance
Definition core.h:1356
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:1380
dimension_pow< length, std::ratio< 2 > > area
< Represents an SI derived unit of force
Definition core.h:1343
make_dimension< radiant_intensity, std::ratio< 1 >, volume, std::ratio<-1 > > spectral_radiance
< Represents an SI derived unit of spectral flux
Definition core.h:1368
make_dimension< luminous_flux, std::ratio< 1 >, length, std::ratio<-2 > > illuminance
< Represents an SI derived unit of luminous flux
Definition core.h:1357
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:1365
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:1377
make_dimension< length, std::ratio< 1 >, time, std::ratio<-3 > > jerk
< Represents an SI derived unit of spectral irradiance
Definition core.h:1372
dimension_divide< volume, time > volume_flow_rate
< Represents an SI derived unit of volume
Definition core.h:1345
dimension_multiply< force, length > torque
< Represents an SI derived unit of jerk
Definition core.h:1373
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:2058
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:1455
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:2559
Unit Conversion Library namespace.
Definition units.h:106
decibels() -> decibels< double >
Nullary guide so bare default-construction decibels{} / decibels() deduces decibels<default> — again ...
Type representing an arbitrary conversion factor between units.
Definition core.h:1563
numerical scale which is decibel
Definition core.h:5030
static T linearize(const T value) noexcept
linearizes value
Definition core.h:5038
static T scale(const T value) noexcept
returns value in dB
Definition core.h:5056
dimensionless unit with decibel scale
Definition core.h:5070
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:3816
static constexpr T scale(const T value) noexcept
scales value
Definition core.h:3836
static constexpr T linearize(const T value) noexcept
linearizes value
Definition core.h:3824
Tag for unit constructors.
Definition core.h:2217
Trait which tests whether a type is inherited from a decibel scale.
Definition core.h:3790
Trait which tests whether a type is inherited from a linear scale.
Definition core.h:3775
BinaryTypeTrait for querying whether Cf1 and Cf2 are conversion factors to the same dimension.
Definition core.h:2044
BinaryTypeTrait for querying whether U1 and U2 are units of the same dimension.
Definition core.h:2574
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:1501
SFINAE-able trait that maps a conversion_factor to its strengthened type.
Definition core.h:1076