#pragma once #include #include namespace util { enum class bound { Inclusive = 0, Exclusive }; struct bounds { bound low, high; }; constexpr inline const bounds default_bounds { bound::Inclusive, bound::Exclusive }; template struct range { constexpr static inline const bounds Bounds = B; using type = T; //constexpr inline range(T start, T end) : start(start), end(end){} constexpr inline range(T&& start, T&& end) : start(std::move(start)), end(std::move(end)){} constexpr inline range(const T& start, const T& end) : start(start), end(end){} constexpr inline range(range&& move) : start(std::move(move.start)), end(std::move(move.end)) {} constexpr inline range(const range& copy) : start(copy.start), end(copy.end){} constexpr inline ~range() {} constexpr inline auto length() const { return end-start; } constexpr inline auto length(const T& from) const { return from - start; } constexpr inline bool negative() const { return length() < 0; } constexpr inline range& normalise() { if(negative()) std::swap(start, end); return *this; } template requires (I < 2) constexpr inline T& get() { return I ? end : start; } template requires (I < 2) constexpr inline const T& get() const { return I ? end : start; } constexpr inline bool contains(const T& value) const { return (Bounds.low == bound::Exclusive ? value > start : value >= start) && (Bounds.high == bound::Exclusive ? value < end : value <= end); } // Clamp `value` in-place to be inside this range. constexpr inline T& clamp(T& value) const { if constexpr(Bounds.low == bound::Exclusive) { if (value <= start) value = start + 1; } else if (value < start) value = start; if constexpr(Bounds.high == bound::Exclusive) { if (value >= end) value = end - 1; } else if (value > end) value = end; return value; } // Clamp to a new value constexpr inline T clamped(T&& value) const { clamp(value); return value; } // Clamp value out-of-place constexpr inline T clamped(const T& value) const { T res = value; clamp(res); return res; } // Scale the `value` from this range to another one (of a compatable type). template constexpr inline auto scale(const range& to, T value) const { clamp(value); const auto diff = length(value); const f64 fract = f64(diff) / f64(length()); const auto diff2 = typename range::type(fract * f64(to.length())); return to.start + diff2; } constexpr inline auto scale(const range& to, T value) const { return scale(to, value); } T start, end; }; }