/mnt/c/Users/david.brown/Documents/git/github.com/bigdavedev/units/units.h
1 #pragma once
2 
27 #include <numeric>
28 #include <ratio>
29 #include <stdexcept>
30 #include <type_traits>
31 
32 #include <cmath>
33 #include <cstdint>
34 
35 #ifndef UNIT_DISABLE_IOSTREAM
36 #include <iostream>
37 #endif
38 
39 namespace units
40 {
41  template <typename Rep, typename Ratio, typename UnitType>
42  struct unit;
43 
44  template <typename T>
45  struct is_unit : std::false_type
46  {
47  };
48 
49  template <typename Rep, typename Ratio, typename UnitType>
50  struct is_unit<unit<Rep, Ratio, UnitType>> : std::true_type
51  {
52  };
53 
54  namespace detail
55  {
56  template <intmax_t Numerator>
57  struct integer_sign : std::integral_constant<intmax_t, (Numerator < 0) ? -1 : 1>
58  {
59  };
60 
61  template <intmax_t Numerator>
62  struct integer_abs : std::integral_constant<intmax_t, Numerator * integer_sign<Numerator>::value>
63  {
64  };
65 
66  template <intmax_t Numerator, intmax_t Quotient>
67  struct greatest_common_divisor;
68 
69  template <intmax_t Numerator, intmax_t Quotient>
70  struct greatest_common_divisor : greatest_common_divisor<Quotient, (Numerator % Quotient)>
71  {
72  };
73 
74  template <intmax_t Numerator>
75  struct greatest_common_divisor<Numerator, 0> : std::integral_constant<intmax_t, integer_abs<Numerator>::value>
76  {
77  };
78 
79  template <intmax_t Quotient>
80  struct greatest_common_divisor<0, Quotient> : std::integral_constant<intmax_t, integer_abs<Quotient>::value>
81  {
82  };
83 
84  template <typename T>
85  auto fmod(T x, T y) -> typename std::enable_if<std::is_floating_point<T>::value, long long int>::type
86  {
87  return y != 0 ? x - std::trunc(x / y) * y : throw std::domain_error{"Dividing by zero!"};
88  };
89 
90  template <class CommonRep,
91  class Ratio,
92  class UnitType,
93  class Rep2,
94  bool = std::is_convertible<Rep2, CommonRep>::value>
95  struct unit_div_mod_base
96  { // return type for unit / rep and unit % rep
98  };
99 
100  template <class CommonRep, class Ratio, class UnitType, class Rep2>
101  struct unit_div_mod_base<CommonRep, Ratio, UnitType, Rep2, false>
102  { // no return type
103  };
104 
105  template <class Rep1, class Ratio1, class UnitType1, class Rep2, bool = is_unit<Rep2>::value>
106  struct unit_div_mod
107  { // no return type
108  };
109 
110  template <class Rep1, class Ratio1, class UnitType1, class Rep2>
111  struct unit_div_mod<Rep1, Ratio1, UnitType1, Rep2, false>
112  : unit_div_mod_base<typename std::common_type<Rep1, Rep2>::type, Ratio1, UnitType1, Rep2>
113  { // return type for unit / rep and unit % rep
114  };
115  }
116 }
117 
118 namespace std
119 {
120  template <typename CommonRep, typename Ratio1, typename Ratio2, typename UnitType>
122  {
123  private:
124  using gcd_num = units::detail::greatest_common_divisor<Ratio1::num, Ratio2::num>;
125  using gcd_den = units::detail::greatest_common_divisor<Ratio1::den, Ratio2::den>;
126  using common_rep = typename CommonRep::type;
127  using ratio = std::ratio<gcd_num::value, (Ratio1::den / gcd_den::value) * Ratio2::den>;
128  using unit_type = UnitType;
129 
130  public:
132  };
133 
134  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
135  struct common_type<units::unit<Rep1, Ratio1, UnitType1>, units::unit<Rep2, Ratio2, UnitType2>>
136  {
137  static_assert(std::is_same<UnitType1, UnitType2>::value, "Incompatible unit types");
138  using type = typename unit_common_type<std::common_type<Rep1, Rep2>, Ratio1, Ratio2, UnitType1>::type;
139  };
140 }
141 
142 namespace units
143 {
144  namespace unit_type
145  {
146  // clang-format off
147  struct distance {};
148  struct mass {};
149  // clang-format on
150  }
151 
152  template <typename ToUnit, typename Rep, typename Ratio, typename UnitType>
153  constexpr auto unit_cast(unit<Rep, Ratio, UnitType> from) ->
154  typename std::enable_if<is_unit<ToUnit>::value, ToUnit>::type;
155 
156  template <typename Rep, typename Ratio, typename UnitType>
157  struct unit
158  {
159  using rep = Rep;
160  using ratio = Ratio;
161  using unit_type = UnitType;
162 
163  constexpr explicit unit(rep value)
164  : value{value}
165  {
166  }
167 
168  template <typename Rep2, typename Ratio2, typename UnitType2>
169  constexpr unit(unit<Rep2, Ratio2, UnitType2> dist)
170  : value{unit_cast<unit<rep, ratio, unit_type>>(dist).count()}
171  {
172  static_assert(std::is_same<unit_type, UnitType2>::value, "Unit types are not compatible");
173  }
174 
175  constexpr rep count() const;
176 
177  constexpr std::common_type_t<unit> operator+() const;
178  constexpr std::common_type_t<unit> operator-() const;
179 
180  unit& operator++();
181  unit operator++(int);
182  unit& operator--();
183  unit operator--(int);
184 
185  unit& operator+=(unit const other);
186  unit& operator-=(unit const other);
187  unit& operator*=(rep const scalar);
188  unit& operator/=(rep const scalar);
189  unit& operator%=(rep const scalar);
190  unit& operator%=(unit const other);
191 
192  private:
193  rep value;
194  };
195 
196  template <typename Rep, typename Ratio = std::ratio<1>>
197  using distance = unit<Rep, Ratio, unit_type::distance>;
198 
199  // Useful aliases
200  using nanometres = distance<double, std::nano>;
201  using micrometres = distance<double, std::micro>;
202  using millimetres = distance<double, std::milli>;
203  using centimetres = distance<double, std::centi>;
204  using decimetres = distance<double, std::deci>;
205  using metres = distance<double>;
206  using kilometres = distance<double, std::kilo>;
207 
208  // American spellings
209  using nanometers = nanometres;
210  using micrometers = micrometres;
211  using millimeters = millimetres;
212  using centimeters = centimetres;
213  using decimeters = decimetres;
214  using meters = metres;
215  using kilometers = kilometres;
216 
217  // Imperial
218  using feet = distance<double, std::ratio_multiply<std::ratio<381, 1250>, metres::ratio>>;
219  using thous = distance<double, std::ratio_divide<feet::ratio, std::ratio<12000>>>;
220  using inches = distance<double, std::ratio_divide<feet::ratio, std::ratio<12>>>;
221  using links = distance<double, std::ratio_multiply<std::ratio<33, 50>, feet::ratio>>;
222  using yards = distance<double, std::ratio_multiply<std::ratio<3>, feet::ratio>>;
223  using rods = distance<double, std::ratio_multiply<std::ratio<25>, links::ratio>>;
224  using chains = distance<double, std::ratio_multiply<std::ratio<4>, rods::ratio>>;
225  using furlongs = distance<double, std::ratio_multiply<std::ratio<10>, chains::ratio>>;
226  using miles = distance<double, std::ratio_multiply<std::ratio<5280>, feet::ratio>>;
227  using leagues = distance<double, std::ratio_multiply<std::ratio<15840>, feet::ratio>>;
228 
229  // Maritime
230  using fathoms = distance<double, std::ratio_multiply<std::ratio<608, 100>, feet::ratio>>;
231  using cables = distance<double, std::ratio_multiply<std::ratio<608>, feet::ratio>>;
232  using nautical_miles = distance<double, std::ratio_multiply<std::ratio<6080>, feet::ratio>>;
233 
234  // Astronimical Units
235  //
236  // Unfortunately, std::ratio uses std::intmax_t which does not have enough precision for defining a hubble
237  // ratio
238  // which is 14.4 billion lightyears.
239  using earth_radii = distance<long double, std::ratio_multiply<std::ratio<6371>, kilometres::ratio>>;
240  using lunar_distances = distance<long double, std::ratio_multiply<std::ratio<384402>, kilometres::ratio>>;
241  using astronimical_units = distance<long double, std::ratio<149597870700>>;
242  using light_years = distance<long double, std::ratio_multiply<std::ratio<94607304725808, 10>, kilometres::ratio>>;
243  using parsecs = distance<long double, std::ratio_multiply<std::ratio<308567758146719, 10>, kilometres::ratio>>;
244 
245  template <typename Rep, typename Ratio = std::ratio<1>>
246  using mass = unit<Rep, Ratio, unit_type::mass>;
247 
248  // Metric
249  using picograms = mass<double, std::pico>;
250  using nanograms = mass<double, std::nano>;
251  using micrograms = mass<double, std::micro>;
252  using milligrams = mass<double, std::milli>;
253  using grams = mass<double>;
254  using kilograms = mass<double, std::kilo>;
255  using tons = mass<double, std::ratio_multiply<std::ratio<1000>, kilograms::ratio>>;
256 
257  // Imperial
258  using pounds = mass<double, std::ratio_multiply<std::ratio<45359237, 100000000>, kilograms::ratio>>;
259  using grains = mass<double, std::ratio_divide<pounds::ratio, std::ratio<7000>>>;
260  using drams = mass<double, std::ratio_multiply<std::ratio<2734375, 100000>, grains::ratio>>;
261  using ounces = mass<double, std::ratio_multiply<std::ratio<16>, drams::ratio>>;
262  using us_hundredweight = mass<double, std::ratio_multiply<std::ratio<100>, pounds::ratio>>;
263  using long_hundredweight = mass<double, std::ratio_multiply<std::ratio<112>, pounds::ratio>>;
264  using short_ton = mass<double, std::ratio_multiply<std::ratio<2000>, pounds::ratio>>;
265  using long_ton = mass<double, std::ratio_multiply<std::ratio<2240>, pounds::ratio>>;
266 
267  // Arithmetic operations
268  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
269  constexpr auto operator+(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs) ->
270  typename std::common_type<unit<Rep1, Ratio1, UnitType1>, unit<Rep2, Ratio2, UnitType2>>::type;
271 
272  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
273  constexpr auto operator-(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs) ->
274  typename std::common_type<unit<Rep1, Ratio1, UnitType1>, unit<Rep2, Ratio2, UnitType2>>::type;
275 
276  template <typename Rep1, typename Ratio, typename UnitType, typename Rep2>
277  constexpr auto operator*(unit<Rep1, Ratio, UnitType> lhs, Rep2 const scalar)
278  -> unit<typename std::common_type<Rep1, Rep2>::type, Ratio, UnitType>;
279 
280  template <typename Rep1, typename Rep2, typename Ratio, typename UnitType>
281  constexpr auto operator*(Rep1 const scalar, unit<Rep2, Ratio, UnitType> rhs)
282  -> unit<typename std::common_type<Rep1, Rep2>::type, Ratio, UnitType>;
283 
284  template <typename Rep1, typename Ratio, typename UnitType, typename Rep2>
285  constexpr auto operator/(unit<Rep1, Ratio, UnitType> lhs, Rep2 const scalar)
286  -> unit<typename std::common_type<Rep1, Rep2>::type, Ratio, UnitType>;
287 
288  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
289  constexpr auto operator%(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs) ->
290  typename std::common_type<unit<Rep1, Ratio1, UnitType1>, unit<Rep2, Ratio2, UnitType2>>::type;
291 
292  template <typename Rep1, typename Ratio, typename UnitType, typename Rep2>
293  constexpr auto operator%(unit<Rep1, Ratio, UnitType> lhs, Rep2 const scalar) ->
294  typename detail::unit_div_mod<Rep1, Ratio, UnitType, Rep2>::type;
295 
296  // Relational operations
297  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
298  constexpr bool operator==(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs);
299 
300  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
301  constexpr bool operator!=(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs);
302 
303  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
304  constexpr bool operator<(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs);
305 
306  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
307  constexpr bool operator<=(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs);
308 
309  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
310  constexpr bool operator>(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs);
311 
312  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
313  constexpr bool operator>=(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs);
314 
315 #ifndef UNITS_DISABLE_IOSTREAM
316  template <typename CharT, typename Traits, typename Rep, typename Ratio, typename UnitType>
317  std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
318  unit<Rep, Ratio, UnitType> const& u);
319 #endif
320 }
321 
322 inline namespace literals
323 {
324  namespace distance_literals
325  {
326  // Metric
327  constexpr units::nanometres operator"" _nm(unsigned long long int dist);
328  constexpr units::micrometres operator"" _um(unsigned long long int dist);
329  constexpr units::millimetres operator"" _mm(unsigned long long int dist);
330  constexpr units::centimetres operator"" _cm(unsigned long long int dist);
331  constexpr units::decimetres operator"" _dm(unsigned long long int dist);
332  constexpr units::metres operator"" _m(unsigned long long int dist);
333  constexpr units::kilometres operator"" _km(unsigned long long int dist);
334 
335  // Imperial
336  constexpr units::thous operator"" _th(unsigned long long int dist);
337  constexpr units::inches operator"" _in(unsigned long long int dist);
338  constexpr units::links operator"" _li(unsigned long long int dist);
339  constexpr units::feet operator"" _ft(unsigned long long int dist);
340  constexpr units::yards operator"" _yd(unsigned long long int dist);
341  constexpr units::rods operator"" _rd(unsigned long long int dist);
342  constexpr units::chains operator"" _ch(unsigned long long int dist);
343  constexpr units::furlongs operator"" _fur(unsigned long long int dist);
344  constexpr units::miles operator"" _mi(unsigned long long int dist);
345  constexpr units::leagues operator"" _lea(unsigned long long int dist);
346 
347  // Maritime
348  constexpr units::fathoms operator"" _ftm(unsigned long long int dist);
349  constexpr units::cables operator"" _cb(unsigned long long int dist);
350  constexpr units::nautical_miles operator"" _NM(unsigned long long int dist);
351  constexpr units::nautical_miles operator"" _nmi(unsigned long long int dist);
352 
353  // Astronomical Units
354  constexpr units::earth_radii operator"" _R(unsigned long long int dist);
355  constexpr units::lunar_distances operator"" _LD(unsigned long long int dist);
356  constexpr units::astronimical_units operator"" _AU(unsigned long long int dist);
357  constexpr units::light_years operator"" _ly(unsigned long long int dist);
358  constexpr units::parsecs operator"" _pc(unsigned long long int dist);
359  }
360 
361  namespace mass_literals
362  {
363  // Metric
364  constexpr units::picograms operator"" _pg(unsigned long long int mass);
365  constexpr units::nanograms operator"" _ng(unsigned long long int mass);
366  constexpr units::micrograms operator"" _ug(unsigned long long int mass);
367  constexpr units::milligrams operator"" _mg(unsigned long long int mass);
368  constexpr units::grams operator"" _g(unsigned long long int mass);
369  constexpr units::kilograms operator"" _kg(unsigned long long int mass);
370 
371  // Imperial
372  constexpr units::grains operator"" _gr(unsigned long long int mass);
373  constexpr units::drams operator"" _dr(unsigned long long int mass);
374  constexpr units::ounces operator"" _oz(unsigned long long int mass);
375  constexpr units::pounds operator"" _lb(unsigned long long int mass);
376  constexpr units::us_hundredweight operator"" _cwr(unsigned long long int mass);
377  }
378 }
379 
380 namespace units
381 {
382  // Implementation
383  template <typename Rep, typename Ratio, typename UnitType>
384  constexpr typename unit<Rep, Ratio, UnitType>::rep unit<Rep, Ratio, UnitType>::count() const
385  {
386  return value;
387  }
388 
389  template <typename Rep, typename Ratio, typename UnitType>
390  constexpr std::common_type_t<unit<Rep, Ratio, UnitType>> unit<Rep, Ratio, UnitType>::operator+() const
391  {
392  return (*this);
393  }
394 
395  template <typename Rep, typename Ratio, typename UnitType>
396  constexpr std::common_type_t<unit<Rep, Ratio, UnitType>> unit<Rep, Ratio, UnitType>::operator-() const
397  {
398  return unit<Rep, Ratio, UnitType>{0 - value};
399  }
400 
401  template <typename Rep, typename Ratio, typename UnitType>
402  unit<Rep, Ratio, UnitType>& unit<Rep, Ratio, UnitType>::operator++()
403  {
404  ++value;
405  return *this;
406  }
407 
408  template <typename Rep, typename Ratio, typename UnitType>
409  unit<Rep, Ratio, UnitType> unit<Rep, Ratio, UnitType>::operator++(int)
410  {
411  auto const temp = value;
412  ++value;
413  return unit<Rep, Ratio, UnitType>{temp};
414  }
415 
416  template <typename Rep, typename Ratio, typename UnitType>
417  unit<Rep, Ratio, UnitType>& unit<Rep, Ratio, UnitType>::operator--()
418  {
419  --value;
420  return *this;
421  }
422 
423  template <typename Rep, typename Ratio, typename UnitType>
424  unit<Rep, Ratio, UnitType> unit<Rep, Ratio, UnitType>::operator--(int)
425  {
426  auto const temp = value;
427  --value;
428  return unit<Rep, Ratio, UnitType>{temp};
429  }
430 
431  template <typename Rep, typename Ratio, typename UnitType>
432  unit<Rep, Ratio, UnitType>& unit<Rep, Ratio, UnitType>::operator+=(unit const other)
433  {
434  value += other.count();
435  return *this;
436  }
437 
438  template <typename Rep, typename Ratio, typename UnitType>
439  unit<Rep, Ratio, UnitType>& unit<Rep, Ratio, UnitType>::operator-=(unit const other)
440  {
441  value -= other.count();
442  return *this;
443  }
444 
445  template <typename Rep, typename Ratio, typename UnitType>
446  unit<Rep, Ratio, UnitType>& unit<Rep, Ratio, UnitType>::operator*=(rep const scalar)
447  {
448  value *= scalar;
449  return *this;
450  }
451 
452  template <typename Rep, typename Ratio, typename UnitType>
453  unit<Rep, Ratio, UnitType>& unit<Rep, Ratio, UnitType>::operator/=(rep const scalar)
454  {
455  value /= scalar;
456  return *this;
457  }
458 
459  template <typename Rep, typename Ratio, typename UnitType>
460  unit<Rep, Ratio, UnitType>& unit<Rep, Ratio, UnitType>::operator%=(rep const scalar)
461  {
462  value = detail::fmod(value, scalar);
463  return *this;
464  }
465 
466  template <typename Rep, typename Ratio, typename UnitType>
467  unit<Rep, Ratio, UnitType>& unit<Rep, Ratio, UnitType>::operator%=(unit const other)
468  {
469  value = detail::fmod(value, other.count());
470  return *this;
471  }
472 
473  // Arithmetic operations
474  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
475  constexpr auto operator+(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs) ->
476  typename std::common_type<unit<Rep1, Ratio1, UnitType1>, unit<Rep2, Ratio2, UnitType2>>::type
477  {
478  using unit1 = unit<Rep1, Ratio1, UnitType1>;
479  using unit2 = unit<Rep2, Ratio2, UnitType2>;
480  using common_type = typename std::common_type<unit1, unit2>::type;
481 
482  return static_cast<common_type>(static_cast<common_type>(lhs).count() + static_cast<common_type>(rhs).count());
483  }
484 
485  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
486  constexpr auto operator-(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs) ->
487  typename std::common_type<unit<Rep1, Ratio1, UnitType1>, unit<Rep2, Ratio2, UnitType2>>::type
488  {
489  using unit1 = unit<Rep1, Ratio1, UnitType1>;
490  using unit2 = unit<Rep2, Ratio2, UnitType2>;
491  using common_type = typename std::common_type<unit1, unit2>::type;
492 
493  return static_cast<common_type>(static_cast<common_type>(lhs).count() - static_cast<common_type>(rhs).count());
494  }
495 
496  template <typename Rep1, typename Ratio, typename UnitType, typename Rep2>
497  constexpr auto operator*(unit<Rep1, Ratio, UnitType> lhs, Rep2 const scalar)
498  -> unit<typename std::common_type<Rep1, Rep2>::type, Ratio, UnitType>
499  {
500  using result_type = unit<typename std::common_type<Rep1, Rep2>::type, Ratio, UnitType>;
501  return static_cast<result_type>(static_cast<result_type>(lhs).count() * scalar);
502  }
503 
504  template <typename Rep1, typename Rep2, typename Ratio, typename UnitType>
505  constexpr auto operator*(Rep1 const scalar, unit<Rep2, Ratio, UnitType> rhs)
506  -> unit<typename std::common_type<Rep1, Rep2>::type, Ratio, UnitType>
507  {
508  using result_type = unit<typename std::common_type<Rep1, Rep2>::type, Ratio, UnitType>;
509  return rhs * scalar;
510  }
511 
512  template <typename Rep1, typename Ratio, typename UnitType, typename Rep2>
513  constexpr auto operator/(unit<Rep1, Ratio, UnitType> lhs, Rep2 const scalar)
514  -> unit<typename std::common_type<Rep1, Rep2>::type, Ratio, UnitType>
515  {
516  using result_type = unit<typename std::common_type<Rep1, Rep2>::type, Ratio, UnitType>;
517  return static_cast<result_type>(static_cast<result_type>(lhs).count() / scalar);
518  }
519 
520  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
521  constexpr auto operator%(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs) ->
522  typename std::common_type<unit<Rep1, Ratio1, UnitType1>, unit<Rep2, Ratio2, UnitType2>>::type
523  {
524  using unit1 = unit<Rep1, Ratio1, UnitType1>;
525  using unit2 = unit<Rep2, Ratio2, UnitType2>;
526  using common_type = typename std::common_type<unit1, unit2>::type;
527 
528  return common_type{common_type{lhs}.count() % common_type{rhs}.count()};
529  }
530 
531  template <typename Rep1, typename Ratio, typename UnitType, typename Rep2>
532  constexpr auto operator%(unit<Rep1, Ratio, UnitType> lhs, Rep2 const scalar) ->
533  typename detail::unit_div_mod<Rep1, Ratio, UnitType, Rep2>::type
534  {
535  using result_type = unit<typename std::common_type<Rep1, Rep2>::type, Ratio, UnitType>;
536  return result_type{result_type{lhs}.count()
537  % result_type{static_cast<typename result_type::rep>(scalar)}.count()};
538  }
539 
540  namespace detail
541  {
542  template <typename T>
543  constexpr auto abs(const T& value)
544  {
545  return (T{} > value) ? -value : value;
546  }
547 
548  constexpr bool unit_compare(double lhs,
549  double rhs,
550  double max_diff = 0.000000001,
551  double max_relative_diff = std::numeric_limits<double>::epsilon())
552  {
553  return (abs(lhs - rhs) <= (((abs(rhs) > abs(lhs)) ? abs(rhs) : abs(lhs)) * max_relative_diff)) || (abs(lhs - rhs) <= max_diff);
554  }
555  }
556 
557  // Relational operations
558  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
559  constexpr bool operator==(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs)
560  {
561  using unit1 = unit<Rep1, Ratio1, UnitType1>;
562  using unit2 = unit<Rep2, Ratio2, UnitType2>;
563  using common_type = typename std::common_type<unit1, unit2>::type;
564  using common_rep = typename common_type::rep;
565 
566  return detail::unit_compare(unit_cast<common_type>(lhs).count(), unit_cast<common_type>(rhs).count());
567  }
568 
569  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
570  constexpr bool operator!=(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs)
571  {
572  using unit1 = unit<Rep1, Ratio1, UnitType1>;
573  using unit2 = unit<Rep2, Ratio2, UnitType2>;
574  using common_type = typename std::common_type<unit1, unit2>::type;
575 
576  return !(lhs == rhs);
577  }
578 
579  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
580  constexpr bool operator<(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs)
581  {
582  using unit1 = unit<Rep1, Ratio1, UnitType1>;
583  using unit2 = unit<Rep2, Ratio2, UnitType2>;
584  using common_type = typename std::common_type<unit1, unit2>::type;
585 
586  return std::isless(unit_cast<common_type>(lhs).count(), unit_cast<common_type>(rhs).count());
587  }
588 
589  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
590  constexpr bool operator<=(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs)
591  {
592  using unit1 = unit<Rep1, Ratio1, UnitType1>;
593  using unit2 = unit<Rep2, Ratio2, UnitType2>;
594  using common_type = typename std::common_type<unit1, unit2>::type;
595 
596  return std::islessequal(unit_cast<common_type>(lhs).count(), unit_cast<common_type>(rhs).count());
597  }
598 
599  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
600  constexpr bool operator>(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs)
601  {
602  using unit1 = unit<Rep1, Ratio1, UnitType1>;
603  using unit2 = unit<Rep2, Ratio2, UnitType2>;
604  using common_type = typename std::common_type<unit1, unit2>::type;
605 
606  return std::isgreater(unit_cast<common_type>(lhs).count(), unit_cast<common_type>(rhs).count());
607  }
608 
609  template <typename Rep1, typename Ratio1, typename UnitType1, typename Rep2, typename Ratio2, typename UnitType2>
610  constexpr bool operator>=(unit<Rep1, Ratio1, UnitType1> lhs, unit<Rep2, Ratio2, UnitType2> rhs)
611  {
612  using unit1 = unit<Rep1, Ratio1, UnitType1>;
613  using unit2 = unit<Rep2, Ratio2, UnitType2>;
614  using common_type = typename std::common_type<unit1, unit2>::type;
615 
616  return std::isgreaterequal(unit_cast<common_type>(lhs).count(), unit_cast<common_type>(rhs).count());
617  }
618 
619  namespace detail
620  {
621  template <typename ToUnit,
622  typename Ratio,
623  typename CommonType,
624  bool RatioNumIsOne = false,
625  bool RatioDenIsOne = false>
626  struct unit_cast
627  {
628  template <typename Rep, typename Length, typename UnitType>
629  static constexpr ToUnit cast(unit<Rep, Length, UnitType> from)
630  {
631  using ToRep = typename ToUnit::rep;
632  return ToUnit{static_cast<ToRep>(static_cast<CommonType>(from.count())
633  / static_cast<CommonType>(Ratio::num)
634  * static_cast<CommonType>(Ratio::den))};
635  }
636  };
637 
638  template <typename ToUnit, typename Ratio, typename CommonType>
639  struct unit_cast<ToUnit, Ratio, CommonType, true, true>
640  {
641  template <typename Rep, typename Length, typename UnitType>
642  static constexpr ToUnit cast(unit<Rep, Length, UnitType> from)
643  {
644  using ToRep = typename ToUnit::rep;
645  return ToUnit{static_cast<ToRep>(static_cast<CommonType>(from.count()))};
646  }
647  };
648 
649  template <typename ToUnit, typename Ratio, typename CommonType>
650  struct unit_cast<ToUnit, Ratio, CommonType, true, false>
651  {
652  template <typename Rep, typename Length, typename UnitType>
653  static constexpr ToUnit cast(unit<Rep, Length, UnitType> from)
654  {
655  using ToRep = typename ToUnit::rep;
656  return ToUnit{
657  static_cast<ToRep>(static_cast<CommonType>(from.count()) * static_cast<CommonType>(Ratio::den))};
658  }
659  };
660 
661  template <typename ToUnit, typename Ratio, typename CommonType>
662  struct unit_cast<ToUnit, Ratio, CommonType, false, true>
663  {
664  template <typename Rep, typename Length, typename UnitType>
665  static constexpr ToUnit cast(unit<Rep, Length, UnitType> from)
666  {
667  using ToRep = typename ToUnit::rep;
668  return ToUnit{
669  static_cast<ToRep>(static_cast<CommonType>(from.count()) / static_cast<CommonType>(Ratio::num))};
670  }
671  };
672  }
673 
674  template <typename ToUnit, typename Rep, typename Ratio, typename UnitType>
675  constexpr auto unit_cast(unit<Rep, Ratio, UnitType> from) ->
676  typename std::enable_if<is_unit<ToUnit>::value, ToUnit>::type
677  {
678  static_assert(std::is_same<typename ToUnit::unit_type, UnitType>::value, "Incompatible types");
679 
680  using ToRatio = typename ToUnit::ratio;
681  using ToRep = typename ToUnit::rep;
682  using CommonType = typename std::common_type<ToRep, Rep, intmax_t>::type;
683  using CommonRatio = std::ratio_divide<ToRatio, Ratio>;
684 
685  return detail::unit_cast<ToUnit, CommonRatio, CommonType, CommonRatio::num == 1, CommonRatio::den == 1>::cast(
686  from);
687  }
688 }
689 
690 inline namespace literals
691 {
692  namespace distance_literals
693  {
694  // Metric
695  constexpr units::nanometres operator"" _nm(unsigned long long int dist)
696  {
697  return units::nanometres{static_cast<units::nanometres::rep>(dist)};
698  }
699 
700  constexpr units::micrometres operator"" _um(unsigned long long int dist)
701  {
702  return units::micrometres{static_cast<units::micrometres::rep>(dist)};
703  }
704 
705  constexpr units::millimetres operator"" _mm(unsigned long long int dist)
706  {
707  return units::millimetres{static_cast<units::millimetres::rep>(dist)};
708  }
709 
710  constexpr units::centimetres operator"" _cm(unsigned long long int dist)
711  {
712  return units::centimetres{static_cast<units::centimetres::rep>(dist)};
713  }
714 
715  constexpr units::decimetres operator"" _dm(unsigned long long int dist)
716  {
717  return units::decimetres{static_cast<units::decimetres::rep>(dist)};
718  }
719 
720  constexpr units::metres operator"" _m(unsigned long long int dist)
721  {
722  return units::metres{static_cast<units::metres::rep>(dist)};
723  }
724 
725  constexpr units::kilometres operator"" _km(unsigned long long int dist)
726  {
727  return units::kilometres{static_cast<units::kilometres::rep>(dist)};
728  }
729 
730  // Imperial
731  constexpr units::thous operator"" _th(unsigned long long int dist)
732  {
733  return units::thous{static_cast<units::thous::rep>(dist)};
734  }
735 
736  constexpr units::inches operator"" _in(unsigned long long int dist)
737  {
738  return units::inches{static_cast<units::inches::rep>(dist)};
739  }
740 
741  constexpr units::links operator"" _li(unsigned long long int dist)
742  {
743  return units::links{static_cast<units::links::rep>(dist)};
744  }
745 
746  constexpr units::feet operator"" _ft(unsigned long long int dist)
747  {
748  return units::feet{static_cast<units::feet::rep>(dist)};
749  }
750 
751  constexpr units::yards operator"" _yd(unsigned long long int dist)
752  {
753  return units::yards{static_cast<units::yards::rep>(dist)};
754  }
755 
756  constexpr units::rods operator"" _rd(unsigned long long int dist)
757  {
758  return units::rods{static_cast<units::rods::rep>(dist)};
759  }
760 
761  constexpr units::chains operator"" _ch(unsigned long long int dist)
762  {
763  return units::chains{static_cast<units::chains::rep>(dist)};
764  }
765 
766  constexpr units::furlongs operator"" _fur(unsigned long long int dist)
767  {
768  return units::furlongs{static_cast<units::furlongs::rep>(dist)};
769  }
770 
771  constexpr units::miles operator"" _mi(unsigned long long int dist)
772  {
773  return units::miles{static_cast<units::miles::rep>(dist)};
774  }
775 
776  constexpr units::leagues operator"" _lea(unsigned long long int dist)
777  {
778  return units::leagues{static_cast<units::leagues::rep>(dist)};
779  }
780 
781  // Maritime
782  constexpr units::fathoms operator"" _ftm(unsigned long long int dist)
783  {
784  return units::fathoms{static_cast<units::fathoms::rep>(dist)};
785  }
786 
787  constexpr units::cables operator"" _cb(unsigned long long int dist)
788  {
789  return units::cables{static_cast<units::cables::rep>(dist)};
790  }
791 
792  constexpr units::nautical_miles operator"" _NM(unsigned long long int dist)
793  {
794  return units::nautical_miles{static_cast<units::nautical_miles::rep>(dist)};
795  }
796 
797  constexpr units::nautical_miles operator"" _nmi(unsigned long long int dist)
798  {
799  return units::nautical_miles{static_cast<units::nautical_miles::rep>(dist)};
800  }
801 
802  // Astronomical Units
803  constexpr units::earth_radii operator"" _R(unsigned long long int dist)
804  {
805  return units::earth_radii{static_cast<units::earth_radii::rep>(dist)};
806  }
807 
808  constexpr units::lunar_distances operator"" _LD(unsigned long long int dist)
809  {
810  return units::lunar_distances{static_cast<units::lunar_distances::rep>(dist)};
811  }
812 
813  constexpr units::astronimical_units operator"" _AU(unsigned long long int dist)
814  {
815  return units::astronimical_units{static_cast<units::astronimical_units::rep>(dist)};
816  }
817 
818  constexpr units::light_years operator"" _ly(unsigned long long int dist)
819  {
820  return units::light_years{static_cast<units::light_years::rep>(dist)};
821  }
822 
823  constexpr units::parsecs operator"" _pc(unsigned long long int dist)
824  {
825  return units::parsecs{static_cast<units::parsecs::rep>(dist)};
826  }
827  }
828 
829  namespace mass_literals
830  {
831  // Metric
832  constexpr units::picograms operator"" _pg(unsigned long long int mass)
833  {
834  return units::picograms{static_cast<units::picograms::rep>(mass)};
835  }
836 
837  constexpr units::nanograms operator"" _ng(unsigned long long int mass)
838  {
839  return units::nanograms{static_cast<units::nanograms::rep>(mass)};
840  }
841 
842  constexpr units::micrograms operator"" _ug(unsigned long long int mass)
843  {
844  return units::micrograms{static_cast<units::micrograms::rep>(mass)};
845  }
846 
847  constexpr units::milligrams operator"" _mg(unsigned long long int mass)
848  {
849  return units::milligrams{static_cast<units::milligrams::rep>(mass)};
850  }
851 
852  constexpr units::grams operator"" _g(unsigned long long int mass)
853  {
854  return units::grams{static_cast<units::grams::rep>(mass)};
855  }
856 
857  constexpr units::kilograms operator"" _kg(unsigned long long int mass)
858  {
859  return units::kilograms{static_cast<units::kilograms::rep>(mass)};
860  }
861 
862  // Imperial
863  constexpr units::grains operator"" _gr(unsigned long long int mass)
864  {
865  return units::grains{static_cast<units::grains::rep>(mass)};
866  }
867 
868  constexpr units::drams operator"" _dr(unsigned long long int mass)
869  {
870  return units::drams{static_cast<units::drams::rep>(mass)};
871  }
872 
873  constexpr units::ounces operator"" _oz(unsigned long long int mass)
874  {
875  return units::ounces{static_cast<units::ounces::rep>(mass)};
876  }
877 
878  constexpr units::pounds operator"" _lb(unsigned long long int mass)
879  {
880  return units::pounds{static_cast<units::pounds::rep>(mass)};
881  }
882 
883  constexpr units::us_hundredweight operator"" _cwt(unsigned long long int mass)
884  {
885  return units::us_hundredweight{static_cast<units::us_hundredweight::rep>(mass)};
886  }
887  }
888 }
889 
890 namespace units
891 {
892 #ifndef UNITS_DISABLE_IOSTREAM
893  namespace detail
894  {
895  template <typename Ratio>
896  inline std::string get_prefix();
897 
898  template <>
899  inline std::string get_prefix<std::ratio<1>>()
900  {
901  return "";
902  }
903 
904  template <>
905  inline std::string get_prefix<std::pico>()
906  {
907  return "p";
908  }
909 
910  template <>
911  inline std::string get_prefix<std::nano>()
912  {
913  return "n";
914  }
915 
916  template <>
917  inline std::string get_prefix<std::micro>()
918  {
919  return "u";
920  }
921 
922  template <>
923  inline std::string get_prefix<std::milli>()
924  {
925  return "m";
926  }
927 
928  template <>
929  inline std::string get_prefix<std::centi>()
930  {
931  return "c";
932  }
933 
934  template <>
935  inline std::string get_prefix<std::deci>()
936  {
937  return "d";
938  }
939 
940  template <>
941  inline std::string get_prefix<std::kilo>()
942  {
943  return "k";
944  }
945 
946  template <typename UnitType>
947  inline std::string get_unit();
948 
949  template<>
950  inline std::string get_unit<unit_type::distance>()
951  {
952  return "m";
953  }
954 
955  template<>
956  inline std::string get_unit<unit_type::mass>()
957  {
958  return "g";
959  }
960 
961  template <typename Ratio, typename UnitType>
962  inline std::string get_unit()
963  {
964  return get_prefix<Ratio>() + get_unit<UnitType>();
965  }
966 
967  template <>
968  inline std::string get_unit<thous::ratio, unit_type::distance>()
969  {
970  return "th";
971  }
972 
973  template <>
974  inline std::string get_unit<inches::ratio, unit_type::distance>()
975  {
976  return "in";
977  }
978 
979  template <>
980  inline std::string get_unit<links::ratio, unit_type::distance>()
981  {
982  return "li";
983  }
984 
985  template <>
986  inline std::string get_unit<feet::ratio, unit_type::distance>()
987  {
988  return "ft";
989  }
990 
991  template <>
992  inline std::string get_unit<yards::ratio, unit_type::distance>()
993  {
994  return "yd";
995  }
996 
997  template <>
998  inline std::string get_unit<rods::ratio, unit_type::distance>()
999  {
1000  return "rd";
1001  }
1002 
1003  template <>
1004  inline std::string get_unit<chains::ratio, unit_type::distance>()
1005  {
1006  return "ch";
1007  }
1008 
1009  template <>
1010  inline std::string get_unit<furlongs::ratio, unit_type::distance>()
1011  {
1012  return "fur";
1013  }
1014 
1015  template <>
1016  inline std::string get_unit<miles::ratio, unit_type::distance>()
1017  {
1018  return "mi";
1019  }
1020 
1021  template <>
1022  inline std::string get_unit<leagues::ratio, unit_type::distance>()
1023  {
1024  return "lea";
1025  }
1026 
1027  template <>
1028  inline std::string get_unit<fathoms::ratio, unit_type::distance>()
1029  {
1030  return "ftm";
1031  }
1032 
1033  template <>
1034  inline std::string get_unit<cables::ratio, unit_type::distance>()
1035  {
1036  return "cb";
1037  }
1038 
1039  template <>
1040  inline std::string get_unit<nautical_miles::ratio, unit_type::distance>()
1041  {
1042  return "nmi";
1043  }
1044 
1045  template <>
1046  inline std::string get_unit<earth_radii::ratio, unit_type::distance>()
1047  {
1048  return "R";
1049  }
1050 
1051  template <>
1052  inline std::string get_unit<lunar_distances::ratio, unit_type::distance>()
1053  {
1054  return "LD";
1055  }
1056 
1057  template <>
1058  inline std::string get_unit<astronimical_units::ratio, unit_type::distance>()
1059  {
1060  return "AU";
1061  }
1062 
1063  template <>
1064  inline std::string get_unit<light_years::ratio, unit_type::distance>()
1065  {
1066  return "ly";
1067  }
1068 
1069  template <>
1070  inline std::string get_unit<parsecs::ratio, unit_type::distance>()
1071  {
1072  return "pc";
1073  }
1074 
1075  template <>
1076  inline std::string get_unit<grains::ratio, unit_type::mass>()
1077  {
1078  return "gr";
1079  }
1080 
1081  template <>
1082  inline std::string get_unit<drams::ratio, unit_type::mass>()
1083  {
1084  return "dr";
1085  }
1086 
1087  template <>
1088  inline std::string get_unit<ounces::ratio, unit_type::mass>()
1089  {
1090  return "oz";
1091  }
1092 
1093  template <>
1094  inline std::string get_unit<pounds::ratio, unit_type::mass>()
1095  {
1096  return "lb";
1097  }
1098 
1099  template <>
1100  inline std::string get_unit<us_hundredweight::ratio, unit_type::mass>()
1101  {
1102  return "cwt";
1103  }
1104  }
1105 
1106  template <typename CharT, typename Traits, typename Rep, typename Ratio, typename UnitType>
1107  inline std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
1108  unit<Rep, Ratio, UnitType> const& u)
1109  {
1110  return os << u.count() << detail::get_unit<Ratio, UnitType>();
1111  }
1112 #endif
1113 }
Definition: units.h:147
Definition: units.h:121
Definition: units.h:45
Definition: units.h:148
Definition: units.h:42