SI 2.5.4
A header only c++ library that provides type safety and user defined literals for handling physical values defined in the International System of Units.
Loading...
Searching...
No Matches
unit.h
Go to the documentation of this file.
1
12#pragma once
13
14#ifdef SI_DISABLE_IMPLICIT_RATIO_CONVERSION
15#define SI_ENABLE_IMPLICIT_RATIO_CONVERSION false
16#else
17#define SI_ENABLE_IMPLICIT_RATIO_CONVERSION true
18#endif
19
20#include "detail.h"
21#include "eps_equal.h"
22#include "unit_cast.h"
23
24#include <ratio>
25#include <type_traits>
26
28namespace SI::detail {
29
30template <typename _unit_lhs, typename _unit_rhs> struct unit_with_common_ratio;
31
37
49template <char _symbol, typename _exponent, typename _type,
50 typename _ratio = std::ratio<1>>
51struct unit_t {
52 static_assert(std::is_arithmetic_v<_type>, "Type is an arithmetic value");
53 static_assert(detail::is_ratio_v<_exponent>, "_exponent is a ratio type");
54 static_assert(detail::is_ratio_v<_ratio>, "_ratio is a std::ratio");
55 using ratio = _ratio;
58 using symbol = std::integral_constant<char, _symbol>;
59
61 explicit constexpr unit_t(_type v) : value_{v} {}
62 constexpr unit_t() = default;
63 constexpr unit_t(const unit_t &) = default;
64 constexpr unit_t(unit_t &&) = default;
65
67 template <typename _type_rhs>
69 : value_(rhs.value()) {
70 static_assert(std::is_convertible<_type_rhs, _type>::value,
71 "Internal representation is convertible");
72 }
73
74 ~unit_t() = default;
75
76 template <typename _rhs_type, typename _rhs_ratio>
78 : value_{
80 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
81 static_assert(
83 std::ratio_equal_v<ratio, _rhs_ratio>,
84 "Implicit ratio conversion disabled, convert before assigning");
85 }
86
87 template <typename _rhs_ratio>
89 : value_{
91 .value())} {
92 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
93 static_assert(
95 std::ratio_equal_v<ratio, _rhs_ratio>,
96 "Implicit ratio conversion disabled, convert before assigning");
97 }
98
100 constexpr _type value() const { return value_; }
101
104 template <typename _unit_rhs> constexpr _unit_rhs as() const {
105 static_assert(is_unit_t_v<_unit_rhs>, "only supported for SI::unit_t");
106 static_assert(std::ratio_equal_v<typename _unit_rhs::exponent, _exponent>,
107 "Exponents must match");
108 static_assert(_unit_rhs::symbol::value == _symbol,
109 "target unit must be of the same type must match");
110
111 return unit_cast<_unit_rhs>(*this);
112 }
113
116 template <template <typename _type_rhs> typename _unit_rhs>
117 constexpr _unit_rhs<_type> as() const {
118 static_assert(is_unit_t_v<_unit_rhs<_type>>,
119 "only supported for SI::unit_t");
120 static_assert(
121 std::ratio_equal_v<typename _unit_rhs<_type>::exponent, _exponent>,
122 "Exponents must match");
124 "target unit must be of the same type must match");
125
126 return unit_cast<_unit_rhs<_type>>(*this);
127 }
128
130 void setValue(_type v) { value_ = v; }
131
133 constexpr unit_t &operator=(const unit_t &rhs) = default;
134
136 constexpr unit_t &operator=(unit_t &&rhs) = default;
137
139 template <
140 typename _rhs_ratio,
141 std::enable_if_t<!std::ratio_equal_v<_rhs_ratio, _ratio>> * = nullptr>
142 constexpr unit_t &
144
145 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
146 static_assert(
148 std::ratio_equal_v<ratio, _rhs_ratio>,
149 "Implicit ratio conversion disabled, convert before assigning");
150
152 return *this;
153 }
154
156 template <
157 typename _rhs_ratio,
158 std::enable_if_t<!std::ratio_equal_v<_rhs_ratio, _ratio>> * = nullptr>
159 constexpr unit_t &
161
162 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
163 static_assert(
165 std::ratio_equal_v<ratio, _rhs_ratio>,
166 "Implicit ratio conversion disabled, convert before assigning");
167
168 *this =
170 return *this;
171 }
172
175 template <typename _rhs_type, typename _rhs_ratio>
176 constexpr bool operator==(
178
179 static_assert(
181 std::ratio_equal_v<ratio, _rhs_ratio>,
182 "Implicit ratio conversion disabled, convert before comparing");
183
184 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
185 static_assert(std::is_integral_v<_type> || std::is_floating_point_v<_type>,
186 "Is integral or floating point");
187 using gcd_unit = typename unit_with_common_ratio<
188 typename std::remove_reference<decltype(rhs)>::type,
189 typename std::remove_reference<decltype(*this)>::type>::type;
190
191 if constexpr (std::is_integral_v<_type>) {
192
193 return unit_cast<gcd_unit>(rhs).value() ==
194 unit_cast<gcd_unit>(*this).value();
195 } else {
197 unit_cast<gcd_unit>(*this).value());
198 }
199 }
200
202 template <typename _rhs_type, typename _rhs_ratio>
203 constexpr bool operator!=(
205 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
206 return !(*this == rhs);
207 }
208
209 template <typename _rhs_type, typename _rhs_ratio>
210 constexpr bool operator<(
212 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
213 static_assert(
215 std::ratio_equal_v<ratio, _rhs_ratio>,
216 "Implicit ratio conversion disabled, convert before comparing");
217
218 using gcd_unit = typename unit_with_common_ratio<
219 typename std::remove_reference<decltype(rhs)>::type,
220 typename std::remove_reference<decltype(*this)>::type>::type;
221 return unit_cast<gcd_unit>(*this).value() <
222 unit_cast<gcd_unit>(rhs).value();
223 }
224
225 template <typename _rhs_type, typename _rhs_ratio>
226 constexpr bool operator<=(
228 return !(*this > rhs);
229 }
230
231 template <typename _rhs_type, typename _rhs_ratio>
232 constexpr bool operator>(
234 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
235 static_assert(
237 std::ratio_equal_v<ratio, _rhs_ratio>,
238 "Implicit ratio conversion disabled, convert before comparing");
239
240 using gcd_unit = typename unit_with_common_ratio<
241 typename std::remove_reference<decltype(rhs)>::type,
242 typename std::remove_reference<decltype(*this)>::type>::type;
243
244 return unit_cast<gcd_unit>(*this).value() >
245 unit_cast<gcd_unit>(rhs).value();
246 }
247
248 template <typename _rhs_type, typename _rhs_ratio>
249 constexpr bool operator>=(
251 return !(*this < rhs);
252 }
253
255 constexpr unit_t operator*(const _type f) const { return unit_t{value_ * f}; }
256
258 template <typename _rhs_exponent, typename _rhs_type>
259 constexpr auto operator*(
261
262 static_assert(detail::is_ratio_v<_rhs_exponent>,
263 "rhs exponent is a ratio type");
265 std::ratio_multiply<ratio, _ratio>>{value() * rhs.value()};
266 }
267
272 template <typename _rhs_exponent, typename _rhs_ratio, typename _rhs_type>
273 constexpr auto operator*(
275 static_assert(detail::is_ratio_v<_rhs_exponent>,
276 "rhs exponent is a ratio type");
277 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
278
279 static_assert(
281 std::ratio_equal_v<ratio, _rhs_ratio>,
282 "Implicit ratio conversion disabled, convert before comparing");
283
285 std::ratio_multiply<ratio, _rhs_ratio>>{value_ * rhs.value()};
286 }
287
289 constexpr unit_t &operator*=(const _type scalar) {
290 value_ *= scalar;
291 return *this;
292 }
293
295 constexpr unit_t operator/(const _type f) const { return unit_t{value_ / f}; }
296
299 template <typename _rhs_exponent, typename _rhs_type,
300 std::enable_if_t<std::ratio_not_equal_v<_rhs_exponent, _exponent>>
301 * = nullptr>
302 constexpr auto operator/(
304 static_assert(detail::is_ratio_v<_rhs_exponent>,
305 "rhs exponent is a ratio type");
306 using rhs_t = typename std::remove_reference<decltype(rhs)>::type;
307
308 return unit_t<_symbol,
309 std::ratio_subtract<_exponent, typename rhs_t::exponent>,
310 _type, std::ratio_divide<ratio, _ratio>>{value_ /
311 rhs.value()};
312 }
313
317 template <typename _rhs_exponent, typename _rhs_type, typename _rhs_ratio,
318 std::enable_if_t<std::ratio_not_equal_v<_rhs_exponent, _exponent>>
319 * = nullptr>
320 constexpr auto operator/(
322 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
323 static_assert(detail::is_ratio_v<_rhs_exponent>,
324 "rhs exponent is a ratio type");
325 static_assert(
327 std::ratio_equal_v<ratio, _rhs_ratio>,
328 "Implicit ratio conversion disabled, convert before dividing");
329
331 std::ratio_divide<ratio, _rhs_ratio>>{value_ / rhs.value()};
332 }
333
335 template <typename _rhs_type>
336 constexpr _type
338 return value() / rhs.value();
339 }
340
343 template <
344 typename _rhs_exponent, typename _rhs_type, typename _rhs_ratio,
345 std::enable_if_t<std::ratio_equal_v<_rhs_exponent, exponent>> * = nullptr>
346 constexpr _type operator/(
349 std::ratio_equal_v<_rhs_ratio, _ratio>,
350 "Implicit ratio conversion disabled, convert to same ratio "
351 "before dividing");
352
353 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
354
355 static_assert(detail::is_ratio_v<_rhs_exponent>,
356 "rhs exponent is a ratio type");
357
358 using gcd_unit = typename unit_with_common_ratio<
359 typename std::remove_reference<decltype(*this)>::type,
360 typename std::remove_reference<decltype(rhs)>::type>::type;
361
363 }
364
366 constexpr unit_t &operator/=(const _type scalar) {
367 value_ /= scalar;
368 return *this;
369 }
370
372 template <typename _rhs_type, typename _rhs_ratio>
373 constexpr unit_t operator+(
375
376 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
377 static_assert(
379 std::ratio_equal_v<ratio, _rhs_ratio>,
380 "Implicit ratio conversion disabled, convert before adding values");
381
382 return unit_t{
383 value() +
385 }
386
388 constexpr unit_t &operator+=(const unit_t &rhs) {
389 value_ += rhs.value();
390 return *this;
391 }
392
394 template <
395 typename _rhs_type, typename _rhs_ratio,
396 std::enable_if_t<!std::ratio_equal_v<_rhs_ratio, _ratio>> * = nullptr>
397 constexpr unit_t &
399
400 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
401 static_assert(
403 std::ratio_equal_v<ratio, _rhs_ratio>,
404 "Implicit ratio conversion disabled, convert before adding values");
405
407
408 return *this;
409 }
410
412 template <typename _rhs_type, typename _rhs_ratio>
413 constexpr unit_t operator-(
415
416 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
417 static_assert(
419 std::ratio_equal_v<ratio, _rhs_ratio>,
420 "Implicit ratio conversion disabled, convert before subtracting");
421
422 return unit_t{
423 value() +
425 }
426
428 constexpr unit_t &operator-=(const unit_t &rhs) {
429 value_ -= rhs.value();
430 return *this;
431 }
432
434 template <typename _rhs_type, typename _rhs_ratio,
435 std::enable_if<!std::ratio_equal_v<_rhs_ratio, _ratio>> * = nullptr>
436 constexpr unit_t &
438
439 static_assert(detail::is_ratio_v<_rhs_ratio>, "_rhs_ratio is a std::ratio");
440 static_assert(
442 std::ratio_equal_v<ratio, _rhs_ratio>,
443 "Implicit ratio conversion disabled, convert before adding values");
444
446
447 return *this;
448 }
449
451 constexpr unit_t operator-() const { return unit_t{-value_}; }
452
455 ++value_;
456 return *this;
457 }
460 auto ret_val(*this);
461 ++(*this);
462
463 return ret_val;
464 }
465
468 --value_;
469 return *this;
470 }
471
474 auto ret_val(*this);
475 --(*this);
476
477 return ret_val;
478 }
479
480private:
481 _type value_;
482};
483
487template <typename _type, char _symbol, typename _exponent, typename _rhs_type,
488 typename _ratio,
489 std::enable_if_t<std::is_integral_v<_type>> * = nullptr>
490constexpr auto
491operator/(const _type &lhs,
494 std::ratio_equal<std::ratio<1>, _ratio>::value,
495 "Implicit ratio conversion disabled, convert to ratio<1> "
496 "before dividing");
497 static_assert(detail::is_ratio_v<_exponent>, "Exponent is a ratio type");
498 return unit_t<_symbol, std::ratio_multiply<std::ratio<-1>, _exponent>, _type,
499 _ratio>{lhs / rhs.value()};
500}
501
506template <typename _type, char _symbol, typename _exponent, typename _rhs_type,
507 typename _ratio,
508 std::enable_if_t<std::is_floating_point_v<_type>> * = nullptr>
509constexpr auto
510operator/(const _type &lhs,
511 const unit_t<_symbol, _exponent, _rhs_type, _ratio> &rhs) {
513 std::ratio_equal_v<_ratio, std::ratio<1>>,
514 "Implicit ratio conversion disabled, convert to ratio<1> "
515 "before dividing");
516 static_assert(detail::is_ratio_v<_exponent>, "Exponent is a ratio type");
517 return unit_t<_symbol, std::ratio_multiply<std::ratio<-1>, _exponent>, _type,
518 _ratio>{lhs / rhs.value()};
519}
520
521} // namespace SI::detail
Namespace containing implementation details for SI.
Definition acceleration.h:34
constexpr auto unit_cast(const _rhs_T &rhs)
function to cast between two units of the same type
Definition unit_cast.h:22
constexpr bool eps_equals(const T &lhs, const T &rhs)
Definition eps_equal.h:22
constexpr auto operator/(const _type &lhs, const unit_t< _symbol, _exponent, _rhs_type, _ratio > &rhs)
Definition unit.h:491
base template class for holding values of type _type to be multiplied with a ratio _ratio
Definition unit.h:51
constexpr unit_t & operator-=(const unit_t &rhs)
Subtract-assign value of the same unit.
Definition unit.h:428
constexpr bool operator>(const unit_t< _symbol, _exponent, _rhs_type, _rhs_ratio > &rhs) const
Definition unit.h:232
_ratio ratio
Definition unit.h:55
constexpr unit_t & operator*=(const _type scalar)
multiply with a non-unit scalar
Definition unit.h:289
constexpr unit_t()=default
constexpr unit_t operator*(const _type f) const
multiply with a non-unit scalar
Definition unit.h:255
constexpr bool operator>=(const unit_t< _symbol, _exponent, _rhs_type, _rhs_ratio > &rhs) const
Definition unit.h:249
void setValue(_type v)
Definition unit.h:130
constexpr auto operator/(const unit_t< _symbol, _rhs_exponent, _rhs_type, _ratio > &rhs) const
Definition unit.h:302
constexpr bool operator<=(const unit_t< _symbol, _exponent, _rhs_type, _rhs_ratio > &rhs) const
Definition unit.h:226
unit_t operator++(int)
increment by postfix ++
Definition unit.h:459
constexpr _type operator/(const unit_t< _symbol, _exponent, _rhs_type, _ratio > &rhs)
divide whit same unit result is a scalar
Definition unit.h:337
unit_t & operator--()
decrement by prefix –
Definition unit.h:467
constexpr _unit_rhs< _type > as() const
Definition unit.h:117
constexpr unit_t & operator+=(const unit_t< _symbol, _exponent, _rhs_type, _rhs_ratio > &rhs)
add value of the same type but possibly different ratio
Definition unit.h:398
_type internal_type
Definition unit.h:56
constexpr _type operator/(const unit_t< _symbol, _rhs_exponent, _rhs_type, _rhs_ratio > &rhs) const
Definition unit.h:346
constexpr unit_t & operator=(unit_t< _symbol, _exponent, _type, _rhs_ratio > &&rhs)
Move assignment of same unit but different ratio.
Definition unit.h:160
constexpr unit_t(const unit_t< _symbol, _exponent, _type_rhs, _ratio > &rhs)
construct from other unit with implicitly convertible type
Definition unit.h:68
constexpr auto operator*(const unit_t< _symbol, _rhs_exponent, _rhs_type, _rhs_ratio > &rhs) const
Definition unit.h:273
constexpr unit_t(unit_t &&)=default
_exponent exponent
Definition unit.h:57
constexpr unit_t operator-(const unit_t< _symbol, _exponent, _rhs_type, _rhs_ratio > &rhs) const
subtracts two values, returning type is type of lhs
Definition unit.h:413
constexpr bool operator<(const unit_t< _symbol, _exponent, _rhs_type, _rhs_ratio > &rhs) const
Definition unit.h:210
constexpr unit_t & operator=(const unit_t &rhs)=default
Assignment for same ratio.
constexpr unit_t operator+(const unit_t< _symbol, _exponent, _rhs_type, _rhs_ratio > &rhs) const
adds two values, returning type is type of lhs
Definition unit.h:373
constexpr unit_t(const unit_t &)=default
constexpr unit_t operator-() const
negate operation
Definition unit.h:451
constexpr bool operator!=(const unit_t< _symbol, _exponent, _rhs_type, _rhs_ratio > &rhs) const
compares two values, considers different ratios.
Definition unit.h:203
unit_t operator--(int)
decrement by postfix –
Definition unit.h:473
constexpr bool operator==(const unit_t< _symbol, _exponent, _rhs_type, _rhs_ratio > &rhs) const
Definition unit.h:176
constexpr auto operator/(const unit_t< _symbol, _rhs_exponent, _rhs_type, _rhs_ratio > &rhs) const
Definition unit.h:320
constexpr _unit_rhs as() const
Definition unit.h:104
constexpr unit_t operator/(const _type f) const
divide by a non-unit scalar
Definition unit.h:295
std::integral_constant< char, _symbol > symbol
Definition unit.h:58
constexpr unit_t(_type v)
Construct with value v.
Definition unit.h:61
constexpr unit_t & operator+=(const unit_t &rhs)
add-assign value of the same unit
Definition unit.h:388
constexpr unit_t(unit_t< _symbol, _exponent, _type, _rhs_ratio > &&rhs)
Definition unit.h:88
constexpr unit_t & operator=(unit_t &&rhs)=default
Move assignment for same ratio.
constexpr _type value() const
returns the stored value as raw type
Definition unit.h:100
constexpr unit_t & operator/=(const _type scalar)
divide with a non-unit scalar
Definition unit.h:366
unit_t & operator++()
increment by prefix ++
Definition unit.h:454
constexpr unit_t & operator=(const unit_t< _symbol, _exponent, _type, _rhs_ratio > &rhs)
Assignment of same unit but different ratio.
Definition unit.h:143
constexpr unit_t(const unit_t< _symbol, _exponent, _rhs_type, _rhs_ratio > &rhs)
Definition unit.h:77
constexpr auto operator*(const unit_t< _symbol, _rhs_exponent, _rhs_type, _ratio > &rhs) const
multiply with an unit of the same ratio
Definition unit.h:259
constexpr unit_t & operator-=(const unit_t< _symbol, _exponent, _type, _rhs_ratio > &rhs)
subtract value of the same type but possibly different ratio
Definition unit.h:437
Definition unit_cast.h:49
#define SI_ENABLE_IMPLICIT_RATIO_CONVERSION
Definition unit.h:17