Skip to content

Commit 991d639

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 991d639

File tree

2 files changed

+30
-13
lines changed

2 files changed

+30
-13
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: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -256,44 +256,53 @@ TEST_CASE("template bit_mask (single bit)", "[bit]") {
256256
TEST_CASE("template bit_mask (array type whole range)", "[bit]") {
257257
using A = std::array<std::uint8_t, 3>;
258258
constexpr auto m = stdx::bit_mask<A>();
259-
CHECK(m == A{0xff, 0xff, 0xff});
259+
STATIC_REQUIRE(m == A{0xff, 0xff, 0xff});
260260
}
261261

262262
TEST_CASE("template bit_mask (array type low bits)", "[bit]") {
263263
using A = std::array<std::uint8_t, 3>;
264264
constexpr auto m = stdx::bit_mask<A, 1, 0>();
265-
CHECK(m == A{0b0000'0011, 0, 0});
265+
STATIC_REQUIRE(m == A{0b0000'0011, 0, 0});
266266
}
267267

268268
TEST_CASE("template bit_mask (array type mid bits)", "[bit]") {
269269
using A = std::array<std::uint8_t, 3>;
270270
constexpr auto m = stdx::bit_mask<A, 19, 4>();
271-
CHECK(m == A{0b1111'0000, 0xff, 0b0000'1111});
271+
STATIC_REQUIRE(m == A{0b1111'0000, 0xff, 0b0000'1111});
272272
}
273273

274274
TEST_CASE("template bit_mask (array type high bits)", "[bit]") {
275275
using A = std::array<std::uint8_t, 3>;
276276
constexpr auto m = stdx::bit_mask<A, 23, 20>();
277-
CHECK(m == A{0, 0, 0b1111'0000});
277+
STATIC_REQUIRE(m == A{0, 0, 0b1111'0000});
278278
}
279279

280280
TEST_CASE("template bit_mask (array type single bit)", "[bit]") {
281281
using A = std::array<std::uint8_t, 3>;
282282
constexpr auto m = stdx::bit_mask<A, 5, 5>();
283-
CHECK(m == A{0b0010'0000, 0, 0});
283+
STATIC_REQUIRE(m == A{0b0010'0000, 0, 0});
284284
}
285285

286286
TEST_CASE("template bit_mask (array of array type)", "[bit]") {
287287
using A = std::array<std::uint8_t, 1>;
288288
using B = std::array<A, 3>;
289289
constexpr auto m = stdx::bit_mask<B, 19, 4>();
290-
CHECK(m == B{A{0b1111'0000}, A{0xff}, A{0b0000'1111}});
290+
STATIC_REQUIRE(m == B{A{0b1111'0000}, A{0xff}, A{0b0000'1111}});
291291
}
292292

293293
TEST_CASE("template bit_mask (large array type)", "[bit]") {
294294
using A = std::array<std::uint64_t, 4>;
295295
constexpr auto m = stdx::bit_mask<A, 192, 192>();
296-
CHECK(m == A{0, 0, 0, 1});
296+
STATIC_REQUIRE(m == A{0, 0, 0, 1});
297+
}
298+
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});
297306
}
298307

299308
TEST_CASE("arg bit_mask (whole range)", "[bit]") {
@@ -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)