diff --git a/.github/workflows/asciidoctor-ghpages.yml b/.github/workflows/asciidoctor-ghpages.yml index a0d6886..47f072d 100644 --- a/.github/workflows/asciidoctor-ghpages.yml +++ b/.github/workflows/asciidoctor-ghpages.yml @@ -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/mermaid-cli@10.6.1 + node /usr/local/lib/node_modules/@mermaid-js/mermaid-cli/node_modules/puppeteer/install.js - name: Install asciidoctor run: | sudo apt update @@ -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 diff --git a/include/stdx/bitset.hpp b/include/stdx/bitset.hpp index ec6b5df..0afb1ba 100644 --- a/include/stdx/bitset.hpp +++ b/include/stdx/bitset.hpp @@ -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 class bitset { @@ -128,6 +134,12 @@ template class bitset { (set(static_cast(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') { @@ -173,6 +185,37 @@ template 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::max() << l_offset; + while (l_index != m_index) { + if (value) { + storage[l_index++] |= static_cast(l_mask); + } else { + storage[l_index++] &= static_cast(~(l_mask)); + } + l_mask = std::numeric_limits::max(); + } + auto const m_mask = std::numeric_limits::max() >> + (storage_elem_size - m_offset - 1); + if (value) { + storage[l_index] |= static_cast(l_mask & m_mask); + } else { + storage[l_index] &= static_cast(~(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(l + length - 1), value); + } + constexpr auto set() -> bitset & { for (auto &elem : storage) { elem = allbits; @@ -193,6 +236,14 @@ template 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(bit << offset); @@ -345,5 +396,18 @@ template using bitset = detail::bitset())>; +namespace literals { +// NOLINTBEGIN(google-runtime-int) +CONSTEVAL auto operator""_lsb(unsigned long long int n) -> lsb_t { + return static_cast(n); +} +CONSTEVAL auto operator""_msb(unsigned long long int n) -> msb_t { + return static_cast(n); +} +CONSTEVAL auto operator""_len(unsigned long long int n) -> length_t { + return static_cast(n); +} +// NOLINTEND(google-runtime-int) +} // namespace literals } // namespace v1 } // namespace stdx diff --git a/include/stdx/utility.hpp b/include/stdx/utility.hpp index 6d982a9..14c756e 100644 --- a/include/stdx/utility.hpp +++ b/include/stdx/utility.hpp @@ -105,3 +105,7 @@ constexpr static auto value_lookup_v = detail::value_t>::value; } // namespace v1 } // namespace stdx + +#ifndef FWD +#define FWD(x) std::forward(x) +#endif diff --git a/test/bitset.cpp b/test/bitset.cpp index 0774dac..164f623 100644 --- a/test/bitset.cpp +++ b/test/bitset.cpp @@ -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); +}