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

Update the internal iteration protocol #100

Closed
wants to merge 6 commits into from
Closed
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
40 changes: 26 additions & 14 deletions include/flux/core/default_impls.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,16 @@ struct sequence_traits<T[N]> {

static constexpr auto size(auto const&) -> distance_t { return N; }

static constexpr auto for_each_while(auto& self, auto&& pred) -> index_t
static constexpr auto iterate_while(auto& self, index_t from, index_t to,
auto&& pred) -> index_t
{
index_t idx = 0;
while (idx < N) {
if (!std::invoke(pred, self[idx])) {
while (from < to) {
if (!std::invoke(pred, self[from])) {
break;
}
++idx;
++from;
}
return idx;
return from;
}
};

Expand Down Expand Up @@ -163,6 +163,20 @@ struct sequence_traits<std::reference_wrapper<Seq>> {
{
return flux::move_at(self.get(), cur);
}

static constexpr auto iterate_while(self_t self, cursor_t<Seq> from,
auto&& pred) -> cursor_t<Seq>
{
return flux::iterate_while(self.get(), std::move(from), FLUX_FWD(pred));
}

static constexpr auto iterate_while(self_t self, cursor_t<Seq> from,
cursor_t<Seq> to, auto&& pred)
-> cursor_t<Seq>
{
return flux::iterate_while(self.get(), std::move(from),
std::move(to), FLUX_FWD(pred));
}
};

// Default implementation for contiguous, sized ranges
Expand Down Expand Up @@ -231,19 +245,17 @@ struct sequence_traits<R> {
return std::ranges::data(self);
}

static constexpr auto for_each_while(auto& self, auto&& pred) -> index_t
static constexpr auto iterate_while(auto& self, index_t from, index_t to,
auto&& pred) -> index_t
{
auto iter = std::ranges::begin(self);
auto const end = std::ranges::end(self);

while (iter != end) {
if (!std::invoke(pred, *iter)) {
while (from < to) {
if (!std::invoke(pred, data(self)[from])) {
break;
}
++iter;
++from;
}

return checked_cast<index_t>(iter - std::ranges::begin(self));
return from;
}
};

Expand Down
59 changes: 59 additions & 0 deletions include/flux/core/sequence_access.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,64 @@ struct back_fn {
}
};

template <typename Seq, typename Pred>
concept has_custom_iterate_while =
sequence<Seq> &&
requires (Seq& seq, cursor_t<Seq> from, Pred&& pred) {
{ traits_t<Seq>::iterate_while(seq, std::move(from), FLUX_FWD(pred)) }
-> std::same_as<cursor_t<Seq>>;
};

template <typename Seq, typename Pred>
concept has_custom_iterate_while_upto =
sequence<Seq> &&
requires (Seq& seq, cursor_t<Seq> from, cursor_t<Seq> to, Pred&& pred) {
{ traits_t<Seq>::iterate_while(seq, std::move(from), std::move(to), FLUX_FWD(pred)) }
-> std::same_as<cursor_t<Seq>>;
};

struct iterate_while_fn {
template <sequence Seq, typename Pred>
requires std::invocable<Pred&, element_t<Seq>> &&
boolean_testable<std::invoke_result_t<Pred&, element_t<Seq>>>
[[nodiscard]]
constexpr auto operator()(Seq& seq, cursor_t<Seq> from, Pred&& pred) const
-> cursor_t<Seq>
{
if constexpr (has_custom_iterate_while<Seq, Pred>) {
return traits_t<Seq>::iterate_while(seq, std::move(from), FLUX_FWD(pred));
} else if constexpr (bounded_sequence<Seq> && has_custom_iterate_while_upto<Seq, Pred>) {
return traits_t<Seq>::iterate_while(seq, std::move(from), last(seq), FLUX_FWD(pred));
} else {
while (!is_last(seq, from)) {
if (!std::invoke(pred, read_at_unchecked(seq, from))) { break; }
inc(seq, from);
}
return from;
}
}

template <sequence Seq, typename Pred>
requires regular_cursor<cursor_t<Seq>> &&
std::invocable<Pred&, element_t<Seq>> &&
boolean_testable<std::invoke_result_t<Pred&, element_t<Seq>>>
[[nodiscard]]
constexpr auto operator()(Seq& seq, cursor_t<Seq> from, cursor_t<Seq> to,
Pred&& pred) const
-> cursor_t<Seq>
{
if constexpr (has_custom_iterate_while_upto<Seq, Pred>) {
return traits_t<Seq>::iterate_while(seq, std::move(from), std::move(to), FLUX_FWD(pred));
} else {
while (from != to) {
if (!std::invoke(pred, read_at_unchecked(seq, from))) { break; }
inc(seq, from);
}
return from;
}
}
};

} // namespace detail


Expand All @@ -364,6 +422,7 @@ inline constexpr auto swap_with = detail::swap_with_fn{};
inline constexpr auto swap_at = detail::swap_at_fn{};
inline constexpr auto front = detail::front_fn{};
inline constexpr auto back = detail::back_fn{};
inline constexpr auto iterate_while = detail::iterate_while_fn{};

} // namespace flux

Expand Down
19 changes: 17 additions & 2 deletions include/flux/op/filter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,31 @@ class filter_adaptor : public inline_sequence_base<filter_adaptor<Base, Pred>>
return flux::last(self.base_);
}

static constexpr auto for_each_while(self_t& self, auto&& func) -> cursor_t<Base>
static constexpr auto iterate_while(self_t& self, cursor_t<Base> from,
auto&& func) -> cursor_t<Base>
{
return flux::for_each_while(self.base_, [&](auto&& elem) {
return flux::iterate_while(self.base_, std::move(from), [&](auto&& elem) {
if (std::invoke(self.pred_, elem)) {
return std::invoke(func, FLUX_FWD(elem));
} else {
return true;
}
});
}

static constexpr auto iterate_while(self_t& self, cursor_t<Base> from,
cursor_t<Base> to, auto&& func)
-> cursor_t<Base>
{
return flux::iterate_while(self.base_, std::move(from), std::move(to),
[&](auto&& elem) {
if (std::invoke(self.pred_, elem)) {
return std::invoke(func, FLUX_FWD(elem));
} else {
return true;
}
});
}
};
};

Expand Down
11 changes: 1 addition & 10 deletions include/flux/op/for_each_while.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,7 @@ struct for_each_while_fn {
boolean_testable<std::invoke_result_t<Pred&, element_t<Seq>>>
constexpr auto operator()(Seq&& seq, Pred pred) const -> cursor_t<Seq>
{
if constexpr (requires { traits_t<Seq>::for_each_while(seq, std::move(pred)); }) {
return traits_t<Seq>::for_each_while(seq, std::move(pred));
} else {
auto cur = first(seq);
while (!is_last(seq, cur)) {
if (!std::invoke(pred, read_at(seq, cur))) { break; }
inc(seq, cur);
}
return cur;
}
return iterate_while(seq, flux::first(seq), FLUX_FWD(pred));
}
};

Expand Down
16 changes: 14 additions & 2 deletions include/flux/op/map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,25 @@ struct map_adaptor : inline_sequence_base<map_adaptor<Base, Func>>
return std::invoke(self.func_, flux::read_at(self.base_, cur));
}

static constexpr auto for_each_while(auto& self, auto&& pred)
static constexpr auto iterate_while(auto& self, cursor_t<Base> from,
auto&& pred)
-> cursor_t<Base>
{
return flux::for_each_while(self.base_, [&](auto&& elem) {
return flux::iterate_while(self.base_, std::move(from), [&](auto&& elem) {
return std::invoke(pred, std::invoke(self.func_, FLUX_FWD(elem)));
});
}

static constexpr auto iterate_while(auto& self, cursor_t<Base> from,
cursor_t<Base> to, auto&& pred)
-> cursor_t<Base>
{
return flux::iterate_while(self.base_, std::move(from),
std::move(to), [&](auto&& elem) {
return std::invoke(pred, std::invoke(self.func_, FLUX_FWD(elem)));
});
}

static void move_at() = delete; // Use the base version of move_at
static void data() = delete; // we're not a contiguous sequence
};
Expand Down