limit.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. //
  2. // limit.h
  3. // utilities
  4. //
  5. // Created by Sam Jaffe on 10/22/13.
  6. // Copyright (c) 2013 Sam Jaffe. All rights reserved.
  7. //
  8. #pragma once
  9. #include <type_traits>
  10. #include <math/clamp.h>
  11. namespace math {
  12. struct {
  13. } assert_bounds;
  14. using AssertBounds = decltype(assert_bounds);
  15. template <typename T, auto MINIMUM_VALUE, auto MAXIMUM_VALUE> class Bound final {
  16. public:
  17. static_assert(MINIMUM_VALUE <= MAXIMUM_VALUE,
  18. "The minimum value must be less than or equal to the maximum");
  19. using value_type = T;
  20. using underlying_type = value_type const &;
  21. using bound_type =
  22. std::common_type_t<decltype(MAXIMUM_VALUE), decltype(MINIMUM_VALUE)>;
  23. static constexpr const bound_type min = MINIMUM_VALUE;
  24. static constexpr const bound_type max = MAXIMUM_VALUE;
  25. private:
  26. value_type value_;
  27. public:
  28. constexpr Bound() : value_(clamp(value_type(), min, max)) {}
  29. constexpr Bound(value_type const & val) noexcept
  30. : value_(clamp(val, min, max)) {}
  31. Bound(AssertBounds, value_type val) : value_(assert_in_bounds(val, min, max)) {}
  32. explicit operator value_type const &() const { return value_; }
  33. value_type const &operator*() const { return value_; }
  34. value_type const *operator->() const { return &value_; }
  35. auto operator<=>(Bound const &other) const noexcept = default;
  36. template <typename F> void mutate(F &&func) {
  37. std::forward<F>(func)(value_);
  38. *this = Bound(value_);
  39. }
  40. Bound & operator-=(value_type by) { return *this = Bound(value_ - by); }
  41. Bound & operator+=(value_type by) { return *this = Bound(value_ + by); }
  42. Bound operator+(value_type by) const { return Bound{*this} += by; }
  43. Bound operator-(value_type by) const { return Bound{*this} -= by; }
  44. Bound & operator--() { return *this -= 1; }
  45. Bound & operator++() { return *this += 1; }
  46. Bound operator--(int) {
  47. Bound tmp = *this;
  48. operator--();
  49. return tmp;
  50. }
  51. Bound operator++(int) {
  52. Bound tmp = *this;
  53. operator++();
  54. return tmp;
  55. }
  56. };
  57. template <typename T, auto MINMAX> using SymBound = Bound<T, -MINMAX, +MINMAX>;
  58. template <typename T, auto VAL>
  59. using UniBound =
  60. std::conditional_t<0 <= VAL, Bound<T, 0, VAL>, Bound<T, VAL, 0>>;
  61. template <typename T, auto MIN, auto MAX, typename R>
  62. auto operator+(Bound<T, MIN, MAX> const &lhs, R const &rhs) {
  63. return *lhs + rhs;
  64. }
  65. template <typename L, auto L_MIN, auto L_MAX, typename R, auto R_MIN, auto R_MAX>
  66. auto operator+(Bound<L, L_MIN, L_MAX> const &lhs, Bound<R, R_MIN, R_MAX> const &rhs) {
  67. return *lhs + *rhs;
  68. }
  69. template <typename T, auto MIN, auto MAX, typename R>
  70. auto operator-(Bound<T, MIN, MAX> const &lhs, R const &rhs) {
  71. return *lhs - rhs;
  72. }
  73. template <typename L, auto L_MIN, auto L_MAX, typename R, auto R_MIN, auto R_MAX>
  74. auto operator-(Bound<L, L_MIN, L_MAX> const &lhs, Bound<R, R_MIN, R_MAX> const &rhs) {
  75. return *lhs - *rhs;
  76. }
  77. template <typename T, auto MIN, auto MAX, typename R>
  78. auto operator*(Bound<T, MIN, MAX> const &lhs, R const &rhs) {
  79. return *lhs * rhs;
  80. }
  81. template <typename L, auto L_MIN, auto L_MAX, typename R, auto R_MIN, auto R_MAX>
  82. auto operator*(Bound<L, L_MIN, L_MAX> const &lhs, Bound<R, R_MIN, R_MAX> const &rhs) {
  83. return *lhs * *rhs;
  84. }
  85. template <typename T, auto MIN, auto MAX, typename R>
  86. auto operator/(Bound<T, MIN, MAX> const &lhs, R const &rhs) {
  87. return *lhs / rhs;
  88. }
  89. template <typename L, auto L_MIN, auto L_MAX, typename R, auto R_MIN, auto R_MAX>
  90. auto operator/(Bound<L, L_MIN, L_MAX> const &lhs, Bound<R, R_MIN, R_MAX> const &rhs) {
  91. return *lhs / *rhs;
  92. }
  93. template <typename T, auto MIN, auto MAX, typename R>
  94. auto min(Bound<T, MIN, MAX> const &lhs, R const &rhs) {
  95. using std::min;
  96. return min(*lhs, rhs);
  97. }
  98. template <typename T, auto MIN, auto MAX, typename R>
  99. auto max(Bound<T, MIN, MAX> const &lhs, R const &rhs) {
  100. using std::max;
  101. return max(*lhs, rhs);
  102. }
  103. }