| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- //
- // limit.h
- // utilities
- //
- // Created by Sam Jaffe on 10/22/13.
- // Copyright (c) 2013 Sam Jaffe. All rights reserved.
- //
- #pragma once
- #include <type_traits>
- #include <math/clamp.h>
- namespace math {
- struct {
- } assert_bounds;
- using AssertBounds = decltype(assert_bounds);
- template <typename T, auto MINIMUM_VALUE, auto MAXIMUM_VALUE> class Bound final {
- public:
- static_assert(MINIMUM_VALUE <= MAXIMUM_VALUE,
- "The minimum value must be less than or equal to the maximum");
- using value_type = T;
- using underlying_type = value_type const &;
- using bound_type =
- std::common_type_t<decltype(MAXIMUM_VALUE), decltype(MINIMUM_VALUE)>;
- static constexpr const bound_type min = MINIMUM_VALUE;
- static constexpr const bound_type max = MAXIMUM_VALUE;
- private:
- value_type value_;
- public:
- constexpr Bound() : value_(clamp(value_type(), min, max)) {}
- constexpr Bound(value_type const & val) noexcept
- : value_(clamp(val, min, max)) {}
- Bound(AssertBounds, value_type val) : value_(assert_in_bounds(val, min, max)) {}
- explicit operator value_type const &() const { return value_; }
- value_type const &operator*() const { return value_; }
- value_type const *operator->() const { return &value_; }
- auto operator<=>(Bound const &other) const noexcept = default;
- template <typename F> void mutate(F &&func) {
- std::forward<F>(func)(value_);
- *this = Bound(value_);
- }
-
- Bound & operator-=(value_type by) { return *this = Bound(value_ - by); }
- Bound & operator+=(value_type by) { return *this = Bound(value_ + by); }
- Bound operator+(value_type by) const { return Bound{*this} += by; }
- Bound operator-(value_type by) const { return Bound{*this} -= by; }
- Bound & operator--() { return *this -= 1; }
- Bound & operator++() { return *this += 1; }
- Bound operator--(int) {
- Bound tmp = *this;
- operator--();
- return tmp;
- }
- Bound operator++(int) {
- Bound tmp = *this;
- operator++();
- return tmp;
- }
- };
- template <typename T, auto MINMAX> using SymBound = Bound<T, -MINMAX, +MINMAX>;
- template <typename T, auto VAL>
- using UniBound =
- std::conditional_t<0 <= VAL, Bound<T, 0, VAL>, Bound<T, VAL, 0>>;
- template <typename T, auto MIN, auto MAX, typename R>
- auto operator+(Bound<T, MIN, MAX> const &lhs, R const &rhs) {
- return *lhs + rhs;
- }
- template <typename L, auto L_MIN, auto L_MAX, typename R, auto R_MIN, auto R_MAX>
- auto operator+(Bound<L, L_MIN, L_MAX> const &lhs, Bound<R, R_MIN, R_MAX> const &rhs) {
- return *lhs + *rhs;
- }
- template <typename T, auto MIN, auto MAX, typename R>
- auto operator-(Bound<T, MIN, MAX> const &lhs, R const &rhs) {
- return *lhs - rhs;
- }
- template <typename L, auto L_MIN, auto L_MAX, typename R, auto R_MIN, auto R_MAX>
- auto operator-(Bound<L, L_MIN, L_MAX> const &lhs, Bound<R, R_MIN, R_MAX> const &rhs) {
- return *lhs - *rhs;
- }
- template <typename T, auto MIN, auto MAX, typename R>
- auto operator*(Bound<T, MIN, MAX> const &lhs, R const &rhs) {
- return *lhs * rhs;
- }
- template <typename L, auto L_MIN, auto L_MAX, typename R, auto R_MIN, auto R_MAX>
- auto operator*(Bound<L, L_MIN, L_MAX> const &lhs, Bound<R, R_MIN, R_MAX> const &rhs) {
- return *lhs * *rhs;
- }
- template <typename T, auto MIN, auto MAX, typename R>
- auto operator/(Bound<T, MIN, MAX> const &lhs, R const &rhs) {
- return *lhs / rhs;
- }
- template <typename L, auto L_MIN, auto L_MAX, typename R, auto R_MIN, auto R_MAX>
- auto operator/(Bound<L, L_MIN, L_MAX> const &lhs, Bound<R, R_MIN, R_MAX> const &rhs) {
- return *lhs / *rhs;
- }
- template <typename T, auto MIN, auto MAX, typename R>
- auto min(Bound<T, MIN, MAX> const &lhs, R const &rhs) {
- using std::min;
- return min(*lhs, rhs);
- }
- template <typename T, auto MIN, auto MAX, typename R>
- auto max(Bound<T, MIN, MAX> const &lhs, R const &rhs) {
- using std::max;
- return max(*lhs, rhs);
- }
- }
|