52 template <typename T, typename Enable = std::enable_if_t<std::is_arithmetic<T>::value>>
53 constexpr operator T()
const {
58 template <
typename Rep,
typename Period>
68static constexpr auto ZERO =
Zero{};
71inline constexpr Zero operator+(Zero, Zero) {
return ZERO; }
72inline constexpr Zero operator-(Zero, Zero) {
return ZERO; }
73inline constexpr bool operator==(Zero, Zero) {
return true; }
74inline constexpr bool operator>=(Zero, Zero) {
return true; }
75inline constexpr bool operator<=(Zero, Zero) {
return true; }
76inline constexpr bool operator!=(Zero, Zero) {
return false; }
77inline constexpr bool operator>(Zero, Zero) {
return false; }
78inline constexpr bool operator<(Zero, Zero) {
return false; }
101template <
class B1,
class... Bn>
102struct conjunction<B1, Bn...> : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
109template <
class B1,
class... Bn>
110struct disjunction<B1, Bn...> : std::conditional_t<bool(B1::value), B1, disjunction<Bn...>> {};
119 typedef std::remove_cv_t<std::remove_reference_t<T>> type;
122using remove_cvref_t =
typename remove_cvref<T>::type;
145template <std::
size_t Strlen>
153template <std::
size_t N>
154constexpr StringConstant<N - 1> as_string_constant(
const char (&c_string)[N]) {
157template <std::
size_t N>
158constexpr StringConstant<N> as_string_constant(
const StringConstant<N> &x) {
168template <
typename... Ts>
169constexpr auto concatenate(
const Ts &...ts);
180template <
typename SepT,
typename... StringTs>
181constexpr auto join_by(
const SepT &sep,
const StringTs &...ts);
186template <
bool Enable,
typename StringT>
187constexpr auto parens_if(
const StringT &s);
205 return string_size(-x) + 1;
222 result += values[i + 1u];
227template <std::
size_t Strlen>
238 constexpr const char *c_str()
const {
return data_array_; }
239 constexpr operator const char *()
const {
return c_str(); }
242 constexpr auto char_array()
const ->
const char (&)[Strlen + 1] {
return data_array_; }
245 constexpr std::size_t size()
const {
return Strlen; }
248 constexpr bool empty()
const {
return size() == 0u; }
254 sum<Ns...>() + Strlen * (
sizeof...(items) > 0 ? (
sizeof...(items) - 1) : 0);
255 char result[N + 1]{
'\0'};
256 join_impl(result, items...);
265 constexpr StringConstant(
const char *data, std::index_sequence<Is...>)
266 : data_array_{data[Is]...,
'\0'} {
271 constexpr void join_impl(
char *)
const {}
275 constexpr void join_impl(
char *out_iter,
283 for (
std::size_t i = 0;
static_cast<int>(i) <
static_cast<int>(N); ++i) {
284 *out_iter++ = head.c_str()[i];
288 if (
sizeof...(tail) > 0) {
292 for (
std::size_t i = 0;
static_cast<int>(i) <
static_cast<int>(Strlen); ++i) {
293 *out_iter++ = data_array_[i];
295 join_impl(out_iter, tail...);
300 const char data_array_[Strlen + 1];
303template <std::
size_t Strlen>
306template <
typename... Ts>
307constexpr auto concatenate(
const Ts &...ts) {
308 return join_by(
"", ts...);
311template <
typename SepT,
typename... StringTs>
312constexpr auto join_by(
const SepT &sep,
const StringTs &...ts) {
313 return as_string_constant(sep).join(as_string_constant(ts)...);
319 static constexpr auto print_to_array() {
320 char data[length + 1] = {
'\0'};
330 data[i--] =
'0' +
static_cast<char>(num % 10);
338 static constexpr std::size_t length = string_size(N);
349template <
bool Enable>
364template <
bool Enable,
typename StringT>
365constexpr auto parens_if(
const StringT &s) {
389namespace no_prior_declaration_workaround {
392template <std::
intmax_t N>
393auto root(no_prior_declaration_workaround::Dummy);
394template <std::
intmax_t N>
395auto pow(no_prior_declaration_workaround::Dummy);
399constexpr auto inverse(T x) ->
decltype(
pow<-1>(x)) {
405constexpr auto squared(T x) ->
decltype(pow<2>(x)) {
411constexpr auto cubed(T x) ->
decltype(pow<3>(x)) {
417constexpr auto sqrt(T x) ->
decltype(root<2>(x)) {
423constexpr auto cbrt(T x) ->
decltype(root<3>(x)) {
442 while (factor * factor <= n) {
443 if (n % factor == 0u) {
453constexpr bool is_prime(
std::uintmax_t n) {
return (n > 1) && (find_first_factor(n) == n); }
460 while (n % factor == 0u) {
468constexpr T square(T n) {
481 if (exp % 2u == 1u) {
482 return base * int_pow(base, exp - 1u);
485 return square(int_pow(base, exp / 2u));
498template <
typename T,
typename U,
typename Enable =
void>
500template <
class T,
class U>
501constexpr bool cmp_equal(T t, U u)
noexcept {
506template <
class T,
class U>
507constexpr bool cmp_not_equal(T t, U u)
noexcept {
508 return !cmp_equal(t, u);
514template <
typename T,
typename U,
typename Enable =
void>
516template <
class T,
class U>
517constexpr bool cmp_less(T t, U u)
noexcept {
522template <
class T,
class U>
523constexpr bool cmp_greater(T t, U u)
noexcept {
524 return cmp_less(u, t);
528template <
class T,
class U>
529constexpr bool cmp_less_equal(T t, U u)
noexcept {
530 return !cmp_greater(t, u);
534template <
class T,
class U>
535constexpr bool cmp_greater_equal(T t, U u)
noexcept {
536 return !cmp_less(t, u);
540template <
class R,
class T>
541constexpr bool in_range(T t)
noexcept {
550template <
typename T,
typename U>
551struct CmpEqualImpl<T, U,
std::enable_if_t<std::is_signed<T>::value == std::is_signed<U>::value>> {
552 constexpr bool operator()(T t, U u) {
return t == u; }
555template <
typename T,
typename U>
556struct CmpEqualImpl<T, U,
std::enable_if_t<std::is_signed<T>::value && !std::is_signed<U>::value>> {
557 constexpr bool operator()(T t, U u) {
return t < 0 ? false : std::make_unsigned_t<T>(t) == u; }
560template <
typename T,
typename U>
561struct CmpEqualImpl<T, U,
std::enable_if_t<!std::is_signed<T>::value && std::is_signed<U>::value>> {
562 constexpr bool operator()(T t, U u) {
return u < 0 ? false : t == std::make_unsigned_t<U>(u); }
565template <
typename T,
typename U>
566struct CmpLessImpl<T, U,
std::enable_if_t<std::is_signed<T>::value == std::is_signed<U>::value>> {
567 constexpr bool operator()(T t, U u) {
return t < u; }
570template <
typename T,
typename U>
571struct CmpLessImpl<T, U,
std::enable_if_t<std::is_signed<T>::value && !std::is_signed<U>::value>> {
572 constexpr bool operator()(T t, U u) {
return t < 0 ? true : std::make_unsigned_t<T>(t) < u; }
575template <
typename T,
typename U>
576struct CmpLessImpl<T, U,
std::enable_if_t<!std::is_signed<T>::value && std::is_signed<U>::value>> {
577 constexpr bool operator()(T t, U u) {
return u < 0 ? false : t < std::make_unsigned_t<U>(u); }
587namespace experimental {
595 void operator=(
nonesuch const &) =
delete;
603template <
class Default,
class AlwaysVoid,
template <
class...>
class Op,
class... Args>
606 using type = Default;
609template <
class Default,
template <
class...>
class Op,
class... Args>
610struct detector<Default, stdx::void_t<Op<Args...>>, Op, Args...> {
612 using type = Op<Args...>;
617template <
template <
class...>
class Op,
class... Args>
620template <
template <
class...>
class Op,
class... Args>
623template <
class Default,
template <
class...>
class Op,
class... Args>
626template <
class Default,
template <
class...>
class Op,
class... Args>
627using detected_or_t =
typename detected_or<Default, Op, Args...>::type;
640 constexpr T &&operator()(T &&t)
const noexcept {
641 return std::forward<T>(t);
671 template <
typename T>
672 constexpr bool operator()(
const T &a,
const T &b)
const {
676constexpr auto equal =
Equal{};
679 template <
typename T>
680 constexpr bool operator()(
const T &a,
const T &b)
const {
684constexpr auto not_equal =
NotEqual{};
687 template <
typename T>
688 constexpr bool operator()(
const T &a,
const T &b)
const {
692constexpr auto greater =
Greater{};
695 template <
typename T>
696 constexpr bool operator()(
const T &a,
const T &b)
const {
700constexpr auto less =
Less{};
703 template <
typename T>
704 constexpr bool operator()(
const T &a,
const T &b)
const {
711 template <
typename T>
712 constexpr bool operator()(
const T &a,
const T &b)
const {
723 template <
typename T,
typename U>
724 constexpr auto operator()(
const T &a,
const U &b)
const {
728constexpr auto plus =
Plus{};
731 template <
typename T,
typename U>
732 constexpr auto operator()(
const T &a,
const U &b)
const {
736constexpr auto minus =
Minus{};
746template <
typename PackT,
typename T>
748template <
typename PackT,
typename T>
751template <
typename T,
typename U>
754template <
typename T,
typename U>
755constexpr bool same_type_ignoring_cvref(T, U) {
762template <
template <
typename...>
class Pack,
typename T,
typename... Us>
764 using type = Pack<T, Us...>;
781template <
typename B, std::
intmax_t N>
785template <
typename B, std::
intmax_t N, std::
intmax_t D>
796using BaseT =
typename Base<T>::type;
808template <
template <
class... Ts>
class Pack, typename T>
810template <
template <
class... Ts>
class Pack, typename T>
811using AsPackT =
typename AsPack<Pack, T>::type;
817template <
template <
class... Ts>
class Pack, typename T>
819template <
template <
class... Ts>
class Pack, typename T>
828template <
template <
class...>
class Pack,
typename A,
typename B>
833template <
typename A,
typename B,
template <
class,
class>
class... Orderings>
839template <
typename T,
typename U>
852template <
template <
class...>
class List,
typename... Ts>
854template <
template <
class...>
class List,
typename... Ts>
866template <
template <
class...>
class Pack,
typename... Ts>
868template <
template <
class...>
class Pack,
typename... Ts>
869using PackProductT = detail::SimplifyBasePowersT<
typename PackProduct<Pack, Ts...>::type>;
872template <
template <
class...>
class Pack,
typename T,
typename E>
874template <
template <
class...>
class Pack,
879 detail::SimplifyBasePowersT<typename PackPower<Pack, T, std::ratio<ExpNum, ExpDen>>::type>;
882template <
template <
class...>
class Pack,
typename T>
883using PackInverseT = PackPowerT<Pack, T, -1>;
886template <
template <
class...>
class Pack,
typename T,
typename U>
887using PackQuotientT = PackProductT<Pack, T, PackInverseT<Pack, U>>;
909template <
template <
class...>
class Pack,
typename T>
914template <
template <
class...>
class Pack,
typename T>
922template <
template <
class...>
class Pack,
typename T>
926template <
template <
class...>
class Pack,
typename T>
938template <
typename... BPs>
941template <
typename... BPs>
950using DimMemberT =
typename U::Dim;
954using DimT =
typename DimImpl<U>::type;
960using MagMemberT =
typename U::Mag;
964using MagT =
typename MagImpl<U>::type;
971template <
typename B, std::
intmax_t N>
974 using Dim = PackPowerT<Dimension, AsPackT<Dimension, detail::DimT<B>>, N>;
975 using Mag = PackPowerT<Magnitude, AsPackT<Magnitude, detail::MagT<B>>, N>;
982template <
typename B, std::
intmax_t N, std::
intmax_t D>
985 using Dim = PackPowerT<Dimension, AsPackT<Dimension, detail::DimT<B>>, N, D>;
986 using Mag = PackPowerT<Magnitude, AsPackT<Magnitude, detail::MagT<B>>, N, D>;
992template <
typename T, std::
intmax_t N>
995template <
typename T, std::
intmax_t N, std::
intmax_t D>
1001template <
typename T, std::
intmax_t N>
1004template <
typename T, std::
intmax_t N, std::
intmax_t D>
1010template <
template <
class... Ts>
class Pack, typename... Ts>
1017template <
template <
class... Ts>
class Pack>
1021template <
template <
class... Ts>
class Pack, typename T, typename... Ts>
1029template <
typename A,
typename B>
1035 "Broken strict total ordering: distinct input types compare equal");
1039template <
typename A,
1041 template <
class,
class>
1042 class PrimaryOrdering,
1043 template <
class,
class>
1044 class... Tiebreakers>
1051 (std::is_same<A, B>::value),
1055 std::conditional_t<(PrimaryOrdering<A, B>::value),
1060 std::conditional_t<(PrimaryOrdering<B, A>::value),
1065 LexicographicTotalOrdering<A, B, Tiebreakers...>>>> {
1073template <
typename T,
typename U>
1075template <
template <
class...>
class P,
typename H1,
typename... T1,
typename H2,
typename... T2>
1079template <
typename T,
typename U>
1081template <
template <
class...>
class P,
typename H1,
typename... T1,
typename H2,
typename... T2>
1086template <typename T, typename U>
1087struct TailsInStandardPackOrder;
1088template <template <class...> class P, typename H1, typename... T1, typename H2, typename... T2>
1089struct TailsInStandardPackOrder<P<H1, T1...>, P<H2, T2...>>
1090 : InStandardPackOrder<P<T1...>, P<T2...>> {};
1094template <template <class...> class P, typename... Ts>
1095struct InStandardPackOrder<P<>, P<Ts...>> : stdx::bool_constant<(sizeof...(Ts) > 0)> {};
1098template <
template <
class...>
class P,
typename H,
typename... T>
1102template <
template <
class...>
class P,
typename H1,
typename... T1,
typename H2,
typename... T2>
1106 detail::LeadBasesInOrder,
1107 detail::LeadExpsInOrder,
1108 detail::TailsInStandardPackOrder> {};
1116template <
template <
class...>
class List,
typename... Ts>
1122template <
template <
class...>
class List,
typename... Ts>
1129template <
template <
class...>
class List,
typename T,
typename H,
typename... Ts>
1134 (std::is_same<T, H>::value),
1138 std::conditional_t<(InOrderFor<List, T, H>::value),
1144 detail::PrependT<FlatDedupedTypeListT<List, List<T>, List<Ts...>>, H>>> {
1148template <
template <
class...>
class List,
1157 FlatDedupedTypeListT<List, List<H2>, List<H1, N1, T1...>>,
1163template <
template <
class...>
class List,
typename L1,
typename L2,
typename L3,
typename... Ls>
1171template <
template <
class...>
class Pack>
1175template <
template <
class...>
class Pack,
typename... Ts>
1179template <
template <
class...>
class Pack>
1183template <
template <
class...>
class Pack,
typename T,
typename... Ts>
1187template <
template <
class...>
class Pack,
typename T,
typename... Ts>
1191template <
typename B,
typename E1,
typename E2>
1196template <
typename B,
typename E1,
typename E2>
1201template <
template <
class...>
class P,
typename H1,
typename... T1,
typename H2,
typename... T2>
1206 (InOrderFor<P, BaseT<H1>, BaseT<H2>>::value),
1207 detail::PrependT<PackProductT<P, P<T1...>, P<H2, T2...>>, H1>,
1211 (InOrderFor<P, BaseT<H2>, BaseT<H1>>::value),
1212 detail::PrependT<PackProductT<P, P<T2...>, P<H1, T1...>>, H2>,
1218 (std::ratio_add<ExpT<H1>, ExpT<H2>>::num == 0),
1219 PackProductT<P, P<T1...>, P<T2...>>,
1220 detail::PrependT<PackProductT<P, P<T2...>, P<T1...>>,
1221 detail::ComputeRationalPowerT<BaseT<H1>, ExpT<H1>, ExpT<H2>>>>>> {
1225template <
template <
class...>
class P,
1231 :
PackProduct<P, P<T1s...>, PackProductT<P, P<T2s...>, P<T3s...>, Ps...>> {};
1237template <
typename T,
typename E>
1241template <
template <
class...>
class P,
typename... Ts,
typename E>
1245 P<RatioPow<BaseT<Ts>,
1246 detail::MultiplyExpFor<Ts, E>::num,
1247 detail::MultiplyExpFor<Ts, E>::den>...>> {};
1253template <
template <
class...>
class Pack,
typename T>
1256template <
template <
class...>
class Pack,
typename... Ts>
1260template <
template <
class...>
class Pack,
typename T>
1262 AreBasesInOrder<Pack, T>,
1263 AreAllPowersNonzero<Pack, T>> {};
1268template <
template <
class...>
class Pack>
1271template <
template <
class...>
class Pack,
typename T>
1274template <
template <
class...>
class Pack,
typename T1,
typename T2,
typename... Ts>
1276 :
stdx::conjunction<InOrderFor<Pack, T1, T2>, AreElementsInOrder<Pack, Pack<T2, Ts...>>> {};
1280constexpr bool all_true() {
return true; }
1282template <
typename... Predicates>
1283constexpr bool all_true(Predicates &&...values) {
1285 const bool value_array[] = {values...};
1287 for (
auto i = 0u; i <
sizeof...(Predicates); ++i) {
1288 if (!value_array[i]) {
1300template <
template <
class...>
class Pack,
typename... Ts>
1306template <
template <
class...>
class Pack,
typename... Ts>
1315template <
typename T>
1317template <
typename T>
1318using SimplifyBasePowerT =
typename SimplifyBasePower<T>::type;
1322template <
typename B, std::
intmax_t N>
1327template <
typename B, std::
intmax_t N, std::
intmax_t D>
1329 :
std::conditional<(D == 1), SimplifyBasePowerT<Pow<B, N>>, RatioPow<B, N, D>> {};
1332template <
template <
class...>
class Pack,
typename... BPs>
1340template <
template <
class...>
class Pack>
1343template <
template <
class...>
class Pack,
typename Head,
typename... Tail>
1346 PackProductT<Pack, Pack<Head>, NumeratorPartT<Pack<Tail...>>>,
1347 NumeratorPartT<Pack<Tail...>>> {};
1349template <
template <
class...>
class Pack,
typename... Ts>
1358template <
typename... BPs>
1363 "All powers must be nonzero");
1365 "Bases must be listed in ascending order");
1374template <
typename... BPs>
1375using DimProductT = PackProductT<
Dimension, BPs...>;
1376template <
typename T, std::
intmax_t ExpNum, std::
intmax_t ExpDen = 1>
1377using DimPowerT = PackPowerT<Dimension, T, ExpNum, ExpDen>;
1378template <
typename T,
typename U>
1379using DimQuotientT = PackQuotientT<Dimension, T, U>;
1380template <
typename T>
1381using DimInverseT = PackInverseT<Dimension, T>;
1383template <
typename... BP1s,
typename... BP2s>
1388template <
typename... BP1s,
typename... BP2s>
1389constexpr auto operator/(Dimension<BP1s...>, Dimension<BP2s...>) {
1390 return DimQuotientT<Dimension<BP1s...>, Dimension<BP2s...>>{};
1395constexpr DimPowerT<Dimension<BPs...>, N>
pow(Dimension<BPs...>) {
1399constexpr DimPowerT<Dimension<BPs...>, 1, N> root(Dimension<BPs...>) {
1403template <
typename... Dims>
1405template <
typename... Dims>
1408template <
typename... BaseDims>
1410template <
typename Head,
typename... Tail>
1412 static_assert(
std::is_same<Head, CommonDimensionT<Tail...>>::value,
1413 "Common dimension only defined when all dimensions are identical");
1420 static constexpr int64_t base_dim_index = I;
1425template <
typename T,
typename U>
1428struct Length : BaseDimension<-99> {};
1429struct Mass : BaseDimension<-98> {};
1430struct Time : BaseDimension<-97> {};
1431struct Current : BaseDimension<-96> {};
1432struct Temperature : BaseDimension<-95> {};
1433struct Angle : BaseDimension<-94> {};
1434struct Information : BaseDimension<-93> {};
1435struct AmountOfSubstance : BaseDimension<-92> {};
1436struct LuminousIntensity : BaseDimension<-91> {};
1440template <typename A, typename B>
1441struct InOrderFor<Dimension, A, B>
1442 : LexicographicTotalOrdering<A, B, base_dim::OrderByBaseDimIndex> {};
1447using Length = Dimension<base_dim::Length>;
1448using Mass = Dimension<base_dim::Mass>;
1449using Time = Dimension<base_dim::Time>;
1450using Current = Dimension<base_dim::Current>;
1451using Temperature = Dimension<base_dim::Temperature>;
1452using Angle = Dimension<base_dim::Angle>;
1453using Information = Dimension<base_dim::Information>;
1454using AmountOfSubstance = Dimension<base_dim::AmountOfSubstance>;
1455using LuminousIntensity = Dimension<base_dim::LuminousIntensity>;
1472template <typename... BPs>
1476 static_assert(AreAllPowersNonzero<Magnitude, Magnitude<BPs...>>::value,
1477 "All powers must be nonzero");
1478 static_assert(AreBasesInOrder<Magnitude, Magnitude<BPs...>>::value,
1479 "Bases must be listed in ascending order");
1484 static_assert(IsValidPack<Magnitude, Magnitude<BPs...>>::value, "Ill-formed Magnitude");
1488template <typename... BPs>
1489using MagProductT = PackProductT<Magnitude, BPs...>;
1490template <typename T, std::intmax_t ExpNum, std::intmax_t ExpDen = 1>
1491using MagPowerT = PackPowerT<Magnitude, T, ExpNum, ExpDen>;
1492template <typename T, typename U>
1493using MagQuotientT = PackQuotientT<Magnitude, T, U>;
1494template <typename T>
1495using MagInverseT = PackInverseT<Magnitude, T>;
1498template <std::size_t N>
1499constexpr auto mag();
1502template <std::uintmax_t N>
1504 static_assert(detail::is_prime(N), "Prime<N> requires that N is prime");
1506 static constexpr std::uintmax_t value() { return N; }
1517 static constexpr long double value() { return 3.14159265358979323846264338327950288419716939L; }
1524template <typename T, typename U>
1525struct OrderByValue : stdx::bool_constant<(T::value() < U::value())> {};
1528template <typename A, typename B>
1529struct InOrderFor<Magnitude, A, B> : LexicographicTotalOrdering<A, B, detail::OrderByValue> {};
1534template <typename MagT>
1535struct IntegerPartImpl;
1536template <typename MagT>
1537using IntegerPartT = typename IntegerPartImpl<MagT>::type;
1539template <typename MagT>
1540struct NumeratorImpl;
1541template <typename MagT>
1542using NumeratorT = typename NumeratorImpl<MagT>::type;
1544template <typename MagT>
1545using DenominatorT = NumeratorT<MagInverseT<MagT>>;
1547template <typename MagT>
1549 : std::is_same<MagT,
1550 MagQuotientT<IntegerPartT<NumeratorT<MagT>>, IntegerPartT<DenominatorT<MagT>>>> {
1553template <typename MagT>
1554struct IsInteger : std::is_same<MagT, IntegerPartT<MagT>> {};
1561template <typename... Ms>
1562struct CommonMagnitude;
1563template <typename... Ms>
1564using CommonMagnitudeT = typename CommonMagnitude<Ms...>::type;
1569static constexpr auto ONE = Magnitude<>{};
1570static constexpr auto PI = Magnitude<Pi>{};
1572template <typename... BP1s, typename... BP2s>
1573constexpr auto operator*(Magnitude<BP1s...>, Magnitude<BP2s...>) {
1574 return MagProductT<Magnitude<BP1s...>, Magnitude<BP2s...>>{};
1577template <typename... BP1s, typename... BP2s>
1578constexpr auto operator/(Magnitude<BP1s...>, Magnitude<BP2s...>) {
1579 return MagQuotientT<Magnitude<BP1s...>, Magnitude<BP2s...>>{};
1582template <int E, typename... BPs>
1583constexpr auto pow(Magnitude<BPs...>) {
1584 return MagPowerT<Magnitude<BPs...>, E>{};
1587template <int N, typename... BPs>
1588constexpr auto root(Magnitude<BPs...>) {
1589 return MagPowerT<Magnitude<BPs...>, 1, N>{};
1592template <typename... BP1s, typename... BP2s>
1593constexpr auto operator==(Magnitude<BP1s...>, Magnitude<BP2s...>) {
1594 return std::is_same<Magnitude<BP1s...>, Magnitude<BP2s...>>::value;
1597template <typename... BP1s, typename... BP2s>
1598constexpr auto operator!=(Magnitude<BP1s...> m1, Magnitude<BP2s...> m2) {
1602template <typename... BPs>
1603constexpr auto integer_part(Magnitude<BPs...>) {
1604 return IntegerPartT<Magnitude<BPs...>>{};
1607template <typename... BPs>
1608constexpr auto numerator(Magnitude<BPs...>) {
1609 return NumeratorT<Magnitude<BPs...>>{};
1612template <typename... BPs>
1613constexpr auto denominator(Magnitude<BPs...>) {
1614 return DenominatorT<Magnitude<BPs...>>{};
1617template <typename... BPs>
1618constexpr bool is_rational(Magnitude<BPs...>) {
1619 return IsRational<Magnitude<BPs...>>::value;
1622template <typename... BPs>
1623constexpr bool is_integer(Magnitude<BPs...>) {
1624 return IsInteger<Magnitude<BPs...>>::value;
1630template <typename T, typename... BPs>
1631constexpr T get_value(Magnitude<BPs...>);
1634template <typename... Ms>
1635constexpr auto common_magnitude(Ms...) {
1636 return CommonMagnitudeT<Ms...>{};
1649template <std::uintmax_t N>
1650struct PrimeFactorization;
1651template <std::uintmax_t N>
1652using PrimeFactorizationT = typename PrimeFactorization<N>::type;
1656struct PrimeFactorization<1u> : stdx::type_identity<Magnitude<>> {};
1658template <std::uintmax_t N>
1659struct PrimeFactorization {
1660 static_assert(N > 0, "Can only factor positive integers");
1662 static constexpr std::uintmax_t first_base = find_first_factor(N);
1663 static constexpr std::uintmax_t first_power = multiplicity(first_base, N);
1664 static constexpr std::uintmax_t remainder = N / int_pow(first_base, first_power);
1667 MagProductT<Magnitude<Pow<Prime<first_base>, first_power>>, PrimeFactorizationT<remainder>>;
1672template <std::size_t N>
1673constexpr auto mag() {
1674 return detail::PrimeFactorizationT<N>{};
1680template <typename B, typename P>
1681struct IntegerPartOfBasePower : stdx::type_identity<Magnitude<>> {};
1684template <std::uintmax_t B, std::intmax_t N, std::intmax_t D>
1685struct IntegerPartOfBasePower<Prime<B>, std::ratio<N, D>>
1686 : stdx::type_identity<MagPowerT<Magnitude<Prime<B>>, ((N >= D) ? (N / D) : 0)>> {};
1688template <
typename... BPs>
1691 MagProductT<typename IntegerPartOfBasePower<BaseT<BPs>, ExpT<BPs>>::type...>> {};
1696template <
typename... BPs>
1699 MagProductT<std::conditional_t<(ExpT<BPs>::num > 0), Magnitude<BPs>, Magnitude<>>...>> {};
1706enum class MagRepresentationOutcome {
1708 ERR_NON_INTEGER_IN_INTEGER_TYPE,
1713template <
typename T>
1715 MagRepresentationOutcome outcome;
1724template <
typename T>
1725using Widen = std::conditional_t<
1727 std::conditional_t<std::is_floating_point<T>::value,
1732template <
typename T>
1736 if (exp % 2u == 1u) {
1738 return MagRepresentationOrError<T>{MagRepresentationOutcome::ERR_CANNOT_FIT};
1740 result.value *= base;
1748 : MagRepresentationOrError<T>{MagRepresentationOutcome::ERR_CANNOT_FIT};
1755template <
typename T>
1756constexpr MagRepresentationOrError<T> root(T x,
std::uintmax_t n) {
1759 return {MagRepresentationOutcome::ERR_INVALID_ROOT};
1764 return {MagRepresentationOutcome::OK, x};
1769 return {MagRepresentationOutcome::ERR_NON_INTEGER_IN_INTEGER_TYPE};
1775 return {MagRepresentationOutcome::ERR_INVALID_ROOT};
1777 const auto negative_result = root(-x, n);
1778 if (negative_result.outcome != MagRepresentationOutcome::OK) {
1779 return {negative_result.outcome};
1781 return {MagRepresentationOutcome::OK,
static_cast<T
>(-negative_result.value)};
1786 if (x == 0 || x == 1) {
1787 return {MagRepresentationOutcome::OK, x};
1792 const auto inverse_result = root(T{1} / x, n);
1793 if (inverse_result.outcome != MagRepresentationOutcome::OK) {
1794 return {inverse_result.outcome};
1796 return {MagRepresentationOutcome::OK,
static_cast<T
>(T{1} / inverse_result.value)};
1805 long double lo = 1.0;
1814 long double mid = lo + (
hi - lo) / 2;
1816 auto result = checked_int_pow(mid, n);
1818 if (result.outcome != MagRepresentationOutcome::OK) {
1819 return {result.outcome};
1823 if (result.value == x) {
1824 return {MagRepresentationOutcome::OK,
static_cast<T
>(mid)};
1828 if (mid == lo || mid ==
hi) {
1833 if (result.value < x) {
1841 const auto lo_diff = x - checked_int_pow(lo, n).value;
1842 const auto hi_diff = checked_int_pow(
hi, n).value - x;
1843 return {MagRepresentationOutcome::OK,
static_cast<T
>(lo_diff < hi_diff ? lo :
hi)};
1846template <
typename T, std::
intmax_t N, std::u
intmax_t D,
typename B>
1847constexpr MagRepresentationOrError<Widen<T>> base_power_value(B base) {
1849 const auto inverse_result = base_power_value<T, -N, D>(base);
1850 if (inverse_result.outcome != MagRepresentationOutcome::OK) {
1851 return inverse_result;
1854 MagRepresentationOutcome::OK,
1855 Widen<T>{1} / inverse_result.value,
1859 const auto power_result =
1860 checked_int_pow(
static_cast<Widen<T>
>(base),
static_cast<std::uintmax_t>(N));
1861 if (power_result.outcome != MagRepresentationOutcome::OK) {
1862 return {power_result.outcome};
1864 return (D > 1) ? root(power_result.value, D) : power_result;
1867template <
typename T, std::
size_t N>
1868constexpr MagRepresentationOrError<T> product(
const MagRepresentationOrError<T> (&values)[N]) {
1869 for (
const auto &x : values) {
1870 if (x.outcome != MagRepresentationOutcome::OK) {
1876 for (
const auto &x : values) {
1878 return {MagRepresentationOutcome::ERR_CANNOT_FIT};
1882 return {MagRepresentationOutcome::OK, result};
1885template <std::
size_t N>
1886constexpr bool all(
const bool (&values)[N]) {
1887 for (
const auto &x : values) {
1895template <
typename Target,
typename Enable =
void>
1897 template <
typename T>
1898 constexpr bool operator()(T x) {
1904template <
typename Target>
1906 template <
typename T>
1907 constexpr bool operator()(T x) {
1914template <
typename T,
typename InputT>
1915constexpr bool safe_to_cast_to(InputT x) {
1919template <
typename T,
typename... BPs>
1920constexpr MagRepresentationOrError<T> get_value_result(Magnitude<BPs...>) {
1922 constexpr bool REPRESENTING_NON_INTEGER_IN_INTEGRAL_TYPE =
1923 stdx::conjunction<std::is_integral<T>, stdx::negation<IsInteger<Magnitude<BPs...>>>>::value;
1924 if (REPRESENTING_NON_INTEGER_IN_INTEGRAL_TYPE) {
1925 return {MagRepresentationOutcome::ERR_NON_INTEGER_IN_INTEGER_TYPE};
1929 constexpr auto widened_result =
1930 product({base_power_value<T, ExpT<BPs>::num,
static_cast<std::uintmax_t>(ExpT<BPs>::den)>(
1931 BaseT<BPs>::value())...});
1933 if ((widened_result.outcome != MagRepresentationOutcome::OK) ||
1934 !safe_to_cast_to<T>(widened_result.value)) {
1935 return {MagRepresentationOutcome::ERR_CANNOT_FIT};
1938 return {MagRepresentationOutcome::OK,
static_cast<T
>(widened_result.value)};
1942template <
typename T>
1943constexpr MagRepresentationOrError<T> get_value_result(Magnitude<>) {
1944 return {MagRepresentationOutcome::OK,
static_cast<T
>(1)};
1948template <
typename T,
typename... BPs>
1949constexpr bool representable_in(Magnitude<BPs...> m) {
1950 using namespace detail;
1952 return get_value_result<T>(m).outcome == MagRepresentationOutcome::OK;
1955template <
typename T,
typename... BPs>
1956constexpr T get_value(Magnitude<BPs...> m) {
1957 using namespace detail;
1959 constexpr auto result = get_value_result<T>(m);
1961 static_assert(result.outcome != MagRepresentationOutcome::ERR_NON_INTEGER_IN_INTEGER_TYPE,
1962 "Cannot represent non-integer in integral destination type");
1963 static_assert(result.outcome != MagRepresentationOutcome::ERR_INVALID_ROOT,
1964 "Could not compute root for rational power of base");
1965 static_assert(result.outcome != MagRepresentationOutcome::ERR_CANNOT_FIT,
1966 "Value outside range of destination type");
1968 static_assert(result.outcome == MagRepresentationOutcome::OK,
"Unknown error occurred");
1969 return result.value;
1977template <
typename BP,
typename MagT>
1979template <
typename BP,
typename MagT>
1981template <
typename BP,
typename... Ts>
1983 :
std::conditional<(ExpT<BP>::num < 0), Magnitude<BP, Ts...>, Magnitude<Ts...>> {};
1986template <typename M>
1987using NegativePowers = MagInverseT<DenominatorPartT<M>>;
1991template <typename M>
1992struct CommonMagnitude<M> : stdx::type_identity<M> {};
1996struct CommonMagnitude<Magnitude<>, Magnitude<>> : stdx::type_identity<Magnitude<>> {};
1999template <typename Head, typename... Tail>
2000struct CommonMagnitude<Magnitude<>, Magnitude<Head, Tail...>>
2001 : stdx::type_identity<detail::NegativePowers<Magnitude<Head, Tail...>>> {};
2004template <typename Head, typename... Tail>
2005struct CommonMagnitude<Magnitude<Head, Tail...>, Magnitude<>>
2006 : stdx::type_identity<detail::NegativePowers<Magnitude<Head, Tail...>>> {};
2009template <typename H1, typename... T1, typename H2, typename... T2>
2010struct CommonMagnitude<Magnitude<H1, T1...>, Magnitude<H2, T2...>> :
2014 (InOrderFor<Magnitude, BaseT<H1>, BaseT<H2>>::value),
2015 detail::PrependIfExpNegativeT<H1, CommonMagnitudeT<Magnitude<T1...>, Magnitude<H2, T2...>>>,
2019 (InOrderFor<Magnitude, BaseT<H2>, BaseT<H1>>::value),
2020 detail::PrependIfExpNegativeT<H2,
2021 CommonMagnitudeT<Magnitude<T2...>, Magnitude<H1, T1...>>>,
2027 (std::ratio_subtract<ExpT<H1>, ExpT<H2>>::num < 0),
2028 detail::PrependT<CommonMagnitudeT<Magnitude<T1...>, Magnitude<T2...>>, H1>,
2029 detail::PrependT<CommonMagnitudeT<Magnitude<T1...>, Magnitude<T2...>>, H2>>>> {};
2032template <typename M1, typename M2, typename... Tail>
2033struct CommonMagnitude<M1, M2, Tail...> : CommonMagnitude<M1, CommonMagnitudeT<M2, Tail...>> {};
2036template <typename M>
2037struct CommonMagnitude<M, Zero> : stdx::type_identity<M> {};
2038template <typename M>
2039struct CommonMagnitude<Zero, M> : stdx::type_identity<M> {};
2041struct CommonMagnitude<Zero, Zero> : stdx::type_identity<Zero> {};
2070template <typename T>
2071struct PromotedTypeImpl {
2072 using type = decltype(std::declval<T>() * std::declval<T>());
2074 static_assert(std::is_same<type, typename PromotedTypeImpl<type>::type>::value,
2075 "We explicitly assume that promoted types are not again promotable");
2077template <typename T>
2078using PromotedType = typename PromotedTypeImpl<T>::type;
2087template <typename T, typename U>
2088constexpr T clamp_to_range_of(U x) {
2089 return stdx::cmp_greater(x, std::numeric_limits<T>::max())
2090 ? std::numeric_limits<T>::max()
2091 : (stdx::cmp_less(x, std::numeric_limits<T>::lowest())
2092 ? std::numeric_limits<T>::lowest()
2093 : static_cast<T>(x));
2102template <typename... BPs>
2103constexpr bool is_known_to_be_less_than_one(Magnitude<BPs...> m) {
2104 using MagT = Magnitude<BPs...>;
2105 static_assert(is_rational(m), "Magnitude must be rational");
2107 constexpr auto num_result = get_value_result<std::uintmax_t>(numerator(MagT{}));
2108 static_assert(num_result.outcome == MagRepresentationOutcome::OK,
2109 "Magnitude must be representable in std::uintmax_t");
2111 constexpr auto den_result = get_value_result<std::uintmax_t>(denominator(MagT{}));
2113 den_result.outcome == MagRepresentationOutcome::OK ||
2114 den_result.outcome == MagRepresentationOutcome::ERR_CANNOT_FIT,
2115 "Magnitude must either be representable in std::uintmax_t, or fail due to overflow");
2117 return den_result.outcome == MagRepresentationOutcome::OK ? num_result.value < den_result.value
2135template <typename T, typename MagT, bool IsMagLessThanOne>
2136struct MaxNonOverflowingValueImplWhenNumFits;
2140template <typename T, typename MagT>
2141struct MaxNonOverflowingValueImplWhenNumFits<T, MagT, true> {
2142 using P = PromotedType<T>;
2144 static constexpr T value() {
2145 return clamp_to_range_of<T>(std::numeric_limits<P>::max() /
2146 get_value<P>(numerator(MagT{})));
2153template <typename T, typename MagT>
2154struct MaxNonOverflowingValueImplWhenNumFits<T, MagT, false> {
2155 using P = PromotedType<T>;
2157 static constexpr T value() {
2158 constexpr auto num = get_value<P>(numerator(MagT{}));
2159 constexpr auto den = get_value<P>(denominator(MagT{}));
2160 constexpr auto t_max = std::numeric_limits<T>::max();
2161 constexpr auto p_max = std::numeric_limits<P>::max();
2162 constexpr auto limit_to_avoid = (den > p_max / t_max) ? p_max : t_max * den;
2163 return clamp_to_range_of<T>(limit_to_avoid / num);
2170template <typename T, typename MagT, MagRepresentationOutcome NumOutcome>
2171struct MaxNonOverflowingValueImpl;
2175template <typename T, typename MagT>
2176struct MaxNonOverflowingValueImpl<T, MagT, MagRepresentationOutcome::OK>
2177 : MaxNonOverflowingValueImplWhenNumFits<T, MagT, is_known_to_be_less_than_one(MagT{})> {};
2180template <typename T, typename MagT>
2181struct MaxNonOverflowingValueImpl<T, MagT, MagRepresentationOutcome::ERR_CANNOT_FIT> {
2182 static constexpr T value() { return T{0}; }
2185template <typename T, typename MagT>
2186struct ValidateTypeAndMagnitude {
2187 static_assert(std::is_integral<T>::value, "Only designed for integral types");
2188 static_assert(is_rational(MagT{}), "Magnitude must be rational");
2189 static_assert(!is_integer(MagT{}), "Magnitude must not be purely integral");
2190 static_assert(!is_integer(inverse(MagT{})), "Magnitude must not be purely inverse-integral");
2193template <typename T, typename MagT>
2194struct MaxNonOverflowingValue
2195 : ValidateTypeAndMagnitude<T, MagT>,
2196 MaxNonOverflowingValueImpl<T,
2198 get_value_result<PromotedType<T>>(numerator(MagT{})).outcome> {};
2214template <typename T, typename MagT, bool IsMagLessThanOne>
2215struct MinNonOverflowingValueImplWhenNumFits;
2219template <typename T, typename MagT>
2220struct MinNonOverflowingValueImplWhenNumFits<T, MagT, true> {
2221 using P = PromotedType<T>;
2223 static constexpr T value() {
2224 return clamp_to_range_of<T>(std::numeric_limits<P>::lowest() /
2225 get_value<P>(numerator(MagT{})));
2232template <typename T, typename MagT>
2233struct MinNonOverflowingValueImplWhenNumFits<T, MagT, false> {
2234 using P = PromotedType<T>;
2236 static constexpr T value() {
2237 constexpr auto num = get_value<P>(numerator(MagT{}));
2238 constexpr auto den = get_value<P>(denominator(MagT{}));
2239 constexpr auto t_min = std::numeric_limits<T>::lowest();
2240 constexpr auto p_min = std::numeric_limits<P>::lowest();
2241 constexpr auto limit_to_avoid = (den > p_min / t_min) ? p_min : t_min * den;
2242 return clamp_to_range_of<T>(limit_to_avoid / num);
2249template <typename T, typename MagT, MagRepresentationOutcome NumOutcome>
2250struct MinNonOverflowingValueImpl;
2254template <typename T, typename MagT>
2255struct MinNonOverflowingValueImpl<T, MagT, MagRepresentationOutcome::OK>
2256 : MinNonOverflowingValueImplWhenNumFits<T, MagT, is_known_to_be_less_than_one(MagT{})> {};
2259template <typename T, typename MagT>
2260struct MinNonOverflowingValueImpl<T, MagT, MagRepresentationOutcome::ERR_CANNOT_FIT> {
2261 static constexpr T value() { return T{0}; }
2264template <typename T, typename MagT>
2265struct MinNonOverflowingValue
2266 : ValidateTypeAndMagnitude<T, MagT>,
2267 MinNonOverflowingValueImpl<T,
2269 get_value_result<PromotedType<T>>(numerator(MagT{})).outcome> {
2270 static_assert(std::is_signed<T>::value, "Only designed for signed types");
2271 static_assert(std::is_signed<PromotedType<T>>::value,
2272 "We assume the promoted type is also signed");
2294template <typename D, typename M = Magnitude<>>
2309template <typename Unit>
2313template <typename Unit>
2314constexpr const auto &unit_label(Unit = Unit{});
2319template <typename T = void>
2320struct DefaultUnitLabel {
2321 static constexpr const char value[] = "[UNLABELED UNIT]";
2323template <typename T>
2324constexpr const char DefaultUnitLabel<T>::value[];
2337template <std::size_t ExtensionStrlen, typename... Us>
2338using ExtendedLabel = StringConstant<concatenate(unit_label<Us>()...).size() + ExtensionStrlen>;
2345template <typename T>
2346struct IsUnit : stdx::conjunction<IsValidPack<Dimension, detail::DimT<T>>,
2347 IsValidPack<Magnitude, detail::MagT<T>>> {};
2350template <typename... Us>
2351struct HasSameDimension;
2358template <typename U1, typename U2>
2359struct AreUnitsQuantityEquivalent;
2366template <typename U1, typename U2>
2367struct AreUnitsPointEquivalent;
2370template <typename U>
2371struct IsDimensionless : std::is_same<detail::DimT<U>, Dimension<>> {};
2377template <typename U>
2378struct IsUnitlessUnit
2379 : stdx::conjunction<IsDimensionless<U>, std::is_same<detail::MagT<U>, Magnitude<>>> {};
2384template <typename U1, typename U2>
2385struct UnitRatio : stdx::type_identity<MagQuotientT<detail::MagT<U1>, detail::MagT<U2>>> {
2386 static_assert(HasSameDimension<U1, U2>::value,
2387 "Can only compute ratio of same-dimension units");
2389template <typename U1, typename U2>
2390using UnitRatioT = typename UnitRatio<U1, U2>::type;
2395template <typename U1, typename U2>
2396struct OriginDisplacement;
2398template <typename U>
2399struct AssociatedUnit : stdx::type_identity<U> {};
2400template <typename U>
2401using AssociatedUnitT = typename AssociatedUnit<U>::type;
2415template <typename... Us>
2416struct ComputeCommonUnit;
2417template <typename... Us>
2418using CommonUnitT = typename ComputeCommonUnit<Us...>::type;
2439template <typename... Us>
2440struct ComputeCommonPointUnit;
2441template <typename... Us>
2442using CommonPointUnitT = typename ComputeCommonPointUnit<Us...>::type;
2448template <typename T>
2449constexpr bool is_unit(T) {
2450 return IsUnit<T>::value;
2454template <typename T>
2455constexpr bool fits_in_unit_slot(T) {
2456 return IsUnit<AssociatedUnitT<T>>::value;
2460template <typename... Us>
2461constexpr bool has_same_dimension(Us...) {
2462 return HasSameDimension<AssociatedUnitT<Us>...>::value;
2466template <typename U1, typename U2>
2467constexpr bool are_units_quantity_equivalent(U1, U2) {
2468 return AreUnitsQuantityEquivalent<AssociatedUnitT<U1>, AssociatedUnitT<U2>>::value;
2472template <typename U1, typename U2>
2473constexpr bool are_units_point_equivalent(U1, U2) {
2474 return AreUnitsPointEquivalent<AssociatedUnitT<U1>, AssociatedUnitT<U2>>::value;
2478template <typename U>
2479constexpr bool is_dimensionless(U) {
2480 return IsDimensionless<AssociatedUnitT<U>>::value;
2484template <typename U>
2485constexpr bool is_unitless_unit(U) {
2486 return IsUnitlessUnit<AssociatedUnitT<U>>::value;
2492template <typename U1, typename U2>
2493constexpr UnitRatioT<AssociatedUnitT<U1>, AssociatedUnitT<U2>> unit_ratio(U1, U2) {
2497template <typename U1, typename U2>
2498constexpr auto origin_displacement(U1, U2) {
2499 return OriginDisplacement<AssociatedUnitT<U1>, AssociatedUnitT<U2>>::value();
2502template <typename U>
2503constexpr auto associated_unit(U) {
2504 return AssociatedUnitT<U>{};
2521template <typename Unit, typename ScaleFactor>
2522struct ScaledUnit : Unit {
2523 static_assert(IsValidPack<Magnitude, ScaleFactor>::value,
2524 "Can only scale by a Magnitude<...> type");
2525 using Dim = detail::DimT<Unit>;
2526 using Mag = MagProductT<detail::MagT<Unit>, ScaleFactor>;
2531 static constexpr auto &label = DefaultUnitLabel<void>::value;
2535template <typename... UnitPows>
2537 using Dim = DimProductT<detail::DimT<UnitPows>...>;
2538 using Mag = MagProductT<detail::MagT<UnitPows>...>;
2546template <typename... UnitPows>
2548 UnpackIfSoloT<UnitProduct, PackProductT<UnitProduct, AsPackT<UnitProduct, UnitPows>...>>;
2551template <typename U, std::intmax_t ExpNum, std::intmax_t ExpDen = 1>
2553 UnpackIfSoloT<UnitProduct, PackPowerT<UnitProduct, AsPackT<UnitProduct, U>, ExpNum, ExpDen>>;
2556template <typename U>
2557using UnitInverseT = UnitPowerT<U, -1>;
2560template <typename U1, typename U2>
2561using UnitQuotientT = UnitProductT<U1, UnitInverseT<U2>>;
2567template <typename U, typename = std::enable_if_t<IsUnit<U>::value>, typename... BPs>
2568constexpr ScaledUnit<U, Magnitude<BPs...>> operator*(U, Magnitude<BPs...>) {
2573template <typename U, typename = std::enable_if_t<IsUnit<U>::value>, typename... BPs>
2574constexpr ScaledUnit<U, MagInverseT<Magnitude<BPs...>>> operator/(U, Magnitude<BPs...>) {
2579template <typename U1,
2581 typename = std::enable_if_t<stdx::conjunction<IsUnit<U1>, IsUnit<U2>>::value>>
2582constexpr UnitProductT<U1, U2> operator*(U1, U2) {
2587template <typename U1,
2589 typename = std::enable_if_t<stdx::conjunction<IsUnit<U1>, IsUnit<U2>>::value>>
2590constexpr UnitQuotientT<U1, U2> operator/(U1, U2) {
2595template <std::intmax_t Exp, typename U, typename = std::enable_if_t<IsUnit<U>::value>>
2596constexpr UnitPowerT<U, Exp> pow(U) {
2601template <std::uintmax_t Deg, typename U, typename = std::enable_if_t<IsUnit<U>::value>>
2602constexpr UnitPowerT<U, 1, Deg> root(U) {
2622template <typename Unit>
2623struct SingularNameFor {
2627 template <typename OtherUnit>
2628 constexpr auto operator*(SingularNameFor<OtherUnit>) const {
2629 return SingularNameFor<UnitProductT<Unit, OtherUnit>>{};
2633template <int Exp, typename Unit>
2634constexpr auto pow(SingularNameFor<Unit>) {
2635 return SingularNameFor<UnitPowerT<Unit, Exp>>{};
2648 static constexpr Zero value() { return Zero{}; }
2651template <typename U>
2652using OriginMemberType = decltype(U::origin());
2655template <typename U>
2656struct OriginMember {
2657 static constexpr const OriginMemberType<U> value() { return U::origin(); }
2660template <typename U>
2661struct OriginOf : std::conditional_t<stdx::experimental::is_detected<OriginMemberType, U>::value,
2665template <typename T, typename U>
2666struct ValueDifference {
2667 static constexpr auto value() { return T::value() - U::value(); }
2686template <typename U1, typename U2>
2687struct OriginDisplacement
2688 : std::conditional_t<detail::OriginOf<U1>::value() == detail::OriginOf<U2>::value(),
2690 detail::ValueDifference<detail::OriginOf<U2>, detail::OriginOf<U1>>> {};
2695template <typename U>
2696struct HasSameDimension<U> : std::true_type {};
2698template <typename U1, typename U2, typename... Us>
2699struct HasSameDimension<U1, U2, Us...>
2700 : stdx::conjunction<std::is_same<detail::DimT<U1>, detail::DimT<U2>>,
2701 HasSameDimension<U2, Us...>> {};
2709template <typename U1, typename U2>
2710struct HasSameMagnitude : std::is_same<detail::MagT<U1>, detail::MagT<U2>> {};
2713template <typename U1, typename U2>
2714struct AreUnitsQuantityEquivalent
2715 : stdx::conjunction<HasSameDimension<U1, U2>, detail::HasSameMagnitude<U1, U2>> {};
2721template <typename U1, typename U2>
2722struct HasSameOrigin : stdx::bool_constant<(OriginDisplacement<U1, U2>::value() == ZERO)> {};
2725template <typename U1, typename U2>
2726struct AreUnitsPointEquivalent
2727 : stdx::conjunction<AreUnitsQuantityEquivalent<U1, U2>, detail::HasSameOrigin<U1, U2>> {};
2737template <typename... Us>
2739 static_assert(AreElementsInOrder<CommonUnit, CommonUnit<Us...>>::value,
2740 "Elements must be listed in ascending order");
2741 static_assert(HasSameDimension<Us...>::value,
2742 "Common unit only meaningful if units have same dimension");
2744 using Dim = CommonDimensionT<detail::DimT<Us>...>;
2745 using Mag = CommonMagnitudeT<detail::MagT<Us>...>;
2748template <typename A, typename B>
2749struct InOrderFor<CommonUnit, A, B> : InOrderFor<UnitProduct, A, B> {};
2757template <template <class, class> class Matcher,
2758 typename TargetUnit,
2759 typename UnitList = TargetUnit>
2760struct FirstMatchingUnit;
2763template <template <class, class> class Matcher,
2764 typename TargetUnit,
2767struct FirstMatchingUnit<Matcher, TargetUnit, List<>> : stdx::type_identity<TargetUnit> {};
2770template <template <class, class> class Matcher,
2771 typename TargetUnit,
2776struct FirstMatchingUnit<Matcher, TargetUnit, List<H, Ts...>>
2777 : std::conditional_t<Matcher<TargetUnit, H>::value,
2778 stdx::type_identity<H>,
2779 FirstMatchingUnit<Matcher, TargetUnit, List<Ts...>>> {};
2783template <typename... Us>
2784using ComputeCommonUnitImpl = FlatDedupedTypeListT<CommonUnit, Us...>;
2786template <typename... Us>
2787struct ComputeCommonUnit
2788 : detail::FirstMatchingUnit<AreUnitsQuantityEquivalent, ComputeCommonUnitImpl<Us...>> {};
2803template <typename T>
2804constexpr auto get_value_in_native_unit(const T &t) {
2805 return t.in(T::unit);
2809constexpr auto get_value_in_native_unit(const Zero &) { return 0; }
2814template <typename... Us>
2817template <typename U>
2818struct CommonOrigin<U> : OriginOf<U> {};
2820template <typename Head, typename... Tail>
2821struct CommonOrigin<Head, Tail...> :
2824 (OriginOf<Head>::value() < CommonOrigin<Tail...>::value()),
2829 (OriginOf<Head>::value() > CommonOrigin<Tail...>::value()),
2830 CommonOrigin<Tail...>,
2836 std::conditional_t<(get_value_in_native_unit(OriginOf<Head>::value()) <
2837 get_value_in_native_unit(CommonOrigin<Tail...>::value())),
2839 CommonOrigin<Tail...>>>> {};
2845template <typename QuantityOrZero>
2846struct MagType : stdx::type_identity<MagT<typename QuantityOrZero::Unit>> {};
2847template <typename QuantityOrZero>
2848using MagTypeT = typename MagType<stdx::remove_cvref_t<QuantityOrZero>>::type;
2850struct MagType<Zero> : stdx::type_identity<Zero> {};
2859template <typename... Us>
2860struct CommonPointUnit {
2861 static_assert(AreElementsInOrder<CommonPointUnit, CommonPointUnit<Us...>>::value,
2862 "Elements must be listed in ascending order");
2863 static_assert(HasSameDimension<Us...>::value,
2864 "Common unit only meaningful if units have same dimension");
2869 struct TypeHoldingCommonOrigin {
2870 using OriginT = decltype(detail::CommonOrigin<Us...>::value());
2871 static constexpr OriginT origin() { return detail::CommonOrigin<Us...>::value(); }
2873 static constexpr auto origin() { return TypeHoldingCommonOrigin::origin(); }
2877 using Dim = CommonDimensionT<detail::DimT<Us>...>;
2883 using OriginDisplacementMagnitude = CommonMagnitudeT<
2884 detail::MagTypeT<decltype(OriginDisplacement<TypeHoldingCommonOrigin, Us>::value())>...>;
2888 using Mag = CommonMagnitudeT<detail::MagT<Us>..., OriginDisplacementMagnitude>;
2891template <typename A, typename B>
2892struct InOrderFor<CommonPointUnit, A, B> : InOrderFor<UnitProduct, A, B> {};
2894template <typename... Us>
2895using ComputeCommonPointUnitImpl = FlatDedupedTypeListT<CommonPointUnit, Us...>;
2897template <typename... Us>
2898struct ComputeCommonPointUnit
2899 : detail::FirstMatchingUnit<AreUnitsPointEquivalent, ComputeCommonPointUnitImpl<Us...>> {};
2905template <std::size_t N>
2906constexpr auto as_char_array(const char (&x)[N]) -> const char (&)[N] {
2910template <std::size_t N>
2911constexpr auto as_char_array(const StringConstant<N> &x) -> const char (&)[N + 1] {
2912 return x.char_array();
2915template <
typename Unit>
2916using HasLabel =
decltype(Unit::label);
2919template <
typename T>
2921 static constexpr auto &value = T::label;
2925template <
typename ExpLabel,
typename Unit>
2928 static constexpr LabelT value = join_by(
"^", unit_label<Unit>(), ExpLabel::value());
2930template <
typename ExpLabeler,
typename Unit>
2934template <std::
intmax_t N>
2936 static constexpr auto value() {
return parens_if<(N < 0)>(
IToA<N>::value); }
2940template <std::
intmax_t N, std::
intmax_t D>
2942 static constexpr auto value() {
2947enum class ParensPolicy {
2952template <
typename T, ParensPolicy Policy = ParensPolicy::ADD_IF_MULITPLE>
2954template <
typename... Us, ParensPolicy Policy>
2956 static constexpr auto value() {
2957 constexpr bool add_parens =
2958 (Policy == ParensPolicy::ADD_IF_MULITPLE) && (
sizeof...(Us) > 1);
2959 return parens_if<add_parens>(join_by(
" * ", unit_label<Us>()...));
2966template <
typename N,
typename D,
typename T =
void>
2970 static constexpr LabelT value =
2973template <
typename N,
typename D,
typename T>
2977template <
typename N,
typename T>
2982template <
typename N,
typename T>
2987template <
typename D,
typename T>
2992template <
typename D,
typename T>
2997template <
typename T>
2999 static constexpr const char value[] =
"";
3001template <
typename T>
3006template <
typename Unit>
3008 : std::conditional_t<stdx::experimental::is_detected<detail::HasLabel, Unit>::value,
3009 detail::LabelRef<Unit>,
3010 DefaultUnitLabel<void>> {};
3013template <
typename Unit, std::
intmax_t N>
3017template <
typename Unit, std::
intmax_t N, std::
intmax_t D>
3022template <
typename... Us>
3025 detail::DenominatorPartT<UnitProduct<Us...>>,
3029template <
typename... Us>
3032 static constexpr LabelT value =
3033 detail::concatenate(
"COM[", detail::join_by(
", ", unit_label(Us{})...),
"]");
3035template <
typename... Us>
3039template <
typename... Us>
3042 static constexpr LabelT value =
3043 detail::concatenate(
"COM_PT[", detail::join_by(
", ", unit_label(Us{})...),
"]");
3045template <
typename... Us>
3049template <
typename Unit>
3050constexpr const auto &unit_label(Unit) {
3051 return detail::as_char_array(
UnitLabel<AssociatedUnitT<Unit>>::value);
3060template <
typename A,
typename B>
3063template <
typename A,
typename B>
3069template <
typename A,
typename B>
3073template <
typename... U1s,
typename... U2s>
3077template <
typename A,
typename B>
3085template <typename T>
3086struct UnitAvoidance : std::integral_constant<int, 0> {};
3088template <typename A, typename B>
3089struct OrderByUnitAvoidance
3090 : stdx::bool_constant<(UnitAvoidance<A>::value < UnitAvoidance<B>::value)> {};
3092template <typename... Ts>
3093struct UnitAvoidance<UnitProduct<Ts...>> : std::integral_constant<int, 1> {};
3095template <typename... Ts>
3096struct UnitAvoidance<UnitImpl<Ts...>> : std::integral_constant<int, 2> {};
3098template <typename... Ts>
3099struct UnitAvoidance<ScaledUnit<Ts...>> : std::integral_constant<int, 3> {};
3101template <typename B, std::intmax_t N>
3102struct UnitAvoidance<Pow<B, N>> : std::integral_constant<int, 4> {};
3104template <typename B, std::intmax_t N, std::intmax_t D>
3105struct UnitAvoidance<RatioPow<B, N, D>> : std::integral_constant<int, 5> {};
3107template <typename... Us>
3108struct UnitAvoidance<CommonUnit<Us...>> : std::integral_constant<int, 6> {};
3110template <typename... Us>
3111struct UnitAvoidance<CommonPointUnit<Us...>> : std::integral_constant<int, 7> {};
3114template <typename A, typename B>
3115struct InOrderFor<UnitProduct, A, B> : LexicographicTotalOrdering<A,
3117 detail::OrderByUnitAvoidance,
3120 detail::OrderByOrigin,
3121 detail::OrderAsUnitProduct> {};
3130template <typename Rep, typename... BPs>
3131constexpr bool can_scale_without_overflow(Magnitude<BPs...> m, Rep value) {
3133 if (get_value<double>(m) <= 1.0) {
3137 return std::numeric_limits<Rep>::max() / get_value<Rep>(m) >= value;
3143constexpr auto OVERFLOW_THRESHOLD = 2'147;
3145// This wrapper for `can_scale_without_overflow<...>(..., OVERFLOW_THRESHOLD)` can prevent an
3146// instantiation via short-circuiting, speeding up compile times.
3147template <typename Rep, typename ScaleFactor>
3148struct CanScaleThresholdWithoutOverflow
3149 : stdx::conjunction<
3150 stdx::bool_constant<stdx::in_range<Rep>(OVERFLOW_THRESHOLD)>,
3151 stdx::bool_constant<can_scale_without_overflow<Rep>(ScaleFactor{}, OVERFLOW_THRESHOLD)>> {
3154template <typename U1, typename U2>
3155struct SameDimension : stdx::bool_constant<U1::dim_ == U2::dim_> {};
3157template <typename Rep, typename ScaleFactor, typename SourceRep>
3158struct CoreImplicitConversionPolicyImpl
3159 : stdx::disjunction<
3160 std::is_floating_point<Rep>,
3161 stdx::conjunction<std::is_integral<SourceRep>,
3162 IsInteger<ScaleFactor>,
3163 detail::CanScaleThresholdWithoutOverflow<Rep, ScaleFactor>>> {};
3165// Always permit the identity scaling.
3166template <typename Rep>
3167struct CoreImplicitConversionPolicyImpl<Rep, Magnitude<>, Rep> : std::true_type {};
3169template <typename Rep, typename ScaleFactor, typename SourceRep>
3170using CoreImplicitConversionPolicy = CoreImplicitConversionPolicyImpl<Rep, ScaleFactor, SourceRep>;
3172template <typename Rep, typename ScaleFactor, typename SourceRep>
3173struct PermitAsCarveOutForIntegerPromotion
3174 : stdx::conjunction<std::is_same<ScaleFactor, Magnitude<>>,
3175 std::is_integral<Rep>,
3176 std::is_integral<SourceRep>,
3177 std::is_assignable<Rep &, SourceRep>> {};
3178} // namespace detail
3180template <typename Rep, typename ScaleFactor>
3181struct ImplicitRepPermitted : detail::CoreImplicitConversionPolicy<Rep, ScaleFactor, Rep> {};
3183template <typename Rep, typename SourceUnitSlot, typename TargetUnitSlot>
3184constexpr bool implicit_rep_permitted_from_source_to_target(SourceUnitSlot, TargetUnitSlot) {
3185 using SourceUnit = AssociatedUnitT<SourceUnitSlot>;
3186 using TargetUnit = AssociatedUnitT<TargetUnitSlot>;
3187 static_assert(HasSameDimension<SourceUnit, TargetUnit>::value,
3188 "Can only convert same-dimension units");
3190 return ImplicitRepPermitted<Rep, UnitRatioT<SourceUnit, TargetUnit>>::value;
3193template <typename Unit, typename Rep>
3194struct ConstructionPolicy {
3195 // Note: it's tempting to use the UnitRatioT trait here, but we can't, because it produces a
3196 // hard error for units with different dimensions. This is for good reason: magnitude ratios
3197 // are meaningless unless the dimension is the same. UnitRatioT is the user-facing tool, so we
3198 // build in this hard error for safety. Here, we need a soft error, so we do the dimension
3199 // check manually below.
3200 template <typename SourceUnit>
3201 using ScaleFactor = MagQuotientT<detail::MagT<SourceUnit>, detail::MagT<Unit>>;
3203 template <typename SourceUnit, typename SourceRep>
3204 using PermitImplicitFrom = stdx::conjunction<
3205 HasSameDimension<Unit, SourceUnit>,
3207 detail::CoreImplicitConversionPolicy<Rep, ScaleFactor<SourceUnit>, SourceRep>,
3208 detail::PermitAsCarveOutForIntegerPromotion<Rep, ScaleFactor<SourceUnit>, SourceRep>>>;
3217// The various categories by which a magnitude can be applied to a numeric quantity.
3222 IRRATIONAL_MULTIPLY,
3225template <typename... BPs>
3226constexpr ApplyAs categorize_magnitude(Magnitude<BPs...>) {
3227 if (IsInteger<Magnitude<BPs...>>::value) {
3228 return ApplyAs::INTEGER_MULTIPLY;
3231 if (IsInteger<MagInverseT<Magnitude<BPs...>>>::value) {
3232 return ApplyAs::INTEGER_DIVIDE;
3235 return IsRational<Magnitude<BPs...>>::value ? ApplyAs::RATIONAL_MULTIPLY
3236 : ApplyAs::IRRATIONAL_MULTIPLY;
3239template <typename Mag, ApplyAs Category, typename T, bool is_T_integral>
3240struct ApplyMagnitudeImpl;
3242template <typename T, bool IsMagnitudeValid>
3243struct OverflowChecker {
3244 // Default case: `IsMagnitudeValid` is true.
3245 static constexpr bool would_product_overflow(T x, T mag_value) {
3246 return (x > (std::numeric_limits<T>::max() / mag_value)) ||
3247 (x < (std::numeric_limits<T>::lowest() / mag_value));
3251template <typename T>
3252struct OverflowChecker<T, false> {
3253 // Specialization for when `IsMagnitudeValid` is false.
3255 // This means that the magnitude itself could not fit inside of the type; therefore, the only
3256 // possible value that would not overflow is zero.
3257 static constexpr bool would_product_overflow(T x, T) { return (x != T{0}); }
3260template <typename T, bool IsTIntegral>
3261struct TruncationCheckerIfMagnitudeValid {
3262 // Default case: T is integral.
3263 static_assert(std::is_integral<T>::value && IsTIntegral,
3264 "Mismatched instantiation (should never be done manually)");
3266 static constexpr bool would_truncate(T x, T mag_value) { return (x % mag_value != T{0}); }
3269template <typename T>
3270struct TruncationCheckerIfMagnitudeValid<T, false> {
3271 // Specialization for when T is not integral: by convention, assume no truncation for floats.
3272 static_assert(!std::is_integral<T>::value,
3273 "Mismatched instantiation (should never be done manually)");
3274 static constexpr bool would_truncate(T, T) { return false; }
3277template <typename T, bool IsMagnitudeValid>
3278// Default case: `IsMagnitudeValid` is true.
3279struct TruncationChecker : TruncationCheckerIfMagnitudeValid<T, std::is_integral<T>::value> {
3280 static_assert(IsMagnitudeValid, "Mismatched instantiation (should never be done manually)");
3283template <typename T>
3284struct TruncationChecker<T, false> {
3285 // Specialization for when `IsMagnitudeValid` is false.
3287 // This means that the magnitude itself could not fit inside of the type; therefore, the only
3288 // possible value that would not truncate is zero.
3289 static constexpr bool would_truncate(T x, T) { return (x != T{0}); }
3292// Multiplying by an integer, for any type T.
3293template <typename Mag, typename T, bool is_T_integral>
3294struct ApplyMagnitudeImpl<Mag, ApplyAs::INTEGER_MULTIPLY, T, is_T_integral> {
3295 static_assert(categorize_magnitude(Mag{}) == ApplyAs::INTEGER_MULTIPLY,
3296 "Mismatched instantiation (should never be done manually)");
3297 static_assert(is_T_integral == std::is_integral<T>::value,
3298 "Mismatched instantiation (should never be done manually)");
3300 constexpr T operator()(const T &x) { return x * get_value<T>(Mag{}); }
3302 static constexpr bool would_overflow(const T &x) {
3303 constexpr auto mag_value_result = get_value_result<T>(Mag{});
3304 return OverflowChecker<T, mag_value_result.outcome == MagRepresentationOutcome::OK>::
3305 would_product_overflow(x, mag_value_result.value);
3308 static constexpr bool would_truncate(const T &) { return false; }
3311// Dividing by an integer, for any type T.
3312template <typename Mag, typename T, bool is_T_integral>
3313struct ApplyMagnitudeImpl<Mag, ApplyAs::INTEGER_DIVIDE, T, is_T_integral> {
3314 static_assert(categorize_magnitude(Mag{}) == ApplyAs::INTEGER_DIVIDE,
3315 "Mismatched instantiation (should never be done manually)");
3316 static_assert(is_T_integral == std::is_integral<T>::value,
3317 "Mismatched instantiation (should never be done manually)");
3319 constexpr T operator()(const T &x) { return x / get_value<T>(MagInverseT<Mag>{}); }
3321 static constexpr bool would_overflow(const T &) { return false; }
3323 static constexpr bool would_truncate(const T &x) {
3324 constexpr auto mag_value_result = get_value_result<T>(MagInverseT<Mag>{});
3325 return TruncationChecker<T, mag_value_result.outcome == MagRepresentationOutcome::OK>::
3326 would_truncate(x, mag_value_result.value);
3330template <typename T, typename Mag, bool is_T_signed>
3331struct RationalOverflowChecker;
3332template <typename T, typename Mag>
3333struct RationalOverflowChecker<T, Mag, true> {
3334 static constexpr bool would_overflow(const T &x) {
3335 static_assert(std::is_signed<T>::value,
3336 "Mismatched instantiation (should never be done manually)");
3337 const bool safe = (x <= MaxNonOverflowingValue<T, Mag>::value()) &&
3338 (x >= MinNonOverflowingValue<T, Mag>::value());
3342template <typename T, typename Mag>
3343struct RationalOverflowChecker<T, Mag, false> {
3344 static constexpr bool would_overflow(const T &x) {
3345 static_assert(!std::is_signed<T>::value,
3346 "Mismatched instantiation (should never be done manually)");
3347 const bool safe = (x <= MaxNonOverflowingValue<T, Mag>::value());
3352// Applying a (non-integer, non-inverse-integer) rational, for any integral type T.
3353template <typename Mag, typename T>
3354struct ApplyMagnitudeImpl<Mag, ApplyAs::RATIONAL_MULTIPLY, T, true> {
3355 static_assert(categorize_magnitude(Mag{}) == ApplyAs::RATIONAL_MULTIPLY,
3356 "Mismatched instantiation (should never be done manually)");
3357 static_assert(std::is_integral<T>::value,
3358 "Mismatched instantiation (should never be done manually)");
3360 constexpr T operator()(const T &x) {
3361 using P = PromotedType<T>;
3362 return static_cast<T>(x * get_value<P>(numerator(Mag{})) /
3363 get_value<P>(denominator(Mag{})));
3366 static constexpr bool would_overflow(const T &x) {
3367 return RationalOverflowChecker<T, Mag, std::is_signed<T>::value>::would_overflow(x);
3370 static constexpr bool would_truncate(const T &x) {
3371 constexpr auto mag_value_result = get_value_result<T>(denominator(Mag{}));
3372 return TruncationChecker<T, mag_value_result.outcome == MagRepresentationOutcome::OK>::
3373 would_truncate(x, mag_value_result.value);
3377// Applying a (non-integer, non-inverse-integer) rational, for any non-integral type T.
3378template <typename Mag, typename T>
3379struct ApplyMagnitudeImpl<Mag, ApplyAs::RATIONAL_MULTIPLY, T, false> {
3380 static_assert(categorize_magnitude(Mag{}) == ApplyAs::RATIONAL_MULTIPLY,
3381 "Mismatched instantiation (should never be done manually)");
3382 static_assert(!std::is_integral<T>::value,
3383 "Mismatched instantiation (should never be done manually)");
3385 constexpr T operator()(const T &x) { return x * get_value<T>(Mag{}); }
3387 static constexpr bool would_overflow(const T &x) {
3388 constexpr auto mag_value_result = get_value_result<T>(Mag{});
3389 return OverflowChecker<T, mag_value_result.outcome == MagRepresentationOutcome::OK>::
3390 would_product_overflow(x, mag_value_result.value);
3393 static constexpr bool would_truncate(const T &) { return false; }
3396// Applying an irrational for any type T (although only non-integral T makes sense).
3397template <typename Mag, typename T, bool is_T_integral>
3398struct ApplyMagnitudeImpl<Mag, ApplyAs::IRRATIONAL_MULTIPLY, T, is_T_integral> {
3399 static_assert(!std::is_integral<T>::value, "Cannot apply irrational magnitude to integer type");
3401 static_assert(categorize_magnitude(Mag{}) == ApplyAs::IRRATIONAL_MULTIPLY,
3402 "Mismatched instantiation (should never be done manually)");
3403 static_assert(is_T_integral == std::is_integral<T>::value,
3404 "Mismatched instantiation (should never be done manually)");
3406 constexpr T operator()(const T &x) { return x * get_value<T>(Mag{}); }
3408 static constexpr bool would_overflow(const T &x) {
3409 constexpr auto mag_value_result = get_value_result<T>(Mag{});
3410 return OverflowChecker<T, mag_value_result.outcome == MagRepresentationOutcome::OK>::
3411 would_product_overflow(x, mag_value_result.value);
3414 static constexpr bool would_truncate(const T &) { return false; }
3417template <typename T, typename MagT>
3418struct ApplyMagnitudeType;
3419template <typename T, typename MagT>
3420using ApplyMagnitudeT = typename ApplyMagnitudeType<T, MagT>::type;
3421template <typename T, typename... BPs>
3422struct ApplyMagnitudeType<T, Magnitude<BPs...>>
3423 : stdx::type_identity<ApplyMagnitudeImpl<Magnitude<BPs...>,
3424 categorize_magnitude(Magnitude<BPs...>{}),
3426 std::is_integral<T>::value>> {};
3428template <typename T, typename... BPs>
3429constexpr T apply_magnitude(const T &x, Magnitude<BPs...>) {
3430 return ApplyMagnitudeT<T, Magnitude<BPs...>>{}(x);
3433} // namespace detail
3440template <typename UnitT>
3441struct QuantityMaker;
3443template <typename UnitT, typename RepT>
3447// Make a Quantity of the given Unit, which has this value as measured in the Unit.
3449template <typename UnitT, typename T>
3450constexpr auto make_quantity(T value) {
3451 return QuantityMaker<UnitT>{}(value);
3454template <typename Unit, typename T>
3455constexpr auto make_quantity_unless_unitless(T value) {
3456 return std::conditional_t<IsUnitlessUnit<Unit>::value, stdx::identity, QuantityMaker<Unit>>{}(
3460// Trait to check whether two Quantity types are exactly equivalent.
3462// For purposes of our library, "equivalent" means that they have the same Dimension and Magnitude.
3463template <typename Q1, typename Q2>
3464struct AreQuantityTypesEquivalent;
3466// Trait for a type T which corresponds exactly to some Quantity type.
3468// "Correspondence" with a `Quantity<U, R>` means that T stores a value in a numeric datatype R, and
3469// this value represents a quantity whose unit of measure is quantity-equivalent to U.
3471// The canonical examples are the `duration` types from the `std::chrono::library`. For example,
3472// `std::chrono::duration<double, std::nano>` exactly corresponds to `QuantityD<Nano<Seconds>>`, and
3473// it is always OK to convert back and forth between these types implicitly.
3475// To add support for a type T which is equivalent to Quantity<U, R>, define a specialization of
3476// `CorrespondingQuantity<T>` with a member alias `Unit` for `U`, and `Rep` for `R`. You should
3477// then add static member functions as follows to add support for each direction of conversion.
3478// - For T -> Quantity, define `R extract_value(T)`.
3479// - For Quantity -> T, define `T construct_from_value(R)`.
3480template <typename T>
3481struct CorrespondingQuantity {};
3482template <typename T>
3483using CorrespondingQuantityT =
3484 Quantity<typename CorrespondingQuantity<T>::Unit, typename CorrespondingQuantity<T>::Rep>;
3486// Redirect various cvref-qualified specializations to the "main" specialization.
3488// We use this slightly counterintuitive approach, rather than a more conventional
3489// `remove_cvref_t`-based approach, because the latter causes an _internal compiler error_ on the
3491template <typename T>
3492struct CorrespondingQuantity<const T> : CorrespondingQuantity<T> {};
3493template <typename T>
3494struct CorrespondingQuantity<T &> : CorrespondingQuantity<T> {};
3495template <typename T>
3496struct CorrespondingQuantity<const T &> : CorrespondingQuantity<T> {};
3498// Request conversion of any type to its corresponding Quantity, if there is one.
3500// This is a way to explicitly and readably "enter the au Quantity domain" when we have some
3501// non-au-Quantity type which is nevertheless exactly and unambiguously equivalent to some Quantity.
3503// `as_quantity()` is SFINAE-friendly: we can use it to constrain templates to types `T` which are
3504// exactly equivalent to some Quantity type.
3505template <typename T>
3506constexpr auto as_quantity(T &&x) -> CorrespondingQuantityT<T> {
3507 using Q = CorrespondingQuantity<T>;
3508 static_assert(IsUnit<typename Q::Unit>{}, "No Quantity corresponding to type");
3510 auto value = Q::extract_value(std::forward<T>(x));
3511 static_assert(std::is_same<decltype(value), typename Q::Rep>{},
3512 "Inconsistent CorrespondingQuantity implementation");
3514 return make_quantity<typename Q::Unit>(value);
3517template <typename UnitT, typename RepT>
3519 template <bool ImplicitOk, typename OtherUnit, typename OtherRep>
3520 using EnableIfImplicitOkIs = std::enable_if_t<
3522 ConstructionPolicy<UnitT, RepT>::template PermitImplicitFrom<OtherUnit, OtherRep>::value>;
3527 static constexpr auto unit = Unit{};
3529 // IMPLICIT constructor for another Quantity of the same Dimension.
3530 template <typename OtherUnit,
3532 typename Enable = EnableIfImplicitOkIs<true, OtherUnit, OtherRep>>
3533 constexpr Quantity(Quantity<OtherUnit, OtherRep> other) // NOLINT(runtime/explicit)
3534 : Quantity{other.template as<Rep>(UnitT{})} {}
3536 // EXPLICIT constructor for another Quantity of the same Dimension.
3537 template <typename OtherUnit,
3539 typename Enable = EnableIfImplicitOkIs<false, OtherUnit, OtherRep>,
3540 typename ThisUnusedTemplateParameterDistinguishesUsFromTheAboveConstructor = void>
3541 // Deleted: use `.as<NewRep>(new_unit)` to force a cast.
3542 explicit constexpr Quantity(Quantity<OtherUnit, OtherRep> other) = delete;
3544 // Construct this Quantity with a value of exactly Zero.
3545 constexpr Quantity(Zero) : value_{0} {}
3547 constexpr Quantity() noexcept = default;
3549 // Implicit construction from any exactly-equivalent type.
3552 std::enable_if_t<std::is_convertible<CorrespondingQuantityT<T>, Quantity>::value, int> = 0>
3553 constexpr Quantity(T &&x) : Quantity{as_quantity(std::forward<T>(x))} {}
3555 template <typename NewRep,
3557 typename = std::enable_if_t<IsUnit<AssociatedUnitT<NewUnit>>::value>>
3558 constexpr auto as(NewUnit) const {
3559 using Common = std::common_type_t<Rep, NewRep>;
3560 using Factor = UnitRatioT<AssociatedUnitT<Unit>, AssociatedUnitT<NewUnit>>;
3562 return make_quantity<AssociatedUnitT<NewUnit>>(
3563 static_cast<NewRep>(detail::apply_magnitude(static_cast<Common>(value_), Factor{})));
3566 template <typename NewUnit,
3567 typename = std::enable_if_t<IsUnit<AssociatedUnitT<NewUnit>>::value>>
3568 constexpr auto as(NewUnit u) const {
3569 constexpr bool IMPLICIT_OK =
3570 implicit_rep_permitted_from_source_to_target<Rep>(unit, NewUnit{});
3571 constexpr bool INTEGRAL_REP = std::is_integral<Rep>::value;
3573 IMPLICIT_OK || INTEGRAL_REP,
3574 "Should never occur. In the following static_assert, we assume that IMPLICIT_OK "
3575 "can never fail unless INTEGRAL_REP is true.");
3578 "Dangerous conversion for integer Rep! See: "
3579 "https://aurora-opensource.github.io/au/main/troubleshooting/#dangerous-conversion");
3583 template <typename NewRep,
3585 typename = std::enable_if_t<IsUnit<AssociatedUnitT<NewUnit>>::value>>
3586 constexpr NewRep in(NewUnit u) const {
3587 if (are_units_quantity_equivalent(unit, u) && std::is_same<Rep, NewRep>::value) {
3588 return static_cast<NewRep>(value_);
3590 return as<NewRep>(u).in(u);
3594 template <typename NewUnit,
3595 typename = std::enable_if_t<IsUnit<AssociatedUnitT<NewUnit>>::value>>
3596 constexpr Rep in(NewUnit u) const {
3597 if (are_units_quantity_equivalent(unit, u)) {
3600 // Since Rep was requested _implicitly_, delegate to `.as()` for its safety checks.
3605 // "Old-style" overloads with <U, R> template parameters, and no function parameters.
3607 // Matches the syntax from the CppCon 2021 talk, and legacy Aurora usage.
3608 template <typename U>
3610 "Do not write `.as<YourUnits>()`; write `.as(your_units)` instead.")]] constexpr auto
3611 as() const -> decltype(as(U{})) {
3614 template <typename U, typename R, typename = std::enable_if_t<IsUnit<U>::value>>
3616 "Do not write `.as<YourUnits, T>()`; write `.as<T>(your_units)` instead.")]] constexpr auto
3620 template <typename U>
3622 "Do not write `.in<YourUnits>()`; write `.in(your_units)` instead.")]] constexpr auto
3623 in() const -> decltype(in(U{})) {
3626 template <typename U, typename R, typename = std::enable_if_t<IsUnit<U>::value>>
3628 "Do not write `.in<YourUnits, T>()`; write `.in<T>(your_units)` instead.")]] constexpr auto
3633 // "Forcing" conversions, which explicitly ignore safety checks for overflow and truncation.
3634 template <typename NewUnit>
3635 constexpr auto coerce_as(NewUnit) const {
3636 // Usage example: `q.coerce_as(new_units)`.
3637 return as<Rep>(NewUnit{});
3639 template <typename NewRep, typename NewUnit>
3640 constexpr auto coerce_as(NewUnit) const {
3641 // Usage example: `q.coerce_as<T>(new_units)`.
3642 return as<NewRep>(NewUnit{});
3644 template <typename NewUnit>
3645 constexpr auto coerce_in(NewUnit) const {
3646 // Usage example: `q.coerce_in(new_units)`.
3647 return in<Rep>(NewUnit{});
3649 template <typename NewRep, typename NewUnit>
3650 constexpr auto coerce_in(NewUnit) const {
3651 // Usage example: `q.coerce_in<T>(new_units)`.
3652 return in<NewRep>(NewUnit{});
3655 // Direct access to the underlying value member, with any Quantity-equivalent Unit.
3657 // Mutable access, QuantityMaker input.
3658 template <typename U>
3659 Rep &data_in(const QuantityMaker<U> &) {
3660 static_assert(AreUnitsQuantityEquivalent<U, Unit>::value,
3661 "Can only access value via Quantity-equivalent unit");
3664 // Mutable access, Unit input.
3665 template <typename U>
3666 Rep &data_in(const U &) {
3667 return data_in(QuantityMaker<U>{});
3669 // Const access, QuantityMaker input.
3670 template <typename U>
3671 const Rep &data_in(const QuantityMaker<U> &) const {
3672 static_assert(AreUnitsQuantityEquivalent<U, Unit>::value,
3673 "Can only access value via Quantity-equivalent unit");
3676 // Const access, Unit input.
3677 template <typename U>
3678 const Rep &data_in(const U &) const {
3679 return data_in(QuantityMaker<U>{});
3682 // Permit this factory functor to access our private constructor.
3684 // We allow this because it explicitly names the unit at the callsite, even if people refer to
3685 // this present Quantity type by an alias that omits the unit. This preserves Unit Safety and
3686 // promotes callsite readability.
3687 friend struct QuantityMaker<UnitT>;
3689 // Comparison operators.
3690 friend constexpr bool operator==(Quantity a, Quantity b) { return a.value_ == b.value_; }
3691 friend constexpr bool operator!=(Quantity a, Quantity b) { return a.value_ != b.value_; }
3692 friend constexpr bool operator<(Quantity a, Quantity b) { return a.value_ < b.value_; }
3693 friend constexpr bool operator<=(Quantity a, Quantity b) { return a.value_ <= b.value_; }
3694 friend constexpr bool operator>(Quantity a, Quantity b) { return a.value_ > b.value_; }
3695 friend constexpr bool operator>=(Quantity a, Quantity b) { return a.value_ >= b.value_; }
3697 // Addition and subtraction for like quantities.
3698 friend constexpr Quantity<UnitT, decltype(std::declval<RepT>() + std::declval<RepT>())>
3699 operator+(Quantity a, Quantity b) {
3700 return make_quantity<UnitT>(a.value_ + b.value_);
3702 friend constexpr Quantity<UnitT, decltype(std::declval<RepT>() - std::declval<RepT>())>
3703 operator-(Quantity a, Quantity b) {
3704 return make_quantity<UnitT>(a.value_ - b.value_);
3707 // Scalar multiplication.
3708 template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value>>
3709 friend constexpr auto operator*(Quantity a, T s) {
3710 return make_quantity<UnitT>(a.value_ * s);
3712 template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value>>
3713 friend constexpr auto operator*(T s, Quantity a) {
3714 return make_quantity<UnitT>(s * a.value_);
3718 template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value>>
3719 friend constexpr auto operator/(Quantity a, T s) {
3720 return make_quantity<UnitT>(a.value_ / s);
3722 template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value>>
3723 friend constexpr auto operator/(T s, Quantity a) {
3724 warn_if_integer_division<T>();
3725 return make_quantity<decltype(pow<-1>(unit))>(s / a.value_);
3728 // Multiplication for dimensioned quantities.
3729 template <typename OtherUnit, typename OtherRep>
3730 constexpr auto operator*(Quantity<OtherUnit, OtherRep> q) const {
3731 return make_quantity_unless_unitless<UnitProductT<Unit, OtherUnit>>(value_ *
3735 // Division for dimensioned quantities.
3736 template <typename OtherUnit, typename OtherRep>
3737 constexpr auto operator/(Quantity<OtherUnit, OtherRep> q) const {
3738 warn_if_integer_division<OtherRep>();
3739 return make_quantity_unless_unitless<UnitQuotientT<Unit, OtherUnit>>(value_ /
3743 // Short-hand addition and subtraction assignment.
3744 constexpr Quantity &operator+=(Quantity other) {
3745 value_ += other.value_;
3748 constexpr Quantity &operator-=(Quantity other) {
3749 value_ -= other.value_;
3753 // Short-hand multiplication assignment.
3754 template <typename T>
3755 constexpr Quantity &operator*=(T s) {
3757 std::is_arithmetic<T>::value,
3758 "This overload is only for scalar multiplication-assignment with arithmetic types");
3761 std::is_floating_point<Rep>::value || std::is_integral<T>::value,
3762 "We don't support compound multiplication of integral types by floating point");
3768 // Short-hand division assignment.
3769 template <typename T>
3770 constexpr Quantity &operator/=(T s) {
3771 static_assert(std::is_arithmetic<T>::value,
3772 "This overload is only for scalar division-assignment with arithmetic types");
3774 static_assert(std::is_floating_point<Rep>::value || std::is_integral<T>::value,
3775 "We don't support compound division of integral types by floating point");
3781 // Unary plus and minus.
3782 constexpr Quantity operator+() const { return {+value_}; }
3783 constexpr Quantity operator-() const { return {-value_}; }
3785 // Automatic conversion to Rep for Unitless type.
3786 template <typename U = UnitT, typename = std::enable_if_t<IsUnitlessUnit<U>::value>>
3787 constexpr operator Rep() const {
3791 // Automatic conversion to any equivalent type that supports it.
3794 std::enable_if_t<std::is_convertible<Quantity, CorrespondingQuantityT<T>>::value, int> = 0>
3795 constexpr operator T() const {
3796 return CorrespondingQuantity<T>::construct_from_value(
3797 CorrespondingQuantityT<T>{*this}.in(typename CorrespondingQuantity<T>::Unit{}));
3801 template <typename OtherRep>
3802 static constexpr void warn_if_integer_division() {
3803 constexpr bool uses_integer_division =
3804 (std::is_integral<Rep>::value && std::is_integral<OtherRep>::value);
3805 static_assert(!uses_integer_division,
3806 "Integer division forbidden: use integer_quotient() if you really want it");
3809 constexpr Quantity(Rep value) : value_{value} {}
3814// Force integer division beteween two integer Quantities, in a callsite-obvious way.
3815template <typename U1, typename R1, typename U2, typename R2>
3816constexpr auto integer_quotient(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
3817 static_assert(std::is_integral<R1>::value && std::is_integral<R2>::value,
3818 "integer_quotient() can only be called with integral Rep");
3819 return make_quantity<UnitQuotientT<U1, U2>>(q1.in(U1{}) / q2.in(U2{}));
3822// Force integer division beteween an integer Quantity and a raw number.
3823template <typename U, typename R, typename T>
3824constexpr auto integer_quotient(Quantity<U, R> q, T x) {
3825 static_assert(std::is_integral<R>::value && std::is_integral<T>::value,
3826 "integer_quotient() can only be called with integral Rep");
3827 return make_quantity<U>(q.in(U{}) / x);
3830// Force integer division beteween a raw number and an integer Quantity.
3831template <typename T, typename U, typename R>
3832constexpr auto integer_quotient(T x, Quantity<U, R> q) {
3833 static_assert(std::is_integral<T>::value && std::is_integral<R>::value,
3834 "integer_quotient() can only be called with integral Rep");
3835 return make_quantity<UnitInverseT<U>>(x / q.in(U{}));
3838// The modulo operator (i.e., the remainder of an integer division).
3840// Only defined whenever (R1{} % R2{}) is defined (i.e., for integral Reps), _and_
3841// `CommonUnitT<U1, U2>` is also defined. We convert to that common unit to perform the operation.
3842template <typename U1, typename R1, typename U2, typename R2>
3843constexpr auto operator%(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
3844 using U = CommonUnitT<U1, U2>;
3845 return make_quantity<U>(q1.in(U{}) % q2.in(U{}));
3848// Type trait to detect whether two Quantity types are equivalent.
3850// In this library, Quantity types are "equivalent" exactly when they use the same Rep, and are
3851// based on equivalent units.
3852template <typename U1, typename U2, typename R1, typename R2>
3853struct AreQuantityTypesEquivalent<Quantity<U1, R1>, Quantity<U2, R2>>
3854 : stdx::conjunction<std::is_same<R1, R2>, AreUnitsQuantityEquivalent<U1, U2>> {};
3856// Cast Quantity to a different underlying type.
3857template <typename NewRep, typename Unit, typename Rep>
3858constexpr auto rep_cast(Quantity<Unit, Rep> q) {
3859 return q.template as<NewRep>(Unit{});
3862// Help Zero act more faithfully like a Quantity.
3864// Casting Zero to any "Rep" is trivial, because it has no Rep, and is already consistent with all.
3865template <typename NewRep>
3866constexpr auto rep_cast(Zero z) {
3871// Quantity aliases to set a particular Rep.
3873// This presents a less cumbersome interface for end users.
3875template <typename UnitT>
3876using QuantityD = Quantity<UnitT, double>;
3877template <typename UnitT>
3878using QuantityF = Quantity<UnitT, float>;
3879template <typename UnitT>
3880using QuantityI = Quantity<UnitT, int>;
3881template <typename UnitT>
3882using QuantityU = Quantity<UnitT, unsigned int>;
3883template <typename UnitT>
3884using QuantityI32 = Quantity<UnitT, int32_t>;
3885template <typename UnitT>
3886using QuantityU32 = Quantity<UnitT, uint32_t>;
3887template <typename UnitT>
3888using QuantityI64 = Quantity<UnitT, int64_t>;
3889template <typename UnitT>
3890using QuantityU64 = Quantity<UnitT, uint64_t>;
3892template <typename UnitT>
3893struct QuantityMaker {
3895 static constexpr auto unit = Unit{};
3897 template <typename T>
3898 constexpr Quantity<Unit, T> operator()(T value) const {
3902 template <typename... BPs>
3903 constexpr auto operator*(Magnitude<BPs...> m) const {
3904 return QuantityMaker<decltype(unit * m)>{};
3907 template <typename... BPs>
3908 constexpr auto operator/(Magnitude<BPs...> m) const {
3909 return QuantityMaker<decltype(unit / m)>{};
3912 template <typename DivisorUnit>
3913 constexpr auto operator/(SingularNameFor<DivisorUnit>) const {
3914 return QuantityMaker<UnitQuotientT<Unit, DivisorUnit>>{};
3917 template <typename MultiplierUnit>
3918 friend constexpr auto operator*(SingularNameFor<MultiplierUnit>, QuantityMaker) {
3919 return QuantityMaker<UnitProductT<MultiplierUnit, Unit>>{};
3922 template <typename OtherUnit>
3923 constexpr auto operator*(QuantityMaker<OtherUnit>) const {
3924 return QuantityMaker<UnitProductT<Unit, OtherUnit>>{};
3927 template <typename OtherUnit>
3928 constexpr auto operator/(QuantityMaker<OtherUnit>) const {
3929 return QuantityMaker<UnitQuotientT<Unit, OtherUnit>>{};
3933template <typename U>
3934struct AssociatedUnit<QuantityMaker<U>> : stdx::type_identity<U> {};
3936template <int Exp, typename Unit>
3937constexpr auto pow(QuantityMaker<Unit>) {
3938 return QuantityMaker<UnitPowerT<Unit, Exp>>{};
3941template <int N, typename Unit>
3942constexpr auto root(QuantityMaker<Unit>) {
3943 return QuantityMaker<UnitPowerT<Unit, 1, N>>{};
3947// Runtime conversion checkers
3949// Check conversion for overflow (no change of rep).
3950template <typename U, typename R, typename TargetUnitSlot>
3951constexpr bool will_conversion_overflow(Quantity<U, R> q, TargetUnitSlot target_unit) {
3952 return detail::ApplyMagnitudeT<R, decltype(unit_ratio(U{}, target_unit))>::would_overflow(
3956// Check conversion for truncation (no change of rep).
3957template <typename U, typename R, typename TargetUnitSlot>
3958constexpr bool will_conversion_truncate(Quantity<U, R> q, TargetUnitSlot target_unit) {
3959 return detail::ApplyMagnitudeT<R, decltype(unit_ratio(U{}, target_unit))>::would_truncate(
3963// Check for any lossiness in conversion (no change of rep).
3964template <typename U, typename R, typename TargetUnitSlot>
3965constexpr bool is_conversion_lossy(Quantity<U, R> q, TargetUnitSlot target_unit) {
3966 return will_conversion_truncate(q, target_unit) || will_conversion_overflow(q, target_unit);
3970// Comparing and/or combining Quantities of different types.
3973// Helper to cast this Quantity to its common type with some other Quantity (explicitly supplied).
3975// Note that `TargetUnit` is supposed to be the common type of the input Quantity and some other
3976// Quantity. This function should never be called directly; it should only be called by
3977// `using_common_type()`. The program behaviour is undefined if anyone calls this function
3978// directly. (In particular, we explicitly assume that the conversion to the Rep of TargetUnit is
3979// not narrowing for the input Quantity.)
3981// We would have liked this to just be a simple lambda, but some old compilers sometimes struggle
3982// with understanding that the lambda implementation of this can be constexpr.
3983template <typename TargetUnit, typename U, typename R>
3984constexpr auto cast_to_common_type(Quantity<U, R> q) {
3985 // When we perform a unit conversion to U, we need to make sure the library permits this
3986 // conversion *implicitly* for a rep R. The form `rep_cast<R>(q).as(U{})` achieves
3987 // this. First, we cast the Rep to R (which will typically be the wider of the input Reps).
3988 // Then, we use the *unit-only* form of the conversion operator: `as(U{})`, not
3989 // `as<R>(U{})`, because only the former actually checks the conversion policy.
3990 return rep_cast<typename TargetUnit::Rep>(q).as(TargetUnit::unit);
3993template <typename T, typename U, typename Func>
3994constexpr auto using_common_type(T t, U u, Func f) {
3995 using C = std::common_type_t<T, U>;
3997 std::is_same<typename C::Rep, std::common_type_t<typename T::Rep, typename U::Rep>>::value,
3998 "Rep of common type is not common type of Reps (this should never occur)");
4000 return f(cast_to_common_type<C>(t), cast_to_common_type<C>(u));
4002} // namespace detail
4004// Comparison functions for compatible Quantity types.
4005template <typename U1, typename U2, typename R1, typename R2>
4006constexpr bool operator==(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
4007 return detail::using_common_type(q1, q2, detail::equal);
4009template <typename U1, typename U2, typename R1, typename R2>
4010constexpr bool operator!=(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
4011 return detail::using_common_type(q1, q2, detail::not_equal);
4013template <typename U1, typename U2, typename R1, typename R2>
4014constexpr bool operator<(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
4015 return detail::using_common_type(q1, q2, detail::less);
4017template <typename U1, typename U2, typename R1, typename R2>
4018constexpr bool operator<=(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
4019 return detail::using_common_type(q1, q2, detail::less_equal);
4021template <typename U1, typename U2, typename R1, typename R2>
4022constexpr bool operator>(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
4023 return detail::using_common_type(q1, q2, detail::greater);
4025template <typename U1, typename U2, typename R1, typename R2>
4026constexpr bool operator>=(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
4027 return detail::using_common_type(q1, q2, detail::greater_equal);
4030// Addition and subtraction functions for compatible Quantity types.
4031template <typename U1, typename U2, typename R1, typename R2>
4032constexpr auto operator+(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
4033 return detail::using_common_type(q1, q2, detail::plus);
4035template <typename U1, typename U2, typename R1, typename R2>
4036constexpr auto operator-(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
4037 return detail::using_common_type(q1, q2, detail::minus);
4040// Mixed-type operations with a left-Quantity, and right-Quantity-equivalent.
4041template <typename U, typename R, typename QLike>
4042constexpr auto operator+(Quantity<U, R> q1, QLike q2) -> decltype(q1 + as_quantity(q2)) {
4043 return q1 + as_quantity(q2);
4045template <typename U, typename R, typename QLike>
4046constexpr auto operator-(Quantity<U, R> q1, QLike q2) -> decltype(q1 - as_quantity(q2)) {
4047 return q1 - as_quantity(q2);
4049template <typename U, typename R, typename QLike>
4050constexpr auto operator==(Quantity<U, R> q1, QLike q2) -> decltype(q1 == as_quantity(q2)) {
4051 return q1 == as_quantity(q2);
4053template <typename U, typename R, typename QLike>
4054constexpr auto operator!=(Quantity<U, R> q1, QLike q2) -> decltype(q1 != as_quantity(q2)) {
4055 return q1 != as_quantity(q2);
4057template <typename U, typename R, typename QLike>
4058constexpr auto operator<(Quantity<U, R> q1, QLike q2) -> decltype(q1 < as_quantity(q2)) {
4059 return q1 < as_quantity(q2);
4061template <typename U, typename R, typename QLike>
4062constexpr auto operator<=(Quantity<U, R> q1, QLike q2) -> decltype(q1 <= as_quantity(q2)) {
4063 return q1 <= as_quantity(q2);
4065template <typename U, typename R, typename QLike>
4066constexpr auto operator>(Quantity<U, R> q1, QLike q2) -> decltype(q1 > as_quantity(q2)) {
4067 return q1 > as_quantity(q2);
4069template <typename U, typename R, typename QLike>
4070constexpr auto operator>=(Quantity<U, R> q1, QLike q2) -> decltype(q1 >= as_quantity(q2)) {
4071 return q1 >= as_quantity(q2);
4074// Mixed-type operations with a left-Quantity-equivalent, and right-Quantity.
4075template <typename U, typename R, typename QLike>
4076constexpr auto operator+(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) + q2) {
4077 return as_quantity(q1) + q2;
4079template <typename U, typename R, typename QLike>
4080constexpr auto operator-(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) - q2) {
4081 return as_quantity(q1) - q2;
4083template <typename U, typename R, typename QLike>
4084constexpr auto operator==(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) == q2) {
4085 return as_quantity(q1) == q2;
4087template <typename U, typename R, typename QLike>
4088constexpr auto operator!=(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) != q2) {
4089 return as_quantity(q1) != q2;
4091template <typename U, typename R, typename QLike>
4092constexpr auto operator<(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) < q2) {
4093 return as_quantity(q1) < q2;
4095template <typename U, typename R, typename QLike>
4096constexpr auto operator<=(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) <= q2) {
4097 return as_quantity(q1) <= q2;
4099template <typename U, typename R, typename QLike>
4100constexpr auto operator>(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) > q2) {
4101 return as_quantity(q1) > q2;
4103template <typename U, typename R, typename QLike>
4104constexpr auto operator>=(QLike q1, Quantity<U, R> q2) -> decltype(as_quantity(q1) >= q2) {
4105 return as_quantity(q1) >= q2;
4108// Helper to compute the `std::common_type_t` of two `Quantity` types.
4110// `std::common_type` requires its specializations to be SFINAE-friendly, meaning that the `type`
4111// member should not exist for specializations with no common type. Unfortunately, we can't
4115template <typename Q1, typename Q2, typename Enable = void>
4116struct CommonQuantity {};
4117template <typename U1, typename U2, typename R1, typename R2>
4118struct CommonQuantity<Quantity<U1, R1>,
4120 std::enable_if_t<HasSameDimension<U1, U2>::value>>
4121 : stdx::type_identity<Quantity<CommonUnitT<U1, U2>, std::common_type_t<R1, R2>>> {};
4130template <typename U1, typename U2, typename R1, typename R2>
4131struct common_type<au::Quantity<U1, R1>, au::Quantity<U2, R2>>
4132 : au::CommonQuantity<au::Quantity<U1, R1>, au::Quantity<U2, R2>> {};
4162struct NoTypeMember {};
4163template <typename T>
4164struct TypeIdentityIfLooksLikeValidRep
4165 : std::conditional_t<std::is_arithmetic<T>::value, stdx::type_identity<T>, NoTypeMember> {};
4166template <typename T>
4167using TypeIdentityIfLooksLikeValidRepT = typename TypeIdentityIfLooksLikeValidRep<T>::type;
4172template <template <typename U> class UnitWrapper, typename Unit>
4173struct MakesQuantityFromNumber {
4175 template <typename T>
4176 friend constexpr auto operator*(T x, UnitWrapper<Unit>)
4177 -> Quantity<Unit, TypeIdentityIfLooksLikeValidRepT<T>> {
4178 return make_quantity<Unit>(x);
4182 template <typename T>
4183 friend constexpr auto operator*(UnitWrapper<Unit>, T x)
4184 ->
Quantity<Unit, TypeIdentityIfLooksLikeValidRepT<T>> {
4185 return make_quantity<Unit>(x);
4189 template <
typename T>
4190 friend constexpr auto operator/(T x, UnitWrapper<Unit>)
4192 return make_quantity<UnitInverseT<Unit>>(x);
4196 template <
typename T>
4197 friend constexpr auto operator/(UnitWrapper<Unit>, T x)
4200 "Dividing by an integer value disallowed: would almost always produce 0");
4201 return make_quantity<Unit>(T{1} / x);
4208template <
template <
typename U>
class UnitWrapper,
typename Unit>
4211 template <
typename U,
typename R>
4212 friend constexpr auto operator*(UnitWrapper<Unit>,
Quantity<U, R> q) {
4213 return make_quantity<UnitProductT<Unit, U>>(q.in(U{}));
4217 template <
typename U,
typename R>
4218 friend constexpr auto operator*(
Quantity<U, R> q, UnitWrapper<Unit>) {
4219 return make_quantity<UnitProductT<U, Unit>>(q.in(U{}));
4223 template <
typename U,
typename R>
4224 friend constexpr auto operator/(
Quantity<U, R> q, UnitWrapper<Unit>) {
4225 return make_quantity<UnitQuotientT<U, Unit>>(q.in(U{}));
4229 template <
typename U,
typename R>
4230 friend constexpr auto operator/(UnitWrapper<Unit>,
Quantity<U, R> q) {
4232 "Dividing by an integer value disallowed: would almost always produce 0");
4233 return make_quantity<UnitQuotientT<Unit, U>>(R{1} / q.in(U{}));
4239template <
template <
typename U>
class UnitWrapper,
4241 template <
typename U>
4243 template <
typename U>
4244 class ResultWrapper>
4247 template <
typename U>
4248 friend constexpr ResultWrapper<UnitProductT<Unit, U>> operator*(UnitWrapper<Unit>,
4254 template <
typename U>
4255 friend constexpr ResultWrapper<UnitQuotientT<Unit, U>> operator/(UnitWrapper<Unit>,
4263template <
template <
typename U>
class UnitWrapper,
4265 template <
typename U>
4267 template <
typename U>
4268 class ResultWrapper>
4271 template <
typename U>
4272 friend constexpr ResultWrapper<UnitProductT<U, Unit>> operator*(OtherWrapper<U>,
4273 UnitWrapper<Unit>) {
4278 template <
typename U>
4279 friend constexpr ResultWrapper<UnitQuotientT<U, Unit>> operator/(OtherWrapper<U>,
4280 UnitWrapper<Unit>) {
4288template <
template <
typename U>
class UnitWrapper,
4290 template <
typename U>
4291 class ResultWrapper>
4297template <
template <
typename U>
class UnitWrapper,
4299 template <
typename U>
4301 template <
typename U>
4302 class ResultWrapper>
4309template <
template <
typename U>
class UnitWrapper,
typename Unit>
4312 template <
typename... BPs>
4314 return UnitWrapper<
decltype(Unit{} * m)>{};
4318 template <
typename... BPs>
4320 return UnitWrapper<
decltype(Unit{} * m)>{};
4324 template <
typename... BPs>
4326 return UnitWrapper<
decltype(UnitInverseT<Unit>{} * m)>{};
4330 template <
typename... BPs>
4332 return UnitWrapper<
decltype(Unit{} / m)>{};
4355template <
typename UnitT,
typename RepT>
4358template <
typename UnitT>
4359struct QuantityPointMaker;
4362template <
typename UnitT,
typename T>
4363constexpr auto make_quantity_point(T value) {
4364 return QuantityPointMaker<UnitT>{}(value);
4368template <
typename P1,
typename P2>
4372template <
typename TargetRep,
typename U1,
typename U2>
4373struct OriginDisplacementFitsIn;
4377template <
typename UnitT,
typename RepT>
4393 template <
typename OtherUnit,
typename OtherRep>
4394 static constexpr bool should_enable_implicit_construction_from() {
4396 decltype(std::declval<typename QuantityPoint<OtherUnit, OtherRep>::Diff>() +
4397 origin_displacement(UnitT{}, OtherUnit{})),
4404 template <
bool ImplicitOk,
typename OtherUnit,
typename OtherRep>
4405 using EnableIfImplicitOkIs = std::enable_if_t<
4407 QuantityPoint::should_enable_implicit_construction_from<OtherUnit, OtherRep>()>;
4412 static constexpr Unit unit{};
4421 template <
typename OtherUnit,
4423 typename Enable = EnableIfImplicitOkIs<true, OtherUnit, OtherRep>>
4427 template <
typename OtherUnit,
4429 typename Enable = EnableIfImplicitOkIs<false, OtherUnit, OtherRep>,
4430 typename ThisUnusedTemplateParameterDistinguishesUsFromTheAboveConstructor =
void>
4438 template <
typename NewRep,
4440 typename = std::enable_if_t<IsUnit<NewUnit>::value>>
4441 constexpr auto as(NewUnit u)
const {
4442 return make_quantity_point<NewUnit>(this->
template in<NewRep>(u));
4445 template <typename NewUnit, typename = std::enable_if_t<IsUnit<NewUnit>::value>>
4446 constexpr auto as(NewUnit u)
const {
4447 return make_quantity_point<NewUnit>(in(u));
4450 template <
typename NewRep,
4452 typename = std::enable_if_t<IsUnit<NewUnit>::value>>
4453 constexpr NewRep in(NewUnit u)
const {
4455 .template in<NewRep>(u);
4458 template <typename NewUnit, typename = std::enable_if_t<IsUnit<NewUnit>::value>>
4459 constexpr Rep in(NewUnit u)
const {
4461 "Cannot represent origin displacement in desired Rep");
4472 template <
typename NewRep,
typename NewUnit>
4474 return as<NewRep>(NewUnit{});
4476 template <
typename NewUnit>
4478 return as(NewUnit{});
4480 template <
typename NewRep,
typename NewUnit>
4482 return in<NewRep>(NewUnit{});
4484 template <
typename NewUnit>
4486 return in(NewUnit{});
4492 template <
typename U>
4494 "Do not write `.as<YourUnits>()`; write `.as(your_units)` instead.")]]
constexpr auto
4495 as()
const ->
decltype(as(U{})) {
4498 template <typename U, typename R, typename = std::enable_if_t<IsUnit<U>::value>>
4500 "Do not write `.as<YourUnits, T>()`; write `.as<T>(your_units)` instead.")]]
constexpr auto
4504 template <
typename U>
4506 "Do not write `.in<YourUnits>()`; write `.in(your_units)` instead.")]]
constexpr auto
4507 in()
const ->
decltype(in(U{})) {
4510 template <typename U, typename R, typename = std::enable_if_t<IsUnit<U>::value>>
4512 "Do not write `.in<YourUnits, T>()`; write `.in<T>(your_units)` instead.")]]
constexpr auto
4518 template <
typename NewUnit>
4519 constexpr auto coerce_as(NewUnit)
const {
4521 return as<Rep>(NewUnit{});
4523 template <
typename NewRep,
typename NewUnit>
4524 constexpr auto coerce_as(NewUnit)
const {
4526 return as<NewRep>(NewUnit{});
4528 template <
typename NewUnit>
4529 constexpr auto coerce_in(NewUnit)
const {
4531 return in<Rep>(NewUnit{});
4533 template <
typename NewRep,
typename NewUnit>
4534 constexpr auto coerce_in(NewUnit)
const {
4536 return in<NewRep>(NewUnit{});
4542 template <
typename U>
4545 "Can only access value via Point-equivalent unit");
4549 template <
typename U>
4550 Rep &data_in(
const U &) {
4554 template <
typename U>
4557 "Can only access value via Point-equivalent unit");
4561 template <
typename U>
4562 const Rep &data_in(
const U &)
const {
4609template <
typename Unit>
4611 static constexpr auto unit = Unit{};
4613 template <
typename T>
4614 constexpr auto operator()(T value)
const {
4618 template <
typename... BPs>
4623 template <
typename... BPs>
4633template <
typename U1,
typename U2,
typename R1,
typename R2>
4638template <
typename NewRep,
typename Unit,
typename Rep>
4640 return q.template as<NewRep>(Unit{});
4648template <
typename UnitT>
4649using QuantityPointD = QuantityPoint<UnitT, double>;
4650template <
typename UnitT>
4651using QuantityPointF = QuantityPoint<UnitT, float>;
4652template <
typename UnitT>
4653using QuantityPointI = QuantityPoint<UnitT, int>;
4654template <
typename UnitT>
4655using QuantityPointU = QuantityPoint<UnitT, unsigned int>;
4656template <
typename UnitT>
4657using QuantityPointI32 = QuantityPoint<UnitT, int32_t>;
4658template <
typename UnitT>
4659using QuantityPointU32 = QuantityPoint<UnitT, uint32_t>;
4660template <
typename UnitT>
4661using QuantityPointI64 = QuantityPoint<UnitT, int64_t>;
4662template <
typename UnitT>
4663using QuantityPointU64 = QuantityPoint<UnitT, uint64_t>;
4666template <
typename X,
typename Y,
typename Func>
4667constexpr auto using_common_point_unit(X x, Y y, Func f) {
4668 using R = std::common_type_t<typename X::Rep, typename Y::Rep>;
4669 constexpr auto u = CommonPointUnitT<typename X::Unit, typename Y::Unit>{};
4670 return f(rep_cast<R>(x).as(u), rep_cast<R>(y).as(u));
4675template <
typename U1,
typename U2,
typename R1,
typename R2>
4676constexpr auto operator<(QuantityPoint<U1, R1> p1, QuantityPoint<U2, R2> p2) {
4677 return detail::using_common_point_unit(p1, p2, detail::less);
4679template <
typename U1,
typename U2,
typename R1,
typename R2>
4680constexpr auto operator>(QuantityPoint<U1, R1> p1, QuantityPoint<U2, R2> p2) {
4681 return detail::using_common_point_unit(p1, p2, detail::greater);
4683template <
typename U1,
typename U2,
typename R1,
typename R2>
4684constexpr auto operator<=(QuantityPoint<U1, R1> p1, QuantityPoint<U2, R2> p2) {
4685 return detail::using_common_point_unit(p1, p2, detail::less_equal);
4687template <
typename U1,
typename U2,
typename R1,
typename R2>
4688constexpr auto operator>=(QuantityPoint<U1, R1> p1, QuantityPoint<U2, R2> p2) {
4689 return detail::using_common_point_unit(p1, p2, detail::greater_equal);
4691template <
typename U1,
typename U2,
typename R1,
typename R2>
4692constexpr auto operator==(QuantityPoint<U1, R1> p1, QuantityPoint<U2, R2> p2) {
4693 return detail::using_common_point_unit(p1, p2, detail::equal);
4695template <
typename U1,
typename U2,
typename R1,
typename R2>
4696constexpr auto operator!=(QuantityPoint<U1, R1> p1, QuantityPoint<U2, R2> p2) {
4697 return detail::using_common_point_unit(p1, p2, detail::not_equal);
4712template <
typename Target,
typename U>
4713constexpr auto borrow_origin(U u) {
4714 return Target{} * unit_ratio(u, Target{});
4719template <
typename UnitP,
typename UnitQ,
typename RepP,
typename RepQ>
4720constexpr auto operator+(QuantityPoint<UnitP, RepP> p, Quantity<UnitQ, RepQ> q) {
4721 constexpr auto new_unit_q = detail::borrow_origin<UnitP>(UnitQ{});
4722 return detail::using_common_point_unit(p, q.as(new_unit_q), detail::plus);
4724template <
typename UnitQ,
typename UnitP,
typename RepQ,
typename RepP>
4725constexpr auto operator+(Quantity<UnitQ, RepQ> q, QuantityPoint<UnitP, RepP> p) {
4726 constexpr auto new_unit_q = detail::borrow_origin<UnitP>(UnitQ{});
4727 return detail::using_common_point_unit(q.as(new_unit_q), p, detail::plus);
4729template <
typename UnitP,
typename UnitQ,
typename R1,
typename RepQ>
4730constexpr auto operator-(QuantityPoint<UnitP, R1> p, Quantity<UnitQ, RepQ> q) {
4731 constexpr auto new_unit_q = detail::borrow_origin<UnitP>(UnitQ{});
4732 return detail::using_common_point_unit(p, q.as(new_unit_q), detail::minus);
4734template <
typename U1,
typename U2,
typename R1,
typename R2>
4735constexpr auto operator-(QuantityPoint<U1, R1> p1, QuantityPoint<U2, R2> p2) {
4736 return detail::using_common_point_unit(p1, p2, detail::minus);
4741template <
typename TargetRep,
typename U,
typename R>
4742constexpr bool underlying_value_in_range(Quantity<U, R> q) {
4743 return stdx::in_range<TargetRep>(q.in(U{}));
4746template <
typename TargetRep>
4747constexpr bool underlying_value_in_range(Zero) {
4751template <
typename TargetRep,
typename U1,
typename U2>
4753 : std::conditional_t<std::is_integral<TargetRep>::value,
4754 stdx::bool_constant<underlying_value_in_range<TargetRep>(
4755 OriginDisplacement<U1, U2>::value())>,
4771template <
typename Unit>
4784template <
typename UnitSlot>
4785constexpr auto symbol_for(UnitSlot) {
4790template <
typename U>
4798template <
template <
class U>
class Prefix>
4801 template <
typename U>
4802 constexpr auto operator()(U)
const {
4807 template <
typename U>
4813 template <
typename U>
4820 template <
typename U>
4827 template <
typename U>
4836template <
typename U>
4837struct Quetta : decltype(U{} * pow<30>(mag<10>())) {
4840template <
typename U>
4844template <
typename U>
4845struct Ronna : decltype(U{} * pow<27>(mag<10>())) {
4848template <
typename U>
4852template <
typename U>
4853struct Yotta : decltype(U{} * pow<24>(mag<10>())) {
4856template <
typename U>
4860template <
typename U>
4861struct Zetta : decltype(U{} * pow<21>(mag<10>())) {
4864template <
typename U>
4868template <
typename U>
4869struct Exa : decltype(U{} * pow<18>(mag<10>())) {
4872template <
typename U>
4876template <
typename U>
4877struct Peta : decltype(U{} * pow<15>(mag<10>())) {
4880template <
typename U>
4884template <
typename U>
4885struct Tera : decltype(U{} * pow<12>(mag<10>())) {
4888template <
typename U>
4892template <
typename U>
4893struct Giga : decltype(U{} * pow<9>(mag<10>())) {
4896template <
typename U>
4900template <
typename U>
4901struct Mega : decltype(U{} * pow<6>(mag<10>())) {
4904template <
typename U>
4908template <
typename U>
4909struct Kilo : decltype(U{} * pow<3>(mag<10>())) {
4912template <
typename U>
4916template <
typename U>
4917struct Hecto : decltype(U{} * pow<2>(mag<10>())) {
4920template <
typename U>
4924template <
typename U>
4925struct Deka : decltype(U{} * pow<1>(mag<10>())) {
4928template <
typename U>
4932template <
typename U>
4933struct Deci : decltype(U{} * pow<-1>(mag<10>())) {
4936template <
typename U>
4940template <
typename U>
4941struct Centi : decltype(U{} * pow<-2>(mag<10>())) {
4944template <
typename U>
4948template <
typename U>
4949struct Milli : decltype(U{} * pow<-3>(mag<10>())) {
4952template <
typename U>
4956template <
typename U>
4957struct Micro : decltype(U{} * pow<-6>(mag<10>())) {
4960template <
typename U>
4964template <
typename U>
4965struct Nano : decltype(U{} * pow<-9>(mag<10>())) {
4968template <
typename U>
4972template <
typename U>
4973struct Pico : decltype(U{} * pow<-12>(mag<10>())) {
4976template <
typename U>
4980template <
typename U>
4981struct Femto : decltype(U{} * pow<-15>(mag<10>())) {
4984template <
typename U>
4988template <
typename U>
4989struct Atto : decltype(U{} * pow<-18>(mag<10>())) {
4992template <
typename U>
4996template <
typename U>
4997struct Zepto : decltype(U{} * pow<-21>(mag<10>())) {
5000template <
typename U>
5004template <
typename U>
5005struct Yocto : decltype(U{} * pow<-24>(mag<10>())) {
5008template <
typename U>
5012template <
typename U>
5013struct Ronto : decltype(U{} * pow<-27>(mag<10>())) {
5016template <
typename U>
5020template <
typename U>
5021struct Quecto : decltype(U{} * pow<-30>(mag<10>())) {
5024template <
typename U>
5031template <
typename U>
5032struct Yobi : decltype(U{} * pow<80>(mag<2>())) {
5035template <
typename U>
5039template <
typename U>
5040struct Zebi : decltype(U{} * pow<70>(mag<2>())) {
5043template <
typename U>
5047template <
typename U>
5048struct Exbi : decltype(U{} * pow<60>(mag<2>())) {
5051template <
typename U>
5055template <
typename U>
5056struct Pebi : decltype(U{} * pow<50>(mag<2>())) {
5059template <
typename U>
5063template <
typename U>
5064struct Tebi : decltype(U{} * pow<40>(mag<2>())) {
5067template <
typename U>
5071template <
typename U>
5072struct Gibi : decltype(U{} * pow<30>(mag<2>())) {
5075template <
typename U>
5079template <
typename U>
5080struct Mebi : decltype(U{} * pow<20>(mag<2>())) {
5083template <
typename U>
5087template <
typename U>
5088struct Kibi : decltype(U{} * pow<10>(mag<2>())) {
5091template <
typename U>
5102template <
typename T>
5104 static constexpr const char label[] =
"rad";
5106template <
typename T>
5112constexpr auto radians = QuantityMaker<Radians>{};
5115constexpr auto rad = SymbolFor<Radians>{};
5134template <
typename Unit>
5142 template <
typename T>
5143 constexpr auto as()
const {
5144 return make_quantity<Unit>(
static_cast<T
>(1));
5148 template <
typename T,
typename OtherUnit>
5149 constexpr auto coerce_as(OtherUnit u)
const {
5150 return as<T>().coerce_as(u);
5154 template <
typename T,
typename OtherUnit>
5155 constexpr auto as(OtherUnit u)
const {
5156 static_assert(can_store_value_in<T>(u),
"Cannot represent constant in this unit/rep");
5157 return coerce_as<T>(u);
5161 template <
typename T,
typename OtherUnit>
5162 constexpr auto coerce_in(OtherUnit u)
const {
5163 return as<T>().coerce_in(u);
5167 template <
typename T,
typename OtherUnit>
5168 constexpr auto in(OtherUnit u)
const {
5169 static_assert(can_store_value_in<T>(u),
"Cannot represent constant in this unit/rep");
5170 return coerce_in<T>(u);
5174 template <
typename U,
typename R>
5181 template <
typename T,
typename OtherUnit>
5182 static constexpr bool can_store_value_in(OtherUnit other) {
5183 return representable_in<T>(unit_ratio(Unit{}, other));
5189 typename = std::enable_if_t<can_store_value_in<typename CorrespondingQuantity<T>::Rep>(
5191 constexpr operator T()
const {
5192 return as<typename CorrespondingQuantity<T>::Rep>(
5201template <
typename UnitSlot>
5207template <
typename Unit>
5217template <
typename T>
5219 static constexpr const char label[] =
"s";
5221template <
typename T>
5227constexpr auto seconds = QuantityMaker<Seconds>{};
5230constexpr auto s = SymbolFor<Seconds>{};
5239template <
typename U,
typename R>
5246 out << +q.in(U{}) <<
" " << unit_label(U{});
5251template <
typename U,
typename R>
5253 out <<
"@(" << (p - rep_cast<R>(make_quantity_point<U>(0))) <<
")";
5270template <
typename T>
5272 static constexpr const char label[] =
"m";
5274template <
typename T>
5280constexpr auto meters = QuantityMaker<Meters>{};
5281constexpr auto meters_pt = QuantityPointMaker<Meters>{};
5284constexpr auto m = SymbolFor<Meters>{};
5311template <
typename U,
typename R>
5312auto in_radians(Quantity<U, R> q) {
5313 static_assert(HasSameDimension<U, Radians>{},
5314 "Can only use trig functions with Angle-dimensioned Quantity instances");
5320 using PromotedT = std::conditional_t<std::is_floating_point<R>::value, R,
double>;
5322 return q.template in<PromotedT>(radians);
5325template <
typename T>
5326constexpr T int_pow_impl(T x,
int exp) {
5328 return T{1} / int_pow_impl(x, -exp);
5336 return x * int_pow_impl(x, exp - 1);
5339 const auto root = int_pow_impl(x, exp / 2);
5360template <
typename Q,
typename RoundingUnits>
5362template <
typename Q,
typename RoundingUnits>
5364template <
typename U,
typename R,
typename RoundingUnits>
5379template <
typename U,
typename R>
5381 return make_quantity<U>(std::abs(q.in(U{})));
5385template <
typename T>
5391template <
typename T>
5397template <
typename T>
5403template <
typename T,
typename U>
5404auto arctan2(T y, U x) {
5409template <
typename U1,
typename R1,
typename U2,
typename R2>
5410auto arctan2(Quantity<U1, R1> y, Quantity<U2, R2> x) {
5411 constexpr auto common_unit = CommonUnitT<U1, U2>{};
5412 return arctan2(y.in(common_unit), x.in(common_unit));
5416template <
typename UV,
typename ULo,
typename UHi,
typename RV,
typename RLo,
typename RHi>
5417constexpr auto clamp(Quantity<UV, RV> v, Quantity<ULo, RLo> lo, Quantity<UHi, RHi>
hi) {
5418 using U = CommonUnitT<UV, ULo, UHi>;
5419 using R = std::common_type_t<RV, RLo, RHi>;
5420 using ResultT = Quantity<U, R>;
5421 return (v < lo) ? ResultT{lo} : (
hi < v) ? ResultT{
hi} : ResultT{v};
5429template <
typename UV,
typename UHi,
typename RV,
typename RHi>
5430constexpr auto clamp(Quantity<UV, RV> v, Zero z, Quantity<UHi, RHi>
hi) {
5431 using U = CommonUnitT<UV, UHi>;
5432 using R = std::common_type_t<RV, RHi>;
5433 using ResultT = Quantity<U, R>;
5434 return (v < z) ? ResultT{z} : (
hi < v) ? ResultT{
hi} : ResultT{v};
5436template <
typename UV,
typename ULo,
typename RV,
typename RLo>
5437constexpr auto clamp(Quantity<UV, RV> v, Quantity<ULo, RLo> lo, Zero z) {
5438 using U = CommonUnitT<UV, ULo>;
5439 using R = std::common_type_t<RV, RLo>;
5440 using ResultT = Quantity<U, R>;
5441 return (v < lo) ? ResultT{lo} : (z < v) ? ResultT{z} : ResultT{v};
5445template <
typename UV,
typename ULo,
typename UHi,
typename RV,
typename RLo,
typename RHi>
5446constexpr auto clamp(QuantityPoint<UV, RV> v,
5447 QuantityPoint<ULo, RLo> lo,
5448 QuantityPoint<UHi, RHi>
hi) {
5449 using U = CommonPointUnitT<UV, ULo, UHi>;
5450 using R = std::common_type_t<RV, RLo, RHi>;
5451 using ResultT = QuantityPoint<U, R>;
5452 return (v < lo) ? ResultT{lo} : (
hi < v) ? ResultT{
hi} : ResultT{v};
5456template <
typename U,
typename R,
typename T>
5457constexpr auto copysign(Quantity<U, R> mag, T sgn) {
5462template <
typename T,
typename U,
typename R>
5463constexpr auto copysign(T mag, Quantity<U, R> sgn) {
5468template <
typename U1,
typename R1,
typename U2,
typename R2>
5469constexpr auto copysign(Quantity<U1, R1> mag, Quantity<U2, R2> sgn) {
5470 return make_quantity<U1>(
std::copysign(mag.in(U1{}), sgn.in(U2{})));
5474template <
typename U,
typename R>
5475auto cos(Quantity<U, R> q) {
5476 return std::cos(detail::in_radians(q));
5480template <
typename U1,
typename R1,
typename U2,
typename R2>
5481auto fmod(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
5482 using U = CommonUnitT<U1, U2>;
5483 using R =
decltype(
std::fmod(R1{}, R2{}));
5484 return make_quantity<U>(
std::fmod(q1.template in<R>(U{}), q2.template in<R>(U{})));
5488template <
int Exp,
typename U,
typename R>
5489constexpr auto int_pow(Quantity<U, R> q) {
5491 "Negative exponent on integral represented units are not supported.");
5493 return make_quantity<UnitPowerT<U, Exp>>(detail::int_pow_impl(q.in(U{}), Exp));
5501template <
typename TargetRep,
typename TargetUnits,
typename U,
typename R>
5502constexpr auto inverse_in(TargetUnits target_units, Quantity<U, R> q) {
5503 using Rep = std::common_type_t<TargetRep, R>;
5504 constexpr auto UNITY = make_constant(UnitProductT<>{});
5505 return static_cast<TargetRep
>(UNITY.in<Rep>(associated_unit(target_units) * U{}) / q.in(U{}));
5515template <
typename TargetUnits,
typename U,
typename R>
5516constexpr auto inverse_in(TargetUnits target_units, Quantity<U, R> q) {
5534 constexpr R threshold = 1'000'000;
5536 constexpr auto UNITY = make_constant(UnitProductT<>{});
5539 UNITY.in<R>(associated_unit(target_units) * U{}) >= threshold ||
5541 "Dangerous inversion risking truncation to 0; must supply explicit Rep if truly desired");
5544 return inverse_in<R>(target_units, q);
5552template <
typename TargetUnits,
typename U,
typename R>
5553constexpr auto inverse_as(TargetUnits target_units, Quantity<U, R> q) {
5554 return make_quantity<AssociatedUnitT<TargetUnits>>(inverse_in(target_units, q));
5562template <
typename TargetRep,
typename TargetUnits,
typename U,
typename R>
5563constexpr auto inverse_as(TargetUnits target_units, Quantity<U, R> q) {
5564 return make_quantity<AssociatedUnitT<TargetUnits>>(inverse_in<TargetRep>(target_units, q));
5570template <
typename U,
typename R>
5571constexpr bool isnan(Quantity<U, R> q) {
5578template <
typename U1,
typename U2,
typename R1,
typename R2>
5579auto max(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
5580 return detail::using_common_type(q1, q2, [](
auto a,
auto b) {
return std::max(a, b); });
5584template <
typename U,
typename R>
5585auto max(Quantity<U, R> a, Quantity<U, R> b) {
5592template <
typename U1,
typename U2,
typename R1,
typename R2>
5593auto max(QuantityPoint<U1, R1> p1, QuantityPoint<U2, R2> p2) {
5594 return detail::using_common_point_unit(p1, p2, [](
auto a,
auto b) {
return std::max(a, b); });
5598template <
typename U,
typename R>
5599auto max(QuantityPoint<U, R> a, QuantityPoint<U, R> b) {
5607template <
typename T>
5608auto max(Zero z, T x) {
5610 "Cannot compare type to abstract notion Zero");
5613template <
typename T>
5614auto max(T x, Zero z) {
5616 "Cannot compare type to abstract notion Zero");
5623template <
typename U1,
typename U2,
typename R1,
typename R2>
5624auto min(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
5625 return detail::using_common_type(q1, q2, [](
auto a,
auto b) {
return std::min(a, b); });
5629template <
typename U,
typename R>
5630auto min(Quantity<U, R> a, Quantity<U, R> b) {
5637template <
typename U1,
typename U2,
typename R1,
typename R2>
5638auto min(QuantityPoint<U1, R1> p1, QuantityPoint<U2, R2> p2) {
5639 return detail::using_common_point_unit(p1, p2, [](
auto a,
auto b) {
return std::min(a, b); });
5643template <
typename U,
typename R>
5644auto min(QuantityPoint<U, R> a, QuantityPoint<U, R> b) {
5652template <
typename T>
5653auto min(Zero z, T x) {
5655 "Cannot compare type to abstract notion Zero");
5658template <
typename T>
5659auto min(T x, Zero z) {
5661 "Cannot compare type to abstract notion Zero");
5666template <
typename U1,
typename R1,
typename U2,
typename R2>
5667auto remainder(Quantity<U1, R1> q1, Quantity<U2, R2> q2) {
5668 using U = CommonUnitT<U1, U2>;
5670 return make_quantity<U>(
std::remainder(q1.template in<R>(U{}), q2.template in<R>(U{})));
5678template <
typename RoundingUnits,
typename U,
typename R>
5679auto round_in(RoundingUnits rounding_units, Quantity<U, R> q) {
5680 using OurRoundingRep = detail::RoundingRepT<Quantity<U, R>, RoundingUnits>;
5681 return std::round(q.template in<OurRoundingRep>(rounding_units));
5689template <
typename OutputRep,
typename RoundingUnits,
typename U,
typename R>
5690auto round_in(RoundingUnits rounding_units, Quantity<U, R> q) {
5691 return static_cast<OutputRep
>(round_in(rounding_units, q));
5699template <
typename RoundingUnits,
typename U,
typename R>
5700auto round_as(RoundingUnits rounding_units, Quantity<U, R> q) {
5701 return make_quantity<AssociatedUnitT<RoundingUnits>>(round_in(rounding_units, q));
5709template <
typename OutputRep,
typename RoundingUnits,
typename U,
typename R>
5710auto round_as(RoundingUnits rounding_units, Quantity<U, R> q) {
5711 return make_quantity<AssociatedUnitT<RoundingUnits>>(round_in<OutputRep>(rounding_units, q));
5719template <
typename RoundingUnits,
typename U,
typename R>
5720auto floor_in(RoundingUnits rounding_units, Quantity<U, R> q) {
5721 using OurRoundingRep = detail::RoundingRepT<Quantity<U, R>, RoundingUnits>;
5722 return std::floor(q.template in<OurRoundingRep>(rounding_units));
5730template <
typename OutputRep,
typename RoundingUnits,
typename U,
typename R>
5731auto floor_in(RoundingUnits rounding_units, Quantity<U, R> q) {
5732 return static_cast<OutputRep
>(floor_in(rounding_units, q));
5740template <
typename RoundingUnits,
typename U,
typename R>
5741auto floor_as(RoundingUnits rounding_units, Quantity<U, R> q) {
5742 return make_quantity<AssociatedUnitT<RoundingUnits>>(floor_in(rounding_units, q));
5751template <
typename OutputRep,
typename RoundingUnits,
typename U,
typename R>
5752auto floor_as(RoundingUnits rounding_units, Quantity<U, R> q) {
5753 return make_quantity<AssociatedUnitT<RoundingUnits>>(floor_in<OutputRep>(rounding_units, q));
5761template <
typename RoundingUnits,
typename U,
typename R>
5762auto ceil_in(RoundingUnits rounding_units, Quantity<U, R> q) {
5763 using OurRoundingRep = detail::RoundingRepT<Quantity<U, R>, RoundingUnits>;
5764 return std::ceil(q.template in<OurRoundingRep>(rounding_units));
5772template <
typename OutputRep,
typename RoundingUnits,
typename U,
typename R>
5773auto ceil_in(RoundingUnits rounding_units, Quantity<U, R> q) {
5774 return static_cast<OutputRep
>(ceil_in(rounding_units, q));
5782template <
typename RoundingUnits,
typename U,
typename R>
5783auto ceil_as(RoundingUnits rounding_units, Quantity<U, R> q) {
5784 return make_quantity<AssociatedUnitT<RoundingUnits>>(ceil_in(rounding_units, q));
5793template <
typename OutputRep,
typename RoundingUnits,
typename U,
typename R>
5794auto ceil_as(RoundingUnits rounding_units, Quantity<U, R> q) {
5795 return make_quantity<AssociatedUnitT<RoundingUnits>>(ceil_in<OutputRep>(rounding_units, q));
5799template <
typename U,
typename R>
5800auto sin(Quantity<U, R> q) {
5801 return std::sin(detail::in_radians(q));
5805template <
typename U,
typename R>
5806auto sqrt(Quantity<U, R> q) {
5807 return make_quantity<UnitPowerT<U, 1, 2>>(
std::sqrt(q.in(U{})));
5811template <
typename U,
typename R>
5812auto tan(Quantity<U, R> q) {
5813 return std::tan(detail::in_radians(q));
5827template <
typename U,
typename R>
5835 static constexpr bool is_specialized =
true;
5897template <
typename U,
typename R>
5899template <
typename U,
typename R>
5901template <
typename U,
typename R>
5904template <
typename U,
typename R>
5907template <
typename U,
typename R>
5910template <
typename U,
typename R>
5913template <
typename U,
typename R>
5916template <
typename U,
typename R>
5919template <
typename U,
typename R>
5922template <
typename U,
typename R>
5925template <
typename U,
typename R>
5928template <
typename U,
typename R>
5931template <
typename U,
typename R>
5934template <
typename U,
typename R>
5937template <
typename U,
typename R>
5940template <
typename U,
typename R>
5943template <
typename U,
typename R>
5946template <
typename U,
typename R>
5949template <
typename U,
typename R>
5952template <
typename U,
typename R>
5955template <
typename U,
typename R>
5958template <
typename U,
typename R>
5961template <
typename U,
typename R>
5964template <
typename U,
typename R>
5967template <
typename U,
typename R>
5970template <
typename U,
typename R>
5980template <
typename RepT,
typename Period>
5982 using Unit =
decltype(
Seconds{} * (mag<Period::num>() / mag<Period::den>()));
5992template <
typename U,
typename R>
5994 constexpr auto ratio = unit_ratio(U{}, seconds);
5995 static_assert(is_rational(ratio),
"Cannot convert to chrono::duration with non-rational ratio");
5998 get_value<std::intmax_t>(denominator(ratio))>>{dt};
6008template <
typename T>
6010 static constexpr const char label[] =
"in";
6012template <
typename T>
6018constexpr auto inches = QuantityMaker<Inches>{};
6021constexpr auto in = SymbolFor<Inches>{};
6031template <
typename T>
6033 static constexpr const char label[] =
"ft";
6035template <
typename T>
6041constexpr auto feet = QuantityMaker<Feet>{};
6044constexpr auto ft = SymbolFor<Feet>{};
6053template <
typename T>
6055 static constexpr const char label[] =
"mi";
6057template <
typename T>
6059struct Miles : decltype(Feet{} * mag<5'280>()), MilesLabel<void> {
6060 using MilesLabel<void>::label;
6062constexpr auto mile = SingularNameFor<Miles>{};
6063constexpr auto miles = QuantityMaker<Miles>{};
6066constexpr auto mi = SymbolFor<Miles>{};
The HikoGUI namespace.
Definition array_generic.hpp:20
T signaling_NaN(T... args)