Skip to content

Commit af2afaa

Browse files
committed
Make take_while() work with iterables
1 parent e52f366 commit af2afaa

File tree

3 files changed

+68
-10
lines changed

3 files changed

+68
-10
lines changed

include/flux/adaptor/take_while.hpp

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace flux {
1212

1313
namespace detail {
1414

15-
template <sequence Base, typename Pred>
15+
template <iterable Base, typename Pred>
1616
struct take_while_adaptor : inline_sequence_base<take_while_adaptor<Base, Pred>> {
1717
private:
1818
Base base_;
@@ -34,19 +34,43 @@ struct take_while_adaptor : inline_sequence_base<take_while_adaptor<Base, Pred>>
3434
};
3535

3636
struct take_while_fn {
37-
template <adaptable_sequence Seq, std::move_constructible Pred>
38-
requires std::predicate<Pred&, element_t<Seq>>
37+
template <sink_iterable It, std::move_constructible Pred>
38+
requires std::predicate<Pred&, element_t<It>>
3939
[[nodiscard]]
40-
constexpr auto operator()(Seq&& seq, Pred pred) const
40+
constexpr auto operator()(It&& it, Pred pred) const
4141
{
42-
return take_while_adaptor<std::decay_t<Seq>, Pred>(
43-
FLUX_FWD(seq), std::move(pred));
42+
return take_while_adaptor<std::decay_t<It>, Pred>(
43+
FLUX_FWD(it), std::move(pred));
4444
}
4545
};
4646

4747
} // namespace detail
4848

49-
template <typename Base, typename Pred>
49+
template <iterable Base, typename Pred>
50+
struct sequence_traits<detail::take_while_adaptor<Base, Pred>>
51+
: default_sequence_traits {
52+
53+
static consteval auto element_type(auto& self)
54+
-> element_t<decltype((self.base_))>;
55+
56+
static constexpr auto iterate(auto& self, auto&& iter_pred) -> bool
57+
{
58+
bool done = false;
59+
bool res = flux::iterate(self.base_, [&](auto&& elem) {
60+
if (!std::invoke(self.pred_, elem)) {
61+
done = true;
62+
return false; // break
63+
} else {
64+
return std::invoke(iter_pred, FLUX_FWD(elem));
65+
}
66+
});
67+
// Return true if take_while was exhausted
68+
return res ? res : done;
69+
}
70+
71+
};
72+
73+
template <sequence Base, typename Pred>
5074
struct sequence_traits<detail::take_while_adaptor<Base, Pred>>
5175
: detail::passthrough_traits_base
5276
{
@@ -57,7 +81,21 @@ struct sequence_traits<detail::take_while_adaptor<Base, Pred>>
5781
static constexpr bool is_infinite = false;
5882

5983
using default_sequence_traits::element_type;
60-
using default_sequence_traits::iterate;
84+
85+
static constexpr auto iterate(auto& self, auto&& iter_pred) -> bool
86+
{
87+
bool done = false;
88+
bool res = flux::iterate(self.base_, [&](auto&& elem) {
89+
if (!std::invoke(self.pred_, elem)) {
90+
done = true;
91+
return false; // break
92+
} else {
93+
return std::invoke(iter_pred, FLUX_FWD(elem));
94+
}
95+
});
96+
// Return true if take_while was exhausted
97+
return res ? res : done;
98+
}
6199

62100
template <typename Self>
63101
static constexpr bool is_last(Self& self, cursor_t<Self> const& cur)

test/test_take_while.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
55

66
#include <array>
7+
#include <ranges>
78

89
#include "test_utils.hpp"
910

@@ -70,6 +71,23 @@ constexpr bool test_take_while()
7071
STATIC_CHECK(check_equal(seq, {4, 16, 36, 64, 100}));
7172
}
7273

74+
// Test with non-sequence iterables
75+
{
76+
auto view = std::views::filter(std::array{1, 2, 3, 4, 5}, flux::pred::true_);
77+
78+
auto taken = flux::take_while(std::move(view), flux::pred::lt(4));
79+
80+
using T = decltype(taken);
81+
82+
static_assert(flux::iterable<T>);
83+
static_assert(not flux::sized_iterable<T>);
84+
static_assert(not flux::sequence<T>);
85+
86+
STATIC_CHECK(flux::contains(taken, 2));
87+
STATIC_CHECK(not flux::contains(taken, 4));
88+
STATIC_CHECK(check_equal(taken, {1, 2, 3}));
89+
}
90+
7391
return true;
7492
}
7593
static_assert(test_take_while());

test/test_utils.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ inline constexpr struct {
4747
std::initializer_list<T> ilist) const
4848
{
4949
auto iter = ilist.begin();
50-
return flux::iterate(it, [&iter](auto&& elem) {
50+
bool r = flux::iterate(it, [&iter](auto&& elem) {
5151
return *iter++ == elem;
5252
});
53+
return r ? iter == ilist.end() : r;
5354
}
5455

5556
template <typename T>
@@ -63,11 +64,12 @@ inline constexpr struct {
6364
flux::sequence auto&& seq) const
6465
{
6566
auto cur = flux::first(seq);
66-
return flux::iterate(it, [&](auto&& elem) {
67+
bool k = flux::iterate(it, [&](auto&& elem) {
6768
bool r = (elem == flux::read_at(seq, cur));
6869
flux::inc(seq, cur);
6970
return r;
7071
});
72+
return k ? flux::is_last(seq, cur) : k;
7173
}
7274

7375
constexpr bool operator()(flux::sequence auto&& seq1,

0 commit comments

Comments
 (0)