|
21 | 21 |
|
22 | 22 | namespace stdx { |
23 | 23 | inline namespace v1 { |
| 24 | +struct set_bit { |
| 25 | + template <auto Bit, typename IterArg, auto Mask> |
| 26 | + constexpr static auto fn(auto e, auto idx, auto &f) { |
| 27 | + using elem_t = decltype(Bit); |
| 28 | + while (e != 0) { |
| 29 | + auto const offset = static_cast<std::size_t>(countr_zero(e)); |
| 30 | + e &= static_cast<elem_t>(~(Bit << offset)); |
| 31 | + f(static_cast<IterArg>(idx + offset)); |
| 32 | + } |
| 33 | + } |
| 34 | +}; |
| 35 | +struct unset_bit { |
| 36 | + template <auto Bit, typename IterArg, auto Mask> |
| 37 | + constexpr static auto fn(auto e, auto idx, auto &f) { |
| 38 | + using elem_t = decltype(Bit); |
| 39 | + while (e != Mask) { |
| 40 | + auto const offset = static_cast<std::size_t>(countr_one(e)); |
| 41 | + e |= static_cast<elem_t>(Bit << offset); |
| 42 | + f(static_cast<IterArg>(idx + offset)); |
| 43 | + } |
| 44 | + } |
| 45 | +}; |
| 46 | +struct bit { |
| 47 | + template <auto Bit, typename IterArg, auto Mask> |
| 48 | + constexpr static auto fn(auto e, auto idx, auto &f) { |
| 49 | + using elem_t = decltype(Bit); |
| 50 | + for (auto i = std::size_t{}; i < popcount(Mask); ++i) { |
| 51 | + bool b = e & static_cast<elem_t>(Bit << i); |
| 52 | + f(static_cast<IterArg>(idx + i), b); |
| 53 | + } |
| 54 | + } |
| 55 | +}; |
| 56 | + |
| 57 | +namespace detail { |
| 58 | +template <typename T> |
| 59 | +concept bit_spec = std::same_as<T, set_bit> or std::same_as<T, unset_bit> or |
| 60 | + std::same_as<T, bit>; |
| 61 | +} |
| 62 | + |
24 | 63 | template <auto Size, |
25 | 64 | typename StorageElem = decltype(smallest_uint<to_underlying(Size)>())> |
26 | 65 | class bitset { |
@@ -106,20 +145,20 @@ class bitset { |
106 | 145 | return not std::is_enum_v<T> or std::is_same_v<T, decltype(Size)>; |
107 | 146 | } |
108 | 147 |
|
109 | | - template <typename F> constexpr auto for_each(F &&f) const -> F { |
110 | | - std::size_t i = 0; |
111 | | - for (auto e : storage) { |
112 | | - while (e != 0) { |
113 | | - auto const offset = static_cast<std::size_t>(countr_zero(e)); |
114 | | - e &= static_cast<elem_t>(~(bit << offset)); |
115 | | - f(static_cast<iter_arg_t>(i + offset)); |
116 | | - } |
117 | | - i += std::numeric_limits<elem_t>::digits; |
| 148 | + template <detail::bit_spec Spec, typename F> |
| 149 | + constexpr auto for_each(F &&f) const -> F { |
| 150 | + std::size_t idx = 0; |
| 151 | + for (auto i = std::size_t{}; i < storage_size - 1; ++i) { |
| 152 | + Spec::template fn<bit, iter_arg_t, |
| 153 | + std::numeric_limits<elem_t>::max()>(storage[i], |
| 154 | + idx, f); |
| 155 | + idx += std::numeric_limits<elem_t>::digits; |
118 | 156 | } |
| 157 | + Spec::template fn<bit, iter_arg_t, lastmask>(highbits(), idx, f); |
119 | 158 | return std::forward<F>(f); |
120 | 159 | } |
121 | 160 |
|
122 | | - template <typename F, auto M, typename... S> |
| 161 | + template <detail::bit_spec Spec, typename F, auto M, typename... S> |
123 | 162 | friend constexpr auto for_each(F &&f, bitset<M, S> const &...bs) -> F; |
124 | 163 |
|
125 | 164 | template <typename T, typename F, typename R> |
@@ -457,10 +496,10 @@ class bitset { |
457 | 496 | } |
458 | 497 | }; |
459 | 498 |
|
460 | | -template <typename F, auto M, typename... S> |
| 499 | +template <detail::bit_spec Spec = set_bit, typename F, auto M, typename... S> |
461 | 500 | constexpr auto for_each(F &&f, bitset<M, S> const &...bs) -> F { |
462 | 501 | if constexpr (sizeof...(bs) == 1) { |
463 | | - return (bs.for_each(std::forward<F>(f)), ...); |
| 502 | + return (bs.template for_each<Spec>(std::forward<F>(f)), ...); |
464 | 503 | } else { |
465 | 504 | static_assert(stdx::always_false_v<F>, "unimplemented"); |
466 | 505 | return f; |
@@ -648,9 +687,10 @@ template <typename... Ts> class type_bitset { |
648 | 687 | return *this; |
649 | 688 | } |
650 | 689 |
|
651 | | - template <typename F> constexpr auto for_each(F &&f) const -> F { |
| 690 | + template <detail::bit_spec Spec = set_bit, typename F> |
| 691 | + constexpr auto for_each(F &&f) const -> F { |
652 | 692 | constexpr auto callers = make_callers<F>(std::make_index_sequence<N>{}); |
653 | | - stdx::for_each([&](auto i) { callers[i](f); }, bs); |
| 693 | + stdx::for_each<Spec>([&](auto i) { callers[i](f); }, bs); |
654 | 694 | return f; |
655 | 695 | } |
656 | 696 | }; |
|
0 commit comments