#pragma once #include #include #include namespace util{ enum class bound { Inclusive, Exclusive, }; template struct range; using bounds = range; constexpr static inline const bounds default_bounds(); template struct range final { 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; } template constexpr inline bool contains(const T& value) const { return (Bounds.get<0>() == bound::Exclusive ? value > start : value >= start) && (Bounds.get<1>() == bound::Exclusive ? value < end : value <= end); } template constexpr inline void clamp(T& value) const { if constexpr(Bounds.get<0>() == bound::Exclusive) { if (value <= start) value = start + 1; } else if (value < start) value = start; if constexpr(Bounds.get<1>() == bound::Exclusive) { if (value >= end) value = end - 1; } else if (value > end) value = end; } // Scale the `value` from this range to another one (of a compatable type). template constexpr inline auto scale(const range& to, T value) { clamp(value); const auto diff = length(value); const f64 fract = f64(diff) / f64(length()); const auto diff2 = decltype(to)::type(fract * f64(to.length())); return to.start + diff2; } template constexpr inline auto scale(const range& to, T value); T start, end; }; constexpr static inline const bounds default_bounds() { return { bound::Inclusive, bound::Exclusive }; } }