diff --git a/docs/bitset.adoc b/docs/bitset.adoc index 843d518..45b1861 100644 --- a/docs/bitset.adoc +++ b/docs/bitset.adoc @@ -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 +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 +---- diff --git a/include/stdx/bitset.hpp b/include/stdx/bitset.hpp index f0a78c9..89da441 100644 --- a/include/stdx/bitset.hpp +++ b/include/stdx/bitset.hpp @@ -15,8 +15,11 @@ namespace stdx { inline namespace v1 { +struct place_bits_t {}; +constexpr inline auto place_bits = place_bits_t{}; + namespace detail { -template class bitset { +template class bitset { static_assert(std::is_unsigned_v, "Underlying storage of bitset must be an unsigned type"); constexpr static auto storage_elem_size = @@ -119,13 +122,21 @@ template class bitset { } } } + + template + constexpr explicit bitset(place_bits_t, Bs... bs) { + static_assert((std::is_integral_v and ...)); + (set(static_cast(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); } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 022d8f1..6df4917 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -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( @@ -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 diff --git a/test/bitset.cpp b/test/bitset.cpp index a010eb5..0774dac 100644 --- a/test/bitset.cpp +++ b/test/bitset.cpp @@ -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,