You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
2.7 KiB
103 lines
2.7 KiB
#pragma once
|
|
|
|
#include <utility>
|
|
|
|
#include <common.h>
|
|
|
|
namespace util {
|
|
enum class bound
|
|
{
|
|
Inclusive = 0,
|
|
Exclusive
|
|
};
|
|
|
|
struct bounds
|
|
{
|
|
bound low, high;
|
|
};
|
|
constexpr inline const bounds default_bounds { bound::Inclusive, bound::Exclusive };
|
|
|
|
template<typename T, bounds B = default_bounds>
|
|
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<T>&& move) : start(std::move(move.start)), end(std::move(move.end)) {}
|
|
constexpr inline range(const range<T>& 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<T>& normalise() {
|
|
if(negative()) std::swap(start, end);
|
|
return *this;
|
|
}
|
|
|
|
template<usize I>
|
|
requires (I < 2)
|
|
constexpr inline T& get() { return I ? end : start; }
|
|
template<usize I>
|
|
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<typename U>
|
|
constexpr inline auto scale(const range<U>& to, T value) const
|
|
{
|
|
clamp(value);
|
|
const auto diff = length(value);
|
|
const f64 fract = f64(diff) / f64(length());
|
|
const auto diff2 = typename range<U>::type(fract * f64(to.length()));
|
|
|
|
return to.start + diff2;
|
|
}
|
|
constexpr inline auto scale(const range<T>& to, T value) const { return scale<T>(to, value); }
|
|
|
|
T start, end;
|
|
};
|
|
}
|