Merge pull request #722 from jpcima/unchecked-range

Add UncheckedRange
This commit is contained in:
JP Cimalando 2021-03-19 21:20:54 +01:00 committed by GitHub
commit d183c8c5a7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 9 deletions

View file

@ -16,8 +16,9 @@ namespace sfz
* @brief This class holds a range with functions to clamp and test if a value is in the range * @brief This class holds a range with functions to clamp and test if a value is in the range
* *
* @tparam Type * @tparam Type
* @tparam Checked whether this range adapts itself to guarantee (start<=end)
*/ */
template <class Type> template <class Type, bool Checked = true>
class Range { class Range {
// static_assert(std::is_arithmetic<Type>::value // static_assert(std::is_arithmetic<Type>::value
// || (std::is_enum<Type>::value && std::is_same<typename std::underlying_type<Type>::type, int>::value), // || (std::is_enum<Type>::value && std::is_same<typename std::underlying_type<Type>::type, int>::value),
@ -27,7 +28,7 @@ public:
constexpr Range() = default; constexpr Range() = default;
constexpr Range(Type start, Type end) noexcept constexpr Range(Type start, Type end) noexcept
: _start(start) : _start(start)
, _end(max(start, end)) , _end(Checked ? max(start, end) : end)
{ {
} }
@ -43,16 +44,28 @@ public:
void setStart(Type start) noexcept void setStart(Type start) noexcept
{ {
_start = start; _start = start;
if (start > _end) if (Checked && start > _end)
_end = start; _end = start;
} }
void setEnd(Type end) noexcept void setEnd(Type end) noexcept
{ {
_end = end; _end = end;
if (end < _start) if (Checked && end < _start)
_start = end; _start = end;
} }
/**
* @brief Check whether the range verifies (start<=end)
*/
bool isValid() const noexcept
{
if (Checked)
return true; // always valid
else
return _start <= _end;
}
/** /**
* @brief Clamp a value within the range including the endpoints * @brief Clamp a value within the range including the endpoints
* *
@ -84,7 +97,7 @@ public:
*/ */
void shrinkIfSmaller(Type start, Type end) void shrinkIfSmaller(Type start, Type end)
{ {
if (start > end) if (Checked && start > end)
std::swap(start, end); std::swap(start, end);
if (start > _start) if (start > _start)
@ -96,12 +109,9 @@ public:
void expandTo(Type value) void expandTo(Type value)
{ {
if (containsWithEnd(value))
return;
if (value > _end) if (value > _end)
_end = value; _end = value;
else else if (value < _start)
_start = value; _start = value;
} }
@ -134,6 +144,9 @@ private:
Type _start { static_cast<Type>(0.0) }; Type _start { static_cast<Type>(0.0) };
Type _end { static_cast<Type>(0.0) }; Type _end { static_cast<Type>(0.0) };
}; };
template <class T> using UncheckedRange = Range<T, false>;
} }
template <class Type> template <class Type>

View file

@ -62,6 +62,32 @@ TEST_CASE("[Range] Contains")
REQUIRE(floatRange.containsWithEnd(10.0)); REQUIRE(floatRange.containsWithEnd(10.0));
} }
TEST_CASE("[Range] Unchecked ranges")
{
sfz::UncheckedRange<int> intRange { 10, 1 };
REQUIRE(intRange.getStart() == 10);
REQUIRE(intRange.getEnd() == 1);
REQUIRE(!intRange.isValid());
for (int v : {0, 1, 5, 10}) {
REQUIRE(!intRange.contains(v));
REQUIRE(!intRange.containsWithEnd(v));
}
sfz::UncheckedRange<float> floatRange { 10.0, 1.0 };
REQUIRE(floatRange.getStart() == 10.0f);
REQUIRE(floatRange.getEnd() == 1.0f);
REQUIRE(!floatRange.isValid());
for (float v : {0.0f, 1.0f, 5.0f, 10.0f}) {
REQUIRE(!floatRange.contains(v));
REQUIRE(!floatRange.containsWithEnd(v));
}
REQUIRE(sfz::UncheckedRange<int> { 1, 10 }.isValid());
REQUIRE(sfz::UncheckedRange<int> { 1, 1 }.isValid());
REQUIRE(sfz::UncheckedRange<float> { 1.0, 10.0 }.isValid());
REQUIRE(sfz::UncheckedRange<float> { 10.0, 10.0 }.isValid());
}
TEST_CASE("[Range] Clamp") TEST_CASE("[Range] Clamp")
{ {
sfz::Range<int> intRange { 1, 10 }; sfz::Range<int> intRange { 1, 10 };