Skip to content

Commit e52f366

Browse files
committed
Make stride() work with iterables
That was more work than expected
1 parent 8f61d82 commit e52f366

File tree

2 files changed

+184
-154
lines changed

2 files changed

+184
-154
lines changed

include/flux/adaptor/stride.hpp

Lines changed: 164 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ inline constexpr struct advance_fn {
1919
{
2020
if (offset > 0) {
2121
distance_t counter = 0;
22-
while (offset-- > 0 && !flux::is_last(seq, cur)) {
22+
while (offset-- > 0 && !flux::is_last(seq, cur)) {
2323
flux::inc(seq, cur);
2424
++counter;
2525
}
@@ -35,7 +35,8 @@ inline constexpr struct advance_fn {
3535
}
3636
return offset;
3737
} else {
38-
runtime_error("advance() called with negative offset and non-bidirectional sequence");
38+
runtime_error(
39+
"advance() called with negative offset and non-bidirectional sequence");
3940
}
4041
} else {
4142
return 0;
@@ -51,8 +52,8 @@ inline constexpr struct advance_fn {
5152
flux::inc(seq, cur, dist);
5253
return num::sub(offset, dist);
5354
} else if (offset < 0) {
54-
auto dist = num::neg((cmp::min)(flux::distance(seq, flux::first(seq), cur),
55-
num::neg(offset)));
55+
auto dist = num::neg(
56+
(cmp::min)(flux::distance(seq, flux::first(seq), cur), num::neg(offset)));
5657
flux::inc(seq, cur, dist);
5758
return num::sub(offset, dist);
5859
} else {
@@ -76,196 +77,205 @@ struct stride_adaptor : inline_sequence_base<stride_adaptor<Base>> {
7677
constexpr auto base() & -> Base& { return base_; }
7778
constexpr auto base() const& -> Base const& { return base_; }
7879

79-
struct flux_sequence_traits : passthrough_traits_base {
80-
81-
using value_type = value_t<Base>;
82-
static inline constexpr bool is_infinite = infinite_sequence<Base>;
83-
84-
using default_sequence_traits::iterate;
80+
constexpr auto stride() const -> distance_t { return stride_; }
81+
};
8582

86-
static constexpr auto inc(auto& self, cursor_t<Base>& cur) -> void
87-
{
88-
advance(self.base(), cur, self.stride_);
89-
}
83+
template <typename Base>
84+
struct stride_iterable_traits {
85+
using value_type = value_t<Base>;
9086

91-
// This version of stride is never bidir
92-
static void dec(...) = delete;
87+
static consteval auto element_type(auto& self) -> element_t<decltype(self.base())>;
9388

94-
static constexpr auto size(auto& self) -> distance_t
95-
requires sized_iterable<Base>
96-
{
97-
auto s = flux::size(self.base_);
98-
return s/self.stride_ + (s % self.stride_ == 0 ? 0 : 1);
99-
}
100-
101-
static constexpr auto for_each_while(auto& self, auto&& pred) -> cursor_t<Base>
102-
requires sequence<decltype((self.base_))>
103-
{
104-
distance_t n = self.stride_;
105-
return flux::for_each_while(self.base_, [&n, &pred, s = self.stride_](auto&& elem) {
106-
if (++n < s) {
107-
return true;
108-
} else {
109-
n = 0;
110-
return std::invoke(pred, FLUX_FWD(elem));
111-
}
112-
});
113-
}
89+
static constexpr auto iterate(auto& self, auto&& pred) -> bool
90+
{
91+
distance_t n = self.stride();
92+
distance_t s = num::sub(n, distance_t{1});
93+
return flux::iterate(self.base(), [&n, &pred, s](auto&& elem) {
94+
if (n < s) {
95+
n = num::add(n, distance_t{1});
96+
return true;
97+
} else {
98+
n = 0;
99+
return std::invoke(pred, FLUX_FWD(elem));
100+
}
101+
});
102+
}
114103

115-
};
104+
static constexpr auto size(auto& self) -> distance_t
105+
requires sized_iterable<Base>
106+
{
107+
auto s = flux::size(self.base());
108+
return num::add(num::div(s, self.stride()),
109+
(num::mod(s, self.stride()) == 0 ? distance_t{0} : distance_t{1}));
110+
}
116111
};
117112

118-
template <bidirectional_sequence Base>
119-
struct stride_adaptor<Base> : inline_sequence_base<stride_adaptor<Base>> {
120-
private:
121-
Base base_;
122-
distance_t stride_;
123-
124-
public:
125-
constexpr stride_adaptor(decays_to<Base> auto&& base, distance_t stride)
126-
: base_(FLUX_FWD(base)),
127-
stride_(stride)
128-
{}
113+
template <typename Base>
114+
struct stride_sequence_traits : stride_iterable_traits<Base>, passthrough_traits_base {
115+
using stride_iterable_traits<Base>::element_type;
116+
using stride_iterable_traits<Base>::iterate;
117+
using stride_iterable_traits<Base>::size;
129118

130-
struct flux_sequence_traits : default_sequence_traits {
131-
private:
132-
struct cursor_type {
133-
cursor_t<Base> cur{};
134-
distance_t missing = 0;
119+
static constexpr auto inc(auto& self, cursor_t<Base>& cur) -> void
120+
{
121+
advance(self.base(), cur, self.stride());
122+
}
135123

136-
friend constexpr auto operator==(cursor_type const& lhs, cursor_type const& rhs) -> bool
137-
{
138-
return lhs.cur == rhs.cur;
139-
}
124+
// This version of stride is never bidir
125+
static void dec(...) = delete;
140126

141-
friend constexpr auto operator<=>(cursor_type const& lhs, cursor_type const& rhs)
142-
-> std::strong_ordering
143-
requires ordered_cursor<cursor_t<Base>>
144-
{
145-
return lhs.cur <=> rhs.cur;
127+
static constexpr auto for_each_while(auto& self, auto&& pred) -> cursor_t<Base>
128+
requires sequence<decltype(self.base())>
129+
{
130+
distance_t n = self.stride();
131+
return flux::for_each_while(self.base(), [&n, &pred, s = self.stride()](auto&& elem) {
132+
if (++n < s) {
133+
return true;
134+
} else {
135+
n = 0;
136+
return std::invoke(pred, FLUX_FWD(elem));
146137
}
147-
};
138+
});
139+
}
140+
};
148141

149-
public:
150-
using value_type = value_t<Base>;
151-
static constexpr bool is_infinite = infinite_sequence<Base>;
142+
template <typename Base>
143+
struct stride_bidir_traits : stride_iterable_traits<Base> {
144+
private:
145+
struct cursor_type {
146+
cursor_t<Base> cur{};
147+
distance_t missing = 0;
152148

153-
static constexpr auto first(auto& self) -> cursor_type
149+
friend constexpr auto operator==(cursor_type const& lhs, cursor_type const& rhs) -> bool
154150
{
155-
return cursor_type {
156-
.cur = flux::first(self.base_),
157-
.missing = 0
158-
};
151+
return lhs.cur == rhs.cur;
159152
}
160153

161-
static constexpr auto is_last(auto& self, cursor_type const& cur) -> bool
154+
friend constexpr auto operator<=>(cursor_type const& lhs, cursor_type const& rhs)
155+
-> std::strong_ordering
156+
requires ordered_cursor<cursor_t<Base>>
162157
{
163-
return flux::is_last(self.base_, cur.cur);
158+
return lhs.cur <=> rhs.cur;
164159
}
160+
};
165161

166-
static constexpr auto inc(auto& self, cursor_type& cur) -> void
167-
{
168-
cur.missing = advance(self.base_, cur.cur, self.stride_);
169-
}
162+
public:
163+
using value_type = value_t<Base>;
164+
static constexpr bool is_infinite = infinite_sequence<Base>;
170165

171-
static constexpr auto read_at(auto& self, cursor_type const& cur)
172-
-> decltype(flux::read_at(self.base_, cur.cur))
173-
{
174-
return flux::read_at(self.base_, cur.cur);
175-
}
166+
static constexpr auto first(auto& self) -> cursor_type
167+
{
168+
return cursor_type{.cur = flux::first(self.base()), .missing = 0};
169+
}
176170

177-
static constexpr auto move_at(auto& self, cursor_type const& cur)
178-
-> decltype(flux::move_at(self.base_, cur.cur))
179-
{
180-
return flux::move_at(self.base_, cur.cur);
181-
}
171+
static constexpr auto is_last(auto& self, cursor_type const& cur) -> bool
172+
{
173+
return flux::is_last(self.base(), cur.cur);
174+
}
182175

183-
static constexpr auto read_at_unchecked(auto& self, cursor_type const& cur)
184-
-> decltype(flux::read_at_unchecked(self.base_, cur.cur))
185-
{
186-
return flux::read_at_unchecked(self.base_, cur.cur);
187-
}
176+
static constexpr auto inc(auto& self, cursor_type& cur) -> void
177+
{
178+
cur.missing = advance(self.base(), cur.cur, self.stride());
179+
}
188180

189-
static constexpr auto move_at_unchecked(auto& self, cursor_type const& cur)
190-
-> decltype(flux::move_at_unchecked(self.base_, cur.cur))
191-
{
192-
return flux::move_at_unchecked(self.base_, cur.cur);
193-
}
181+
static constexpr auto read_at(auto& self, cursor_type const& cur)
182+
-> decltype(flux::read_at(self.base(), cur.cur))
183+
{
184+
return flux::read_at(self.base(), cur.cur);
185+
}
194186

195-
static constexpr auto last(auto& self) -> cursor_type
196-
requires bounded_sequence<Base> && sized_iterable<Base>
197-
{
198-
distance_t missing =
199-
(self.stride_ - flux::size(self.base_) % self.stride_) % self.stride_;
200-
return cursor_type{
201-
.cur = flux::last(self.base_),
202-
.missing = missing
203-
};
204-
}
187+
static constexpr auto move_at(auto& self, cursor_type const& cur)
188+
-> decltype(flux::move_at(self.base(), cur.cur))
189+
{
190+
return flux::move_at(self.base(), cur.cur);
191+
}
205192

206-
static constexpr auto dec(auto& self, cursor_type& cur) -> void
207-
requires bidirectional_sequence<Base>
208-
{
209-
advance(self.base_, cur.cur, cur.missing - self.stride_);
210-
cur.missing = 0;
211-
}
193+
static constexpr auto read_at_unchecked(auto& self, cursor_type const& cur)
194+
-> decltype(flux::read_at_unchecked(self.base(), cur.cur))
195+
{
196+
return flux::read_at_unchecked(self.base(), cur.cur);
197+
}
212198

213-
static constexpr auto size(auto& self) -> distance_t
214-
requires sized_iterable<Base>
215-
{
216-
auto s = flux::size(self.base_);
217-
return s/self.stride_ + (s % self.stride_ == 0 ? 0 : 1);
218-
}
199+
static constexpr auto move_at_unchecked(auto& self, cursor_type const& cur)
200+
-> decltype(flux::move_at_unchecked(self.base(), cur.cur))
201+
{
202+
return flux::move_at_unchecked(self.base(), cur.cur);
203+
}
219204

220-
static constexpr auto distance(auto& self, cursor_type const& from,
221-
cursor_type const& to) -> distance_t
222-
requires random_access_sequence<Base>
223-
{
224-
return (flux::distance(self.base_, from.cur, to.cur) - from.missing + to.missing)/self.stride_;
225-
}
205+
static constexpr auto last(auto& self) -> cursor_type
206+
requires bounded_sequence<Base> && sized_iterable<Base>
207+
{
208+
distance_t missing = (self.stride() - flux::size(self.base()) % self.stride()) % self.stride();
209+
return cursor_type{.cur = flux::last(self.base()), .missing = missing};
210+
}
226211

227-
static constexpr auto inc(auto& self, cursor_type& cur, distance_t offset) -> void
228-
requires random_access_sequence<Base>
229-
{
230-
if (offset > 0) {
231-
cur.missing = num::mod(advance(self.base_, cur.cur, num::mul(offset, self.stride_)),
232-
self.stride_);
233-
} else if (offset < 0) {
234-
advance(self.base_, cur.cur, num::add(num::mul(offset, self.stride_), cur.missing));
235-
cur.missing = 0;
236-
}
237-
}
212+
static constexpr auto dec(auto& self, cursor_type& cur) -> void
213+
requires bidirectional_sequence<Base>
214+
{
215+
advance(self.base(), cur.cur, cur.missing - self.stride());
216+
cur.missing = 0;
217+
}
238218

239-
static constexpr auto for_each_while(auto& self, auto&& pred) -> cursor_type
240-
requires sequence<decltype((self.base_))>
241-
{
242-
distance_t n = self.stride_;
243-
auto c = flux::for_each_while(self.base_, [&n, &pred, s = self.stride_](auto&& elem) {
244-
if (++n < s) {
245-
return true;
246-
} else {
247-
n = 0;
248-
return std::invoke(pred, FLUX_FWD(elem));
249-
}
250-
});
251-
return cursor_type{std::move(c), (n + 1) % self.stride_};
219+
static constexpr auto distance(auto& self, cursor_type const& from, cursor_type const& to)
220+
-> distance_t
221+
requires random_access_sequence<Base>
222+
{
223+
return (flux::distance(self.base(), from.cur, to.cur) - from.missing + to.missing)
224+
/ self.stride();
225+
}
226+
227+
static constexpr auto inc(auto& self, cursor_type& cur, distance_t offset) -> void
228+
requires random_access_sequence<Base>
229+
{
230+
if (offset > 0) {
231+
cur.missing = num::mod(advance(self.base(), cur.cur, num::mul(offset, self.stride())),
232+
self.stride());
233+
} else if (offset < 0) {
234+
advance(self.base(), cur.cur, num::add(num::mul(offset, self.stride()), cur.missing));
235+
cur.missing = 0;
252236
}
253-
};
237+
}
238+
239+
static constexpr auto for_each_while(auto& self, auto&& pred) -> cursor_type
240+
requires sequence<decltype(self.base())>
241+
{
242+
distance_t n = self.stride();
243+
auto c = flux::for_each_while(self.base(), [&n, &pred, s = self.stride()](auto&& elem) {
244+
if (++n < s) {
245+
return true;
246+
} else {
247+
n = 0;
248+
return std::invoke(pred, FLUX_FWD(elem));
249+
}
250+
});
251+
return cursor_type{std::move(c), (n + 1) % self.stride()};
252+
}
254253
};
255254

256255
struct stride_fn {
257-
template <adaptable_sequence Seq>
256+
template <sink_iterable It>
258257
[[nodiscard]]
259-
constexpr auto operator()(Seq&& seq, num::integral auto by) const
258+
constexpr auto operator()(It&& it, num::integral auto by) const
260259
{
261260
FLUX_ASSERT(by > 0);
262-
return stride_adaptor<std::decay_t<Seq>>(FLUX_FWD(seq),
263-
num::checked_cast<distance_t>(by));
261+
return stride_adaptor<std::decay_t<It>>(FLUX_FWD(it), num::checked_cast<distance_t>(by));
264262
}
265263
};
266264

267265
} // namespace detail
268266

267+
template <typename Base>
268+
struct sequence_traits<detail::stride_adaptor<Base>>
269+
: detail::stride_iterable_traits<Base> {};
270+
271+
template <sequence Base>
272+
struct sequence_traits<detail::stride_adaptor<Base>>
273+
: detail::stride_sequence_traits<Base> {};
274+
275+
template <bidirectional_sequence Base>
276+
struct sequence_traits<detail::stride_adaptor<Base>>
277+
: detail::stride_bidir_traits<Base> {};
278+
269279
FLUX_EXPORT inline constexpr auto stride = detail::stride_fn{};
270280

271281
template <typename D>

0 commit comments

Comments
 (0)