@@ -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
256255struct 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+
269279FLUX_EXPORT inline constexpr auto stride = detail::stride_fn{};
270280
271281template <typename D>
0 commit comments