From 5a010269bdc86b044b9b2ffc1430344f525db43f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 22 Feb 2019 12:22:00 +0100 Subject: [PATCH] Math: implement component-wise bool operations on BoolVector. --- doc/changelog.dox | 3 ++ doc/snippets/MagnumMath.cpp | 11 +++++++ src/Magnum/Math/BoolVector.h | 42 +++++++++++++++++++++++++ src/Magnum/Math/Test/BoolVectorTest.cpp | 28 ++++++++++++++--- 4 files changed, 80 insertions(+), 4 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 9746d6be0..b03543051 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -64,6 +64,9 @@ See also: @ref Animation::Extrapolation::Extrapolated to @ref Animation::Extrapolation::Constant to be consistent with @ref Animation::Track +- @ref Math::BoolVector now implements component-wise @cpp && @ce, + @cpp || @ce and @cpp ! @ce for better consistency with boolean operations + done on scalar types @subsubsection changelog-latest-changes-audio Audio library diff --git a/doc/snippets/MagnumMath.cpp b/doc/snippets/MagnumMath.cpp index 6f2349762..779420a83 100644 --- a/doc/snippets/MagnumMath.cpp +++ b/doc/snippets/MagnumMath.cpp @@ -690,6 +690,17 @@ static_cast(tan1); static_cast(tan2); } +{ +Vector3 epsilon; +/* [BoolVector-boolean] */ +Vector3 a, b; + +if(!(b < a - epsilon || a + epsilon < b)) { + // b is around a +} +/* [BoolVector-boolean] */ +} + { /* [Color3-pack] */ Color3 a{1.0f, 0.5f, 0.75f}; diff --git a/src/Magnum/Math/BoolVector.h b/src/Magnum/Math/BoolVector.h index 95d467b30..596908533 100644 --- a/src/Magnum/Math/BoolVector.h +++ b/src/Magnum/Math/BoolVector.h @@ -66,6 +66,20 @@ stored as bits in array of unsigned bytes, unused bits have undefined value which doesn't affect comparison or @ref all() / @ref none() / @ref any() functions. See also @ref matrix-vector for brief introduction. +@section Math-BoolVector-boolean Boolean operations + +The class implements @cpp && @ce, @cpp || @ce and @cpp ! @ce operators +component-wise, in other words equivalently to @cpp & @ce, @cpp | @ce and +@cpp ~ @ce. This is done in order to have consistent behavior with boolean +operations on scalar types --- in the following example, it causes the final +conversion to @cpp bool @ce done at the end (instead of it happening already in +the boolean subexpressions). Combined with @ref operator bool() returning +@cpp true @ce only if all bits are set, this means the condition will be passed +only if @cpp b @ce is around @cpp a @ce in *all dimensions*, and work the same +way as if the variables were just scalars: + +@snippet MagnumMath.cpp BoolVector-boolean + @m_keyword{bvec2,GLSL bvec2,} @m_keyword{bvec3,GLSL bvec3,} @m_keyword{bvec4,GLSL bvec4,} @@ -175,6 +189,14 @@ template class BoolVector { /** @brief Bitwise inversion */ BoolVector operator~() const; + /** + * @brief Component-wise boolean negation + * + * Equivalent to @ref operator~(). See @ref Math-BoolVector-boolean for + * more information. + */ + BoolVector operator!() const { return operator~(); } + /** * @brief Bitwise AND and assign * @@ -196,6 +218,16 @@ template class BoolVector { return BoolVector(*this) &= other; } + /** + * @brief Component-wise boolean AND + * + * Equivalent to @ref operator&(). See @ref Math-BoolVector-boolean for + * more information. + */ + BoolVector operator&&(const BoolVector& other) const { + return BoolVector(*this) &= other; + } + /** * @brief Bitwise OR and assign * @@ -217,6 +249,16 @@ template class BoolVector { return BoolVector(*this) |= other; } + /** + * @brief Component-wise boolean OR + * + * Equivalent to @ref operator&(). See @ref Math-BoolVector-boolean for + * more information. + */ + BoolVector operator||(const BoolVector& other) const { + return BoolVector(*this) |= other; + } + /** * @brief Bitwise XOR and assign * diff --git a/src/Magnum/Math/Test/BoolVectorTest.cpp b/src/Magnum/Math/Test/BoolVectorTest.cpp index 01e00dda2..7b4ddd0ef 100644 --- a/src/Magnum/Math/Test/BoolVectorTest.cpp +++ b/src/Magnum/Math/Test/BoolVectorTest.cpp @@ -73,6 +73,7 @@ struct BoolVectorTest: Corrade::TestSuite::Tester { void bitInverse(); void bitAndOrXor(); + void booleanOperationEquivalents(); void strictWeakOrdering(); @@ -105,6 +106,7 @@ BoolVectorTest::BoolVectorTest() { &BoolVectorTest::bitInverse, &BoolVectorTest::bitAndOrXor, + &BoolVectorTest::booleanOperationEquivalents, &BoolVectorTest::strictWeakOrdering, @@ -248,11 +250,15 @@ void BoolVectorTest::compareUndefined() { } void BoolVectorTest::convertBool() { - /* The ! operation should *just work* using the bool conversion operator */ CORRADE_VERIFY(BoolVector19(0xff, 0xff, 0x07)); - CORRADE_VERIFY(!BoolVector19(0xff, 0xff, 0x04)); - CORRADE_VERIFY(!BoolVector19(0x00, 0x00, 0x00)); - CORRADE_VERIFY(!!BoolVector19(0xff, 0xff, 0xff)); + CORRADE_VERIFY(!bool(BoolVector19(0xff, 0xff, 0x04))); + CORRADE_VERIFY(!bool(BoolVector19(0x00, 0x00, 0x00))); + CORRADE_VERIFY(BoolVector19(0xff, 0xff, 0xff)); + + /* Using ! before and after bool conversion will produce a different + result -- first is equivalent to !a.all(), while second is (~a).all() */ + CORRADE_COMPARE(!bool(BoolVector19(0xff, 0xff, 0x04)), true); + CORRADE_COMPARE(bool(!BoolVector19(0xff, 0xff, 0x04)), false); /* Implicit conversion is not allowed */ CORRADE_VERIFY(!(std::is_convertible::value)); @@ -284,6 +290,7 @@ void BoolVectorTest::any() { void BoolVectorTest::bitInverse() { CORRADE_COMPARE(~BoolVector19(0xa5, 0x5f, 0x03), BoolVector19(0x5a, 0xa0, 0x04)); + CORRADE_COMPARE(!BoolVector19(0xa5, 0x5f, 0x03), BoolVector19(0x5a, 0xa0, 0x04)); } void BoolVectorTest::bitAndOrXor() { @@ -291,10 +298,23 @@ void BoolVectorTest::bitAndOrXor() { BoolVector19 b(0x37, 0xf3, 0x06); CORRADE_COMPARE(a & b, BoolVector19(0x25, 0x53, 0x02)); + CORRADE_COMPARE(a && b, BoolVector19(0x25, 0x53, 0x02)); + CORRADE_COMPARE(a | b, BoolVector19(0xb7, 0xff, 0x07)); + CORRADE_COMPARE(a || b, BoolVector19(0xb7, 0xff, 0x07)); + CORRADE_COMPARE(a ^ b, BoolVector19(0x92, 0xac, 0x05)); } +void BoolVectorTest::booleanOperationEquivalents() { + Math::BoolVector<2> a{0x3}; + Math::BoolVector<2> b{0x2}; + + CORRADE_COMPARE(!(a || b), !a && !b); + CORRADE_COMPARE(!(a || b), ~(a | b)); + CORRADE_COMPARE(!a && !b, ~a & ~b); +} + void BoolVectorTest::strictWeakOrdering() { BoolVector<11> a, b, c;