Skip to content

Commit 95432a2

Browse files
committed
✨ Add set range capability to bitset
1 parent 7ff0a49 commit 95432a2

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

Diff for: include/stdx/bitset.hpp

+64
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ namespace stdx {
1717
inline namespace v1 {
1818
struct place_bits_t {};
1919
constexpr inline auto place_bits = place_bits_t{};
20+
struct all_bits_t {};
21+
constexpr inline auto all_bits = all_bits_t{};
22+
23+
enum struct lsb_t : std::size_t {};
24+
enum struct msb_t : std::size_t {};
25+
enum struct length_t : std::size_t {};
2026

2127
namespace detail {
2228
template <std::size_t N, typename StorageElem> class bitset {
@@ -128,6 +134,12 @@ template <std::size_t N, typename StorageElem> class bitset {
128134
(set(static_cast<std::size_t>(bs)), ...);
129135
}
130136

137+
constexpr explicit bitset(all_bits_t) {
138+
for (auto &elem : storage) {
139+
elem = allbits;
140+
}
141+
}
142+
131143
constexpr explicit bitset(std::string_view str, std::size_t pos = 0,
132144
std::size_t n = std::string_view::npos,
133145
char one = '1') {
@@ -173,6 +185,37 @@ template <std::size_t N, typename StorageElem> class bitset {
173185
return *this;
174186
}
175187

188+
constexpr auto set(lsb_t lsb, msb_t msb, bool value = true) -> bitset & {
189+
auto const l = to_underlying(lsb);
190+
auto const m = to_underlying(msb);
191+
auto [l_index, l_offset] = indices(l);
192+
auto const [m_index, m_offset] = indices(m);
193+
194+
auto l_mask = std::numeric_limits<StorageElem>::max() << l_offset;
195+
while (l_index != m_index) {
196+
if (value) {
197+
storage[l_index++] |= static_cast<StorageElem>(l_mask);
198+
} else {
199+
storage[l_index++] &= static_cast<StorageElem>(~(l_mask));
200+
}
201+
l_mask = std::numeric_limits<StorageElem>::max();
202+
}
203+
auto const m_mask = std::numeric_limits<StorageElem>::max() >>
204+
(storage_elem_size - m_offset - 1);
205+
if (value) {
206+
storage[l_index] |= static_cast<StorageElem>(l_mask & m_mask);
207+
} else {
208+
storage[l_index] &= static_cast<StorageElem>(~(l_mask & m_mask));
209+
}
210+
return *this;
211+
}
212+
213+
constexpr auto set(lsb_t lsb, length_t len, bool value = true) -> bitset & {
214+
auto const l = to_underlying(lsb);
215+
auto const length = to_underlying(len);
216+
return set(lsb, static_cast<msb_t>(l + length - 1), value);
217+
}
218+
176219
constexpr auto set() -> bitset & {
177220
for (auto &elem : storage) {
178221
elem = allbits;
@@ -193,6 +236,14 @@ template <std::size_t N, typename StorageElem> class bitset {
193236
return *this;
194237
}
195238

239+
constexpr auto reset(lsb_t lsb, msb_t msb) -> bitset & {
240+
return set(lsb, msb, false);
241+
}
242+
243+
constexpr auto reset(lsb_t lsb, length_t len) -> bitset & {
244+
return set(lsb, len, false);
245+
}
246+
196247
constexpr auto flip(std::size_t pos) -> bitset & {
197248
auto const [index, offset] = indices(pos);
198249
storage[index] ^= static_cast<StorageElem>(bit << offset);
@@ -345,5 +396,18 @@ template <std::size_t N, typename StorageElem = void>
345396
using bitset =
346397
detail::bitset<N, decltype(detail::select_storage<N, StorageElem>())>;
347398

399+
namespace literals {
400+
// NOLINTBEGIN(google-runtime-int)
401+
CONSTEVAL auto operator""_lsb(unsigned long long int n) -> lsb_t {
402+
return static_cast<lsb_t>(n);
403+
}
404+
CONSTEVAL auto operator""_msb(unsigned long long int n) -> msb_t {
405+
return static_cast<msb_t>(n);
406+
}
407+
CONSTEVAL auto operator""_len(unsigned long long int n) -> length_t {
408+
return static_cast<length_t>(n);
409+
}
410+
// NOLINTEND(google-runtime-int)
411+
} // namespace literals
348412
} // namespace v1
349413
} // namespace stdx

Diff for: test/bitset.cpp

+54
Original file line numberDiff line numberDiff line change
@@ -304,3 +304,57 @@ TEMPLATE_TEST_CASE("for_each iterates in order lsb to msb", "[bitset]",
304304
bs);
305305
CHECK(result == bs);
306306
}
307+
308+
TEMPLATE_TEST_CASE("set range of bits (lsb, length)", "[bitset]", std::uint8_t,
309+
std::uint16_t, std::uint32_t, std::uint64_t) {
310+
using namespace stdx::literals;
311+
auto bs = stdx::bitset<64, TestType>{};
312+
bs.set(6_lsb, 4_len);
313+
CHECK(bs[6]);
314+
CHECK(bs[7]);
315+
CHECK(bs[8]);
316+
CHECK(bs[9]);
317+
CHECK(bs.count() == 4u);
318+
}
319+
320+
TEMPLATE_TEST_CASE("set range of bits (lsb, msb)", "[bitset]", std::uint8_t,
321+
std::uint16_t, std::uint32_t, std::uint64_t) {
322+
using namespace stdx::literals;
323+
auto bs = stdx::bitset<64, TestType>{};
324+
bs.set(6_lsb, 9_msb);
325+
CHECK(bs[6]);
326+
CHECK(bs[7]);
327+
CHECK(bs[8]);
328+
CHECK(bs[9]);
329+
CHECK(bs.count() == 4u);
330+
}
331+
332+
TEMPLATE_TEST_CASE("construct with all bits set", "[bitset]", std::uint8_t,
333+
std::uint16_t, std::uint32_t, std::uint64_t) {
334+
constexpr auto bs = stdx::bitset<9, TestType>{stdx::all_bits};
335+
static_assert(bs.all());
336+
}
337+
338+
TEMPLATE_TEST_CASE("reset range of bits (lsb, length)", "[bitset]",
339+
std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t) {
340+
using namespace stdx::literals;
341+
auto bs = stdx::bitset<64, TestType>{stdx::all_bits};
342+
bs.reset(6_lsb, 4_len);
343+
CHECK(not bs[6]);
344+
CHECK(not bs[7]);
345+
CHECK(not bs[8]);
346+
CHECK(not bs[9]);
347+
CHECK(bs.count() == 60);
348+
}
349+
350+
TEMPLATE_TEST_CASE("reset range of bits (lsb, msb)", "[bitset]", std::uint8_t,
351+
std::uint16_t, std::uint32_t, std::uint64_t) {
352+
using namespace stdx::literals;
353+
auto bs = stdx::bitset<64, TestType>{stdx::all_bits};
354+
bs.reset(6_lsb, 9_msb);
355+
CHECK(not bs[6]);
356+
CHECK(not bs[7]);
357+
CHECK(not bs[8]);
358+
CHECK(not bs[9]);
359+
CHECK(bs.count() == 60);
360+
}

0 commit comments

Comments
 (0)