From 889c1d322ba549783474707af330d7aea1e12b87 Mon Sep 17 00:00:00 2001 From: tmadlener Date: Fri, 28 Jun 2024 10:36:16 +0200 Subject: [PATCH] Add more utility functionality for checking / setting bitfields --- test/utils/test_bit_utils.cpp | 42 ++++++++++++ utils/include/edm4hep/utils/bit_utils.h | 87 +++++++++++++++++++++++-- 2 files changed, 125 insertions(+), 4 deletions(-) diff --git a/test/utils/test_bit_utils.cpp b/test/utils/test_bit_utils.cpp index 11731c88d..be8e23ac9 100644 --- a/test/utils/test_bit_utils.cpp +++ b/test/utils/test_bit_utils.cpp @@ -20,6 +20,48 @@ TEMPLATE_LIST_TEST_CASE("Bitfield utils set and get", "[bit_utils]", BitFieldTyp bitField = utils::setBit(bitField, 3, true); REQUIRE(utils::checkBit(bitField, 3)); + bitField = utils::setBit(bitField, 4, true); + REQUIRE(utils::checkBit(bitField, 3)); + REQUIRE(utils::checkBit(bitField, 4)); + bitField = utils::setBit(bitField, 3, false); REQUIRE_FALSE(utils::checkBit(bitField, 3)); + REQUIRE(utils::checkBit(bitField, 4)); +} + +TEMPLATE_LIST_TEST_CASE("Bitfield utils set multiple", "[bit_utils]", BitFieldTypes) { + using namespace edm4hep; + auto bitField = TestType{}; + bitField = utils::setBits(bitField, true, 3, 4, 7); + + REQUIRE(utils::checkBit(bitField, 3)); + REQUIRE(utils::checkBit(bitField, 4)); + REQUIRE(utils::checkBit(bitField, 7)); + REQUIRE_FALSE(utils::checkBit(bitField, 1)); + REQUIRE_FALSE(utils::checkBit(bitField, 2)); + REQUIRE_FALSE(utils::checkBit(bitField, 5)); + REQUIRE_FALSE(utils::checkBit(bitField, 6)); + REQUIRE_FALSE(utils::checkBit(bitField, 8)); +} + +TEMPLATE_LIST_TEST_CASE("Bitfield utils check all ", "[bit_utils]", BitFieldTypes) { + using namespace edm4hep; + auto bitField = TestType{}; + bitField = utils::setBits(bitField, true, 3, 4, 7); + + REQUIRE(utils::checkAllBits(bitField, 7, 3, 4)); + REQUIRE(utils::checkAllBits(bitField, 3, 4)); + REQUIRE_FALSE(utils::checkAllBits(bitField, 2, 3, 4, 7)); + REQUIRE_FALSE(utils::checkAllBits(bitField, 2, 3, 4)); +} + +TEMPLATE_LIST_TEST_CASE("Bitfield utils check any ", "[bit_utils]", BitFieldTypes) { + using namespace edm4hep; + auto bitField = TestType{}; + bitField = utils::setBits(bitField, true, 3, 4, 7); + + REQUIRE(utils::checkAnyBits(bitField, 3, 4)); + REQUIRE(utils::checkAnyBits(bitField, 3)); + REQUIRE(utils::checkAnyBits(bitField, 1, 2, 3)); + REQUIRE_FALSE(utils::checkAnyBits(bitField, 1, 2, 6, 8)); } diff --git a/utils/include/edm4hep/utils/bit_utils.h b/utils/include/edm4hep/utils/bit_utils.h index 0ec72a1f7..f23fa2bce 100644 --- a/utils/include/edm4hep/utils/bit_utils.h +++ b/utils/include/edm4hep/utils/bit_utils.h @@ -1,16 +1,95 @@ #ifndef EDM4HEP_UTILS_BIT_UTILS_HH #define EDM4HEP_UTILS_BIT_UTILS_HH +#include + namespace edm4hep::utils { + +/// Set a bit in the passed bitfield to the desired value +/// +/// @tparam T any integer type that can be used as a bitfield, typically an +/// unsigned integer type +/// +/// @param bitfield The bitfield for which the bit should be set +/// @param bit The bit (number) that should be set +/// @param value The value to which the bit should be set +/// +/// @returns The new value of the bitfield after setting bits template -constexpr T setBit(T bits, int bitNum, bool value) { - return (bits & ~(1 << bitNum)) | (value << bitNum); +constexpr T setBit(T bitfield, int bit, bool value) { + return (bitfield & ~(0x1 << bit)) | (value << bit); +} + +/// Set multiple bits to one desired value in the passed bitfield +/// +/// @tparam T any integer type that can be used as a bitfield, typically an +/// unsigned integer type +/// @tparam Bits A variable number of bits (numbers) that should be set +/// +/// @param bitfield The bitfield for which the bit should be set +/// @param value The value to which the bit should be set +/// @param bits The bits that should be set +template +constexpr T setBits(T bitfield, bool value, Bits... bits) { + static_assert((std::is_same_v && ...), "All bit numbers to set must be integers"); + static_assert(sizeof...(bits) > 0, "Need at least one bit to set"); + + for (auto n : {bits...}) { + bitfield = setBit(bitfield, n, value); + } + return bitfield; } +/// Check if a bit is set in the bitfield +/// +/// @tparam T any integer type that can be used as a bitfield, typically an +/// unsigned integer type +/// +/// @param bitfield The bitfield that should be checked +/// @param bit The bit (number) that should be checked +/// +/// @returns true if the passed bit is set in the bitfield and false otherwise template -constexpr bool checkBit(T bits, int bitNum) { - return bits & (0x1 << bitNum); +constexpr bool checkBit(T bitfield, int bit) { + return bitfield & (0x1 << bit); } + +/// Check if all the passed bits are set in the bitfield +/// +/// @tparam T any integer type that can be used as a bitfield, typically an +/// unsigned integer type +/// @tparam Bits A variable number of bits (numbers) that should be checked +/// +/// @param bitfield The bitfield that should be checked +/// @param bits The bits that should be checked +/// +/// @returns true if all the passed bits are set in the bitfield and false +/// otherwise +template +constexpr bool checkAllBits(T bitfield, Bits... bits) { + static_assert((std::is_same_v && ...), "All bit numbers to set must be integers"); + static_assert(sizeof...(bits) > 0, "Need at least one bit to check"); + return (true && ... && checkBit(bitfield, bits)); +} + +/// Check if any of the passed bits is set in the bitfield +/// +/// @tparam T any integer type that can be used as a bitfield, typically an +/// unsigned integer type +/// @tparam Bits A variable number of bits (numbers) that should be checked +/// +/// @param bitfield The bitfield that should be checked +/// @param bits The bits that should be checked +/// +/// @returns true if any of the passed bits is set in the bitfield and false +/// otherwise +template +constexpr bool checkAnyBits(T bitfield, Bits... bits) { + static_assert((std::is_same_v && ...), "All bit numbers to set must be integers"); + static_assert(sizeof...(bits) > 0, "Need at least one bit to check"); + return (false || ... || checkBit(bitfield, bits)); +} + } // namespace edm4hep::utils #endif // EDM4HEP_UTILS_BIT_UTILS_HH