Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions include/stdx/bit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,21 +399,24 @@ template <typename T, std::size_t N> struct bitmask_subtract<std::array<T, N>> {
};
} // namespace detail

template <typename T, std::size_t Msb = detail::num_digits_v<T> - 1,
template <typename T,
std::size_t Msb = detail::num_digits_v<underlying_type_t<T>> - 1,
std::size_t Lsb = 0>
[[nodiscard]] CONSTEVAL auto bit_mask() noexcept -> T {
static_assert(Msb < detail::num_digits_v<T>,
using U = underlying_type_t<T>;
static_assert(Msb < detail::num_digits_v<U>,
"bit_mask requested exceeds the range of the type");
static_assert(Msb >= Lsb, "bit_mask range is invalid");
return detail::bitmask_subtract<T>{}(detail::mask_bits_t<T>{}(Msb + 1),
detail::mask_bits_t<T>{}(Lsb));
return static_cast<T>(detail::bitmask_subtract<U>{}(
detail::mask_bits_t<U>{}(Msb + 1), detail::mask_bits_t<U>{}(Lsb)));
}

template <typename T>
[[nodiscard]] constexpr auto bit_mask(std::size_t Msb,
std::size_t Lsb = 0) noexcept -> T {
return detail::bitmask_subtract<T>{}(detail::mask_bits_t<T>{}(Msb + 1),
detail::mask_bits_t<T>{}(Lsb));
using U = underlying_type_t<T>;
return static_cast<T>(detail::bitmask_subtract<U>{}(
detail::mask_bits_t<U>{}(Msb + 1), detail::mask_bits_t<U>{}(Lsb)));
}

template <typename T> constexpr auto bit_size() -> std::size_t {
Expand Down
14 changes: 14 additions & 0 deletions test/bit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,15 @@ TEST_CASE("template bit_mask (large array type)", "[bit]") {
CHECK(m == A{0, 0, 0, 1});
}

namespace {
enum struct scoped_enum : std::uint8_t { A, B, C };
} // namespace

TEST_CASE("template bit_mask (enum type)", "[bit]") {
constexpr auto m = stdx::bit_mask<scoped_enum>();
STATIC_REQUIRE(m == scoped_enum{0xffu});
}

TEST_CASE("arg bit_mask (whole range)", "[bit]") {
constexpr auto m = stdx::bit_mask<std::uint64_t>(63);
STATIC_REQUIRE(m == std::numeric_limits<std::uint64_t>::max());
Expand Down Expand Up @@ -326,6 +335,11 @@ TEST_CASE("arg bit_mask (single bit)", "[bit]") {
STATIC_REQUIRE(std::is_same_v<decltype(m), std::uint8_t const>);
}

TEST_CASE("arg bit_mask (enum type)", "[bit]") {
constexpr auto m = stdx::bit_mask<scoped_enum>(1);
STATIC_REQUIRE(m == scoped_enum{0b11u});
}

TEMPLATE_TEST_CASE("bit_size", "[bit]", std::uint8_t, std::uint16_t,
std::uint32_t, std::uint64_t, std::int8_t, std::int16_t,
std::int32_t, std::int64_t) {
Expand Down