Skip to content

Add bitset range set #45

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 5, 2024
Merged
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
9 changes: 8 additions & 1 deletion .github/workflows/asciidoctor-ghpages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ jobs:
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18
- name: Install Mermaid
run: |
sudo npm install -g @mermaid-js/[email protected]
node /usr/local/lib/node_modules/@mermaid-js/mermaid-cli/node_modules/puppeteer/install.js
- name: Install asciidoctor
run: |
sudo apt update
Expand All @@ -45,7 +53,6 @@ jobs:
if [ -e docs/static ]; then cp -rf docs/static ./generated-html; fi
touch ./generated-html/.nojekyll
ls -la ./generated-html
cat ./generated-html/index.html
- name: Setup github pages
if: needs.configure.outputs.enable_publish == 'true'
uses: actions/configure-pages@v4
Expand Down
64 changes: 64 additions & 0 deletions include/stdx/bitset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ namespace stdx {
inline namespace v1 {
struct place_bits_t {};
constexpr inline auto place_bits = place_bits_t{};
struct all_bits_t {};
constexpr inline auto all_bits = all_bits_t{};

enum struct lsb_t : std::size_t {};
enum struct msb_t : std::size_t {};
enum struct length_t : std::size_t {};

namespace detail {
template <std::size_t N, typename StorageElem> class bitset {
Expand Down Expand Up @@ -128,6 +134,12 @@ template <std::size_t N, typename StorageElem> class bitset {
(set(static_cast<std::size_t>(bs)), ...);
}

constexpr explicit bitset(all_bits_t) {
for (auto &elem : storage) {
elem = allbits;
}
}

constexpr explicit bitset(std::string_view str, std::size_t pos = 0,
std::size_t n = std::string_view::npos,
char one = '1') {
Expand Down Expand Up @@ -173,6 +185,37 @@ template <std::size_t N, typename StorageElem> class bitset {
return *this;
}

constexpr auto set(lsb_t lsb, msb_t msb, bool value = true) -> bitset & {
auto const l = to_underlying(lsb);
auto const m = to_underlying(msb);
auto [l_index, l_offset] = indices(l);
auto const [m_index, m_offset] = indices(m);

auto l_mask = std::numeric_limits<StorageElem>::max() << l_offset;
while (l_index != m_index) {
if (value) {
storage[l_index++] |= static_cast<StorageElem>(l_mask);
} else {
storage[l_index++] &= static_cast<StorageElem>(~(l_mask));
}
l_mask = std::numeric_limits<StorageElem>::max();
}
auto const m_mask = std::numeric_limits<StorageElem>::max() >>
(storage_elem_size - m_offset - 1);
if (value) {
storage[l_index] |= static_cast<StorageElem>(l_mask & m_mask);
} else {
storage[l_index] &= static_cast<StorageElem>(~(l_mask & m_mask));
}
return *this;
}

constexpr auto set(lsb_t lsb, length_t len, bool value = true) -> bitset & {
auto const l = to_underlying(lsb);
auto const length = to_underlying(len);
return set(lsb, static_cast<msb_t>(l + length - 1), value);
}

constexpr auto set() -> bitset & {
for (auto &elem : storage) {
elem = allbits;
Expand All @@ -193,6 +236,14 @@ template <std::size_t N, typename StorageElem> class bitset {
return *this;
}

constexpr auto reset(lsb_t lsb, msb_t msb) -> bitset & {
return set(lsb, msb, false);
}

constexpr auto reset(lsb_t lsb, length_t len) -> bitset & {
return set(lsb, len, false);
}

constexpr auto flip(std::size_t pos) -> bitset & {
auto const [index, offset] = indices(pos);
storage[index] ^= static_cast<StorageElem>(bit << offset);
Expand Down Expand Up @@ -345,5 +396,18 @@ template <std::size_t N, typename StorageElem = void>
using bitset =
detail::bitset<N, decltype(detail::select_storage<N, StorageElem>())>;

namespace literals {
// NOLINTBEGIN(google-runtime-int)
CONSTEVAL auto operator""_lsb(unsigned long long int n) -> lsb_t {
return static_cast<lsb_t>(n);
}
CONSTEVAL auto operator""_msb(unsigned long long int n) -> msb_t {
return static_cast<msb_t>(n);
}
CONSTEVAL auto operator""_len(unsigned long long int n) -> length_t {
return static_cast<length_t>(n);
}
// NOLINTEND(google-runtime-int)
} // namespace literals
} // namespace v1
} // namespace stdx
4 changes: 4 additions & 0 deletions include/stdx/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,7 @@ constexpr static auto value_lookup_v =
detail::value_t<Default>>::value;
} // namespace v1
} // namespace stdx

#ifndef FWD
#define FWD(x) std::forward<decltype(x)>(x)
#endif
54 changes: 54 additions & 0 deletions test/bitset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,3 +304,57 @@ TEMPLATE_TEST_CASE("for_each iterates in order lsb to msb", "[bitset]",
bs);
CHECK(result == bs);
}

TEMPLATE_TEST_CASE("set range of bits (lsb, length)", "[bitset]", std::uint8_t,
std::uint16_t, std::uint32_t, std::uint64_t) {
using namespace stdx::literals;
auto bs = stdx::bitset<64, TestType>{};
bs.set(6_lsb, 4_len);
CHECK(bs[6]);
CHECK(bs[7]);
CHECK(bs[8]);
CHECK(bs[9]);
CHECK(bs.count() == 4u);
}

TEMPLATE_TEST_CASE("set range of bits (lsb, msb)", "[bitset]", std::uint8_t,
std::uint16_t, std::uint32_t, std::uint64_t) {
using namespace stdx::literals;
auto bs = stdx::bitset<64, TestType>{};
bs.set(6_lsb, 9_msb);
CHECK(bs[6]);
CHECK(bs[7]);
CHECK(bs[8]);
CHECK(bs[9]);
CHECK(bs.count() == 4u);
}

TEMPLATE_TEST_CASE("construct with all bits set", "[bitset]", std::uint8_t,
std::uint16_t, std::uint32_t, std::uint64_t) {
constexpr auto bs = stdx::bitset<9, TestType>{stdx::all_bits};
static_assert(bs.all());
}

TEMPLATE_TEST_CASE("reset range of bits (lsb, length)", "[bitset]",
std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t) {
using namespace stdx::literals;
auto bs = stdx::bitset<64, TestType>{stdx::all_bits};
bs.reset(6_lsb, 4_len);
CHECK(not bs[6]);
CHECK(not bs[7]);
CHECK(not bs[8]);
CHECK(not bs[9]);
CHECK(bs.count() == 60);
}

TEMPLATE_TEST_CASE("reset range of bits (lsb, msb)", "[bitset]", std::uint8_t,
std::uint16_t, std::uint32_t, std::uint64_t) {
using namespace stdx::literals;
auto bs = stdx::bitset<64, TestType>{stdx::all_bits};
bs.reset(6_lsb, 9_msb);
CHECK(not bs[6]);
CHECK(not bs[7]);
CHECK(not bs[8]);
CHECK(not bs[9]);
CHECK(bs.count() == 60);
}