From ddc738ba29bd5b1461dfb18a50e2bb523f48f3d5 Mon Sep 17 00:00:00 2001 From: Oliver James Date: Mon, 17 Apr 2023 12:16:54 +0100 Subject: [PATCH] Core: Add Scoped Enum Bitwise Operators This commit adds the JUCE_DECLARE_SCOPED_ENUM_BITWISE_OPERATORS macro, enabling bitwise operators on scoped enums. This feature simplifies the use of scoped enums in situations where bitwise operations are needed. --- modules/juce_core/juce_core.cpp | 1 + modules/juce_core/juce_core.h | 1 + modules/juce_core/misc/juce_EnumHelpers.h | 103 ++++++++++++++++++ .../juce_core/misc/juce_EnumHelpers_test.cpp | 94 ++++++++++++++++ 4 files changed, 199 insertions(+) create mode 100644 modules/juce_core/misc/juce_EnumHelpers.h create mode 100644 modules/juce_core/misc/juce_EnumHelpers_test.cpp diff --git a/modules/juce_core/juce_core.cpp b/modules/juce_core/juce_core.cpp index 3b69d2c514..2f178d62ff 100644 --- a/modules/juce_core/juce_core.cpp +++ b/modules/juce_core/juce_core.cpp @@ -262,6 +262,7 @@ #include "containers/juce_HashMap_test.cpp" #include "containers/juce_Optional_test.cpp" + #include "misc/juce_EnumHelpers_test.cpp" #endif //============================================================================== diff --git a/modules/juce_core/juce_core.h b/modules/juce_core/juce_core.h index 8f2acf0516..65c519b6e0 100644 --- a/modules/juce_core/juce_core.h +++ b/modules/juce_core/juce_core.h @@ -219,6 +219,7 @@ namespace juce extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noexcept; } +#include "misc/juce_EnumHelpers.h" #include "memory/juce_Memory.h" #include "maths/juce_MathsFunctions.h" #include "memory/juce_ByteOrder.h" diff --git a/modules/juce_core/misc/juce_EnumHelpers.h b/modules/juce_core/misc/juce_EnumHelpers.h new file mode 100644 index 0000000000..ec648ab5e6 --- /dev/null +++ b/modules/juce_core/misc/juce_EnumHelpers.h @@ -0,0 +1,103 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +//============================================================================== +/** + Macro to enable bitwise operations for scoped enums (enum struct/class). + + To use this, add the line JUCE_DECLARE_SCOPED_ENUM_BITWISE_OPERATORS (MyEnum) + after your enum declaration at file scope level. + + e.g. @code + + enum class MyEnum + { + one = 1 << 0, + two = 1 << 1, + three = 1 << 2 + }; + + JUCE_DECLARE_SCOPED_ENUM_BITWISE_OPERATORS (MyEnum) + + MyEnum e = MyEnum::one | MyEnum::two; + + bool hasTwo = (e & MyEnum::two) != MyEnum{}; // true + bool hasTwo = hasBitValueSet (e, MyEnum::two); // true + + e = withBitValueCleared (e, MyEnum::two); + + bool hasTwo = hasBitValueSet (e, MyEnum::two); // false + + @endcode +*/ +#define JUCE_DECLARE_SCOPED_ENUM_BITWISE_OPERATORS(EnumType) \ + static_assert (std::is_enum_v, \ + "JUCE_DECLARE_SCOPED_ENUM_BITWISE_OPERATORS " \ + "should only be used with enum types"); \ + constexpr auto operator& (EnumType a, EnumType b) \ + { \ + using base_type = std::underlying_type::type; \ + return static_cast (base_type (a) & base_type (b)); \ + } \ + constexpr auto operator| (EnumType a, EnumType b) \ + { \ + using base_type = std::underlying_type::type; \ + return static_cast (base_type (a) | base_type (b)); \ + } \ + constexpr auto operator~ (EnumType a) \ + { \ + using base_type = std::underlying_type::type; \ + return static_cast (~base_type (a)); \ + } \ + constexpr auto& operator|= (EnumType& a, EnumType b) \ + { \ + a = (a | b); \ + return a; \ + } \ + constexpr auto& operator&= (EnumType& a, EnumType b) \ + { \ + a = (a & b); \ + return a; \ + } + + +namespace juce +{ + +template , int> = 0> +constexpr bool hasBitValueSet (EnumType enumValue, EnumType valueToLookFor) noexcept +{ + return (enumValue & valueToLookFor) != EnumType{}; +} + +template , int> = 0> +constexpr EnumType withBitValueSet (EnumType enumValue, EnumType valueToAdd) noexcept +{ + return enumValue | valueToAdd; +} + +template , int> = 0> +constexpr EnumType withBitValueCleared (EnumType enumValue, EnumType valueToRemove) noexcept +{ + return enumValue & ~valueToRemove; +} +} diff --git a/modules/juce_core/misc/juce_EnumHelpers_test.cpp b/modules/juce_core/misc/juce_EnumHelpers_test.cpp new file mode 100644 index 0000000000..0441e4c302 --- /dev/null +++ b/modules/juce_core/misc/juce_EnumHelpers_test.cpp @@ -0,0 +1,94 @@ +/* +============================================================================== + +This file is part of the JUCE library. +Copyright (c) 2022 - Raw Material Software Limited + +JUCE is an open source library subject to commercial or open-source +licensing. + +The code included in this file is provided under the terms of the ISC license +http://www.isc.org/downloads/software-support-policy/isc-license. Permission +To use, copy, modify, and/or distribute this software for any purpose with or +without fee is hereby granted provided that the above copyright notice and +this permission notice appear in all copies. + +JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER +EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE +DISCLAIMED. + +============================================================================== +*/ + +namespace juce +{ + +namespace detail +{ +enum class TestEnum +{ + one = 1 << 0, + four = 1 << 1, + other = 1 << 2 +}; + +JUCE_DECLARE_SCOPED_ENUM_BITWISE_OPERATORS (TestEnum) +} + +class EnumHelperTest : public UnitTest +{ +public: + EnumHelperTest() : UnitTest ("EnumHelpers", UnitTestCategories::containers) {} + + void runTest() override + { + using detail::TestEnum; + + TestEnum e = {}; + + beginTest ("Default initialised enum is 'none'"); + { + expect (e == TestEnum{}); + expect (! hasBitValueSet (e, TestEnum{})); + } + + beginTest ("withBitValueSet sets correct bit on empty enum"); + { + e = withBitValueSet (e, TestEnum::other); + expect (e == TestEnum::other); + expect (hasBitValueSet (e, TestEnum::other)); + } + + beginTest ("withBitValueSet sets correct bit on non-empty enum"); + { + e = withBitValueSet (e, TestEnum::one); + expect (hasBitValueSet (e, TestEnum::one)); + } + + beginTest ("withBitValueCleared clears correct bit"); + { + e = withBitValueCleared (e, TestEnum::one); + expect (e != TestEnum::one); + expect (hasBitValueSet (e, TestEnum::other)); + expect (! hasBitValueSet (e, TestEnum::one)); + } + + beginTest ("operators work as expected"); + { + e = {}; + + e = TestEnum::one; + expect ((e & TestEnum::one) != TestEnum{}); + e |= TestEnum::other; + expect ((e & TestEnum::other) != TestEnum{}); + + e &= ~TestEnum::one; + expect ((e & TestEnum::one) == TestEnum{}); + expect ((e & TestEnum::other) != TestEnum{}); + } + } +}; + +static EnumHelperTest enumHelperTest; + +} // namespace juce