Skip to content

Commit

Permalink
Merge pull request #196 from elbeno/bitset-enum-clash
Browse files Browse the repository at this point in the history
🎨 Prevent bitsets from mixing enum types
  • Loading branch information
bdeane-intel authored Feb 19, 2025
2 parents 9ed827d + ca7d4a6 commit e8530c2
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 1 deletion.
16 changes: 16 additions & 0 deletions include/stdx/bitset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ class bitset {
using iter_arg_t = conditional_t<std::is_enum_v<decltype(Size)>,
decltype(Size), std::size_t>;

template <typename T> CONSTEVAL static auto admissible_enum() {
return not std::is_enum_v<T> or std::is_same_v<T, decltype(Size)>;
}

template <typename F> constexpr auto for_each(F &&f) const -> F {
std::size_t i = 0;
for (auto e : storage) {
Expand Down Expand Up @@ -216,13 +220,19 @@ class bitset {

template <typename T>
[[nodiscard]] constexpr auto operator[](T idx) const -> bool {
static_assert(admissible_enum<T>() or
stdx::always_false_v<T, decltype(Size)>,
"T is not the required enumeration type");
auto const pos = static_cast<std::size_t>(to_underlying(idx));
auto const [index, offset] = indices(pos);
return (storage[index] & (bit << offset)) != 0;
}

template <typename T>
constexpr auto set(T idx, bool value = true) LIFETIMEBOUND -> bitset & {
static_assert(admissible_enum<T>() or
stdx::always_false_v<T, decltype(Size)>,
"T is not the required enumeration type");
auto const pos = static_cast<std::size_t>(to_underlying(idx));
auto const [index, offset] = indices(pos);
if (value) {
Expand Down Expand Up @@ -278,6 +288,9 @@ class bitset {

template <typename T>
constexpr auto reset(T idx) LIFETIMEBOUND -> bitset & {
static_assert(admissible_enum<T>() or
stdx::always_false_v<T, decltype(Size)>,
"T is not the required enumeration type");
auto const pos = static_cast<std::size_t>(to_underlying(idx));
auto const [index, offset] = indices(pos);
storage[index] &= static_cast<elem_t>(~(bit << offset));
Expand All @@ -300,6 +313,9 @@ class bitset {
}

template <typename T> constexpr auto flip(T idx) LIFETIMEBOUND -> bitset & {
static_assert(admissible_enum<T>() or
stdx::always_false_v<T, decltype(Size)>,
"T is not the required enumeration type");
auto const pos = static_cast<std::size_t>(to_underlying(idx));
auto const [index, offset] = indices(pos);
storage[index] ^= static_cast<elem_t>(bit << offset);
Expand Down
3 changes: 2 additions & 1 deletion test/fail/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ endfunction()
add_fail_tests(
as_signed_bool
as_unsigned_bool
bitset_signed_storage
bitset_mixed_enumeration
bitset_nonintegral_bit_places
bitset_signed_storage
bitset_to_uint64_over_64_bits
for_each_n_args_bad_size
optional_without_tombstone
Expand Down
11 changes: 11 additions & 0 deletions test/fail/bitset_mixed_enumeration.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <stdx/bitset.hpp>

// EXPECT: T is not the required enumeration type

enum struct E1 { A, B, C, MAX };
enum struct E2 { X, Y, Z };

auto main() -> int {
auto b = stdx::bitset<E1::MAX>{};
b.set(E2::X);
}

0 comments on commit e8530c2

Please sign in to comment.