diff options
-rw-r--r-- | AK/EnumBits.h | 101 | ||||
-rw-r--r-- | AK/Tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | AK/Tests/TestEnumBits.cpp | 90 |
3 files changed, 192 insertions, 0 deletions
diff --git a/AK/EnumBits.h b/AK/EnumBits.h new file mode 100644 index 0000000000..57dea9b6b5 --- /dev/null +++ b/AK/EnumBits.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021, Brian Gianforcaro <b.gianfo@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "AK/StdLibExtras.h" + +// Enables bitwise operators for the specified Enum type. +// +#define AK_ENUM_BITWISE_OPERATORS(Enum) \ + _AK_ENUM_BITWISE_OPERATORS_INTERNAL(Enum, ) + +// Enables bitwise operators for the specified Enum type, this +// version is meant for use on enums which are private to the +// containing type. +// +#define AK_ENUM_BITWISE_FRIEND_OPERATORS(Enum) \ + _AK_ENUM_BITWISE_OPERATORS_INTERNAL(Enum, friend) + +#define _AK_ENUM_BITWISE_OPERATORS_INTERNAL(Enum, Prefix) \ + \ + [[nodiscard]] Prefix constexpr inline Enum operator|(Enum lhs, Enum rhs) \ + { \ + using Type = UnderlyingType<Enum>::Type; \ + return static_cast<Enum>( \ + static_cast<Type>(lhs) | static_cast<Type>(rhs)); \ + } \ + \ + [[nodiscard]] Prefix constexpr inline Enum operator&(Enum lhs, Enum rhs) \ + { \ + using Type = UnderlyingType<Enum>::Type; \ + return static_cast<Enum>( \ + static_cast<Type>(lhs) & static_cast<Type>(rhs)); \ + } \ + \ + [[nodiscard]] Prefix constexpr inline Enum operator^(Enum lhs, Enum rhs) \ + { \ + using Type = UnderlyingType<Enum>::Type; \ + return static_cast<Enum>( \ + static_cast<Type>(lhs) ^ static_cast<Type>(rhs)); \ + } \ + \ + [[nodiscard]] Prefix constexpr inline Enum operator~(Enum rhs) \ + { \ + using Type = UnderlyingType<Enum>::Type; \ + return static_cast<Enum>( \ + ~static_cast<Type>(rhs)); \ + } \ + \ + Prefix constexpr inline Enum& operator|=(Enum& lhs, Enum rhs) \ + { \ + using Type = UnderlyingType<Enum>::Type; \ + lhs = static_cast<Enum>( \ + static_cast<Type>(lhs) | static_cast<Type>(rhs)); \ + return lhs; \ + } \ + \ + Prefix constexpr inline Enum& operator&=(Enum& lhs, Enum rhs) \ + { \ + using Type = UnderlyingType<Enum>::Type; \ + lhs = static_cast<Enum>( \ + static_cast<Type>(lhs) & static_cast<Type>(rhs)); \ + return lhs; \ + } \ + \ + Prefix constexpr inline Enum& operator^=(Enum& lhs, Enum rhs) \ + { \ + using Type = UnderlyingType<Enum>::Type; \ + lhs = static_cast<Enum>( \ + static_cast<Type>(lhs) ^ static_cast<Type>(rhs)); \ + return lhs; \ + } \ + \ + Prefix constexpr inline bool has_flag(Enum value, Enum mask) \ + { \ + using Type = UnderlyingType<Enum>::Type; \ + return static_cast<Type>(value & mask) != 0; \ + } diff --git a/AK/Tests/CMakeLists.txt b/AK/Tests/CMakeLists.txt index 1aed6c50de..c7057d5a9d 100644 --- a/AK/Tests/CMakeLists.txt +++ b/AK/Tests/CMakeLists.txt @@ -17,6 +17,7 @@ set(AK_TEST_SOURCES TestDistinctNumeric.cpp TestDoublyLinkedList.cpp TestEndian.cpp + TestEnumBits.cpp TestFind.cpp TestFormat.cpp TestHashFunctions.cpp diff --git a/AK/Tests/TestEnumBits.cpp b/AK/Tests/TestEnumBits.cpp new file mode 100644 index 0000000000..9380c6d2df --- /dev/null +++ b/AK/Tests/TestEnumBits.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2021, Brian Gianforcaro <b.gianfo@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <AK/EnumBits.h> +#include <AK/TestSuite.h> + +enum class VideoIntro : u8 { + None = 0x0, + Well = 0x1, + Hello = 0x2, + Friends = 0x4, + ExclimationMark = 0x8, + CompleteIntro = Well | Hello | Friends | ExclimationMark, +}; + +AK_ENUM_BITWISE_OPERATORS(VideoIntro); + +TEST_CASE(bitwise_or) +{ + auto intro = VideoIntro::Well | VideoIntro::Hello | VideoIntro::Friends | VideoIntro::ExclimationMark; + EXPECT_EQ(intro, VideoIntro::CompleteIntro); +} + +TEST_CASE(bitwise_and) +{ + auto intro = VideoIntro::CompleteIntro; + EXPECT_EQ(intro & VideoIntro::Hello, VideoIntro::Hello); +} + +TEST_CASE(bitwise_xor) +{ + auto intro = VideoIntro::Well | VideoIntro::Hello | VideoIntro::Friends; + EXPECT_EQ(intro ^ VideoIntro::CompleteIntro, VideoIntro::ExclimationMark); +} + +TEST_CASE(bitwise_not) +{ + auto intro = ~VideoIntro::CompleteIntro; + EXPECT_EQ(intro & VideoIntro::CompleteIntro, VideoIntro::None); +} + +TEST_CASE(bitwise_or_equal) +{ + auto intro = VideoIntro::Well | VideoIntro::Hello | VideoIntro::Friends; + EXPECT_EQ(intro |= VideoIntro::ExclimationMark, VideoIntro::CompleteIntro); +} + +TEST_CASE(bitwise_and_equal) +{ + auto intro = VideoIntro::CompleteIntro; + EXPECT_EQ(intro &= VideoIntro::Hello, VideoIntro::Hello); +} + +TEST_CASE(bitwise_xor_equal) +{ + auto intro = VideoIntro::Well | VideoIntro::Hello | VideoIntro::Friends; + EXPECT_EQ(intro ^= VideoIntro::CompleteIntro, VideoIntro::ExclimationMark); +} + +TEST_CASE(has_flag) +{ + auto intro = VideoIntro::Hello | VideoIntro::Friends; + EXPECT(has_flag(intro, VideoIntro::Friends)); + EXPECT(!has_flag(intro, VideoIntro::Well)); +} + +TEST_MAIN(EnumBits) |