19template <
int M,
int L,
int Ti,
int I,
int Th,
int N,
int J,
int A>
21 static constexpr int mass = M;
22 static constexpr int length = L;
23 static constexpr int time = Ti;
24 static constexpr int current = I;
25 static constexpr int temperature = Th;
26 static constexpr int amount = N;
27 static constexpr int luminous_intensity = J;
28 static constexpr int angle = A;
31template <
class LeftDim,
class RightDim>
33 typedef dim<LeftDim::mass + RightDim::mass, LeftDim::length + RightDim::length, LeftDim::time + RightDim::time,
34 LeftDim::current + RightDim::current, LeftDim::temperature + RightDim::temperature,
35 LeftDim::amount + RightDim::amount, LeftDim::luminous_intensity + RightDim::luminous_intensity,
36 LeftDim::angle + RightDim::angle>
40template <
class LeftDim,
class RightDim>
42 typedef dim<LeftDim::mass - RightDim::mass, LeftDim::length - RightDim::length, LeftDim::time - RightDim::time,
43 LeftDim::current - RightDim::current, LeftDim::temperature - RightDim::temperature,
44 LeftDim::amount - RightDim::amount, LeftDim::luminous_intensity - RightDim::luminous_intensity,
45 LeftDim::angle - RightDim::angle>
49typedef dim<0, 0, 0, 0, 0, 0, 0, 0> dim_none;
54template <
class UnitTag>
56 typedef typename UnitTag::dimension dimension;
57 static constexpr double scale_num = UnitTag::scale_num;
58 static constexpr double scale_den = UnitTag::scale_den;
59 static constexpr bool is_affine = UnitTag::is_affine;
62template <
class UnitTag>
64 static const char* symbol() {
return UnitTag::symbol(); }
65 static const char* name() {
return UnitTag::name(); }
68template <
class Quantity>
69struct default_unit_for_quantity;
71template <
class Quantity>
72struct dimension_for_quantity;
78class anonymous_quantity;
81anonymous_quantity<Dim> quantity_for_dimension_probe(Dim*, ...);
84struct quantity_for_dimension {
85 typedef decltype(quantity_for_dimension_probe(
static_cast<Dim*
>(0), 0)) type;
88template <
class Quantity>
89struct is_quantity : std::false_type {};
95template <class Left, class Right, bool Enabled = is_quantity<Left>::value && is_quantity<Right>::value>
96struct same_dimension : std::false_type {};
98template <
class Left,
class Right>
99struct same_dimension<Left, Right, true> : std::is_same<typename Left::dimension, typename Right::dimension> {};
101template <
bool Condition,
class Type>
102using enable_if_t =
typename std::enable_if<Condition, Type>::type;
104template <
class Quantity>
105using quantity_result_t = enable_if_t<is_quantity<Quantity>::value, Quantity>;
107template <
class Left,
class Right>
108using same_dimension_result_t =
109 enable_if_t<same_dimension<Left, Right>::value,
typename quantity_for_dimension<typename Left::dimension>::type>;
111template <
class Left,
class Right>
112using dim_add_result_t = enable_if_t<
113 is_quantity<Left>::value && is_quantity<Right>::value,
114 typename quantity_for_dimension<typename dim_add<typename Left::dimension, typename Right::dimension>::type>::type>;
116template <
class Left,
class Right>
117using dim_sub_result_t = enable_if_t<
118 is_quantity<Left>::value && is_quantity<Right>::value,
119 typename quantity_for_dimension<typename dim_sub<typename Left::dimension, typename Right::dimension>::type>::type>;
121template <
class Quantity>
122using inverse_quantity_result_t =
123 enable_if_t<is_quantity<Quantity>::value,
124 typename quantity_for_dimension<typename dim_sub<dim_none, typename Quantity::dimension>::type>::type>;
126template <
class Left,
class Right>
127using comparison_result_t = enable_if_t<same_dimension<Left, Right>::value,
bool>;
129template <
int Factor,
class Dim>
131 typedef dim<Dim::mass * Factor, Dim::length * Factor, Dim::time * Factor, Dim::current * Factor,
132 Dim::temperature * Factor, Dim::amount * Factor, Dim::luminous_intensity * Factor, Dim::angle * Factor>
136template <
class Dim,
int Divisor>
137struct dim_divisible_by
138 : std::integral_constant<bool, Dim::mass % Divisor == 0 && Dim::length % Divisor == 0 && Dim::time % Divisor == 0 &&
139 Dim::current % Divisor == 0 && Dim::temperature % Divisor == 0 &&
140 Dim::amount % Divisor == 0 && Dim::luminous_intensity % Divisor == 0 &&
141 Dim::angle % Divisor == 0> {};
143template <
class Dim,
int Divisor>
145 typedef dim<Dim::mass / Divisor, Dim::length / Divisor, Dim::time / Divisor, Dim::current / Divisor,
146 Dim::temperature / Divisor, Dim::amount / Divisor, Dim::luminous_intensity / Divisor,
147 Dim::angle / Divisor>
151template <
class Quantity,
int Factor>
152using scaled_dimension_t =
typename dim_scale<Factor, typename Quantity::dimension>::type;
153template <
class Quantity,
int Divisor>
154using divided_dimension_t =
typename dim_divide<typename Quantity::dimension, Divisor>::type;
155template <
class Quantity,
int Factor>
156using scaled_quantity_t =
typename quantity_for_dimension<scaled_dimension_t<Quantity, Factor> >::type;
157template <
class Quantity,
int Divisor>
158using divided_quantity_t =
typename quantity_for_dimension<divided_dimension_t<Quantity, Divisor> >::type;
160template <class Quantity, int Factor, bool = is_quantity<Quantity>::value>
161struct can_scale_quantity_impl : std::false_type {};
162template <
class Quantity,
int Factor>
163struct can_scale_quantity_impl<Quantity, Factor, true> : std::true_type {};
164template <class Quantity, int Divisor, bool = is_quantity<Quantity>::value>
165struct can_root_quantity_impl : std::false_type {};
166template <
class Quantity,
int Divisor>
167struct can_root_quantity_impl<Quantity, Divisor, true> : dim_divisible_by<typename Quantity::dimension, Divisor> {};
168template <
class Quantity,
int Factor>
169struct can_scale_quantity : can_scale_quantity_impl<Quantity, Factor> {};
170template <
class Quantity,
int Divisor>
171struct can_root_quantity : can_root_quantity_impl<Quantity, Divisor> {};
172template <
class Quantity>
173using quantity_bool_result_t = enable_if_t<is_quantity<Quantity>::value,
bool>;
174template <
class Quantity,
int Power>
175using power_result_t = enable_if_t<can_scale_quantity<Quantity, Power>::value, scaled_quantity_t<Quantity, Power> >;
176template <
class Quantity,
int Divisor>
177using root_result_t = enable_if_t<can_root_quantity<Quantity, Divisor>::value, divided_quantity_t<Quantity, Divisor> >;
182template <
class Derived,
class Dim>
185 typedef Dim dimension;
187 constexpr explicit quantity_base(
double canonical_value = 0.0) : canonical_value_(canonical_value) {}
189 template <
class OtherQuantity>
190 constexpr quantity_base(
const OtherQuantity& other) : canonical_value_(other.canonical_value()) {}
192 constexpr double canonical_value()
const {
return canonical_value_; }
194 template <
class UnitTag>
195 constexpr double as()
const {
196 static_assert(std::is_same<typename unit_traits<UnitTag>::dimension, Dim>::value,
"unit dimension mismatch");
197 return canonical_value_ * unit_traits<UnitTag>::scale_den / unit_traits<UnitTag>::scale_num;
200 static constexpr Derived from_canonical(
double value) {
return Derived(value); }
202 template <
class UnitTag>
203 static constexpr Derived from(
double value) {
204 return Derived(to_canonical<UnitTag>(value));
208 template <
class UnitTag>
209 static constexpr double to_canonical(
double value) {
210 static_assert(std::is_same<typename unit_traits<UnitTag>::dimension, Dim>::value,
"unit dimension mismatch");
211 return value * unit_traits<UnitTag>::scale_num / unit_traits<UnitTag>::scale_den;
214 void set_canonical_value(
double canonical_value) { canonical_value_ = canonical_value; }
217 template <
class OtherQuantity>
218 Derived& operator+=(
const OtherQuantity& other) {
219 set_canonical_value(canonical_value() + other.canonical_value());
220 return static_cast<Derived&
>(*this);
223 template <
class OtherQuantity>
224 Derived& operator-=(
const OtherQuantity& other) {
225 set_canonical_value(canonical_value() - other.canonical_value());
226 return static_cast<Derived&
>(*this);
229 Derived& operator*=(
double scalar) {
230 set_canonical_value(canonical_value() * scalar);
231 return static_cast<Derived&
>(*this);
234 Derived& operator/=(
double scalar) {
235 set_canonical_value(canonical_value() / scalar);
236 return static_cast<Derived&
>(*this);
239 Derived& operator++() {
240 set_canonical_value(canonical_value() + 1.0);
241 return static_cast<Derived&
>(*this);
244 Derived operator++(
int) {
245 Derived copy =
static_cast<Derived&
>(*this);
250 Derived& operator--() {
251 set_canonical_value(canonical_value() - 1.0);
252 return static_cast<Derived&
>(*this);
255 Derived operator--(
int) {
256 Derived copy =
static_cast<Derived&
>(*this);
262 double canonical_value_;
265template <
class Derived,
class Dim>
266using semantic_quantity_base = quantity_base<Derived, Dim>;
269class anonymous_quantity :
public quantity_base<anonymous_quantity<Dim>, Dim> {
271 typedef quantity_base<anonymous_quantity<Dim>, Dim> base_type;
272 typedef Dim dimension;
274 constexpr explicit anonymous_quantity(
double canonical_value = 0.0) : base_type(canonical_value) {}
276 template <
class OtherQuantity>
277 constexpr anonymous_quantity(
const OtherQuantity& other,
278 enable_if_t<same_dimension<anonymous_quantity<Dim>, OtherQuantity>::value,
int> = 0)
279 : base_type(other.canonical_value()) {}
281 static constexpr anonymous_quantity from_canonical(
double value) {
return anonymous_quantity(value); }
285struct is_quantity<anonymous_quantity<Dim> > : std::true_type {};
290template <
class Left,
class Right>
291constexpr same_dimension_result_t<Left, Right> operator+(
const Left& left,
const Right& right) {
292 return same_dimension_result_t<Left, Right>::from_canonical(left.canonical_value() + right.canonical_value());
295template <
class Left,
class Right>
296constexpr same_dimension_result_t<Left, Right> operator-(
const Left& left,
const Right& right) {
297 return same_dimension_result_t<Left, Right>::from_canonical(left.canonical_value() - right.canonical_value());
300template <
class Left,
class Right>
301constexpr dim_add_result_t<Left, Right> operator*(
const Left& left,
const Right& right) {
302 return dim_add_result_t<Left, Right>::from_canonical(left.canonical_value() * right.canonical_value());
305template <
class Left,
class Right>
306constexpr dim_sub_result_t<Left, Right> operator/(
const Left& left,
const Right& right) {
307 return dim_sub_result_t<Left, Right>::from_canonical(left.canonical_value() / right.canonical_value());
310template <
class Quantity>
311constexpr quantity_result_t<Quantity> operator*(
const Quantity& quantity,
double scalar) {
312 return Quantity::from_canonical(quantity.canonical_value() * scalar);
315template <
class Quantity>
316constexpr quantity_result_t<Quantity> operator*(
double scalar,
const Quantity& quantity) {
317 return Quantity::from_canonical(quantity.canonical_value() * scalar);
320template <
class Quantity>
321constexpr quantity_result_t<Quantity> operator/(
const Quantity& quantity,
double scalar) {
322 return Quantity::from_canonical(quantity.canonical_value() / scalar);
325template <
class Quantity>
326constexpr inverse_quantity_result_t<Quantity> operator/(
double scalar,
const Quantity& quantity) {
327 return inverse_quantity_result_t<Quantity>::from_canonical(scalar / quantity.canonical_value());
330template <
class Quantity>
331constexpr quantity_result_t<Quantity> operator-(
const Quantity& quantity) {
332 return Quantity::from_canonical(-quantity.canonical_value());
335template <
class Quantity>
336constexpr quantity_result_t<Quantity> operator+(
const Quantity& quantity) {
340template <
class Left,
class Right>
341constexpr comparison_result_t<Left, Right> operator==(
const Left& left,
const Right& right) {
342 return left.canonical_value() == right.canonical_value();
345template <
class Left,
class Right>
346constexpr comparison_result_t<Left, Right> operator!=(
const Left& left,
const Right& right) {
347 return !(left == right);
350template <
class Left,
class Right>
351constexpr comparison_result_t<Left, Right> operator<(
const Left& left,
const Right& right) {
352 return left.canonical_value() < right.canonical_value();
355template <
class Left,
class Right>
356constexpr comparison_result_t<Left, Right> operator<=(
const Left& left,
const Right& right) {
357 return left.canonical_value() <= right.canonical_value();
360template <
class Left,
class Right>
361constexpr comparison_result_t<Left, Right> operator>(
const Left& left,
const Right& right) {
362 return left.canonical_value() > right.canonical_value();
365template <
class Left,
class Right>
366constexpr comparison_result_t<Left, Right> operator>=(
const Left& left,
const Right& right) {
367 return left.canonical_value() >= right.canonical_value();
377#include "core/units/catalog.h"
378#include "core/units/number.h"
379#include "core/units/angle.h"
380#include "core/units/temperature.h"
386template <
class Quantity>
387constexpr quantity_result_t<Quantity> abs(
const Quantity& quantity) {
388 return Quantity::from_canonical(gcem::abs(quantity.canonical_value()));
390template <
class Quantity>
391constexpr quantity_result_t<Quantity> min(
const Quantity& left,
const Quantity& right) {
392 return left < right ? left : right;
394template <
class Quantity>
395constexpr quantity_result_t<Quantity> max(
const Quantity& left,
const Quantity& right) {
396 return left < right ? right : left;
398inline constexpr Number abs(
const Number& value) {
return Number(gcem::abs(value.value())); }
399inline constexpr Number min(
const Number& left,
const Number& right) {
400 return left.value() < right.value() ? left : right;
402inline constexpr Number max(
const Number& left,
const Number& right) {
403 return left.value() < right.value() ? right : left;
405template <
class Quantity>
406inline constexpr Number sgn(
const Quantity& quantity) {
407 return Number((quantity.canonical_value() > 0.0) - (quantity.canonical_value() < 0.0));
409inline constexpr Number sgn(
const Number& value) {
return Number((value.value() > 0.0) - (value.value() < 0.0)); }
410template <
int Power,
class Quantity>
411constexpr power_result_t<Quantity, Power> pow(
const Quantity& quantity) {
412 return scaled_quantity_t<Quantity, Power>::from_canonical(gcem::pow(quantity.canonical_value(), Power));
415inline constexpr Number pow(
const Number& value) {
416 return Number(gcem::pow(value.value(), Power));
418template <
typename Root,
class Quantity>
419constexpr root_result_t<Quantity, Root::value> root(
const Quantity& quantity) {
420 return divided_quantity_t<Quantity, Root::value>::from_canonical(
421 gcem::pow(quantity.canonical_value(), 1.0 / Root::value));
423template <
typename Root>
424inline constexpr Number root(
const Number& value) {
425 return Number(gcem::pow(value.value(), 1.0 / Root::value));
427template <
class Quantity>
428constexpr root_result_t<Quantity, 2> sqrt(
const Quantity& quantity) {
429 return root<std::integral_constant<int, 2> >(quantity);
431inline constexpr Number sqrt(
const Number& value) {
return root<std::integral_constant<int, 2> >(value); }
432template <
class Quantity>
433constexpr root_result_t<Quantity, 3> cbrt(
const Quantity& quantity) {
434 return root<std::integral_constant<int, 3> >(quantity);
436inline constexpr Number cbrt(
const Number& value) {
return root<std::integral_constant<int, 3> >(value); }
437template <
class Quantity>
438constexpr quantity_result_t<Quantity> hypot(
const Quantity& left,
const Quantity& right) {
439 return Quantity::from_canonical(gcem::hypot(left.canonical_value(), right.canonical_value()));
441inline constexpr Number hypot(
const Number& left,
const Number& right) {
442 return Number(gcem::hypot(left.value(), right.value()));
444template <
class Quantity>
445constexpr quantity_result_t<Quantity> mod(
const Quantity& left,
const Quantity& right) {
446 return Quantity::from_canonical(gcem::fmod(left.canonical_value(), right.canonical_value()));
448inline constexpr Number mod(
const Number& left,
const Number& right) {
449 return Number(gcem::fmod(left.value(), right.value()));
451template <
class Quantity>
452constexpr quantity_result_t<Quantity> remainder(
const Quantity& left,
const Quantity& right) {
453 return Quantity::from_canonical(
454 left.canonical_value() - gcem::round(left.canonical_value() / right.canonical_value()) * right.canonical_value());
456inline constexpr Number remainder(
const Number& left,
const Number& right) {
457 return Number(left.value() - gcem::round(left.value() / right.value()) * right.value());
459template <
class Quantity>
460constexpr quantity_result_t<Quantity> copysign(
const Quantity& left,
const Quantity& right) {
461 return Quantity::from_canonical(gcem::copysign(left.canonical_value(), right.canonical_value()));
463inline constexpr Number copysign(
const Number& left,
const Number& right) {
464 return Number(gcem::copysign(left.value(), right.value()));
466template <
class Quantity>
467constexpr quantity_bool_result_t<Quantity> signbit(
const Quantity& quantity) {
468 return gcem::signbit(quantity.canonical_value());
470inline constexpr bool signbit(
const Number& value) {
return gcem::signbit(value.value()); }
471template <
class Quantity>
472constexpr quantity_result_t<Quantity> clamp(
const Quantity& value,
const Quantity& low,
const Quantity& high) {
473 return max(low, min(value, high));
475inline constexpr Number clamp(
const Number& value,
const Number& low,
const Number& high) {
476 return max(low, min(value, high));
478template <
class Quantity>
479constexpr quantity_result_t<Quantity> ceil(
const Quantity& value,
const Quantity& step) {
480 return Quantity::from_canonical(gcem::ceil(value.canonical_value() / step.canonical_value()) *
481 step.canonical_value());
483template <
class Quantity>
484constexpr quantity_result_t<Quantity> floor(
const Quantity& value,
const Quantity& step) {
485 return Quantity::from_canonical(gcem::floor(value.canonical_value() / step.canonical_value()) *
486 step.canonical_value());
488template <
class Quantity>
489constexpr quantity_result_t<Quantity> trunc(
const Quantity& value,
const Quantity& step) {
490 return Quantity::from_canonical(gcem::trunc(value.canonical_value() / step.canonical_value()) *
491 step.canonical_value());
493template <
class Quantity>
494constexpr quantity_result_t<Quantity> round(
const Quantity& value,
const Quantity& step) {
495 return Quantity::from_canonical(gcem::round(value.canonical_value() / step.canonical_value()) *
496 step.canonical_value());
498inline constexpr Number ceil(
const Number& value,
const Number& step) {
499 return Number(gcem::ceil(value.value() / step.value()) * step.value());
501inline constexpr Number floor(
const Number& value,
const Number& step) {
502 return Number(gcem::floor(value.value() / step.value()) * step.value());
504inline constexpr Number trunc(
const Number& value,
const Number& step) {
505 return Number(gcem::trunc(value.value() / step.value()) * step.value());
507inline constexpr Number round(
const Number& value,
const Number& step) {
508 return Number(gcem::round(value.value() / step.value()) * step.value());
510template <
class Quantity>
511constexpr quantity_result_t<Quantity> fma(
const Quantity& x,
double y,
const Quantity& z) {
512 return Quantity::from_canonical(x.canonical_value() * y + z.canonical_value());
514template <
class Quantity>
515constexpr quantity_result_t<Quantity> fma(
double x,
const Quantity& y,
const Quantity& z) {
516 return Quantity::from_canonical(x * y.canonical_value() + z.canonical_value());
518inline constexpr Number fma(
const Number& x,
const Number& y,
const Number& z) {
519 return Number(x.value() * y.value() + z.value());
521template <
class Quantity>
522inline constexpr power_result_t<Quantity, 2> square(
const Quantity& quantity) {
523 return pow<2>(quantity);
525inline constexpr Number square(
const Number& value) {
return pow<2>(value); }
526template <
class Quantity>
527inline constexpr power_result_t<Quantity, 3> cube(
const Quantity& quantity) {
528 return pow<3>(quantity);
530inline constexpr Number cube(
const Number& value) {
return pow<3>(value); }
532template <
class UnitTag,
class Quantity>
533inline typename std::enable_if<is_quantity<Quantity>::value,
double>::type unit_value_for_text(
534 const Quantity& quantity) {
535 return quantity.template as<UnitTag>();
540inline std::string humanize_identifier(
const char* text) {
541 std::string result(text);
542 for (std::string::size_type i = 0; i < result.size(); ++i) {
543 if (result[i] ==
'_') result[i] =
' ';
548template <
class Quantity>
549inline std::string format_with_default_unit(
const Quantity& quantity) {
550 typedef typename default_unit_for_quantity<Quantity>::type unit_t;
551 std::ostringstream stream;
552 stream << unit_value_for_text<unit_t>(quantity) <<
' ' << unit_text<unit_t>::symbol();
556template <
class UnitTag>
557inline const char* symbol() {
558 return unit_text<UnitTag>::symbol();
560template <
class UnitTag>
561inline std::string display_name() {
562 return humanize_identifier(unit_text<UnitTag>::name());
564template <
class UnitTag,
class Quantity>
565inline std::string to_string_as(
const Quantity& quantity) {
566 std::ostringstream stream;
567 stream << unit_value_for_text<UnitTag>(quantity) <<
' ' << symbol<UnitTag>();
570inline std::string to_string(
const Number& number) {
571 std::ostringstream stream;
572 stream << number.value();
575template <
class Quantity>
577 typename std::enable_if<is_quantity<Quantity>::value && !std::is_same<Quantity, Number>::value, std::string>::type
578 to_string(
const Quantity& quantity) {
579 return format_with_default_unit(quantity);
581inline std::string to_string(
const Temperature& quantity) {
return format_with_default_unit(quantity); }
582inline std::string to_string(
const TemperatureDelta& quantity) {
return format_with_default_unit(quantity); }
583inline std::ostream& operator<<(std::ostream& stream,
const Number& number) {
584 stream << number.value();
587template <
class Quantity>
589 typename std::enable_if<is_quantity<Quantity>::value && !std::is_same<Quantity, Number>::value, std::ostream&>::type
590 operator<<(std::ostream& stream,
const Quantity& quantity) {
591 stream << to_string(quantity);
594inline std::ostream& operator<<(std::ostream& stream,
const Temperature& quantity) {
595 stream << to_string(quantity);
598inline std::ostream& operator<<(std::ostream& stream,
const TemperatureDelta& quantity) {
599 stream << to_string(quantity);
609constexpr LinearDerivativeGain
operator""_VpMPs(
long double value) {
610 return LinearDerivativeGain::from<volt_second_per_meter_t>(
static_cast<double>(value));
612constexpr LinearDerivativeGain
operator""_VpMPs(
unsigned long long value) {
613 return LinearDerivativeGain::from<volt_second_per_meter_t>(
static_cast<double>(value));
615constexpr LinearDerivativeGain
operator""_VpInPs(
long double value) {
616 return LinearDerivativeGain::from<volt_second_per_inch_t>(
static_cast<double>(value));
618constexpr LinearDerivativeGain
operator""_VpInPs(
unsigned long long value) {
619 return LinearDerivativeGain::from<volt_second_per_inch_t>(
static_cast<double>(value));
621constexpr LinearVelocityDerivativeGain
operator""_VpMPs2(
long double value) {
622 return LinearVelocityDerivativeGain::from<volt_second_squared_per_meter_t>(
static_cast<double>(value));
624constexpr LinearVelocityDerivativeGain
operator""_VpMPs2(
unsigned long long value) {
625 return LinearVelocityDerivativeGain::from<volt_second_squared_per_meter_t>(
static_cast<double>(value));
627constexpr LinearVelocityDerivativeGain
operator""_VpInPs2(
long double value) {
628 return LinearVelocityDerivativeGain::from<volt_second_squared_per_inch_t>(
static_cast<double>(value));
630constexpr LinearVelocityDerivativeGain
operator""_VpInPs2(
unsigned long long value) {
631 return LinearVelocityDerivativeGain::from<volt_second_squared_per_inch_t>(
static_cast<double>(value));
637using namespace units;
638using namespace units::literals;