Skip to content
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
10 changes: 0 additions & 10 deletions docs/bitset.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>` 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.
Expand Down
1 change: 0 additions & 1 deletion docs/header_graph.mmd
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 22 additions & 28 deletions include/stdx/bitset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <stdx/bit.hpp>
#include <stdx/compiler.hpp>
#include <stdx/concepts.hpp>
#include <stdx/ct_string.hpp>
#include <stdx/detail/bitset_common.hpp>
#include <stdx/type_traits.hpp>
#include <stdx/udls.hpp>
Expand All @@ -15,7 +14,6 @@
#include <cstddef>
#include <cstdint>
#include <limits>
#include <string_view>
#include <type_traits>
#include <utility>

Expand Down Expand Up @@ -58,6 +56,17 @@ namespace detail {
template <typename T>
concept bit_spec = std::same_as<T, set_bit> or std::same_as<T, unset_bit> or
std::same_as<T, bit>;

template <typename T> consteval auto bitset_size(T t) {
if constexpr (std::integral<T>) {
return static_cast<std::size_t>(t);
} else if constexpr (std::is_enum_v<T>) {
return t;
} else {
static_assert(
always_false_v<T>,
"bitset must be instantiated with an integral or an enum argument");
}
}

template <auto Size,
Expand Down Expand Up @@ -145,13 +154,6 @@ class bitset {
return not std::is_enum_v<T> or std::is_same_v<T, decltype(Size)>;
}

template <detail::bit_spec Spec, typename F, auto M, typename... S>
friend constexpr auto for_each(F &&f, bitset<M, S> const &...bs) -> F;

template <typename T, typename F, typename R, auto M, typename... S>
friend constexpr auto transform_reduce(F &&f, R &&r, T init,
bitset<M, S> const &...bs) -> T;

public:
constexpr bitset() = default;
constexpr explicit bitset(std::uint64_t value) {
Expand Down Expand Up @@ -184,21 +186,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<N + 1> s)
: bitset{static_cast<std::string_view>(s)} {}

template <typename T> [[nodiscard]] constexpr auto to() const -> T {
if constexpr (N == 0) {
return {};
Expand Down Expand Up @@ -495,9 +482,14 @@ class bitset {
return init;
}
};
} // namespace detail

template <auto Size,
typename StorageElem = decltype(smallest_uint<to_underlying(Size)>())>
using bitset = detail::bitset<detail::bitset_size(Size), StorageElem>;

template <detail::bit_spec Spec = set_bit, typename F, auto M, typename... S>
constexpr auto for_each(F &&f, bitset<M, S> const &...bs) -> F {
constexpr auto for_each(F &&f, detail::bitset<M, S> const &...bs) -> F {
if constexpr (sizeof...(bs) == 1) {
return (bs.template for_each<Spec>(std::forward<F>(f)), ...);
} else {
Expand All @@ -508,7 +500,8 @@ constexpr auto for_each(F &&f, bitset<M, S> const &...bs) -> F {

template <typename T, typename F, typename R, auto M, typename... S>
[[nodiscard]] constexpr auto transform_reduce(F &&f, R &&r, T init,
bitset<M, S> const &...bs) -> T {
detail::bitset<M, S> const &...bs)
-> T {
if constexpr (sizeof...(bs) == 1) {
return (bs.transform_reduce(std::forward<F>(f), std::forward<R>(r),
std::move(init)),
Expand All @@ -519,9 +512,10 @@ template <typename T, typename F, typename R, auto M, typename... S>
}
}

template <std::size_t N> bitset(ct_string<N>) -> bitset<N - 1>;

namespace detail {
using ::stdx::for_each;
using ::stdx::transform_reduce;

template <typename...> constexpr std::size_t index_of = 0;

template <typename T, typename... Us>
Expand Down
29 changes: 7 additions & 22 deletions test/bitset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -590,3 +568,10 @@ TEST_CASE("zero size bitset", "[bitset]") {
bs3 = stdx::bitset<0>{stdx::all_bits};
CHECK(bs3.to<std::uint8_t>() == 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<A, B>);
STATIC_CHECK(std::same_as<A, stdx::bitset<std::size_t{16}>>);
}