Skip to content

Commit 6d0eccc

Browse files
authored
enum_bitfield_t - operators ~, ^, ^= (#30)
* enum_bitfield_t - operators ~, ^, ^= * bump version 0.9.2 --------- Co-authored-by: Artur Bać <[email protected]>
1 parent fdb4182 commit 6d0eccc

File tree

4 files changed

+98
-3
lines changed

4 files changed

+98
-3
lines changed

docs/enum_bitfiled.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ enum_bitfield_t support class template argument deducation when using arguments
4848
```
4949

5050
```cpp
51-
// operators |, &, |= &=
51+
// operators |, &, |=, &=, ~, ^, ^=
5252
static_assert((enum_bitfield_t{v16, v21} | enum_bitfield_t{v31, v5})
5353
== enum_bitfield_t{v21, v16, v5, v31});
5454
static_assert((enum_bitfield_t{v16, v21, v34, v1} & enum_bitfield_t{v16, v21, v5})
@@ -61,5 +61,9 @@ enum_bitfield_t support class template argument deducation when using arguments
6161
enum_bitfield_t b{v16, v21};
6262
b |= enum_bitfield_t{v31, v5};
6363
expect(b == enum_bitfield_t{v21, v16, v5, v31});
64+
65+
expect((enum_bitfield_t{v1, v2, v5, v6, v7} ^ enum_bitfield_t{v2, v5, v6}) == enum_bitfield_t{v1, v7});
66+
67+
static_assert((~enum_bitfield_t{v1, v2, v5, v6, v7}) == enum_bitfield_t{v0, v3, v4, v8});
6468
```
6569

include/simple_enum/core.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include <concepts>
77
#include <type_traits>
88

9-
#define SIMPLE_ENUM_NAME_VERSION "0.9.1"
9+
#define SIMPLE_ENUM_NAME_VERSION "0.9.2"
1010

1111
namespace simple_enum::inline v0_9
1212
{

include/simple_enum/enum_bitfield.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,34 @@ namespace detail
7070
}
7171
};
7272

73+
/// \brief compile time bitmsk calculating
74+
template<std::unsigned_integral T, std::size_t N>
75+
struct bitmask_t
76+
{
77+
static T constexpr value = bitmask_t<T, (N - 1u)>::value | T(T(1u) << (N - 1));
78+
};
79+
80+
template<std::unsigned_integral T>
81+
struct bitmask_t<T, 0u>
82+
{
83+
static T constexpr value = T(0u);
84+
};
85+
86+
template<std::unsigned_integral T, std::size_t N>
87+
inline constexpr T bitmask_v = bitmask_t<T, N>::value;
7388
} // namespace detail
7489

7590
/// @brief A template struct providing a bitfield with enum indexing.
7691
template<enum_concept enum_type_t>
7792
struct enum_bitfield_t
7893
{
7994
using storage_t = detail::select_storage_for_enum_t<enum_type_t>;
95+
static constexpr storage_t bits_mask{detail::bitmask_v<storage_t, enum_size_v<enum_type_t>>};
8096

8197
storage_t bits_{0};
8298

99+
explicit operator storage_t() const noexcept { return bits_; }
100+
83101
constexpr enum_bitfield_t() noexcept = default;
84102

85103
explicit constexpr enum_bitfield_t(std::same_as<storage_t> auto bits) noexcept : bits_{bits} {}
@@ -114,6 +132,12 @@ struct enum_bitfield_t
114132
constexpr auto operator==(enum_bitfield_t const &) const noexcept -> bool
115133
= default;
116134

135+
[[nodiscard]]
136+
constexpr auto operator~() const noexcept -> enum_bitfield_t
137+
{
138+
return enum_bitfield_t{storage_t((~bits_) & bits_mask)};
139+
}
140+
117141
[[nodiscard]]
118142
constexpr auto operator|(enum_bitfield_t const values) const noexcept -> enum_bitfield_t
119143
{
@@ -126,6 +150,12 @@ struct enum_bitfield_t
126150
return enum_bitfield_t{storage_t(bits_ & values.bits_)};
127151
}
128152

153+
[[nodiscard]]
154+
constexpr auto operator^(enum_bitfield_t const values) const noexcept -> enum_bitfield_t
155+
{
156+
return enum_bitfield_t{storage_t((bits_ ^ values.bits_) & bits_mask)};
157+
}
158+
129159
constexpr auto operator|=(enum_bitfield_t const values) noexcept -> enum_bitfield_t &
130160
{
131161
bits_ |= values.bits_;
@@ -137,6 +167,12 @@ struct enum_bitfield_t
137167
bits_ &= values.bits_;
138168
return *this;
139169
}
170+
171+
constexpr auto operator^=(enum_bitfield_t const values) noexcept -> enum_bitfield_t &
172+
{
173+
bits_ = (bits_ ^ values.bits_) & bits_mask;
174+
return *this;
175+
}
140176
};
141177

142178
template<enum_concept enum_type_t>

tests/enum_bitfield_ut.cc

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ enum struct color_t { red, green, blue, yellow, first = red, last = yellow };
1717
enum struct permission_t { read = 4, write = 8, execute = 16, first = read, last = execute };
1818

1919
// Enum that should use uint16_t (9 values)
20-
enum struct medium_enum_t { v0, v1, v2, v3, v4, v5, v6, v7, v8, first = v0, last = v8 };
20+
enum struct medium_enum_t { v0 = 5, v1, v2, v3, v4, v5, v6, v7, v8, first = v0, last = v8 };
2121

2222
// Enum that should use uint64_t (40 values)
2323
enum struct large_enum_t {
@@ -169,6 +169,61 @@ int main()
169169
}
170170
};
171171

172+
"operator ~"_test = []
173+
{
174+
{
175+
using enum color_t;
176+
expect((~enum_bitfield_t{red}) != enum_bitfield_t{red});
177+
expect((~enum_bitfield_t{red, green}) == enum_bitfield_t{blue, yellow});
178+
expect((~enum_bitfield_t{green}) == enum_bitfield_t{red, blue, yellow});
179+
static_assert((~enum_bitfield_t{red, green}) == enum_bitfield_t{blue, yellow});
180+
static_assert((~enum_bitfield_t{green}) == enum_bitfield_t{red, blue, yellow});
181+
}
182+
{
183+
using enum medium_enum_t;
184+
expect((~enum_bitfield_t{v1, v2, v5, v6, v7}) == enum_bitfield_t{v0, v3, v4, v8});
185+
static_assert((~enum_bitfield_t{v1, v2, v5, v6, v7}) == enum_bitfield_t{v0, v3, v4, v8});
186+
}
187+
};
188+
189+
"operator ^"_test = []
190+
{
191+
using enum medium_enum_t;
192+
expect((enum_bitfield_t{v1, v2, v5, v6, v7} ^ enum_bitfield_t{v2, v5, v6}) == enum_bitfield_t{v1, v7});
193+
expect((enum_bitfield_t{v1, v2} ^ enum_bitfield_t{v5, v6}) == enum_bitfield_t{v1, v2, v5, v6});
194+
195+
static_assert((enum_bitfield_t{v1, v2, v5, v6, v7} ^ enum_bitfield_t{v2, v5, v6}) == enum_bitfield_t{v1, v7});
196+
static_assert((enum_bitfield_t{v1, v2} ^ enum_bitfield_t{v5, v6}) == enum_bitfield_t{v1, v2, v5, v6});
197+
};
198+
199+
"operator ^="_test = []
200+
{
201+
using enum medium_enum_t;
202+
enum_bitfield_t a{v1, v2, v5, v6, v7};
203+
a ^= enum_bitfield_t{v2, v5, v6};
204+
expect(a == enum_bitfield_t{v1, v7});
205+
206+
enum_bitfield_t b{v1, v2};
207+
b ^= enum_bitfield_t{v5, v6};
208+
expect(b == enum_bitfield_t{v1, v2, v5, v6});
209+
210+
auto constexpr fn_a = []()
211+
{
212+
enum_bitfield_t x{v1, v2, v5, v6, v7};
213+
x ^= enum_bitfield_t{v2, v5, v6};
214+
return x;
215+
};
216+
static_assert(fn_a() == enum_bitfield_t{v1, v7});
217+
218+
auto constexpr fn_b = []()
219+
{
220+
enum_bitfield_t x{v1, v2};
221+
x ^= enum_bitfield_t{v5, v6};
222+
return x;
223+
};
224+
static_assert(fn_b() == enum_bitfield_t{v1, v2, v5, v6});
225+
};
226+
172227
"operator |"_test = []
173228
{
174229
using enum large_enum_t;

0 commit comments

Comments
 (0)