Skip to content

Commit 8fdd526

Browse files
committed
🎨 Use enums with bit_mask
Problem: - It's useful to compute a `bit_mask` and give it an enumeration type. Solution: - Allow `bit_mask` to return values that are enumeration type.
1 parent ca9e67a commit 8fdd526

File tree

2 files changed

+23
-6
lines changed

2 files changed

+23
-6
lines changed

include/stdx/bit.hpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -399,21 +399,24 @@ template <typename T, std::size_t N> struct bitmask_subtract<std::array<T, N>> {
399399
};
400400
} // namespace detail
401401

402-
template <typename T, std::size_t Msb = detail::num_digits_v<T> - 1,
402+
template <typename T,
403+
std::size_t Msb = detail::num_digits_v<underlying_type_t<T>> - 1,
403404
std::size_t Lsb = 0>
404405
[[nodiscard]] CONSTEVAL auto bit_mask() noexcept -> T {
405-
static_assert(Msb < detail::num_digits_v<T>,
406+
using U = underlying_type_t<T>;
407+
static_assert(Msb < detail::num_digits_v<U>,
406408
"bit_mask requested exceeds the range of the type");
407409
static_assert(Msb >= Lsb, "bit_mask range is invalid");
408-
return detail::bitmask_subtract<T>{}(detail::mask_bits_t<T>{}(Msb + 1),
409-
detail::mask_bits_t<T>{}(Lsb));
410+
return static_cast<T>(detail::bitmask_subtract<U>{}(
411+
detail::mask_bits_t<U>{}(Msb + 1), detail::mask_bits_t<U>{}(Lsb)));
410412
}
411413

412414
template <typename T>
413415
[[nodiscard]] constexpr auto bit_mask(std::size_t Msb,
414416
std::size_t Lsb = 0) noexcept -> T {
415-
return detail::bitmask_subtract<T>{}(detail::mask_bits_t<T>{}(Msb + 1),
416-
detail::mask_bits_t<T>{}(Lsb));
417+
using U = underlying_type_t<T>;
418+
return static_cast<T>(detail::bitmask_subtract<U>{}(
419+
detail::mask_bits_t<U>{}(Msb + 1), detail::mask_bits_t<U>{}(Lsb)));
417420
}
418421

419422
template <typename T> constexpr auto bit_size() -> std::size_t {

test/bit.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,15 @@ TEST_CASE("template bit_mask (large array type)", "[bit]") {
296296
CHECK(m == A{0, 0, 0, 1});
297297
}
298298

299+
namespace {
300+
enum struct scoped_enum : std::uint8_t { A, B, C };
301+
} // namespace
302+
303+
TEST_CASE("template bit_mask (enum type)", "[bit]") {
304+
constexpr auto m = stdx::bit_mask<scoped_enum>();
305+
STATIC_REQUIRE(m == scoped_enum{0xffu});
306+
}
307+
299308
TEST_CASE("arg bit_mask (whole range)", "[bit]") {
300309
constexpr auto m = stdx::bit_mask<std::uint64_t>(63);
301310
STATIC_REQUIRE(m == std::numeric_limits<std::uint64_t>::max());
@@ -326,6 +335,11 @@ TEST_CASE("arg bit_mask (single bit)", "[bit]") {
326335
STATIC_REQUIRE(std::is_same_v<decltype(m), std::uint8_t const>);
327336
}
328337

338+
TEST_CASE("arg bit_mask (enum type)", "[bit]") {
339+
constexpr auto m = stdx::bit_mask<scoped_enum>(1);
340+
STATIC_REQUIRE(m == scoped_enum{0b11u});
341+
}
342+
329343
TEMPLATE_TEST_CASE("bit_size", "[bit]", std::uint8_t, std::uint16_t,
330344
std::uint32_t, std::uint64_t, std::int8_t, std::int16_t,
331345
std::int32_t, std::int64_t) {

0 commit comments

Comments
 (0)