Skip to content
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

Bitset changes #10

Merged
merged 3 commits into from
Sep 14, 2023
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
42 changes: 42 additions & 0 deletions docs/bitset.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,45 @@ platform.
* Stream input and output operators are not implemented.
* A `std::hash` specialization is not implemented.
* `to_string`, `to_ulong` and `to_ullong` are not implemented; `to_uint64_t` is available.

A bitset has two template parameters: the size of the bitset and the storage
element type to use. The storage element type must be unsigned.
[source,cpp]
----
template <std::size_t N, typename Element = void>
struct bitset;
----

If the storage element type is omitted, the smallest unsigned type that will fit
the size is selected, or `std::uint64_t` if the size is more than 64.
[source,cpp]
----
using A = stdx::bitset<8>; // uses uint8_t
using B = stdx::bitset<16>; // uses uint16_t
using C = stdx::bitset<32>; // uses uint32_t
using D = stdx::bitset<64>; // uses uint64_t
using E = stdx::bitset<128>; // uses (array of) uint64_t
using F = stdx::bitset<128, std::uint8_t>; // uses (array of) uint8_t
----

A bitset can be created from a `std::uint64_t`:
[source,cpp]
----
auto bs = stdx::bitset<8>{0b1100}; // bits 2 and 3 set
----

Or by specifying which bits are set and using `stdx::place_bits`:
[source,cpp]
----
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
----
17 changes: 14 additions & 3 deletions include/stdx/bitset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@

namespace stdx {
inline namespace v1 {
struct place_bits_t {};
constexpr inline auto place_bits = place_bits_t{};

namespace detail {
template <std::size_t N, typename StorageElem = std::uint8_t> class bitset {
template <std::size_t N, typename StorageElem> class bitset {
static_assert(std::is_unsigned_v<StorageElem>,
"Underlying storage of bitset must be an unsigned type");
constexpr static auto storage_elem_size =
Expand Down Expand Up @@ -119,13 +122,21 @@ template <std::size_t N, typename StorageElem = std::uint8_t> class bitset {
}
}
}

template <typename... Bs>
constexpr explicit bitset(place_bits_t, Bs... bs) {
static_assert((std::is_integral_v<Bs> and ...));
(set(static_cast<std::size_t>(bs)), ...);
}

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{};
for (auto c : str.substr(pos, std::min(len, N))) {
set(i++, c == one);
auto const s = str.substr(pos, std::min(len, N));
for (auto it = std::rbegin(s); it != std::rend(s); ++it) {
set(i++, *it == one);
}
}

Expand Down
131 changes: 36 additions & 95 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,33 +1,39 @@
add_unit_test(
stdx_test
CATCH2
FILES
always_false.cpp
bit.cpp
bitset.cpp
callable.cpp
concepts.cpp
conditional.cpp
function_traits.cpp
intrusive_list.cpp
overload.cpp
priority.cpp
remove_cvref.cpp
to_underlying.cpp
with_result_of.cpp
udls.cpp
LIBRARIES
warnings
stdx)

add_unit_test(
ct_conversions_test
CATCH2
FILES
ct_conversions.cpp
LIBRARIES
warnings
stdx)
function(add_tests)
foreach(name ${ARGN})
add_unit_test(
"${name}_test"
CATCH2
FILES
"${name}.cpp"
LIBRARIES
warnings
stdx)
endforeach()
endfunction()

add_tests(
always_false
bit
bitset
callable
concepts
conditional
ct_conversions
cx_map
cx_multimap
cx_queue
cx_set
cx_vector
default_panic
function_traits
intrusive_list
overload
panic
priority
remove_cvref
to_underlying
with_result_of
udls)

if(${CMAKE_CXX_STANDARD} GREATER_EQUAL 20)
add_unit_test(
Expand All @@ -38,72 +44,7 @@ if(${CMAKE_CXX_STANDARD} GREATER_EQUAL 20)
LIBRARIES
warnings
stdx)
endif()

add_unit_test(
cx_map_test
CATCH2
FILES
cx_map.cpp
LIBRARIES
warnings
stdx)

add_unit_test(
cx_multimap_test
CATCH2
FILES
cx_multimap.cpp
LIBRARIES
warnings
stdx)

add_unit_test(
cx_queue_test
CATCH2
FILES
cx_queue.cpp
LIBRARIES
warnings
stdx)

add_unit_test(
cx_set_test
CATCH2
FILES
cx_set.cpp
LIBRARIES
warnings
stdx)

add_unit_test(
cx_vector_test
CATCH2
FILES
cx_vector.cpp
LIBRARIES
warnings
stdx)

add_unit_test(
default_panic_test
CATCH2
FILES
default_panic.cpp
LIBRARIES
warnings
stdx)

add_unit_test(
panic_test
CATCH2
FILES
panic.cpp
LIBRARIES
warnings
stdx)

if(${CMAKE_CXX_STANDARD} GREATER_EQUAL 20)
add_unit_test(
tuple_test
CATCH2
Expand Down
17 changes: 13 additions & 4 deletions test/bitset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,27 @@ TEMPLATE_TEST_CASE("construct with a value", "[bitset]", std::uint8_t,
static_assert(bs2[1]);
}

TEMPLATE_TEST_CASE("construct with values for bits", "[bitset]", std::uint8_t,
std::uint16_t, std::uint32_t, std::uint64_t) {
constexpr auto bs = stdx::bitset<1, TestType>{stdx::place_bits, 1, 3, 5};
static_assert(not bs[0]);
static_assert(bs[1]);
static_assert(bs[3]);
static_assert(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_assert(stdx::bitset<5, TestType>{"10101"sv} ==
stdx::bitset<5, TestType>{0b10101ul});
static_assert(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_assert(stdx::bitset<3, TestType>{"XOXOX"sv, 2, 3, 'X'} ==
stdx::bitset<3, TestType>{0b101ul});
static_assert(stdx::bitset<4, TestType>{"XOXOXO"sv, 2, 4, 'X'} ==
stdx::bitset<4, TestType>{0b1010ul});
}

TEMPLATE_TEST_CASE("convert to uint64_t", "[bitset]", std::uint8_t,
Expand Down