diff --git a/include/range.h b/include/range.h new file mode 100644 index 0000000..96476bc --- /dev/null +++ b/include/range.h @@ -0,0 +1,91 @@ +#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 }; } +} diff --git a/include/rng/crand.h b/include/rng/crand.h index 0466dea..71ce921 100644 --- a/include/rng/crand.h +++ b/include/rng/crand.h @@ -20,6 +20,9 @@ namespace rng inline i64 next_i64() override { return _sample_int(); } u64 next_u64() override; + + i32 next_i32() override; + u32 next_u32() override; protected: inline constexpr i64 _max_i64() const override { return RANGE_MAX; } inline constexpr u64 _max_u64() const override { return (u64)RANGE_MAX; } diff --git a/src/rng.cpp b/src/rng.cpp index d5cf204..24356ae 100644 --- a/src/rng.cpp +++ b/src/rng.cpp @@ -1,5 +1,6 @@ #include +#include template static inline constexpr T _scale(f64 sample, T max) @@ -48,3 +49,9 @@ N_INTS #undef NEXT //TODO: next_*(min, max) + +void __() +{ + util::range test(-10, 20); + test.scale({ 100, 200 }, 5); +} diff --git a/src/rng/crand.cpp b/src/rng/crand.cpp index aca200b..899d92d 100644 --- a/src/rng/crand.cpp +++ b/src/rng/crand.cpp @@ -32,12 +32,20 @@ namespace rng // Overrides // u64 crand::next_u64() { return std::bit_cast(std::abs(_sample_int()) & INT32_MAX); } // next_i/u64(max) overrides not nessicary, the impl would be same as base. same with array next_*(p, n) overrides + i32 crand::next_i32() { return (i32)next_i64(); } + u32 crand::next_u32() { return std::bit_cast((i32)_sample_int()); } // I think keeping the sign bit in the transmute here doesn't violate the distribution, since it's between int32's min and max value... //TODO: next_bytes(), next_v*() } void rng_test() { - rng::crand r(123); + rng::crand _r(123); + Random& r = _r; printf("%lu %lu %lu\n", r.next_u64(), r.next_u64(), r.next_u64()); + printf("%d %d %d\n", r.next_i32(), r.next_i32(), r.next_i32()); + printf("%u %u %u\n", r.next_u32(), r.next_u32(), r.next_u32()); + + // TODO: these aren't implemented yet in the base Random huh... + printf("---\n%u %d %d %u\n", r.next_u32(10, 20), r.next_i32(10, 20), r.next_i32(10), r.next_u32(10)); }