OGLplus  (0.59.0) a C++ wrapper for rendering APIs

tagged_quantity.hpp
Go to the documentation of this file.
1 
9 #ifndef EAGINE_TAGGED_QUANTITY_HPP
10 #define EAGINE_TAGGED_QUANTITY_HPP
11 
12 #include "compare.hpp"
13 #include "diagnostic.hpp"
14 #include "units/default.hpp"
15 #include "units/traits.hpp"
16 #include <cmath>
17 #include <type_traits>
18 
19 #ifdef __clang__
20 EAGINE_DIAG_PUSH()
21 EAGINE_DIAG_OFF(double-promotion)
22 #endif
23 
24 namespace eagine {
25 //------------------------------------------------------------------------------
26 template <typename T, typename U>
28 //------------------------------------------------------------------------------
29 template <typename U, typename T>
30 static constexpr auto make_tagged_quantity(const T& value)
32 //------------------------------------------------------------------------------
35 template <typename T, typename U>
36 class tagged_quantity {
37 public:
39  using unit_type = U;
40 
42  using value_type = T;
43 
45  tagged_quantity() = default;
46 
48  explicit constexpr tagged_quantity(T v) noexcept
49  : _v{std::move(v)} {}
50 
52  template <
53  typename X,
54  typename UX,
55  typename = std::enable_if_t<
56  std::is_convertible_v<X, T> && units::is_convertible_v<UX, U>>>
57  constexpr tagged_quantity(const tagged_quantity<X, UX>& tq) noexcept
58  : _v(T(units::value_conv<UX, U>()(tq._v))) {}
59 
61  template <
62  typename UX,
63  typename = std::enable_if_t<units::is_convertible_v<U, UX>>>
64  constexpr auto to() const noexcept {
65  return make_tagged_quantity<UX>(units::value_conv<U, UX>()(_v));
66  }
67 
69  constexpr auto value() const noexcept -> T {
70  return _v;
71  }
72 
74  static constexpr auto unit() noexcept -> U {
75  return {};
76  }
77 
79  template <
80  typename X,
81  typename = std::enable_if_t<std::is_convertible_v<T, X>>>
82  explicit constexpr operator X() const noexcept {
83  return X(_v);
84  }
85 
87  template <
88  typename X,
89  typename UX,
90  typename = std::enable_if_t<
91  std::is_convertible_v<X, T> && units::is_convertible_v<UX, U>>>
92  auto operator+=(const tagged_quantity<X, UX>& q) noexcept -> auto& {
93  _v += T(units::value_conv<UX, U>()(q._v));
94  return *this;
95  }
96 
98  template <
99  typename X,
100  typename UX,
101  typename = std::enable_if_t<
102  std::is_convertible_v<X, T> && units::is_convertible_v<UX, U>>>
103  auto operator-=(const tagged_quantity<X, UX>& q) noexcept -> auto& {
104  _v -= T(units::value_conv<UX, U>()(q._v));
105  return *this;
106  }
107 
108 private:
109  static_assert(std::is_arithmetic_v<T>);
110  T _v{};
111 
112  template <typename, typename>
113  friend class tagged_quantity;
114 };
115 //------------------------------------------------------------------------------
116 // is_tagged_quantity
117 template <typename T>
118 struct is_tagged_quantity : std::false_type {};
119 //------------------------------------------------------------------------------
120 template <typename T>
121 using is_tagged_quantity_t = typename is_tagged_quantity<T>::type;
122 //------------------------------------------------------------------------------
123 template <typename T>
124 constexpr bool is_tagged_quantity_v = is_tagged_quantity<T>::value;
125 //------------------------------------------------------------------------------
126 template <typename T, typename U>
127 struct is_tagged_quantity<tagged_quantity<T, U>> : std::true_type {};
128 //------------------------------------------------------------------------------
129 // is_convertible_quantity
130 template <typename Qty, typename Unit>
131 struct is_convertible_quantity : std::false_type {};
132 //------------------------------------------------------------------------------
133 template <typename Q, typename U>
134 using is_convertible_quantity_t = typename is_convertible_quantity<Q, U>::type;
135 //------------------------------------------------------------------------------
136 template <typename Q, typename U>
137 constexpr bool is_convertible_quantity_v = is_convertible_quantity<Q, U>::value;
138 //------------------------------------------------------------------------------
139 template <typename T, typename QU, typename U>
140 struct is_convertible_quantity<tagged_quantity<T, QU>, U>
141  : units::is_convertible<QU, U> {};
142 //------------------------------------------------------------------------------
143 // make_tagged_quantity
144 template <typename U, typename T>
145 static constexpr auto make_tagged_quantity(const T& value)
146  -> tagged_quantity<T, U> {
147  return tagged_quantity<T, U>{value};
148 }
149 //------------------------------------------------------------------------------
150 template <
151  typename T,
152  typename U,
153  typename = std::enable_if_t<
154  !is_tagged_quantity_v<T> && !units::is_unit_v<T> && units::is_unit_v<U>>>
155 static constexpr auto operator*(const T& v, U) {
156  return make_tagged_quantity<U>(v);
157 }
158 //------------------------------------------------------------------------------
159 template <typename UX, typename T, typename U>
160 static inline auto convert_to(const tagged_quantity<T, U>& q) {
161  return q.template to<UX>();
162 }
163 //------------------------------------------------------------------------------
164 template <typename T, typename U>
165 static inline auto value(const tagged_quantity<T, U>& q) {
166  return q.value();
167 }
168 //------------------------------------------------------------------------------
169 template <typename T1, typename U1, typename T2, typename U2>
170 struct equal_cmp<tagged_quantity<T1, U1>, tagged_quantity<T2, U2>> {
171 
172  static_assert(units::is_convertible_v<U2, U1>);
173 
174  static constexpr auto check(
175  const tagged_quantity<T1, U1>& l,
176  const tagged_quantity<T2, U2>& r) noexcept -> bool {
177  return are_equal(value(l), units::value_conv<U2, U1>()(value(r)));
178  }
179 };
180 //------------------------------------------------------------------------------
184 template <typename T1, typename U1, typename T2, typename U2>
185 constexpr auto
187  -> std::enable_if_t<units::is_convertible_v<U2, U1>, bool> {
188  return value(a) == units::value_conv<U2, U1>()(value(b));
189 }
190 //------------------------------------------------------------------------------
194 template <typename T1, typename U1, typename T2, typename U2>
195 constexpr auto
197  -> std::enable_if_t<units::is_convertible_v<U2, U1>, bool> {
198  return value(a) != units::value_conv<U2, U1>()(value(b));
199 }
200 //------------------------------------------------------------------------------
204 template <typename T1, typename U1, typename T2, typename U2>
205 constexpr auto
207  -> std::enable_if_t<units::is_convertible_v<U2, U1>, bool> {
208  return value(a) < units::value_conv<U2, U1>()(value(b));
209 }
210 //------------------------------------------------------------------------------
214 template <typename T1, typename U1, typename T2, typename U2>
215 constexpr auto
217  -> std::enable_if_t<units::is_convertible_v<U2, U1>, bool> {
218  return value(a) <= units::value_conv<U2, U1>()(value(b));
219 }
220 //------------------------------------------------------------------------------
224 template <typename T1, typename U1, typename T2, typename U2>
225 constexpr auto
227  -> std::enable_if_t<units::is_convertible_v<U2, U1>, bool> {
228  return value(a) > units::value_conv<U2, U1>()(value(b));
229 }
230 //------------------------------------------------------------------------------
234 template <typename T1, typename U1, typename T2, typename U2>
235 constexpr auto
237  -> std::enable_if_t<units::is_convertible_v<U2, U1>, bool> {
238  return value(a) >= units::value_conv<U2, U1>()(value(b));
239 }
240 //------------------------------------------------------------------------------
244 template <typename T, typename U>
245 constexpr auto operator+(const tagged_quantity<T, U>& a) {
246  return a;
247 }
248 //------------------------------------------------------------------------------
252 template <typename T, typename U>
253 constexpr auto operator-(const tagged_quantity<T, U>& a) {
254  return make_tagged_quantity<U>(-value(a));
255 }
256 //------------------------------------------------------------------------------
260 template <typename T1, typename U1, typename T2, typename U2>
261 constexpr auto
263  using UR = units::add_result_t<U1, U2>;
264  return make_tagged_quantity<UR>(
265  units::value_conv<U1, UR>()(value(a)) +
266  units::value_conv<U2, UR>()(value(b)));
267 }
268 //------------------------------------------------------------------------------
272 template <typename T1, typename U1, typename T2, typename U2>
273 constexpr auto
275  using UR = units::sub_result_t<U1, U2>;
276  return make_tagged_quantity<UR>(
277  units::value_conv<U1, UR>()(value(a)) -
278  units::value_conv<U2, UR>()(value(b)));
279 }
280 //------------------------------------------------------------------------------
284 template <typename T1, typename U1, typename T2, typename U2>
285 constexpr auto
287  using UO1 = units::mul_l_operand_t<U1, U2>;
288  using UO2 = units::mul_r_operand_t<U1, U2>;
289  using UR = units::mul_result_t<U1, U2>;
290  return make_tagged_quantity<UR>(
291  units::value_conv<U1, UO1>()(value(a)) *
292  units::value_conv<U2, UO2>()(value(b)));
293 }
294 //------------------------------------------------------------------------------
298 template <
299  typename T1,
300  typename U,
301  typename T2,
302  typename = std::enable_if_t<!units::is_unit_v<T2> && !is_tagged_quantity_v<T2>>>
303 constexpr auto operator*(const tagged_quantity<T1, U>& a, const T2& c) {
304  return make_tagged_quantity<U>(value(a) * c);
305 }
306 //------------------------------------------------------------------------------
310 template <typename T1, typename T2, typename U>
311 constexpr auto operator*(const T1& c, const tagged_quantity<T2, U>& a) {
312  return make_tagged_quantity<U>(c * value(a));
313 }
314 //------------------------------------------------------------------------------
318 template <
319  typename T1,
320  typename U1,
321  typename U2,
322  typename = std::enable_if_t<units::is_unit_v<U2>>>
323 constexpr auto operator*(const tagged_quantity<T1, U1>& a, U2) {
324  return a * make_tagged_quantity<U2>(1);
325 }
326 //------------------------------------------------------------------------------
330 template <typename T1, typename U1, typename T2, typename U2>
331 constexpr auto
333  using UO1 = units::div_l_operand_t<U1, U2>;
334  using UO2 = units::div_r_operand_t<U1, U2>;
335  using UR = units::div_result_t<U1, U2>;
336  return make_tagged_quantity<UR>(
337  units::value_conv<U1, UO1>()(value(a)) /
338  units::value_conv<U2, UO2>()(value(b)));
339 }
340 //------------------------------------------------------------------------------
344 template <
345  typename T1,
346  typename U,
347  typename T2,
348  typename = std::enable_if_t<!units::is_unit_v<T2>>>
349 constexpr auto operator/(const tagged_quantity<T1, U>& a, const T2& c) {
350  return make_tagged_quantity<U>((1.F * value(a)) / c);
351 }
352 //------------------------------------------------------------------------------
356 template <
357  typename T1,
358  typename U1,
359  typename U2,
360  typename = std::enable_if_t<units::is_unit_v<U2>>>
361 constexpr auto operator/(const tagged_quantity<T1, U1>& a, U2) {
362  return a / make_tagged_quantity<U2>(1);
363 }
364 //------------------------------------------------------------------------------
365 } // namespace eagine
366 
367 #ifdef __clang__
368 EAGINE_DIAG_POP()
369 #endif
370 
371 #endif // EAGINE_TAGGED_QUANTITY_HPP
constexpr auto operator/(const tagged_quantity< T1, U1 > &a, U2)
Constant division operator.
Definition: tagged_quantity.hpp:361
constexpr auto operator/(const tagged_quantity< T1, U > &a, const T2 &c)
Division by constant operator.
Definition: tagged_quantity.hpp:349
U unit_type
Alias for the unit type.
Definition: tagged_quantity.hpp:39
constexpr tagged_quantity(const tagged_quantity< X, UX > &tq) noexcept
Converting constructor from another tagged quantity.
Definition: tagged_quantity.hpp:57
constexpr auto operator>=(const tagged_quantity< T1, U1 > &a, const tagged_quantity< T2, U2 > &b) -> std::enable_if_t< units::is_convertible_v< U2, U1 >, bool >
Greater-equal comparison.
Definition: tagged_quantity.hpp:236
Common code is placed in this namespace.
Definition: eagine.hpp:21
static constexpr auto operator<=(const valid_if< T, P1 > &v1, const valid_if< T, P2 > &v2) noexcept -> tribool
Less-equal comparison of two conditionally valid values.
Definition: decl.hpp:202
constexpr auto operator-(const tagged_quantity< T, U > &a)
Unary negation operator.
Definition: tagged_quantity.hpp:253
constexpr auto operator+(const tagged_quantity< T, U > &a)
Unary plus operator.
Definition: tagged_quantity.hpp:245
constexpr auto operator*(const tagged_quantity< T1, U > &a, const T2 &c)
Multiplication by constant operator.
Definition: tagged_quantity.hpp:303
constexpr auto operator==(const tagged_quantity< T1, U1 > &a, const tagged_quantity< T2, U2 > &b) -> std::enable_if_t< units::is_convertible_v< U2, U1 >, bool >
Equality comparison.
Definition: tagged_quantity.hpp:186
constexpr auto operator*(const tagged_quantity< T1, U1 > &a, U2)
Multiplication by unit operator.
Definition: tagged_quantity.hpp:323
auto operator-=(const tagged_quantity< X, UX > &q) noexcept -> auto &
Subtraction of another tagged quantity.
Definition: tagged_quantity.hpp:103
static constexpr auto unit() noexcept -> U
Returns the unit.
Definition: tagged_quantity.hpp:74
auto operator+=(const tagged_quantity< X, UX > &q) noexcept -> auto &
Addition of another tagged quantity.
Definition: tagged_quantity.hpp:92
constexpr auto operator/(const tagged_quantity< T1, U1 > &a, const tagged_quantity< T2, U2 > &b)
Division operator.
Definition: tagged_quantity.hpp:332
constexpr auto to() const noexcept
Conversion to a quantity in another unit type.
Definition: tagged_quantity.hpp:64
constexpr auto operator+(const tagged_quantity< T1, U1 > &a, const tagged_quantity< T2, U2 > &b)
Addition operator.
Definition: tagged_quantity.hpp:262
constexpr auto value() const noexcept -> T
Returns the value.
Definition: tagged_quantity.hpp:69
constexpr auto operator>(const tagged_quantity< T1, U1 > &a, const tagged_quantity< T2, U2 > &b) -> std::enable_if_t< units::is_convertible_v< U2, U1 >, bool >
Greater-than comparison.
Definition: tagged_quantity.hpp:226
T value_type
Alias for the value type.
Definition: tagged_quantity.hpp:42
constexpr auto operator*(const T1 &c, const tagged_quantity< T2, U > &a)
Multiplication by constant operator.
Definition: tagged_quantity.hpp:311
constexpr auto operator-(const tagged_quantity< T1, U1 > &a, const tagged_quantity< T2, U2 > &b)
Subtraction operator.
Definition: tagged_quantity.hpp:274
constexpr auto operator*(const tagged_quantity< T1, U1 > &a, const tagged_quantity< T2, U2 > &b)
Multiplication operator.
Definition: tagged_quantity.hpp:286
static constexpr auto operator<(const valid_if< T, P1 > &v1, const valid_if< T, P2 > &v2) noexcept -> tribool
Less-than comparison of two conditionally valid values.
Definition: decl.hpp:180
constexpr auto operator!=(const tagged_quantity< T1, U1 > &a, const tagged_quantity< T2, U2 > &b) -> std::enable_if_t< units::is_convertible_v< U2, U1 >, bool >
Nonequality comparison.
Definition: tagged_quantity.hpp:196
Value of type T with a specified unit or tag type U.
Definition: tagged_quantity.hpp:27
constexpr tagged_quantity(T v) noexcept
Explicit constructor initializing the value.
Definition: tagged_quantity.hpp:48

Copyright © 2015-2021 Matúš Chochlík.
<chochlik -at -gmail.com>
Documentation generated on Tue Apr 13 2021 by Doxygen (version 1.8.17).