3939#include < string_view>
4040#include < string>
4141#include < vector>
42+ #include < optional>
4243
4344#include " test_macros.h"
4445#include " test_range.h"
5051#endif
5152
5253using std::ranges::fold_left;
54+ using std::ranges::fold_left_first;
5355using std::ranges::fold_left_with_iter;
56+ using std::ranges::fold_left_first_with_iter;
5457
5558template <class Result , class Range , class T >
5659concept is_in_value_result =
@@ -105,6 +108,47 @@ constexpr void check_iterator(R& r, T const& init, F f, Expected const& expected
105108 }
106109}
107110
111+ template <std::ranges::input_range R, class F , std::equality_comparable Expected>
112+ requires std::copyable<R>
113+ constexpr void check_iterator (R& r, F f, std::optional<Expected> const & expected) {
114+ {
115+ is_in_value_result<R, std::optional<Expected>> decltype (auto ) result = fold_left_first_with_iter (r.begin (), r.end (), f);
116+ assert (result.in == r.end ());
117+ assert (result.value == expected);
118+ }
119+
120+ {
121+ auto telemetry = invocable_telemetry ();
122+ auto f2 = invocable_with_telemetry (f, telemetry);
123+ is_in_value_result<R, std::optional<Expected>> decltype (auto ) result = fold_left_first_with_iter (r.begin (), r.end (), f2);
124+ assert (result.in == r.end ());
125+ assert (result.value == expected);
126+ if (result.value .has_value ()) {
127+ assert (telemetry.invocations == std::ranges::distance (r) - 1 );
128+ assert (telemetry.moves == 0 );
129+ assert (telemetry.copies == 1 );
130+ }
131+ }
132+
133+ {
134+ std::same_as<std::optional<Expected>> decltype (auto ) result = fold_left_first (r.begin (), r.end (), f);
135+ assert (result == expected);
136+ }
137+
138+ {
139+ auto telemetry = invocable_telemetry ();
140+ auto f2 = invocable_with_telemetry (f, telemetry);
141+ std::same_as<std::optional<Expected>> decltype (auto ) result = fold_left_first (r.begin (), r.end (), f2);
142+ assert (result == expected);
143+ if (result.has_value ()) {
144+ assert (telemetry.invocations == std::ranges::distance (r) - 1 );
145+ assert (telemetry.moves == 0 );
146+ assert (telemetry.copies == 1 );
147+ }
148+ }
149+ }
150+
151+
108152template <std::ranges::input_range R, class T , class F , std::equality_comparable Expected>
109153 requires std::copyable<R>
110154constexpr void check_lvalue_range (R& r, T const & init, F f, Expected const & expected) {
@@ -186,26 +230,37 @@ constexpr void check(R r, T const& init, F f, Expected const& expected) {
186230 check_rvalue_range (r, init, f, expected);
187231}
188232
233+ template <std::ranges::input_range R, class F , std::equality_comparable Expected>
234+ requires std::copyable<R>
235+ constexpr void check (R r, F f, std::optional<Expected> const & expected) {
236+ check_iterator (r, f, expected);
237+ }
238+
189239constexpr void empty_range_test_case () {
190240 auto const data = std::vector<int >{};
191241 check (data, 100 , std::plus (), 100 );
192242 check (data, -100 , std::multiplies (), -100 );
243+ check (data, std::plus (), std::optional<int >());
193244
194245 check (data | std::views::take_while ([](auto ) { return false ; }), 1.23 , std::plus (), 1.23 );
195246 check (data, Integer (52 ), &Integer::plus, Integer (52 ));
247+ check (data | std::views::take_while ([](auto ) { return false ; }), std::plus (), std::optional<int >());
196248}
197249
198250constexpr void common_range_test_case () {
199251 auto const data = std::vector<int >{1 , 2 , 3 , 4 };
200252 check (data, 0 , std::plus (), triangular_sum (data));
201253 check (data, 1 , std::multiplies (), factorial (data.back ()));
254+ check (data, std::plus (), std::optional (triangular_sum (data)));
255+ check (data, std::multiplies (), std::optional (factorial (data.back ())));
202256
203257 auto multiply_with_prev = [n = 1 ](auto const x, auto const y) mutable {
204258 auto const result = x * y * n;
205259 n = y;
206260 return static_cast <std::size_t >(result);
207261 };
208262 check (data, 1 , multiply_with_prev, factorial (data.size ()) * factorial (data.size () - 1 ));
263+ check (data, multiply_with_prev, std::optional (factorial (data.size ()) * factorial (data.size () - 1 )));
209264
210265 auto fib = [n = 1 ](auto x, auto ) mutable {
211266 auto old_x = x;
@@ -237,6 +292,7 @@ constexpr void non_common_range_test_case() {
237292 auto data = std::vector<std::string>{" five" , " three" , " two" , " six" , " one" , " four" };
238293 auto range = data | std::views::transform (parse);
239294 check (range, 0 , std::plus (), triangular_sum (range));
295+ check (range, std::plus (), std::optional (triangular_sum (range)));
240296 }
241297
242298 {
@@ -248,6 +304,7 @@ constexpr void non_common_range_test_case() {
248304 auto range =
249305 std::views::lazy_split (data, ' ' ) | std::views::transform (to_string_view) | std::views::transform (parse);
250306 check (range, 0 , std::plus (), triangular_sum (range));
307+ check (range, std::plus (), std::optional (triangular_sum (range)));
251308 }
252309}
253310
0 commit comments