@@ -15,6 +15,12 @@ namespace flux {
1515
1616namespace detail {
1717
18+ template <typename , typename , typename >
19+ struct scan_first_iterable_traits ;
20+
21+ template <typename , typename , typename >
22+ struct scan_first_sequence_traits ;
23+
1824template <typename Base, typename Func, typename R>
1925struct scan_first_adaptor : inline_sequence_base<scan_first_adaptor<Base, Func, R>> {
2026private:
@@ -28,104 +34,140 @@ struct scan_first_adaptor : inline_sequence_base<scan_first_adaptor<Base, Func,
2834 func_(std::move(func))
2935 {}
3036
31- struct flux_sequence_traits : default_sequence_traits {
32- private:
33- struct cursor_type {
34- cursor_type (cursor_type&&) = default ;
35- cursor_type& operator =(cursor_type&&) = default ;
37+ friend struct scan_first_iterable_traits <Base, Func, R>;
38+ friend struct scan_first_sequence_traits <Base, Func, R>;
39+ };
3640
37- private:
38- friend struct flux_sequence_traits ;
41+ template <typename Base, typename Func, typename R>
42+ struct scan_first_iterable_traits : default_sequence_traits {
43+ private:
44+ using self_t = scan_first_adaptor<Base, Func, R>;
3945
40- constexpr explicit cursor_type (cursor_t <Base>&& base_cur)
41- : base_cur(std::move(base_cur))
42- {}
46+ public:
47+ static consteval auto element_type (self_t &) -> R const &;
4348
44- cursor_t <Base> base_cur;
45- };
49+ static constexpr auto iterate(self_t & self, auto && pred) -> bool
50+ {
51+ return flux::iterate (self.base_ , [&](auto && elem) {
52+ if (self.accum_ .has_value ()) {
53+ self.accum_ .emplace (
54+ std::invoke (self.func_ ,
55+ std::move (self.accum_ .value_unchecked ()),
56+ FLUX_FWD (elem)));
57+ } else {
58+ self.accum_ .emplace (FLUX_FWD (elem));
59+ }
60+ return std::invoke (pred, self.accum_ .value_unchecked ());
61+ });
62+ }
4663
47- using self_t = scan_first_adaptor;
64+ static constexpr auto size (self_t & self) -> distance_t
65+ requires sized_iterable<Base>
66+ {
67+ return flux::size (self.base_ );
68+ }
69+ };
4870
49- public:
50- static constexpr auto first (self_t & self) -> cursor_type
51- {
52- auto cur = flux::first (self.base_ );
53- if (!flux::is_last (self.base_ , cur)) {
54- self.accum_ .emplace (flux::read_at (self.base_ , cur));
55- }
56- return cursor_type (std::move (cur));
57- }
71+ template <typename Base, typename Func, typename R>
72+ struct scan_first_sequence_traits : scan_first_iterable_traits<Base, Func, R> {
73+ private:
74+ struct cursor_type {
75+ cursor_type (cursor_type&&) = default ;
76+ cursor_type& operator =(cursor_type&&) = default ;
5877
59- static constexpr auto is_last (self_t & self, cursor_type const & cur) -> bool
60- {
61- return flux::is_last (self.base_ , cur.base_cur );
62- }
78+ private:
79+ friend struct scan_first_sequence_traits ;
6380
64- static constexpr auto inc (self_t & self, cursor_type& cur) -> void
65- {
66- flux::inc (self.base_ , cur.base_cur );
67- if (!flux::is_last (self.base_ , cur.base_cur )) {
68- self.accum_ .emplace (
69- std::invoke (self.func_ ,
70- std::move (self.accum_ .value_unchecked ()),
71- flux::read_at (self.base_ , cur.base_cur )));
72- }
73- }
81+ constexpr explicit cursor_type (cursor_t <Base>&& base_cur)
82+ : base_cur(std::move(base_cur))
83+ {}
7484
75- static constexpr auto read_at (self_t & self, cursor_type const &) -> R const &
76- {
77- return self.accum_ .value ();
78- }
85+ cursor_t <Base> base_cur;
86+ };
7987
80- static constexpr auto read_at_unchecked (self_t & self, cursor_type const &)
81- -> R const &
82- {
83- return self.accum_ .value_unchecked ();
84- }
88+ using self_t = scan_first_adaptor<Base, Func, R>;
8589
86- static constexpr auto last (self_t & self) -> cursor_type
87- requires bounded_sequence<Base>
88- {
89- return cursor_type (flux::last (self.base_ ));
90+ public:
91+ static constexpr auto first (self_t & self) -> cursor_type
92+ {
93+ auto cur = flux::first (self.base_ );
94+ if (!flux::is_last (self.base_ , cur)) {
95+ self.accum_ .emplace (flux::read_at (self.base_ , cur));
9096 }
97+ return cursor_type (std::move (cur));
98+ }
9199
92- static constexpr auto size (self_t & self) -> distance_t
93- requires sized_iterable<Base>
94- {
95- return flux::size (self.base_ );
96- }
100+ static constexpr auto is_last (self_t & self, cursor_type const & cur) -> bool
101+ {
102+ return flux::is_last (self.base_ , cur.base_cur );
103+ }
97104
98- static constexpr auto for_each_while (self_t & self, auto && pred) -> cursor_type
99- {
100- return cursor_type (flux::for_each_while (self.base_ , [&](auto && elem) {
101- if (self.accum_ .has_value ()) {
102- self.accum_ .emplace (
103- std::invoke (self.func_ ,
104- std::move (self.accum_ .value_unchecked ()),
105- FLUX_FWD (elem)));
106- } else {
107- self.accum_ .emplace (FLUX_FWD (elem));
108- }
109- return std::invoke (pred, self.accum_ .value_unchecked ());
110- }));
105+ static constexpr auto inc (self_t & self, cursor_type& cur) -> void
106+ {
107+ flux::inc (self.base_ , cur.base_cur );
108+ if (!flux::is_last (self.base_ , cur.base_cur )) {
109+ self.accum_ .emplace (
110+ std::invoke (self.func_ ,
111+ std::move (self.accum_ .value_unchecked ()),
112+ flux::read_at (self.base_ , cur.base_cur )));
111113 }
112- };
114+ }
115+
116+ static constexpr auto read_at (self_t & self, cursor_type const &) -> R const &
117+ {
118+ return self.accum_ .value ();
119+ }
120+
121+ static constexpr auto read_at_unchecked (self_t & self, cursor_type const &)
122+ -> R const &
123+ {
124+ return self.accum_ .value_unchecked ();
125+ }
126+
127+ static constexpr auto last (self_t & self) -> cursor_type
128+ requires bounded_sequence<Base>
129+ {
130+ return cursor_type (flux::last (self.base_ ));
131+ }
132+
133+ static constexpr auto for_each_while (self_t & self, auto && pred) -> cursor_type
134+ {
135+ return cursor_type (flux::for_each_while (self.base_ , [&](auto && elem) {
136+ if (self.accum_ .has_value ()) {
137+ self.accum_ .emplace (
138+ std::invoke (self.func_ ,
139+ std::move (self.accum_ .value_unchecked ()),
140+ FLUX_FWD (elem)));
141+ } else {
142+ self.accum_ .emplace (FLUX_FWD (elem));
143+ }
144+ return std::invoke (pred, self.accum_ .value_unchecked ());
145+ }));
146+ }
113147};
114148
115149struct scan_first_fn {
116- template <adaptable_sequence Seq , typename Func>
117- requires foldable<Seq , Func, element_t <Seq >>
150+ template <sink_iterable It , typename Func>
151+ requires foldable<It , Func, element_t <It >>
118152 [[nodiscard]]
119- constexpr auto operator ()(Seq && seq , Func func) const -> sequence auto
153+ constexpr auto operator ()(It && it , Func func) const -> iterable auto
120154 {
121- using R = fold_result_t <Seq , Func, element_t <Seq >>;
122- return scan_first_adaptor<std::decay_t <Seq >, Func, R>(
123- FLUX_FWD (seq ), std::move (func));
155+ using R = fold_result_t <It , Func, element_t <It >>;
156+ return scan_first_adaptor<std::decay_t <It >, Func, R>(
157+ FLUX_FWD (it ), std::move (func));
124158 }
125159};
126160
127161} // namespace detail
128162
163+ template <iterable Base, typename Func, typename R>
164+ struct sequence_traits <detail::scan_first_adaptor<Base, Func, R>>
165+ : detail::scan_first_iterable_traits<Base, Func, R> {};
166+
167+ template <sequence Base, typename Func, typename R>
168+ struct sequence_traits <detail::scan_first_adaptor<Base, Func, R>>
169+ : detail::scan_first_sequence_traits<Base, Func, R> {};
170+
129171FLUX_EXPORT inline constexpr auto scan_first = detail::scan_first_fn{};
130172
131173template <typename Derived>
0 commit comments