33#include < stdx/bit.hpp>
44#include < stdx/compiler.hpp>
55#include < stdx/concepts.hpp>
6+ #include < stdx/ct_string.hpp>
67#include < stdx/detail/bitset_common.hpp>
78#include < stdx/type_traits.hpp>
89#include < stdx/udls.hpp>
1819
1920namespace stdx {
2021inline namespace v1 {
21- namespace detail {
22- template <std::size_t N, typename StorageElem> class bitset {
22+ template <auto Size, typename StorageElem =
23+ decltype (smallest_uint<to_underlying(Size), void >())>
24+ class bitset {
25+ constexpr static std::size_t N = to_underlying(Size);
26+ using elem_t = StorageElem;
27+
2328 constexpr static auto storage_elem_size =
24- std::numeric_limits<StorageElem >::digits;
29+ std::numeric_limits<elem_t >::digits;
2530 constexpr static auto storage_size =
2631 (N + storage_elem_size - 1 ) / storage_elem_size;
27- constexpr static auto bit = StorageElem {1U };
28- constexpr static auto allbits = std::numeric_limits<StorageElem >::max();
32+ constexpr static auto bit = elem_t {1U };
33+ constexpr static auto allbits = std::numeric_limits<elem_t >::max();
2934
30- std::array<StorageElem , storage_size> storage{};
35+ std::array<elem_t , storage_size> storage{};
3136
32- constexpr static auto lastmask = []() -> StorageElem {
37+ constexpr static auto lastmask = []() -> elem_t {
3338 if constexpr (N % storage_elem_size != 0 ) {
3439 return allbits >> (storage_elem_size - N % storage_elem_size);
3540 } else {
3641 return allbits;
3742 }
3843 }();
39- constexpr auto highbits () const -> StorageElem {
44+ constexpr auto highbits () const -> elem_t {
4045 return storage.back () & lastmask;
4146 }
4247
@@ -99,21 +104,21 @@ template <std::size_t N, typename StorageElem> class bitset {
99104 for (auto e : storage) {
100105 while (e != 0 ) {
101106 auto const offset = static_cast <std::size_t >(countr_zero (e));
102- e &= static_cast <StorageElem >(~(bit << offset));
107+ e &= static_cast <elem_t >(~(bit << offset));
103108 f (i + offset);
104109 }
105- i += std::numeric_limits<StorageElem >::digits;
110+ i += std::numeric_limits<elem_t >::digits;
106111 }
107112 return std::forward<F>(f);
108113 }
109114
110- template <typename F, std:: size_t M, typename ... S>
115+ template <typename F, auto M, typename ... S>
111116 friend constexpr auto for_each (F &&f, bitset<M, S> const &...bs) -> F;
112117
113118 public:
114119 constexpr bitset () = default;
115120 constexpr explicit bitset (std::uint64_t value) {
116- if constexpr (std::is_same_v<StorageElem , std::uint64_t >) {
121+ if constexpr (std::is_same_v<elem_t , std::uint64_t >) {
117122 storage[0 ] = value;
118123 } else {
119124 for (auto &elem : storage) {
@@ -151,14 +156,19 @@ template <std::size_t N, typename StorageElem> class bitset {
151156 }
152157 }
153158
159+ #if __cplusplus >= 202002L
160+ constexpr explicit bitset (ct_string<N + 1 > s)
161+ : bitset{static_cast <std::string_view>(s)} {}
162+ #endif
163+
154164 template <typename T> [[nodiscard]] constexpr auto to () const -> T {
155165 using U = underlying_type_t <T>;
156166 static_assert (
157167 unsigned_integral<U>,
158168 " Conversion must be to an unsigned integral type or enum!" );
159169 static_assert (N <= std::numeric_limits<U>::digits,
160170 " Bitset too big for conversion to T" );
161- if constexpr (std::is_same_v<StorageElem , U>) {
171+ if constexpr (std::is_same_v<elem_t , U>) {
162172 return static_cast <T>(storage[0 ] & lastmask);
163173 } else {
164174 U result{highbits ()};
@@ -191,9 +201,9 @@ template <std::size_t N, typename StorageElem> class bitset {
191201 auto const pos = static_cast <std::size_t >(to_underlying (idx));
192202 auto const [index, offset] = indices (pos);
193203 if (value) {
194- storage[index] |= static_cast <StorageElem >(bit << offset);
204+ storage[index] |= static_cast <elem_t >(bit << offset);
195205 } else {
196- storage[index] &= static_cast <StorageElem >(~(bit << offset));
206+ storage[index] &= static_cast <elem_t >(~(bit << offset));
197207 }
198208 return *this ;
199209 }
@@ -205,25 +215,25 @@ template <std::size_t N, typename StorageElem> class bitset {
205215 auto [l_index, l_offset] = indices (l);
206216 auto const [m_index, m_offset] = indices (m);
207217
208- using setfn = auto (*)(StorageElem *, StorageElem )->void ;
218+ using setfn = auto (*)(elem_t *, elem_t )->void ;
209219 auto const fn = [&]() -> setfn {
210220 if (value) {
211- return [](StorageElem *ptr, StorageElem val) { *ptr |= val; };
221+ return [](elem_t *ptr, elem_t val) { *ptr |= val; };
212222 }
213- return [](StorageElem *ptr, StorageElem val) { *ptr &= ~val; };
223+ return [](elem_t *ptr, elem_t val) { *ptr &= ~val; };
214224 }();
215225
216- auto l_mask = std::numeric_limits<StorageElem >::max () << l_offset;
226+ auto l_mask = std::numeric_limits<elem_t >::max () << l_offset;
217227 if (l_index != m_index) {
218- fn (&storage[l_index++], static_cast <StorageElem >(l_mask));
219- l_mask = std::numeric_limits<StorageElem >::max ();
228+ fn (&storage[l_index++], static_cast <elem_t >(l_mask));
229+ l_mask = std::numeric_limits<elem_t >::max ();
220230 }
221231 while (l_index != m_index) {
222- fn (&storage[l_index++], static_cast <StorageElem >(l_mask));
232+ fn (&storage[l_index++], static_cast <elem_t >(l_mask));
223233 }
224- auto const m_mask = std::numeric_limits<StorageElem >::max () >>
234+ auto const m_mask = std::numeric_limits<elem_t >::max () >>
225235 (storage_elem_size - m_offset - 1 );
226- fn (&storage[l_index], static_cast <StorageElem >(l_mask & m_mask));
236+ fn (&storage[l_index], static_cast <elem_t >(l_mask & m_mask));
227237 return *this ;
228238 }
229239
@@ -245,7 +255,7 @@ template <std::size_t N, typename StorageElem> class bitset {
245255 constexpr auto reset (T idx) LIFETIMEBOUND -> bitset & {
246256 auto const pos = static_cast <std::size_t >(to_underlying (idx));
247257 auto const [index, offset] = indices (pos);
248- storage[index] &= static_cast <StorageElem >(~(bit << offset));
258+ storage[index] &= static_cast <elem_t >(~(bit << offset));
249259 return *this ;
250260 }
251261
@@ -267,7 +277,7 @@ template <std::size_t N, typename StorageElem> class bitset {
267277 template <typename T> constexpr auto flip (T idx) LIFETIMEBOUND -> bitset & {
268278 auto const pos = static_cast <std::size_t >(to_underlying (idx));
269279 auto const [index, offset] = indices (pos);
270- storage[index] ^= static_cast <StorageElem >(bit << offset);
280+ storage[index] ^= static_cast <elem_t >(bit << offset);
271281 return *this ;
272282 }
273283
@@ -310,10 +320,10 @@ template <std::size_t N, typename StorageElem> class bitset {
310320 std::size_t i = 0 ;
311321 for (auto e : storage) {
312322 if (auto offset = static_cast <std::size_t >(countr_one (e));
313- offset != std::numeric_limits<StorageElem >::digits) {
323+ offset != std::numeric_limits<elem_t >::digits) {
314324 return i + offset;
315325 }
316- i += std::numeric_limits<StorageElem >::digits;
326+ i += std::numeric_limits<elem_t >::digits;
317327 }
318328 return i;
319329 }
@@ -358,13 +368,13 @@ template <std::size_t N, typename StorageElem> class bitset {
358368 } else {
359369 auto const borrow_shift = storage_elem_size - pos;
360370 for (auto i = start; i > std::size_t {}; --i) {
361- storage[dst] = static_cast <StorageElem >(storage[i] << pos);
371+ storage[dst] = static_cast <elem_t >(storage[i] << pos);
362372 storage[dst] |=
363- static_cast <StorageElem >(storage[i - 1 ] >> borrow_shift);
373+ static_cast <elem_t >(storage[i - 1 ] >> borrow_shift);
364374 --dst;
365375 }
366376 }
367- storage[dst] = static_cast <StorageElem >(storage.front () << pos);
377+ storage[dst] = static_cast <elem_t >(storage.front () << pos);
368378 while (dst > std::size_t {}) {
369379 storage[--dst] = 0 ;
370380 }
@@ -384,21 +394,21 @@ template <std::size_t N, typename StorageElem> class bitset {
384394 } else {
385395 auto const borrow_shift = storage_elem_size - pos;
386396 for (auto i = start; i < storage_size - 1 ; ++i) {
387- storage[dst] = static_cast <StorageElem >(storage[i] >> pos);
397+ storage[dst] = static_cast <elem_t >(storage[i] >> pos);
388398 storage[dst] |=
389- static_cast <StorageElem >(storage[i + 1 ] << borrow_shift);
399+ static_cast <elem_t >(storage[i + 1 ] << borrow_shift);
390400 ++dst;
391401 }
392402 }
393- storage[dst++] = static_cast <StorageElem >(storage.back () >> pos);
403+ storage[dst++] = static_cast <elem_t >(storage.back () >> pos);
394404 while (dst < storage_size) {
395405 storage[dst++] = 0 ;
396406 }
397407 return *this ;
398408 }
399409};
400410
401- template <typename F, std:: size_t M, typename ... S>
411+ template <typename F, auto M, typename ... S>
402412constexpr auto for_each (F &&f, bitset<M, S> const &...bs) -> F {
403413 if constexpr (sizeof ...(bs) == 1 ) {
404414 return (bs.for_each (std::forward<F>(f)), ...);
@@ -407,12 +417,9 @@ constexpr auto for_each(F &&f, bitset<M, S> const &...bs) -> F {
407417 return f;
408418 }
409419}
410- } // namespace detail
411-
412- template <auto N, typename StorageElem = void >
413- using bitset =
414- detail::bitset<to_underlying(N),
415- decltype (smallest_uint<to_underlying(N), StorageElem>())>;
416420
421+ #if __cplusplus >= 202002L
422+ template <std::size_t N> bitset (ct_string<N>) -> bitset<N - 1>;
423+ #endif
417424} // namespace v1
418425} // namespace stdx
0 commit comments