From 97f29773b445a0655bc24ae85dbbc6797cca48ed Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Wed, 9 Sep 2026 16:42:07 -0600 Subject: [PATCH 1/3] :fire: Remove `bitset` constructor from `string_view` Problem: - `bitset` construction from a `string_view` uses `substr` which may throw, and it's a really niche use case anyway. Solution: - Remove it. --- docs/bitset.adoc | 10 ---------- docs/header_graph.mmd | 1 - include/stdx/bitset.hpp | 19 ------------------- 3 files changed, 30 deletions(-) diff --git a/docs/bitset.adoc b/docs/bitset.adoc index d3ae08f..7a96248 100644 --- a/docs/bitset.adoc +++ b/docs/bitset.adoc @@ -55,16 +55,6 @@ Or by specifying which bits are set and using `stdx::place_bits`: auto bs = stdx::bitset<8>{stdx::place_bits, 2, 3}; // bits 2 and 3 set ---- -Or with a string_view (potentially by substring and with a known value for -set bits): -[source,cpp] ----- -using namespace std::string_view_literals; -auto bs1 = stdx::bitset<8>{"1100"sv}; // bits 2 and 3 set -auto bs2 = stdx::bitset<8>{"1100"sv, 0, 2}; // bits 0 and 1 set -auto bs3 = stdx::bitset<8>{"AABB"sv, 0, 2, 'A'}; // bits 0 and 1 set ----- - To convert a bitset back to an integral type, `to` is available where `T` is an unsigned integral type large enough to fit all the bits. And `to_natural` produces the smallest such unsigned integral type. diff --git a/docs/header_graph.mmd b/docs/header_graph.mmd index c38efc0..60a2598 100644 --- a/docs/header_graph.mmd +++ b/docs/header_graph.mmd @@ -83,7 +83,6 @@ flowchart BT byterator --> bit cx_set ---> cx_map bitset --> bit - bitset --> ct_string panic --> ct_string env --> ct_string tuple_algorithms --> tuple diff --git a/include/stdx/bitset.hpp b/include/stdx/bitset.hpp index 0fc78c0..5a80fc9 100644 --- a/include/stdx/bitset.hpp +++ b/include/stdx/bitset.hpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -15,7 +14,6 @@ #include #include #include -#include #include #include @@ -184,21 +182,6 @@ class bitset { } } - constexpr explicit bitset(std::string_view str, std::size_t pos = 0, - std::size_t n = std::string_view::npos, - char one = '1') { - auto const len = std::min(n, str.size() - pos); - auto i = std::size_t{}; - auto const s = str.substr(pos, std::min(len, N)); - // NOLINTNEXTLINE(modernize-loop-convert) - for (auto it = std::rbegin(s); it != std::rend(s); ++it) { - set(i++, *it == one); - } - } - - constexpr explicit bitset(ct_string s) - : bitset{static_cast(s)} {} - template [[nodiscard]] constexpr auto to() const -> T { if constexpr (N == 0) { return {}; @@ -519,8 +502,6 @@ template } } -template bitset(ct_string) -> bitset; - namespace detail { template constexpr std::size_t index_of = 0; From 81c259dfb8bca4a6e7fdf7e7c460fa1278ee71fe Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Wed, 9 Sep 2026 16:43:28 -0600 Subject: [PATCH 2/3] :fire: Remove `friend` declarations in `bitset` Problem: - There's no need for `for_each` and `transform` to be `friend`s of `bitset` since the member functions are public. Solution: - Remove the `friend` declarations. --- include/stdx/bitset.hpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/stdx/bitset.hpp b/include/stdx/bitset.hpp index 5a80fc9..e1304e7 100644 --- a/include/stdx/bitset.hpp +++ b/include/stdx/bitset.hpp @@ -143,13 +143,6 @@ class bitset { return not std::is_enum_v or std::is_same_v; } - template - friend constexpr auto for_each(F &&f, bitset const &...bs) -> F; - - template - friend constexpr auto transform_reduce(F &&f, R &&r, T init, - bitset const &...bs) -> T; - public: constexpr bitset() = default; constexpr explicit bitset(std::uint64_t value) { From 808b836fe0433c06838c21a7f4e5fb7a4cf18b0d Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Wed, 9 Sep 2026 16:44:21 -0600 Subject: [PATCH 3/3] :art: Fix type of `bitset` argument Problem: - It's awkward that `bitset<16>` and `bitset<16u>` are different types. Solution: - Fix the argument of `bitset` to a `std::size_t` in the cases it's not an enum. --- include/stdx/bitset.hpp | 24 ++++++++++++++++++++++-- test/bitset.cpp | 29 +++++++---------------------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/include/stdx/bitset.hpp b/include/stdx/bitset.hpp index e1304e7..1f780e2 100644 --- a/include/stdx/bitset.hpp +++ b/include/stdx/bitset.hpp @@ -56,6 +56,17 @@ namespace detail { template concept bit_spec = std::same_as or std::same_as or std::same_as; + +template consteval auto bitset_size(T t) { + if constexpr (std::integral) { + return static_cast(t); + } else if constexpr (std::is_enum_v) { + return t; + } else { + static_assert( + always_false_v, + "bitset must be instantiated with an integral or an enum argument"); + } } template ())> +using bitset = detail::bitset; template -constexpr auto for_each(F &&f, bitset const &...bs) -> F { +constexpr auto for_each(F &&f, detail::bitset const &...bs) -> F { if constexpr (sizeof...(bs) == 1) { return (bs.template for_each(std::forward(f)), ...); } else { @@ -484,7 +500,8 @@ constexpr auto for_each(F &&f, bitset const &...bs) -> F { template [[nodiscard]] constexpr auto transform_reduce(F &&f, R &&r, T init, - bitset const &...bs) -> T { + detail::bitset const &...bs) + -> T { if constexpr (sizeof...(bs) == 1) { return (bs.transform_reduce(std::forward(f), std::forward(r), std::move(init)), @@ -496,6 +513,9 @@ template } namespace detail { +using ::stdx::for_each; +using ::stdx::transform_reduce; + template constexpr std::size_t index_of = 0; template diff --git a/test/bitset.cpp b/test/bitset.cpp index 86175d0..9864606 100644 --- a/test/bitset.cpp +++ b/test/bitset.cpp @@ -132,20 +132,6 @@ TEMPLATE_TEST_CASE("construct with values for bits", "[bitset]", std::uint8_t, STATIC_REQUIRE(bs[5]); } -TEMPLATE_TEST_CASE("construct with a string_view", "[bitset]", std::uint8_t, - std::uint16_t, std::uint32_t, std::uint64_t) { - using namespace std::string_view_literals; - STATIC_REQUIRE(stdx::bitset<4, TestType>{"1010"sv} == - stdx::bitset<4, TestType>{0b1010ul}); -} - -TEMPLATE_TEST_CASE("construct with a substring", "[bitset]", std::uint8_t, - std::uint16_t, std::uint32_t, std::uint64_t) { - using namespace std::string_view_literals; - STATIC_REQUIRE(stdx::bitset<4, TestType>{"XOXOXO"sv, 2, 4, 'X'} == - stdx::bitset<4, TestType>{0b1010ul}); -} - TEMPLATE_TEST_CASE("convert to unsigned integral type (same underlying type)", "[bitset]", std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t) { @@ -563,14 +549,6 @@ TEST_CASE("use bitset with enum struct (lowest_unset)", "[bitset]") { CHECK(bs.lowest_unset() == Bits::ONE); } -TEST_CASE("construct with a ct_string", "[bitset]") { - using namespace stdx::literals; - STATIC_REQUIRE(stdx::bitset{"1010"_cts} == - stdx::bitset<4ul, std::uint8_t>{0b1010ul}); - STATIC_REQUIRE(stdx::bitset{"101010101"_cts} == - stdx::bitset<9ul, std::uint16_t>{0b101010101ul}); -} - TEST_CASE("zero size bitset", "[bitset]") { constexpr auto bs1 = stdx::bitset<0>{}; STATIC_REQUIRE(bs1.count() == 0u); @@ -590,3 +568,10 @@ TEST_CASE("zero size bitset", "[bitset]") { bs3 = stdx::bitset<0>{stdx::all_bits}; CHECK(bs3.to() == 0); } + +TEST_CASE("fix type of bitset argument to std::size_t", "[bitset]") { + using A = stdx::bitset<16>; + using B = stdx::bitset<16u>; + STATIC_CHECK(std::same_as); + STATIC_CHECK(std::same_as>); +}