diff --git a/Sming/Core/Data/Range.h b/Sming/Core/Data/Range.h index ee2e251c8e..d6e60564c0 100644 --- a/Sming/Core/Data/Range.h +++ b/Sming/Core/Data/Range.h @@ -11,6 +11,7 @@ #pragma once #include +#include #include /** @@ -80,7 +81,7 @@ template struct TRange { /** * @brief Determine if range contains a value */ - bool contains(T value) const + template constexpr bool contains(V value) const { return (value >= min) && (value <= max); } @@ -96,9 +97,9 @@ template struct TRange { /** * @brief Clip values to within the range */ - T clip(T value) const + template constexpr T clip(V value) const { - return (value < min) ? min : (value > max) ? max : value; + return (value < min) ? min : (value > max) ? max : T(value); } /** @@ -106,11 +107,14 @@ template struct TRange { */ T random() const { - auto n = 1 + max - min; + uint64_t n = 1 + max - min; if(n == 0) { return 0; } - auto value = os_random(); + T value = os_random(); + if(n > std::numeric_limits::max()) { + value |= uint64_t(os_random()) << 32; + } return min + value % n; } diff --git a/tests/HostTests/include/modules.h b/tests/HostTests/include/modules.h index 037dedb112..75c8319ac4 100644 --- a/tests/HostTests/include/modules.h +++ b/tests/HostTests/include/modules.h @@ -22,6 +22,7 @@ XX(Libc) \ XX(PreCache) \ XX(BitSet) \ + XX(Range) \ XX(String) \ XX(ArduinoString) \ XX(Wiring) \ diff --git a/tests/HostTests/modules/Range.cpp b/tests/HostTests/modules/Range.cpp new file mode 100644 index 0000000000..50bbd522f9 --- /dev/null +++ b/tests/HostTests/modules/Range.cpp @@ -0,0 +1,56 @@ +#include +#include + +class RangeTest : public TestGroup +{ +public: + RangeTest() : TestGroup(_F("Range")) + { + } + + void execute() override + { + TEST_CASE("constexpr") + { + constexpr TRange range(0, 100); + constexpr auto int64 = 120000000000LL; + constexpr auto val = range.clip(int64); + static_assert(val == 100, "Bad clip"); + + constexpr int64_t tmp = 0x8000000000LL; + static_assert(!range.contains(tmp)); + + for(unsigned i = 0; i < 10; ++i) { + Serial << range.random() << endl; + } + } + + TEST_CASE("truncation") + { + constexpr TRange range(0, 100); + int val = 0x1020; + val = range.clip(val); + REQUIRE_EQ(val, 100); + } + + TEST_CASE("Membership") + { + constexpr TRange range(0, 100); + int val = 0x8000; + REQUIRE(!range.contains(val)); + } + + TEST_CASE("Random") + { + constexpr TRange range(-0x10000000000LL, 0x10000000000LL); + for(unsigned i = 0; i < 10; ++i) { + Serial << range.random() << endl; + } + } + } +}; + +void REGISTER_TEST(Range) +{ + registerGroup(); +}