BoundedValue.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Louis Langholtz https://github.com/louis-langholtz/PlayRho
3  *
4  * This software is provided 'as-is', without any express or implied
5  * warranty. In no event will the authors be held liable for any damages
6  * arising from the use of this software.
7  *
8  * Permission is granted to anyone to use this software for any purpose,
9  * including commercial applications, and to alter it and redistribute it
10  * freely, subject to the following restrictions:
11  *
12  * 1. The origin of this software must not be misrepresented; you must not
13  * claim that you wrote the original software. If you use this software
14  * in a product, an acknowledgment in the product documentation would be
15  * appreciated but is not required.
16  * 2. Altered source versions must be plainly marked as such, and must not be
17  * misrepresented as being the original software.
18  * 3. This notice may not be removed or altered from any source distribution.
19  */
20 
21 #ifndef PLAYRHO_COMMON_BOUNDEDVALUE_HPP
22 #define PLAYRHO_COMMON_BOUNDEDVALUE_HPP
23 
26 
27 #include <limits>
28 #include <type_traits>
29 #include <iostream>
30 #include <utility>
31 
32 namespace playrho {
33 
35  enum class LoValueCheck
36  {
37  Any,
38  AboveZero,
39  ZeroOrMore,
41  NonZero
42  };
43 
45  enum class HiValueCheck
46  {
47  Any,
48  BelowZero,
49  ZeroOrLess,
50  OneOrLess,
52  };
53 
55  template <typename T, class Enable = void>
57  {
59  static PLAYRHO_CONSTEXPR const bool has_one = false;
60 
62  static PLAYRHO_CONSTEXPR inline T one() noexcept { return T{0}; }
63  };
64 
65  template<class T, class = void>
66  struct HasOne: std::false_type {};
67 
69  template<class T>
70  struct HasOne<T, detail::VoidT<decltype(T{1}) > >: std::true_type {};
71 
73  template <typename T>
74  struct ValueCheckHelper<T, std::enable_if_t<HasOne<T>::value>>
75  {
77  static PLAYRHO_CONSTEXPR const bool has_one = true;
78 
80  static PLAYRHO_CONSTEXPR inline T one() noexcept { return T{1}; }
81  };
82 
84  template <typename T>
85  PLAYRHO_CONSTEXPR inline std::enable_if_t<std::numeric_limits<T>::has_infinity, void>
87  {
88  if (!(value > -std::numeric_limits<T>::infinity()))
89  {
90  throw InvalidArgument{"BoundedValue: value not > -inf"};;
91  }
92  }
93 
95  template <typename T>
96  PLAYRHO_CONSTEXPR inline std::enable_if_t<!std::numeric_limits<T>::has_infinity, void>
97  CheckIfAboveNegInf(T /*value*/)
98  {
99  // Intentionally empty.
100  }
101 
103  template <typename T>
104  PLAYRHO_CONSTEXPR inline std::enable_if_t<std::numeric_limits<T>::has_infinity, void>
106  {
107  if (!(value < +std::numeric_limits<T>::infinity()))
108  {
109  throw InvalidArgument{"BoundedValue: value not < +inf"};;
110  }
111  }
112 
114  template <typename T>
115  PLAYRHO_CONSTEXPR inline std::enable_if_t<!std::numeric_limits<T>::has_infinity, void>
116  CheckIfBelowPosInf(T /*value*/)
117  {
118  // Intentionally empty.
119  }
120 
124  template <typename T, LoValueCheck lo, HiValueCheck hi>
126  {
127  public:
129  using value_type = T;
130 
132  using remove_pointer_type = typename std::remove_pointer<T>::type;
133 
136 
139 
141  static PLAYRHO_CONSTEXPR inline LoValueCheck GetLoCheck() { return lo; }
142 
144  static PLAYRHO_CONSTEXPR inline HiValueCheck GetHiCheck() { return hi; }
145 
147  static PLAYRHO_CONSTEXPR inline void DoLoCheck(value_type value)
148  {
149  switch (GetLoCheck())
150  {
151  case LoValueCheck::Any:
152  return;
154  if (!(value > value_type{0}))
155  {
156  throw exception_type{"BoundedValue: value not > 0"};
157  }
158  return;
160  if (!(value >= value_type{0}))
161  {
162  throw exception_type{"BoundedValue: value not >= 0"};
163  }
164  return;
166  CheckIfAboveNegInf<T>(value);
167  return;
169  if (value == static_cast<value_type>(0))
170  {
171  throw exception_type{"BoundedValue: value may not be 0"};
172  }
173  return;
174  }
175  }
176 
178  static PLAYRHO_CONSTEXPR inline void DoHiCheck(value_type value)
179  {
180  switch (GetHiCheck())
181  {
182  case HiValueCheck::Any:
183  return;
185  if (!(value < value_type{0}))
186  {
187  throw exception_type{"BoundedValue: value not < 0"};
188  }
189  return;
191  if (!(value <= value_type{0}))
192  {
193  throw exception_type{"BoundedValue: value not <= 0"};
194  }
195  return;
198  {
199  throw exception_type{"BoundedValue: value's type does not have trivial 1"};
200  }
201  if (!(value <= ValueCheckHelper<value_type>::one()))
202  {
203  throw exception_type{"BoundedValue: value not <= 1"};
204  }
205  return;
207  CheckIfBelowPosInf(value);
208  return;
209  }
210  }
211 
213  PLAYRHO_CONSTEXPR inline BoundedValue(value_type value): m_value{value}
214  {
215  DoLoCheck(value);
216  DoHiCheck(value);
217  }
218 
220  template <typename U>
221  PLAYRHO_CONSTEXPR inline BoundedValue(U value): m_value{value_type(value)}
222  {
223  DoLoCheck(value_type(value));
224  DoHiCheck(value_type(value));
225  }
226 
228  PLAYRHO_CONSTEXPR inline BoundedValue(const this_type& value) = default;
229 
231  PLAYRHO_CONSTEXPR inline BoundedValue(this_type&& value) noexcept:
232  m_value{std::move(value.m_value)}
233  {
234  // Intentionally empty.
235  // Note that the exception specification of this constructor
236  // doesn't match the defaulted one (when built with boost units).
237  }
238 
239  ~BoundedValue() noexcept = default;
240 
242  PLAYRHO_CONSTEXPR inline BoundedValue& operator= (const this_type& other) noexcept
243  {
244  m_value = other.m_value;
245  return *this;
246  }
247 
249  PLAYRHO_CONSTEXPR inline BoundedValue& operator= (const T& value)
250  {
251  DoLoCheck(value);
252  DoHiCheck(value);
253  m_value = value;
254  return *this;
255  }
256 
258  template <typename U>
259  PLAYRHO_CONSTEXPR inline std::enable_if_t<std::is_convertible<U, T>::value, BoundedValue&>
260  operator= (const U& tmpVal)
261  {
262  const auto value = T(tmpVal);
263  DoLoCheck(value);
264  DoHiCheck(value);
265  m_value = value;
266  return *this;
267  }
268 
271  {
272  // Note that the exception specification of this method
273  // doesn't match the defaulted one (when built with boost units).
274  m_value = std::move(value.m_value);
275  return *this;
276  }
277 
279  PLAYRHO_CONSTEXPR inline value_type get() const noexcept
280  {
281  return m_value;
282  }
283 
285  PLAYRHO_CONSTEXPR inline operator value_type () const noexcept
286  {
287  return m_value;
288  }
289 
291  template <typename U = T>
292  PLAYRHO_CONSTEXPR inline std::enable_if_t<std::is_pointer<U>::value, U> operator-> () const
293  {
294  return m_value;
295  }
296 
298  template <typename U = T>
299  PLAYRHO_CONSTEXPR inline std::enable_if_t<std::is_pointer<U>::value, remove_pointer_type>&
300  operator* () const
301  {
302  return *m_value;
303  }
304 
305  private:
306  value_type m_value;
307  };
308 
309  // Common logical operations for BoundedValue<T, lo, hi> OP BoundedValue<T, lo, hi>
310 
312  template <typename T, LoValueCheck lo, HiValueCheck hi>
314  {
315  return T{lhs} == T{rhs};
316  }
317 
319  template <typename T, LoValueCheck lo, HiValueCheck hi>
321  {
322  return T{lhs} != T{rhs};
323  }
324 
325  // Logical operations for numerical BoundedValue<T, lo, hi> OP BoundedValue<T, lo, hi>
326 
328  template <typename T, LoValueCheck lo, HiValueCheck hi>
330  {
331  return T{lhs} <= T{rhs};
332  }
333 
335  template <typename T, LoValueCheck lo, HiValueCheck hi>
337  {
338  return T{lhs} >= T{rhs};
339  }
340 
342  template <typename T, LoValueCheck lo, HiValueCheck hi>
344  {
345  return T{lhs} < T{rhs};
346  }
347 
349  template <typename T, LoValueCheck lo, HiValueCheck hi>
351  {
352  return T{lhs} > T{rhs};
353  }
354 
356  template <typename T, LoValueCheck lo, HiValueCheck hi>
358  {
359  return T{lhs} * T{rhs};
360  }
361 
363  template <typename T, LoValueCheck lo, HiValueCheck hi>
365  {
366  return T{lhs} / T{rhs};
367  }
368 
370  template <typename T, LoValueCheck lo, HiValueCheck hi>
372  {
373  return T{lhs} + T{rhs};
374  }
375 
377  template <typename T, LoValueCheck lo, HiValueCheck hi>
379  {
380  return T{lhs} - T{rhs};
381  }
382 
383  // Commmon logical operations for BoundedValue<T, lo, hi> OP T
384 
386  template <typename T, LoValueCheck lo, HiValueCheck hi>
387  PLAYRHO_CONSTEXPR inline bool operator== (const BoundedValue<T, lo, hi> lhs, const T rhs)
388  {
389  return T{lhs} == rhs;
390  }
391 
393  template <typename T, LoValueCheck lo, HiValueCheck hi>
394  PLAYRHO_CONSTEXPR inline bool operator!= (const BoundedValue<T, lo, hi> lhs, const T rhs)
395  {
396  return T{lhs} != rhs;
397  }
398 
399  // Logical operations for numerical BoundedValue<T, lo, hi> OP T
400 
402  template <typename T, LoValueCheck lo, HiValueCheck hi>
403  PLAYRHO_CONSTEXPR inline bool operator<= (const BoundedValue<T, lo, hi> lhs, const T rhs)
404  {
405  return T{lhs} <= rhs;
406  }
407 
409  template <typename T, LoValueCheck lo, HiValueCheck hi>
410  PLAYRHO_CONSTEXPR inline bool operator>= (const BoundedValue<T, lo, hi> lhs, const T rhs)
411  {
412  return T{lhs} >= rhs;
413  }
414 
416  template <typename T, LoValueCheck lo, HiValueCheck hi>
417  PLAYRHO_CONSTEXPR inline bool operator< (const BoundedValue<T, lo, hi> lhs, const T rhs)
418  {
419  return T{lhs} < rhs;
420  }
421 
423  template <typename T, LoValueCheck lo, HiValueCheck hi>
424  PLAYRHO_CONSTEXPR inline bool operator> (const BoundedValue<T, lo, hi> lhs, const T rhs)
425  {
426  return T{lhs} > rhs;
427  }
428 
430  template <typename T, typename U, LoValueCheck lo, HiValueCheck hi>
431  PLAYRHO_CONSTEXPR inline auto operator* (const BoundedValue<T, lo, hi> lhs, const U rhs)
432  {
433  return T{lhs} * rhs;
434  }
435 
437  template <typename T, typename U, LoValueCheck lo, HiValueCheck hi>
438  PLAYRHO_CONSTEXPR inline auto operator/ (const BoundedValue<T, lo, hi> lhs, const U rhs)
439  {
440  return T{lhs} / rhs;
441  }
442 
444  template <typename T, typename U, LoValueCheck lo, HiValueCheck hi>
445  PLAYRHO_CONSTEXPR inline auto operator+ (const BoundedValue<T, lo, hi> lhs, const U rhs)
446  {
447  return T{lhs} + rhs;
448  }
449 
451  template <typename T, typename U, LoValueCheck lo, HiValueCheck hi>
452  PLAYRHO_CONSTEXPR inline auto operator- (const BoundedValue<T, lo, hi> lhs, const U rhs)
453  {
454  return T{lhs} - T{rhs};
455  }
456 
457  // Commmon logical operations for T OP BoundedValue<T, lo, hi>
458 
460  template <typename T, LoValueCheck lo, HiValueCheck hi>
461  PLAYRHO_CONSTEXPR inline bool operator== (const T lhs, const BoundedValue<T, lo, hi> rhs)
462  {
463  return lhs == T{rhs};
464  }
465 
467  template <typename T, LoValueCheck lo, HiValueCheck hi>
468  PLAYRHO_CONSTEXPR inline bool operator!= (const T lhs, const BoundedValue<T, lo, hi> rhs)
469  {
470  return lhs != T{rhs};
471  }
472 
473  // Logical operations for numerical T OP BoundedValue<T, lo, hi>
474 
476  template <typename T, LoValueCheck lo, HiValueCheck hi>
477  PLAYRHO_CONSTEXPR inline bool operator<= (const T lhs, const BoundedValue<T, lo, hi> rhs)
478  {
479  return lhs <= T{rhs};
480  }
481 
483  template <typename T, LoValueCheck lo, HiValueCheck hi>
484  PLAYRHO_CONSTEXPR inline bool operator>= (const T lhs, const BoundedValue<T, lo, hi> rhs)
485  {
486  return lhs >= T{rhs};
487  }
488 
490  template <typename T, LoValueCheck lo, HiValueCheck hi>
491  PLAYRHO_CONSTEXPR inline bool operator< (const T lhs, const BoundedValue<T, lo, hi> rhs)
492  {
493  return lhs < T{rhs};
494  }
495 
497  template <typename T, LoValueCheck lo, HiValueCheck hi>
498  PLAYRHO_CONSTEXPR inline bool operator> (const T lhs, const BoundedValue<T, lo, hi> rhs)
499  {
500  return lhs > T{rhs};
501  }
502 
504  template <typename T, typename U, LoValueCheck lo, HiValueCheck hi>
505  PLAYRHO_CONSTEXPR inline auto operator* (const U lhs, const BoundedValue<T, lo, hi> rhs)
506  {
507  return lhs * T{rhs};
508  }
509 
511  template <typename T, typename U, LoValueCheck lo, HiValueCheck hi>
512  PLAYRHO_CONSTEXPR inline auto operator/ (const U lhs, const BoundedValue<T, lo, hi> rhs)
513  {
514  return lhs / T{rhs};
515  }
516 
518  template <typename T, typename U, LoValueCheck lo, HiValueCheck hi>
519  PLAYRHO_CONSTEXPR inline auto operator+ (const U lhs, const BoundedValue<T, lo, hi> rhs)
520  {
521  return lhs + T{rhs};
522  }
523 
525  template <typename T, typename U, LoValueCheck lo, HiValueCheck hi>
526  PLAYRHO_CONSTEXPR inline auto operator- (const U lhs, const BoundedValue<T, lo, hi> rhs)
527  {
528  return lhs - T{rhs};
529  }
530 
531  // Unary operations for BoundedValue<T, lo, hi>
532 
533  // Common useful aliases...
534 
543 
545  template <typename T>
546  using NonNegative = std::enable_if_t<!std::is_pointer<T>::value,
548 
550  template <typename T>
552 
554  template <typename T>
556 
558  template <typename T>
560 
562  template <typename T>
564 
566  template <typename T>
567  using NonZero = std::enable_if_t<!std::is_pointer<T>::value,
569 
572  template <typename T>
573  using NonNull = std::enable_if_t<std::is_pointer<T>::value,
575 
577  template <typename T>
579 
581 
583  template <typename T, LoValueCheck lo, HiValueCheck hi>
584  ::std::ostream& operator<<(::std::ostream& os, const BoundedValue<T, lo, hi>& value)
585  {
586  return os << T{value};
587  }
588 
589 } // namespace playrho
590 
591 #endif // PLAYRHO_COMMON_BOUNDEDVALUE_HPP