Skip to content

Commit

Permalink
Add more utility functionality for checking / setting bitfields
Browse files Browse the repository at this point in the history
  • Loading branch information
tmadlener committed Jun 28, 2024
1 parent 62e87cc commit 3380fcd
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 4 deletions.
42 changes: 42 additions & 0 deletions test/utils/test_bit_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
87 changes: 83 additions & 4 deletions utils/include/edm4hep/utils/bit_utils.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,95 @@
#ifndef EDM4HEP_UTILS_BIT_UTILS_HH
#define EDM4HEP_UTILS_BIT_UTILS_HH

#include <type_traits>

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 <typename T>
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 <typename T, typename... Bits>
constexpr T setBits(T bitfield, bool value, Bits... bits) {
static_assert((std::is_same_v<Bits, int> && ...), "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 <typename T>
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 <typename T, typename... Bits>
constexpr bool checkAllBits(T bitfield, Bits... bits) {
static_assert((std::is_same_v<Bits, int> && ...), "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 <typename T, typename... Bits>
constexpr bool checkAnyBits(T bitfield, Bits... bits) {
static_assert((std::is_same_v<Bits, int> && ...), "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

0 comments on commit 3380fcd

Please sign in to comment.