[bit-utils] add MaskForBitSize() helper function (#13295)

This commit adds `MaskForBitSize<UintType>(uint8_t aBitSize)` as a
`constexpr inline` template helper function in `bit_utils.hpp`. It
generates an unsigned integer bit-mask with the specified number of
lowest bits set to 1.

Key changes:
- Adds `MaskForBitSize<UintType>(aBitSize)` in `bit_utils.hpp`.
- Adds runtime (`VerifyOrQuit`) and compile-time (`static_assert`)
  unit tests in `test_bit_utils.cpp`.
This commit is contained in:
Abtin Keshavarzian
2026-07-06 10:10:35 -07:00
committed by GitHub
parent b678a4f63b
commit 8ad056634c
2 changed files with 81 additions and 0 deletions
+17
View File
@@ -98,6 +98,23 @@ uint16_t CountMatchingBits(const uint8_t *aFirst, const uint8_t *aSecond, uint16
*/
uint8_t DetermineMinBitSizeFor(uint32_t aValue);
/**
* Generates an unsigned integer bit-mask with a specified number of lowest bits set to 1.
*
* @tparam UintType The value type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`).
*
* @param[in] aBitSize The number of lowest bits to set to 1.
*
* @returns The generated bit-mask.
*/
template <typename UintType> constexpr inline UintType MaskForBitSize(uint8_t aBitSize)
{
static_assert(TypeTraits::IsUint<UintType>::kValue, "UintType must be an unsigned int (8, 16, 32, or 64 bit len)");
return (aBitSize >= BitSizeOf(UintType)) ? NumericLimits<UintType>::kMax
: static_cast<UintType>((static_cast<UintType>(1) << aBitSize) - 1);
}
/**
* Sets the specified bit in a given integer to 1.
*
+64
View File
@@ -176,6 +176,69 @@ void TestDetermineMinBitSize(void)
printf("TestDetermineMinBitSize() passed\n");
}
void TestMaskForBitSize(void)
{
VerifyOrQuit(MaskForBitSize<uint8_t>(0) == 0);
VerifyOrQuit(MaskForBitSize<uint8_t>(1) == 0x01);
VerifyOrQuit(MaskForBitSize<uint8_t>(2) == 0x03);
VerifyOrQuit(MaskForBitSize<uint8_t>(3) == 0x07);
VerifyOrQuit(MaskForBitSize<uint8_t>(4) == 0x0f);
VerifyOrQuit(MaskForBitSize<uint8_t>(7) == 0x7f);
VerifyOrQuit(MaskForBitSize<uint8_t>(8) == 0xff);
VerifyOrQuit(MaskForBitSize<uint8_t>(9) == 0xff);
VerifyOrQuit(MaskForBitSize<uint16_t>(0) == 0);
VerifyOrQuit(MaskForBitSize<uint16_t>(7) == 0x007f);
VerifyOrQuit(MaskForBitSize<uint16_t>(8) == 0x00ff);
VerifyOrQuit(MaskForBitSize<uint16_t>(11) == 0x07ff);
VerifyOrQuit(MaskForBitSize<uint16_t>(16) == 0xffff);
VerifyOrQuit(MaskForBitSize<uint16_t>(20) == 0xffff);
VerifyOrQuit(MaskForBitSize<uint32_t>(0) == 0);
VerifyOrQuit(MaskForBitSize<uint32_t>(16) == 0x0000ffff);
VerifyOrQuit(MaskForBitSize<uint32_t>(31) == 0x7fffffff);
VerifyOrQuit(MaskForBitSize<uint32_t>(32) == 0xffffffff);
VerifyOrQuit(MaskForBitSize<uint32_t>(33) == 0xffffffff);
VerifyOrQuit(MaskForBitSize<uint64_t>(0) == 0);
VerifyOrQuit(MaskForBitSize<uint64_t>(32) == 0xffffffffULL);
VerifyOrQuit(MaskForBitSize<uint64_t>(63) == 0x7fffffffffffffffULL);
VerifyOrQuit(MaskForBitSize<uint64_t>(64) == 0xffffffffffffffffULL);
VerifyOrQuit(MaskForBitSize<uint64_t>(65) == 0xffffffffffffffffULL);
// Compile-time checks
static_assert(MaskForBitSize<uint8_t>(0) == 0, "MaskForBitSize<uint8_t>(0) failed");
static_assert(MaskForBitSize<uint8_t>(1) == 0x01, "MaskForBitSize<uint8_t>(1) failed");
static_assert(MaskForBitSize<uint8_t>(2) == 0x03, "MaskForBitSize<uint8_t>(2) failed");
static_assert(MaskForBitSize<uint8_t>(3) == 0x07, "MaskForBitSize<uint8_t>(3) failed");
static_assert(MaskForBitSize<uint8_t>(4) == 0x0f, "MaskForBitSize<uint8_t>(4) failed");
static_assert(MaskForBitSize<uint8_t>(7) == 0x7f, "MaskForBitSize<uint8_t>(7) failed");
static_assert(MaskForBitSize<uint8_t>(8) == 0xff, "MaskForBitSize<uint8_t>(8) failed");
static_assert(MaskForBitSize<uint8_t>(9) == 0xff, "MaskForBitSize<uint8_t>(9) failed");
static_assert(MaskForBitSize<uint16_t>(0) == 0, "MaskForBitSize<uint16_t>(0) failed");
static_assert(MaskForBitSize<uint16_t>(7) == 0x007f, "MaskForBitSize<uint16_t>(7) failed");
static_assert(MaskForBitSize<uint16_t>(8) == 0x00ff, "MaskForBitSize<uint16_t>(8) failed");
static_assert(MaskForBitSize<uint16_t>(11) == 0x07ff, "MaskForBitSize<uint16_t>(11) failed");
static_assert(MaskForBitSize<uint16_t>(16) == 0xffff, "MaskForBitSize<uint16_t>(16) failed");
static_assert(MaskForBitSize<uint16_t>(20) == 0xffff, "MaskForBitSize<uint16_t>(20) failed");
static_assert(MaskForBitSize<uint32_t>(0) == 0, "MaskForBitSize<uint32_t>(0) failed");
static_assert(MaskForBitSize<uint32_t>(16) == 0x0000ffff, "MaskForBitSize<uint32_t>(16) failed");
static_assert(MaskForBitSize<uint32_t>(31) == 0x7fffffff, "MaskForBitSize<uint32_t>(31) failed");
static_assert(MaskForBitSize<uint32_t>(32) == 0xffffffff, "MaskForBitSize<uint32_t>(32) failed");
static_assert(MaskForBitSize<uint32_t>(33) == 0xffffffff, "MaskForBitSize<uint32_t>(33) failed");
static_assert(MaskForBitSize<uint64_t>(0) == 0, "MaskForBitSize<uint64_t>(0) failed");
static_assert(MaskForBitSize<uint64_t>(32) == 0xffffffffULL, "MaskForBitSize<uint64_t>(32) failed");
static_assert(MaskForBitSize<uint64_t>(63) == 0x7fffffffffffffffULL, "MaskForBitSize<uint64_t>(63) failed");
static_assert(MaskForBitSize<uint64_t>(64) == 0xffffffffffffffffULL, "MaskForBitSize<uint64_t>(64) failed");
static_assert(MaskForBitSize<uint64_t>(65) == 0xffffffffffffffffULL, "MaskForBitSize<uint64_t>(65) failed");
printf("TestMaskForBitSize() passed\n");
}
} // namespace ot
int main(void)
@@ -184,6 +247,7 @@ int main(void)
ot::TestCountMatchingBitsAllCombinations();
ot::TestCountMatchingBitsExamples();
ot::TestDetermineMinBitSize();
ot::TestMaskForBitSize();
printf("All tests passed\n");
return 0;