// // limit.h // utilities // // Created by Sam Jaffe on 10/22/13. // Copyright (c) 2013 Sam Jaffe. All rights reserved. // #pragma once #include #include namespace math { struct { } assert_bounds; using AssertBounds = decltype(assert_bounds); template 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; 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 void mutate(F &&func) { std::forward(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 using SymBound = Bound; template using UniBound = std::conditional_t<0 <= VAL, Bound, Bound>; template auto operator+(Bound const &lhs, R const &rhs) { return *lhs + rhs; } template auto operator+(Bound const &lhs, Bound const &rhs) { return *lhs + *rhs; } template auto operator-(Bound const &lhs, R const &rhs) { return *lhs - rhs; } template auto operator-(Bound const &lhs, Bound const &rhs) { return *lhs - *rhs; } template auto operator*(Bound const &lhs, R const &rhs) { return *lhs * rhs; } template auto operator*(Bound const &lhs, Bound const &rhs) { return *lhs * *rhs; } template auto operator/(Bound const &lhs, R const &rhs) { return *lhs / rhs; } template auto operator/(Bound const &lhs, Bound const &rhs) { return *lhs / *rhs; } template auto min(Bound const &lhs, R const &rhs) { using std::min; return min(*lhs, rhs); } template auto max(Bound const &lhs, R const &rhs) { using std::max; return max(*lhs, rhs); } }