xref: /aosp_15_r20/external/cronet/base/ranges/algorithm.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_RANGES_ALGORITHM_H_
6 #define BASE_RANGES_ALGORITHM_H_
7 
8 #include <algorithm>
9 #include <functional>
10 #include <initializer_list>
11 #include <iterator>
12 #include <type_traits>
13 #include <utility>
14 
15 #include "base/check.h"
16 #include "base/compiler_specific.h"
17 #include "base/memory/raw_ptr_exclusion.h"
18 #include "base/ranges/functional.h"
19 #include "base/ranges/ranges.h"
20 
21 namespace base {
22 
23 namespace internal {
24 
25 // Returns a transformed version of the unary predicate `pred` applying `proj`
26 // to its argument before invoking `pred` on it.
27 // Ensures that the return type of `invoke(pred, ...)` is convertible to bool.
28 template <typename Pred, typename Proj>
ProjectedUnaryPredicate(Pred & pred,Proj & proj)29 constexpr auto ProjectedUnaryPredicate(Pred& pred, Proj& proj) noexcept {
30   return [&pred, &proj](auto&& arg) -> bool {
31     return std::invoke(pred,
32                        std::invoke(proj, std::forward<decltype(arg)>(arg)));
33   };
34 }
35 
36 // Returns a transformed version of the binary predicate `pred` applying `proj1`
37 // and `proj2` to its arguments before invoking `pred` on them.
38 //
39 // Provides an opt-in to considers all four permutations of projections and
40 // argument types. This is sometimes necessary to allow usage with legacy
41 // non-ranges std:: algorithms that don't support projections.
42 //
43 // These permutations are assigned different priorities to break ambiguities in
44 // case several permutations are possible, e.g. when Proj1 and Proj2 are the
45 // same type.
46 //
47 // Note that even when opting in to using all permutations of projections,
48 // calling code should still ensure that the canonical mapping of {Proj1, Proj2}
49 // to {LHS, RHS} compiles for all members of the range. This can be done by
50 // adding the following constraint:
51 //
52 //   typename =
53 //       std::indirect_result_t<Pred&,
54 //                              std::projected<iterator_t<Range1>, Proj1>,
55 //                              std::projected<iterator_t<Range2>, Proj2>>
56 //
57 // Ensures that the return type of `invoke(pred, ...)` is convertible to bool.
58 template <typename Pred, typename Proj1, typename Proj2, bool kPermute = false>
59 class BinaryPredicateProjector {
60  public:
BinaryPredicateProjector(Pred & pred,Proj1 & proj1,Proj2 & proj2)61   constexpr BinaryPredicateProjector(Pred& pred, Proj1& proj1, Proj2& proj2)
62       : pred_(pred), proj1_(proj1), proj2_(proj2) {}
63 
64  private:
65   template <typename ProjT, typename ProjU, typename T, typename U>
66   using InvokeResult = std::invoke_result_t<Pred&,
67                                             std::invoke_result_t<ProjT&, T&&>,
68                                             std::invoke_result_t<ProjU&, U&&>>;
69 
70   template <typename T, typename U, typename = InvokeResult<Proj1, Proj2, T, U>>
GetProjs(priority_tag<3>)71   constexpr std::pair<Proj1&, Proj2&> GetProjs(priority_tag<3>) const {
72     return {proj1_, proj2_};
73   }
74 
75   template <typename T,
76             typename U,
77             bool LazyPermute = kPermute,
78             typename = std::enable_if_t<LazyPermute>,
79             typename = InvokeResult<Proj2, Proj1, T, U>>
GetProjs(priority_tag<2>)80   constexpr std::pair<Proj2&, Proj1&> GetProjs(priority_tag<2>) const {
81     return {proj2_, proj1_};
82   }
83 
84   template <typename T,
85             typename U,
86             bool LazyPermute = kPermute,
87             typename = std::enable_if_t<LazyPermute>,
88             typename = InvokeResult<Proj1, Proj1, T, U>>
GetProjs(priority_tag<1>)89   constexpr std::pair<Proj1&, Proj1&> GetProjs(priority_tag<1>) const {
90     return {proj1_, proj1_};
91   }
92 
93   template <typename T,
94             typename U,
95             bool LazyPermute = kPermute,
96             typename = std::enable_if_t<LazyPermute>,
97             typename = InvokeResult<Proj2, Proj2, T, U>>
GetProjs(priority_tag<0>)98   constexpr std::pair<Proj2&, Proj2&> GetProjs(priority_tag<0>) const {
99     return {proj2_, proj2_};
100   }
101 
102  public:
103   template <typename T, typename U>
operator()104   constexpr bool operator()(T&& lhs, U&& rhs) const {
105     auto projs = GetProjs<T, U>(priority_tag<3>());
106     return std::invoke(pred_, std::invoke(projs.first, std::forward<T>(lhs)),
107                        std::invoke(projs.second, std::forward<U>(rhs)));
108   }
109 
110  private:
111   // RAW_PTR_EXCLUSION: Binary size increase (~120K on Android).
112   RAW_PTR_EXCLUSION Pred& pred_;
113   RAW_PTR_EXCLUSION Proj1& proj1_;
114   RAW_PTR_EXCLUSION Proj2& proj2_;
115 };
116 
117 // Small wrappers around BinaryPredicateProjector to make the calling side more
118 // readable.
119 template <typename Pred, typename Proj1, typename Proj2>
ProjectedBinaryPredicate(Pred & pred,Proj1 & proj1,Proj2 & proj2)120 constexpr auto ProjectedBinaryPredicate(Pred& pred,
121                                         Proj1& proj1,
122                                         Proj2& proj2) noexcept {
123   return BinaryPredicateProjector<Pred, Proj1, Proj2>(pred, proj1, proj2);
124 }
125 
126 template <typename Pred, typename Proj1, typename Proj2>
PermutedProjectedBinaryPredicate(Pred & pred,Proj1 & proj1,Proj2 & proj2)127 constexpr auto PermutedProjectedBinaryPredicate(Pred& pred,
128                                                 Proj1& proj1,
129                                                 Proj2& proj2) noexcept {
130   return BinaryPredicateProjector<Pred, Proj1, Proj2, true>(pred, proj1, proj2);
131 }
132 
133 // This alias is used below to restrict iterator based APIs to types for which
134 // `iterator_category` and the pre-increment and post-increment operators are
135 // defined. This is required in situations where otherwise an undesired overload
136 // would be chosen, e.g. copy_if. In spirit this is similar to C++20's
137 // std::input_or_output_iterator, a concept that each iterator should satisfy.
138 template <typename Iter,
139           typename = decltype(++std::declval<Iter&>()),
140           typename = decltype(std::declval<Iter&>()++)>
141 using iterator_category_t =
142     typename std::iterator_traits<Iter>::iterator_category;
143 
144 // This alias is used below to restrict range based APIs to types for which
145 // `iterator_category_t` is defined for the underlying iterator. This is
146 // required in situations where otherwise an undesired overload would be chosen,
147 // e.g. transform. In spirit this is similar to C++20's std::ranges::range, a
148 // concept that each range should satisfy.
149 template <typename Range>
150 using range_category_t = iterator_category_t<ranges::iterator_t<Range>>;
151 
152 }  // namespace internal
153 
154 namespace ranges {
155 
156 // C++14 implementation of std::ranges::in_fun_result.
157 //
158 // Reference: https://wg21.link/algorithms.results#:~:text=in_fun_result
159 template <typename I, typename F>
160 struct in_fun_result {
161   NO_UNIQUE_ADDRESS I in;
162   NO_UNIQUE_ADDRESS F fun;
163 
164   template <typename I2,
165             typename F2,
166             std::enable_if_t<std::is_convertible<const I&, I2>{} &&
167                              std::is_convertible<const F&, F2>{}>>
in_fun_resultin_fun_result168   constexpr operator in_fun_result<I2, F2>() const& {
169     return {in, fun};
170   }
171 
172   template <typename I2,
173             typename F2,
174             std::enable_if_t<std::is_convertible<I, I2>{} &&
175                              std::is_convertible<F, F2>{}>>
in_fun_resultin_fun_result176   constexpr operator in_fun_result<I2, F2>() && {
177     return {std::move(in), std::move(fun)};
178   }
179 };
180 
181 // TODO(crbug.com/1071094): Implement the other result types.
182 
183 // [alg.nonmodifying] Non-modifying sequence operations
184 // Reference: https://wg21.link/alg.nonmodifying
185 
186 // [alg.all.of] All of
187 // Reference: https://wg21.link/alg.all.of
188 
189 // Let `E(i)` be `invoke(pred, invoke(proj, *i))`.
190 //
191 // Returns: `false` if `E(i)` is `false` for some iterator `i` in the range
192 // `[first, last)`, and `true` otherwise.
193 //
194 // Complexity: At most `last - first` applications of the predicate and any
195 // projection.
196 //
197 // Reference: https://wg21.link/alg.all.of#:~:text=ranges::all_of(I
198 template <typename InputIterator,
199           typename Pred,
200           typename Proj = std::identity,
201           typename = internal::iterator_category_t<InputIterator>>
202 constexpr bool all_of(InputIterator first,
203                       InputIterator last,
204                       Pred pred,
205                       Proj proj = {}) {
206   for (; first != last; ++first) {
207     if (!std::invoke(pred, std::invoke(proj, *first))) {
208       return false;
209     }
210   }
211 
212   return true;
213 }
214 
215 // Let `E(i)` be `invoke(pred, invoke(proj, *i))`.
216 //
217 // Returns: `false` if `E(i)` is `false` for some iterator `i` in `range`, and
218 // `true` otherwise.
219 //
220 // Complexity: At most `size(range)` applications of the predicate and any
221 // projection.
222 //
223 // Reference: https://wg21.link/alg.all.of#:~:text=ranges::all_of(R
224 template <typename Range,
225           typename Pred,
226           typename Proj = std::identity,
227           typename = internal::range_category_t<Range>>
228 constexpr bool all_of(Range&& range, Pred pred, Proj proj = {}) {
229   return ranges::all_of(ranges::begin(range), ranges::end(range),
230                         std::move(pred), std::move(proj));
231 }
232 
233 // [alg.any.of] Any of
234 // Reference: https://wg21.link/alg.any.of
235 
236 // Let `E(i)` be `invoke(pred, invoke(proj, *i))`.
237 //
238 // Returns: `true` if `E(i)` is `true` for some iterator `i` in the range
239 // `[first, last)`, and `false` otherwise.
240 //
241 // Complexity: At most `last - first` applications of the predicate and any
242 // projection.
243 //
244 // Reference: https://wg21.link/alg.any.of#:~:text=ranges::any_of(I
245 template <typename InputIterator,
246           typename Pred,
247           typename Proj = std::identity,
248           typename = internal::iterator_category_t<InputIterator>>
249 constexpr bool any_of(InputIterator first,
250                       InputIterator last,
251                       Pred pred,
252                       Proj proj = {}) {
253   for (; first != last; ++first) {
254     if (std::invoke(pred, std::invoke(proj, *first))) {
255       return true;
256     }
257   }
258 
259   return false;
260 }
261 
262 // Let `E(i)` be `invoke(pred, invoke(proj, *i))`.
263 //
264 // Returns: `true` if `E(i)` is `true` for some iterator `i` in `range`, and
265 // `false` otherwise.
266 //
267 // Complexity: At most `size(range)` applications of the predicate and any
268 // projection.
269 //
270 // Reference: https://wg21.link/alg.any.of#:~:text=ranges::any_of(R
271 template <typename Range,
272           typename Pred,
273           typename Proj = std::identity,
274           typename = internal::range_category_t<Range>>
275 constexpr bool any_of(Range&& range, Pred pred, Proj proj = {}) {
276   return ranges::any_of(ranges::begin(range), ranges::end(range),
277                         std::move(pred), std::move(proj));
278 }
279 
280 // [alg.none.of] None of
281 // Reference: https://wg21.link/alg.none.of
282 
283 // Let `E(i)` be `invoke(pred, invoke(proj, *i))`.
284 //
285 // Returns: `false` if `E(i)` is `true` for some iterator `i` in the range
286 // `[first, last)`, and `true` otherwise.
287 //
288 // Complexity: At most `last - first` applications of the predicate and any
289 // projection.
290 //
291 // Reference: https://wg21.link/alg.none.of#:~:text=ranges::none_of(I
292 template <typename InputIterator,
293           typename Pred,
294           typename Proj = std::identity,
295           typename = internal::iterator_category_t<InputIterator>>
296 constexpr bool none_of(InputIterator first,
297                        InputIterator last,
298                        Pred pred,
299                        Proj proj = {}) {
300   for (; first != last; ++first) {
301     if (std::invoke(pred, std::invoke(proj, *first))) {
302       return false;
303     }
304   }
305 
306   return true;
307 }
308 
309 // Let `E(i)` be `invoke(pred, invoke(proj, *i))`.
310 //
311 // Returns: `false` if `E(i)` is `true` for some iterator `i` in `range`, and
312 // `true` otherwise.
313 //
314 // Complexity: At most `size(range)` applications of the predicate and any
315 // projection.
316 //
317 // Reference: https://wg21.link/alg.none.of#:~:text=ranges::none_of(R
318 template <typename Range,
319           typename Pred,
320           typename Proj = std::identity,
321           typename = internal::range_category_t<Range>>
322 constexpr bool none_of(Range&& range, Pred pred, Proj proj = {}) {
323   return ranges::none_of(ranges::begin(range), ranges::end(range),
324                          std::move(pred), std::move(proj));
325 }
326 
327 // [alg.foreach] For each
328 // Reference: https://wg21.link/alg.foreach
329 
330 // Reference: https://wg21.link/algorithm.syn#:~:text=for_each_result
331 template <typename I, typename F>
332 using for_each_result = in_fun_result<I, F>;
333 
334 // Effects: Calls `invoke(f, invoke(proj, *i))` for every iterator `i` in the
335 // range `[first, last)`, starting from `first` and proceeding to `last - 1`.
336 //
337 // Returns: `{last, std::move(f)}`.
338 //
339 // Complexity: Applies `f` and `proj` exactly `last - first` times.
340 //
341 // Remarks: If `f` returns a result, the result is ignored.
342 //
343 // Reference: https://wg21.link/alg.foreach#:~:text=ranges::for_each(I
344 template <typename InputIterator,
345           typename Fun,
346           typename Proj = std::identity,
347           typename = internal::iterator_category_t<InputIterator>>
348 constexpr auto for_each(InputIterator first,
349                         InputIterator last,
350                         Fun f,
351                         Proj proj = {}) {
352   for (; first != last; ++first)
353     std::invoke(f, std::invoke(proj, *first));
354   return for_each_result<InputIterator, Fun>{first, std::move(f)};
355 }
356 
357 // Effects: Calls `invoke(f, invoke(proj, *i))` for every iterator `i` in the
358 // range `range`, starting from `begin(range)` and proceeding to `end(range) -
359 // 1`.
360 //
361 // Returns: `{last, std::move(f)}`.
362 //
363 // Complexity: Applies `f` and `proj` exactly `size(range)` times.
364 //
365 // Remarks: If `f` returns a result, the result is ignored.
366 //
367 // Reference: https://wg21.link/alg.foreach#:~:text=ranges::for_each(R
368 template <typename Range,
369           typename Fun,
370           typename Proj = std::identity,
371           typename = internal::range_category_t<Range>>
372 constexpr auto for_each(Range&& range, Fun f, Proj proj = {}) {
373   return ranges::for_each(ranges::begin(range), ranges::end(range),
374                           std::move(f), std::move(proj));
375 }
376 
377 // Reference: https://wg21.link/algorithm.syn#:~:text=for_each_n_result
378 template <typename I, typename F>
379 using for_each_n_result = in_fun_result<I, F>;
380 
381 // Preconditions: `n >= 0` is `true`.
382 //
383 // Effects: Calls `invoke(f, invoke(proj, *i))` for every iterator `i` in the
384 // range `[first, first + n)` in order.
385 //
386 // Returns: `{first + n, std::move(f)}`.
387 //
388 // Remarks: If `f` returns a result, the result is ignored.
389 //
390 // Reference: https://wg21.link/alg.foreach#:~:text=ranges::for_each_n
391 template <typename InputIterator,
392           typename Size,
393           typename Fun,
394           typename Proj = std::identity,
395           typename = internal::iterator_category_t<InputIterator>>
396 constexpr auto for_each_n(InputIterator first, Size n, Fun f, Proj proj = {}) {
397   while (n > 0) {
398     std::invoke(f, std::invoke(proj, *first));
399     ++first;
400     --n;
401   }
402 
403   return for_each_n_result<InputIterator, Fun>{first, std::move(f)};
404 }
405 
406 // [alg.find] Find
407 // Reference: https://wg21.link/alg.find
408 
409 // Let `E(i)` be `bool(invoke(proj, *i) == value)`.
410 //
411 // Returns: The first iterator `i` in the range `[first, last)` for which `E(i)`
412 // is `true`. Returns `last` if no such iterator is found.
413 //
414 // Complexity: At most `last - first` applications of the corresponding
415 // predicate and any projection.
416 //
417 // Reference: https://wg21.link/alg.find#:~:text=ranges::find(I
418 template <typename InputIterator,
419           typename T,
420           typename Proj = std::identity,
421           typename = internal::iterator_category_t<InputIterator>>
422 constexpr auto find(InputIterator first,
423                     InputIterator last,
424                     const T& value,
425                     Proj proj = {}) {
426   for (; first != last; ++first) {
427     if (std::invoke(proj, *first) == value) {
428       break;
429     }
430   }
431 
432   return first;
433 }
434 
435 // Let `E(i)` be `bool(invoke(proj, *i) == value)`.
436 //
437 // Returns: The first iterator `i` in `range` for which `E(i)` is `true`.
438 // Returns `end(range)` if no such iterator is found.
439 //
440 // Complexity: At most `size(range)` applications of the corresponding predicate
441 // and any projection.
442 //
443 // Reference: https://wg21.link/alg.find#:~:text=ranges::find(R
444 template <typename Range,
445           typename T,
446           typename Proj = std::identity,
447           typename = internal::range_category_t<Range>>
448 constexpr auto find(Range&& range, const T& value, Proj proj = {}) {
449   return ranges::find(ranges::begin(range), ranges::end(range), value,
450                       std::move(proj));
451 }
452 
453 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`.
454 //
455 // Returns: The first iterator `i` in the range `[first, last)` for which `E(i)`
456 // is `true`. Returns `last` if no such iterator is found.
457 //
458 // Complexity: At most `last - first` applications of the corresponding
459 // predicate and any projection.
460 //
461 // Reference: https://wg21.link/alg.find#:~:text=ranges::find_if(I
462 template <typename InputIterator,
463           typename Pred,
464           typename Proj = std::identity,
465           typename = internal::iterator_category_t<InputIterator>>
466 constexpr auto find_if(InputIterator first,
467                        InputIterator last,
468                        Pred pred,
469                        Proj proj = {}) {
470   return std::find_if(first, last,
471                       internal::ProjectedUnaryPredicate(pred, proj));
472 }
473 
474 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`.
475 //
476 // Returns: The first iterator `i` in `range` for which `E(i)` is `true`.
477 // Returns `end(range)` if no such iterator is found.
478 //
479 // Complexity: At most `size(range)` applications of the corresponding predicate
480 // and any projection.
481 //
482 // Reference: https://wg21.link/alg.find#:~:text=ranges::find_if(R
483 template <typename Range,
484           typename Pred,
485           typename Proj = std::identity,
486           typename = internal::range_category_t<Range>>
487 constexpr auto find_if(Range&& range, Pred pred, Proj proj = {}) {
488   return ranges::find_if(ranges::begin(range), ranges::end(range),
489                          std::move(pred), std::move(proj));
490 }
491 
492 // Let `E(i)` be `bool(!invoke(pred, invoke(proj, *i)))`.
493 //
494 // Returns: The first iterator `i` in the range `[first, last)` for which `E(i)`
495 // is `true`. Returns `last` if no such iterator is found.
496 //
497 // Complexity: At most `last - first` applications of the corresponding
498 // predicate and any projection.
499 //
500 // Reference: https://wg21.link/alg.find#:~:text=ranges::find_if_not(I
501 template <typename InputIterator,
502           typename Pred,
503           typename Proj = std::identity,
504           typename = internal::iterator_category_t<InputIterator>>
505 constexpr auto find_if_not(InputIterator first,
506                            InputIterator last,
507                            Pred pred,
508                            Proj proj = {}) {
509   return std::find_if_not(first, last,
510                           internal::ProjectedUnaryPredicate(pred, proj));
511 }
512 
513 // Let `E(i)` be `bool(!invoke(pred, invoke(proj, *i)))`.
514 //
515 // Returns: The first iterator `i` in `range` for which `E(i)` is `true`.
516 // Returns `end(range)` if no such iterator is found.
517 //
518 // Complexity: At most `size(range)` applications of the corresponding predicate
519 // and any projection.
520 //
521 // Reference: https://wg21.link/alg.find#:~:text=ranges::find_if_not(R
522 template <typename Range,
523           typename Pred,
524           typename Proj = std::identity,
525           typename = internal::range_category_t<Range>>
526 constexpr auto find_if_not(Range&& range, Pred pred, Proj proj = {}) {
527   return ranges::find_if_not(ranges::begin(range), ranges::end(range),
528                              std::move(pred), std::move(proj));
529 }
530 
531 // [alg.find.end] Find end
532 // Reference: https://wg21.link/alg.find.end
533 
534 // Let:
535 // - `E(i,n)` be `invoke(pred, invoke(proj1, *(i + n)),
536 //                             invoke(proj2, *(first2 + n)))`
537 //
538 // - `i` be `last1` if `[first2, last2)` is empty, or if
539 //   `(last2 - first2) > (last1 - first1)` is `true`, or if there is no iterator
540 //   in the range `[first1, last1 - (last2 - first2))` such that for every
541 //   non-negative integer `n < (last2 - first2)`, `E(i,n)` is `true`. Otherwise
542 //   `i` is the last such iterator in `[first1, last1 - (last2 - first2))`.
543 //
544 // Returns: `i`
545 // Note: std::ranges::find_end(I1 first1,...) returns a range, rather than an
546 // iterator. For simplicitly we match std::find_end's return type instead.
547 //
548 // Complexity:
549 // At most `(last2 - first2) * (last1 - first1 - (last2 - first2) + 1)`
550 // applications of the corresponding predicate and any projections.
551 //
552 // Reference: https://wg21.link/alg.find.end#:~:text=ranges::find_end(I1
553 template <
554     typename ForwardIterator1,
555     typename ForwardIterator2,
556     typename Pred = ranges::equal_to,
557     typename Proj1 = std::identity,
558     typename Proj2 = std::identity,
559     typename = internal::iterator_category_t<ForwardIterator1>,
560     typename = internal::iterator_category_t<ForwardIterator2>,
561     typename = std::indirect_result_t<Pred&,
562                                       std::projected<ForwardIterator1, Proj1>,
563                                       std::projected<ForwardIterator2, Proj2>>>
564 constexpr auto find_end(ForwardIterator1 first1,
565                         ForwardIterator1 last1,
566                         ForwardIterator2 first2,
567                         ForwardIterator2 last2,
568                         Pred pred = {},
569                         Proj1 proj1 = {},
570                         Proj2 proj2 = {}) {
571   return std::find_end(first1, last1, first2, last2,
572                        internal::ProjectedBinaryPredicate(pred, proj1, proj2));
573 }
574 
575 // Let:
576 // - `E(i,n)` be `invoke(pred, invoke(proj1, *(i + n)),
577 //                             invoke(proj2, *(first2 + n)))`
578 //
579 // - `i` be `end(range1)` if `range2` is empty, or if
580 //   `size(range2) > size(range1)` is `true`, or if there is no iterator in the
581 //   range `[begin(range1), end(range1) - size(range2))` such that for every
582 //   non-negative integer `n < size(range2)`, `E(i,n)` is `true`. Otherwise `i`
583 //   is the last such iterator in `[begin(range1), end(range1) - size(range2))`.
584 //
585 // Returns: `i`
586 // Note: std::ranges::find_end(R1&& r1,...) returns a range, rather than an
587 // iterator. For simplicitly we match std::find_end's return type instead.
588 //
589 // Complexity: At most `size(range2) * (size(range1) - size(range2) + 1)`
590 // applications of the corresponding predicate and any projections.
591 //
592 // Reference: https://wg21.link/alg.find.end#:~:text=ranges::find_end(R1
593 template <typename Range1,
594           typename Range2,
595           typename Pred = ranges::equal_to,
596           typename Proj1 = std::identity,
597           typename Proj2 = std::identity,
598           typename = internal::range_category_t<Range1>,
599           typename = internal::range_category_t<Range2>,
600           typename =
601               std::indirect_result_t<Pred&,
602                                      std::projected<iterator_t<Range1>, Proj1>,
603                                      std::projected<iterator_t<Range2>, Proj2>>>
604 constexpr auto find_end(Range1&& range1,
605                         Range2&& range2,
606                         Pred pred = {},
607                         Proj1 proj1 = {},
608                         Proj2 proj2 = {}) {
609   return ranges::find_end(ranges::begin(range1), ranges::end(range1),
610                           ranges::begin(range2), ranges::end(range2),
611                           std::move(pred), std::move(proj1), std::move(proj2));
612 }
613 
614 // [alg.find.first.of] Find first
615 // Reference: https://wg21.link/alg.find.first.of
616 
617 // Let `E(i,j)` be `bool(invoke(pred, invoke(proj1, *i), invoke(proj2, *j)))`.
618 //
619 // Effects: Finds an element that matches one of a set of values.
620 //
621 // Returns: The first iterator `i` in the range `[first1, last1)` such that for
622 // some iterator `j` in the range `[first2, last2)` `E(i,j)` holds. Returns
623 // `last1` if `[first2, last2)` is empty or if no such iterator is found.
624 //
625 // Complexity: At most `(last1 - first1) * (last2 - first2)` applications of the
626 // corresponding predicate and any projections.
627 //
628 // Reference:
629 // https://wg21.link/alg.find.first.of#:~:text=ranges::find_first_of(I1
630 template <
631     typename ForwardIterator1,
632     typename ForwardIterator2,
633     typename Pred = ranges::equal_to,
634     typename Proj1 = std::identity,
635     typename Proj2 = std::identity,
636     typename = internal::iterator_category_t<ForwardIterator1>,
637     typename = internal::iterator_category_t<ForwardIterator2>,
638     typename = std::indirect_result_t<Pred&,
639                                       std::projected<ForwardIterator1, Proj1>,
640                                       std::projected<ForwardIterator2, Proj2>>>
641 constexpr auto find_first_of(ForwardIterator1 first1,
642                              ForwardIterator1 last1,
643                              ForwardIterator2 first2,
644                              ForwardIterator2 last2,
645                              Pred pred = {},
646                              Proj1 proj1 = {},
647                              Proj2 proj2 = {}) {
648   return std::find_first_of(
649       first1, last1, first2, last2,
650       internal::ProjectedBinaryPredicate(pred, proj1, proj2));
651 }
652 
653 // Let `E(i,j)` be `bool(invoke(pred, invoke(proj1, *i), invoke(proj2, *j)))`.
654 //
655 // Effects: Finds an element that matches one of a set of values.
656 //
657 // Returns: The first iterator `i` in `range1` such that for some iterator `j`
658 // in `range2` `E(i,j)` holds. Returns `end(range1)` if `range2` is empty or if
659 // no such iterator is found.
660 //
661 // Complexity: At most `size(range1) * size(range2)` applications of the
662 // corresponding predicate and any projections.
663 //
664 // Reference:
665 // https://wg21.link/alg.find.first.of#:~:text=ranges::find_first_of(R1
666 template <typename Range1,
667           typename Range2,
668           typename Pred = ranges::equal_to,
669           typename Proj1 = std::identity,
670           typename Proj2 = std::identity,
671           typename = internal::range_category_t<Range1>,
672           typename = internal::range_category_t<Range2>,
673           typename =
674               std::indirect_result_t<Pred&,
675                                      std::projected<iterator_t<Range1>, Proj1>,
676                                      std::projected<iterator_t<Range2>, Proj2>>>
677 constexpr auto find_first_of(Range1&& range1,
678                              Range2&& range2,
679                              Pred pred = {},
680                              Proj1 proj1 = {},
681                              Proj2 proj2 = {}) {
682   return ranges::find_first_of(
683       ranges::begin(range1), ranges::end(range1), ranges::begin(range2),
684       ranges::end(range2), std::move(pred), std::move(proj1), std::move(proj2));
685 }
686 
687 // [alg.adjacent.find] Adjacent find
688 // Reference: https://wg21.link/alg.adjacent.find
689 
690 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i), invoke(proj, *(i + 1))))`.
691 //
692 // Returns: The first iterator `i` such that both `i` and `i + 1` are in the
693 // range `[first, last)` for which `E(i)` holds. Returns `last` if no such
694 // iterator is found.
695 //
696 // Complexity: Exactly `min((i - first) + 1, (last - first) - 1)` applications
697 // of the corresponding predicate, where `i` is `adjacent_find`'s return value.
698 //
699 // Reference:
700 // https://wg21.link/alg.adjacent.find#:~:text=ranges::adjacent_find(I
701 template <typename ForwardIterator,
702           typename Pred = ranges::equal_to,
703           typename Proj = std::identity,
704           typename = internal::iterator_category_t<ForwardIterator>>
705 constexpr auto adjacent_find(ForwardIterator first,
706                              ForwardIterator last,
707                              Pred pred = {},
708                              Proj proj = {}) {
709   // Implementation inspired by cppreference.com:
710   // https://en.cppreference.com/w/cpp/algorithm/adjacent_find
711   //
712   // A reimplementation is required, because std::adjacent_find is not constexpr
713   // prior to C++20. Once we have C++20, we should switch to standard library
714   // implementation.
715   if (first == last)
716     return last;
717 
718   for (ForwardIterator next = first; ++next != last; ++first) {
719     if (std::invoke(pred, std::invoke(proj, *first),
720                     std::invoke(proj, *next))) {
721       return first;
722     }
723   }
724 
725   return last;
726 }
727 
728 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i), invoke(proj, *(i + 1))))`.
729 //
730 // Returns: The first iterator `i` such that both `i` and `i + 1` are in the
731 // range `range` for which `E(i)` holds. Returns `end(range)` if no such
732 // iterator is found.
733 //
734 // Complexity: Exactly `min((i - begin(range)) + 1, size(range) - 1)`
735 // applications of the corresponding predicate, where `i` is `adjacent_find`'s
736 // return value.
737 //
738 // Reference:
739 // https://wg21.link/alg.adjacent.find#:~:text=ranges::adjacent_find(R
740 template <typename Range,
741           typename Pred = ranges::equal_to,
742           typename Proj = std::identity,
743           typename = internal::range_category_t<Range>>
744 constexpr auto adjacent_find(Range&& range, Pred pred = {}, Proj proj = {}) {
745   return ranges::adjacent_find(ranges::begin(range), ranges::end(range),
746                                std::move(pred), std::move(proj));
747 }
748 
749 // [alg.count] Count
750 // Reference: https://wg21.link/alg.count
751 
752 // Let `E(i)` be `invoke(proj, *i) == value`.
753 //
754 // Effects: Returns the number of iterators `i` in the range `[first, last)` for
755 // which `E(i)` holds.
756 //
757 // Complexity: Exactly `last - first` applications of the corresponding
758 // predicate and any projection.
759 //
760 // Reference: https://wg21.link/alg.count#:~:text=ranges::count(I
761 template <typename InputIterator,
762           typename T,
763           typename Proj = std::identity,
764           typename = internal::iterator_category_t<InputIterator>>
765 constexpr auto count(InputIterator first,
766                      InputIterator last,
767                      const T& value,
768                      Proj proj = {}) {
769   // Note: In order to be able to apply `proj` to each element in [first, last)
770   // we are dispatching to std::count_if instead of std::count.
771   return std::count_if(first, last, [&proj, &value](auto&& lhs) {
772     return std::invoke(proj, std::forward<decltype(lhs)>(lhs)) == value;
773   });
774 }
775 
776 // Let `E(i)` be `invoke(proj, *i) == value`.
777 //
778 // Effects: Returns the number of iterators `i` in `range` for which `E(i)`
779 // holds.
780 //
781 // Complexity: Exactly `size(range)` applications of the corresponding predicate
782 // and any projection.
783 //
784 // Reference: https://wg21.link/alg.count#:~:text=ranges::count(R
785 template <typename Range,
786           typename T,
787           typename Proj = std::identity,
788           typename = internal::range_category_t<Range>>
789 constexpr auto count(Range&& range, const T& value, Proj proj = {}) {
790   return ranges::count(ranges::begin(range), ranges::end(range), value,
791                        std::move(proj));
792 }
793 
794 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`.
795 //
796 // Effects: Returns the number of iterators `i` in the range `[first, last)` for
797 // which `E(i)` holds.
798 //
799 // Complexity: Exactly `last - first` applications of the corresponding
800 // predicate and any projection.
801 //
802 // Reference: https://wg21.link/alg.count#:~:text=ranges::count_if(I
803 template <typename InputIterator,
804           typename Pred,
805           typename Proj = std::identity,
806           typename = internal::iterator_category_t<InputIterator>>
807 constexpr auto count_if(InputIterator first,
808                         InputIterator last,
809                         Pred pred,
810                         Proj proj = {}) {
811   return std::count_if(first, last,
812                        internal::ProjectedUnaryPredicate(pred, proj));
813 }
814 
815 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`.
816 //
817 // Effects: Returns the number of iterators `i` in `range` for which `E(i)`
818 // holds.
819 //
820 // Complexity: Exactly `size(range)` applications of the corresponding predicate
821 // and any projection.
822 //
823 // Reference: https://wg21.link/alg.count#:~:text=ranges::count_if(R
824 template <typename Range,
825           typename Pred,
826           typename Proj = std::identity,
827           typename = internal::range_category_t<Range>>
828 constexpr auto count_if(Range&& range, Pred pred, Proj proj = {}) {
829   return ranges::count_if(ranges::begin(range), ranges::end(range),
830                           std::move(pred), std::move(proj));
831 }
832 
833 // [mismatch] Mismatch
834 // Reference: https://wg21.link/mismatch
835 
836 // Let `E(n)` be `!invoke(pred, invoke(proj1, *(first1 + n)),
837 //                              invoke(proj2, *(first2 + n)))`.
838 //
839 // Let `N` be `min(last1 - first1, last2 - first2)`.
840 //
841 // Returns: `{ first1 + n, first2 + n }`, where `n` is the smallest integer in
842 // `[0, N)` such that `E(n)` holds, or `N` if no such integer exists.
843 //
844 // Complexity: At most `N` applications of the corresponding predicate and any
845 // projections.
846 //
847 // Reference: https://wg21.link/mismatch#:~:text=ranges::mismatch(I1
848 template <
849     typename ForwardIterator1,
850     typename ForwardIterator2,
851     typename Pred = ranges::equal_to,
852     typename Proj1 = std::identity,
853     typename Proj2 = std::identity,
854     typename = internal::iterator_category_t<ForwardIterator1>,
855     typename = internal::iterator_category_t<ForwardIterator2>,
856     typename = std::indirect_result_t<Pred&,
857                                       std::projected<ForwardIterator1, Proj1>,
858                                       std::projected<ForwardIterator2, Proj2>>>
859 constexpr auto mismatch(ForwardIterator1 first1,
860                         ForwardIterator1 last1,
861                         ForwardIterator2 first2,
862                         ForwardIterator2 last2,
863                         Pred pred = {},
864                         Proj1 proj1 = {},
865                         Proj2 proj2 = {}) {
866   return std::mismatch(first1, last1, first2, last2,
867                        internal::ProjectedBinaryPredicate(pred, proj1, proj2));
868 }
869 
870 // Let `E(n)` be `!invoke(pred, invoke(proj1, *(begin(range1) + n)),
871 //                              invoke(proj2, *(begin(range2) + n)))`.
872 //
873 // Let `N` be `min(size(range1), size(range2))`.
874 //
875 // Returns: `{ begin(range1) + n, begin(range2) + n }`, where `n` is the
876 // smallest integer in `[0, N)` such that `E(n)` holds, or `N` if no such
877 // integer exists.
878 //
879 // Complexity: At most `N` applications of the corresponding predicate and any
880 // projections.
881 //
882 // Reference: https://wg21.link/mismatch#:~:text=ranges::mismatch(R1
883 template <typename Range1,
884           typename Range2,
885           typename Pred = ranges::equal_to,
886           typename Proj1 = std::identity,
887           typename Proj2 = std::identity,
888           typename = internal::range_category_t<Range1>,
889           typename = internal::range_category_t<Range2>,
890           typename =
891               std::indirect_result_t<Pred&,
892                                      std::projected<iterator_t<Range1>, Proj1>,
893                                      std::projected<iterator_t<Range2>, Proj2>>>
894 constexpr auto mismatch(Range1&& range1,
895                         Range2&& range2,
896                         Pred pred = {},
897                         Proj1 proj1 = {},
898                         Proj2 proj2 = {}) {
899   return ranges::mismatch(ranges::begin(range1), ranges::end(range1),
900                           ranges::begin(range2), ranges::end(range2),
901                           std::move(pred), std::move(proj1), std::move(proj2));
902 }
903 
904 // [alg.equal] Equal
905 // Reference: https://wg21.link/alg.equal
906 
907 // Let `E(i)` be
908 //   `invoke(pred, invoke(proj1, *i), invoke(proj2, *(first2 + (i - first1))))`.
909 //
910 // Returns: If `last1 - first1 != last2 - first2`, return `false.` Otherwise
911 // return `true` if `E(i)` holds for every iterator `i` in the range `[first1,
912 // last1)`. Otherwise, returns `false`.
913 //
914 // Complexity: If the types of `first1`, `last1`, `first2`, and `last2` meet the
915 // `RandomAccessIterator` requirements and `last1 - first1 != last2 - first2`,
916 // then no applications of the corresponding predicate and each projection;
917 // otherwise, at most `min(last1 - first1, last2 - first2)` applications of the
918 // corresponding predicate and any projections.
919 //
920 // Reference: https://wg21.link/alg.equal#:~:text=ranges::equal(I1
921 template <
922     typename ForwardIterator1,
923     typename ForwardIterator2,
924     typename Pred = ranges::equal_to,
925     typename Proj1 = std::identity,
926     typename Proj2 = std::identity,
927     typename = internal::iterator_category_t<ForwardIterator1>,
928     typename = internal::iterator_category_t<ForwardIterator2>,
929     typename = std::indirect_result_t<Pred&,
930                                       std::projected<ForwardIterator1, Proj1>,
931                                       std::projected<ForwardIterator2, Proj2>>>
932 constexpr bool equal(ForwardIterator1 first1,
933                      ForwardIterator1 last1,
934                      ForwardIterator2 first2,
935                      ForwardIterator2 last2,
936                      Pred pred = {},
937                      Proj1 proj1 = {},
938                      Proj2 proj2 = {}) {
939   if (std::is_constant_evaluated()) {
940     for (; first1 != last1 && first2 != last2; ++first1, ++first2) {
941       if (!std::invoke(pred, std::invoke(proj1, *first1),
942                        std::invoke(proj2, *first2))) {
943         return false;
944       }
945     }
946 
947     return first1 == last1 && first2 == last2;
948   }
949 
950   return std::equal(first1, last1, first2, last2,
951                     internal::ProjectedBinaryPredicate(pred, proj1, proj2));
952 }
953 
954 // Let `E(i)` be
955 //   `invoke(pred, invoke(proj1, *i),
956 //                 invoke(proj2, *(begin(range2) + (i - begin(range1)))))`.
957 //
958 // Returns: If `size(range1) != size(range2)`, return `false.` Otherwise return
959 // `true` if `E(i)` holds for every iterator `i` in `range1`. Otherwise, returns
960 // `false`.
961 //
962 // Complexity: If the types of `begin(range1)`, `end(range1)`, `begin(range2)`,
963 // and `end(range2)` meet the `RandomAccessIterator` requirements and
964 // `size(range1) != size(range2)`, then no applications of the corresponding
965 // predicate and each projection;
966 // otherwise, at most `min(size(range1), size(range2))` applications of the
967 // corresponding predicate and any projections.
968 //
969 // Reference: https://wg21.link/alg.equal#:~:text=ranges::equal(R1
970 template <typename Range1,
971           typename Range2,
972           typename Pred = ranges::equal_to,
973           typename Proj1 = std::identity,
974           typename Proj2 = std::identity,
975           typename = internal::range_category_t<Range1>,
976           typename = internal::range_category_t<Range2>,
977           typename =
978               std::indirect_result_t<Pred&,
979                                      std::projected<iterator_t<Range1>, Proj1>,
980                                      std::projected<iterator_t<Range2>, Proj2>>>
981 constexpr bool equal(Range1&& range1,
982                      Range2&& range2,
983                      Pred pred = {},
984                      Proj1 proj1 = {},
985                      Proj2 proj2 = {}) {
986   return ranges::equal(ranges::begin(range1), ranges::end(range1),
987                        ranges::begin(range2), ranges::end(range2),
988                        std::move(pred), std::move(proj1), std::move(proj2));
989 }
990 
991 // [alg.is.permutation] Is permutation
992 // Reference: https://wg21.link/alg.is.permutation
993 
994 // Returns: If `last1 - first1 != last2 - first2`, return `false`. Otherwise
995 // return `true` if there exists a permutation of the elements in the range
996 // `[first2, last2)`, bounded by `[pfirst, plast)`, such that
997 // `ranges::equal(first1, last1, pfirst, plast, pred, proj, proj)` returns
998 // `true`; otherwise, returns `false`.
999 //
1000 // Complexity: No applications of the corresponding predicate if
1001 // ForwardIterator1 and ForwardIterator2 meet the requirements of random access
1002 // iterators and `last1 - first1 != last2 - first2`. Otherwise, exactly
1003 // `last1 - first1` applications of the corresponding predicate and projections
1004 // if `ranges::equal(first1, last1, first2, last2, pred, proj, proj)` would
1005 // return true;
1006 // otherwise, at worst `O(N^2)`, where `N` has the value `last1 - first1`.
1007 //
1008 // Reference:
1009 // https://wg21.link/alg.is.permutation#:~:text=ranges::is_permutation(I1
1010 template <
1011     typename ForwardIterator1,
1012     typename ForwardIterator2,
1013     typename Pred = ranges::equal_to,
1014     typename Proj1 = std::identity,
1015     typename Proj2 = std::identity,
1016     typename = internal::iterator_category_t<ForwardIterator1>,
1017     typename = internal::iterator_category_t<ForwardIterator2>,
1018     typename = std::indirect_result_t<Pred&,
1019                                       std::projected<ForwardIterator1, Proj1>,
1020                                       std::projected<ForwardIterator2, Proj2>>>
1021 constexpr bool is_permutation(ForwardIterator1 first1,
1022                               ForwardIterator1 last1,
1023                               ForwardIterator2 first2,
1024                               ForwardIterator2 last2,
1025                               Pred pred = {},
1026                               Proj1 proj1 = {},
1027                               Proj2 proj2 = {}) {
1028   // Needs to opt-in to all permutations, since std::is_permutation expects
1029   // pred(proj1(lhs), proj1(rhs)) to compile.
1030   return std::is_permutation(
1031       first1, last1, first2, last2,
1032       internal::PermutedProjectedBinaryPredicate(pred, proj1, proj2));
1033 }
1034 
1035 // Returns: If `size(range1) != size(range2)`, return `false`. Otherwise return
1036 // `true` if there exists a permutation of the elements in `range2`, bounded by
1037 // `[pbegin, pend)`, such that
1038 // `ranges::equal(range1, [pbegin, pend), pred, proj, proj)` returns `true`;
1039 // otherwise, returns `false`.
1040 //
1041 // Complexity: No applications of the corresponding predicate if Range1 and
1042 // Range2 meet the requirements of random access ranges and
1043 // `size(range1) != size(range2)`. Otherwise, exactly `size(range1)`
1044 // applications of the corresponding predicate and projections if
1045 // `ranges::equal(range1, range2, pred, proj, proj)` would return true;
1046 // otherwise, at worst `O(N^2)`, where `N` has the value `size(range1)`.
1047 //
1048 // Reference:
1049 // https://wg21.link/alg.is.permutation#:~:text=ranges::is_permutation(R1
1050 template <typename Range1,
1051           typename Range2,
1052           typename Pred = ranges::equal_to,
1053           typename Proj1 = std::identity,
1054           typename Proj2 = std::identity,
1055           typename = internal::range_category_t<Range1>,
1056           typename = internal::range_category_t<Range2>,
1057           typename =
1058               std::indirect_result_t<Pred&,
1059                                      std::projected<iterator_t<Range1>, Proj1>,
1060                                      std::projected<iterator_t<Range2>, Proj2>>>
1061 constexpr bool is_permutation(Range1&& range1,
1062                               Range2&& range2,
1063                               Pred pred = {},
1064                               Proj1 proj1 = {},
1065                               Proj2 proj2 = {}) {
1066   return ranges::is_permutation(
1067       ranges::begin(range1), ranges::end(range1), ranges::begin(range2),
1068       ranges::end(range2), std::move(pred), std::move(proj1), std::move(proj2));
1069 }
1070 
1071 // [alg.search] Search
1072 // Reference: https://wg21.link/alg.search
1073 
1074 // Returns: `i`, where `i` is the first iterator in the range
1075 // `[first1, last1 - (last2 - first2))` such that for every non-negative integer
1076 // `n` less than `last2 - first2` the condition
1077 // `bool(invoke(pred, invoke(proj1, *(i + n)), invoke(proj2, *(first2 + n))))`
1078 // is `true`.
1079 // Returns `last1` if no such iterator exists.
1080 // Note: std::ranges::search(I1 first1,...) returns a range, rather than an
1081 // iterator. For simplicitly we match std::search's return type instead.
1082 //
1083 // Complexity: At most `(last1 - first1) * (last2 - first2)` applications of the
1084 // corresponding predicate and projections.
1085 //
1086 // Reference: https://wg21.link/alg.search#:~:text=ranges::search(I1
1087 template <
1088     typename ForwardIterator1,
1089     typename ForwardIterator2,
1090     typename Pred = ranges::equal_to,
1091     typename Proj1 = std::identity,
1092     typename Proj2 = std::identity,
1093     typename = internal::iterator_category_t<ForwardIterator1>,
1094     typename = internal::iterator_category_t<ForwardIterator2>,
1095     typename = std::indirect_result_t<Pred&,
1096                                       std::projected<ForwardIterator1, Proj1>,
1097                                       std::projected<ForwardIterator2, Proj2>>>
1098 constexpr auto search(ForwardIterator1 first1,
1099                       ForwardIterator1 last1,
1100                       ForwardIterator2 first2,
1101                       ForwardIterator2 last2,
1102                       Pred pred = {},
1103                       Proj1 proj1 = {},
1104                       Proj2 proj2 = {}) {
1105   return std::search(first1, last1, first2, last2,
1106                      internal::ProjectedBinaryPredicate(pred, proj1, proj2));
1107 }
1108 
1109 // Returns: `i`, where `i` is the first iterator in the range
1110 // `[begin(range1), end(range1) - size(range2))` such that for every
1111 // non-negative integer `n` less than `size(range2)` the condition
1112 // `bool(invoke(pred, invoke(proj1, *(i + n)),
1113 //                    invoke(proj2, *(begin(range2) + n))))` is `true`.
1114 // Returns `end(range1)` if no such iterator exists.
1115 // Note: std::ranges::search(R1&& r1,...) returns a range, rather than an
1116 // iterator. For simplicitly we match std::search's return type instead.
1117 //
1118 // Complexity: At most `size(range1) * size(range2)` applications of the
1119 // corresponding predicate and projections.
1120 //
1121 // Reference: https://wg21.link/alg.search#:~:text=ranges::search(R1
1122 template <typename Range1,
1123           typename Range2,
1124           typename Pred = ranges::equal_to,
1125           typename Proj1 = std::identity,
1126           typename Proj2 = std::identity,
1127           typename = internal::range_category_t<Range1>,
1128           typename = internal::range_category_t<Range2>,
1129           typename =
1130               std::indirect_result_t<Pred&,
1131                                      std::projected<iterator_t<Range1>, Proj1>,
1132                                      std::projected<iterator_t<Range2>, Proj2>>>
1133 constexpr auto search(Range1&& range1,
1134                       Range2&& range2,
1135                       Pred pred = {},
1136                       Proj1 proj1 = {},
1137                       Proj2 proj2 = {}) {
1138   return ranges::search(ranges::begin(range1), ranges::end(range1),
1139                         ranges::begin(range2), ranges::end(range2),
1140                         std::move(pred), std::move(proj1), std::move(proj2));
1141 }
1142 
1143 // Mandates: The type `Size` is convertible to an integral type.
1144 //
1145 // Returns: `i` where `i` is the first iterator in the range
1146 // `[first, last - count)` such that for every non-negative integer `n` less
1147 // than `count`, the following condition holds:
1148 // `invoke(pred, invoke(proj, *(i + n)), value)`.
1149 // Returns `last` if no such iterator is found.
1150 // Note: std::ranges::search_n(I1 first1,...) returns a range, rather than an
1151 // iterator. For simplicitly we match std::search_n's return type instead.
1152 //
1153 // Complexity: At most `last - first` applications of the corresponding
1154 // predicate and projection.
1155 //
1156 // Reference: https://wg21.link/alg.search#:~:text=ranges::search_n(I
1157 template <typename ForwardIterator,
1158           typename Size,
1159           typename T,
1160           typename Pred = ranges::equal_to,
1161           typename Proj = std::identity,
1162           typename = internal::iterator_category_t<ForwardIterator>>
1163 constexpr auto search_n(ForwardIterator first,
1164                         ForwardIterator last,
1165                         Size count,
1166                         const T& value,
1167                         Pred pred = {},
1168                         Proj proj = {}) {
1169   // The second arg is guaranteed to be `value`, so we'll simply apply the
1170   // std::identity projection.
1171   std::identity value_proj;
1172   return std::search_n(
1173       first, last, count, value,
1174       internal::ProjectedBinaryPredicate(pred, proj, value_proj));
1175 }
1176 
1177 // Mandates: The type `Size` is convertible to an integral type.
1178 //
1179 // Returns: `i` where `i` is the first iterator in the range
1180 // `[begin(range), end(range) - count)` such that for every non-negative integer
1181 // `n` less than `count`, the following condition holds:
1182 // `invoke(pred, invoke(proj, *(i + n)), value)`.
1183 // Returns `end(arnge)` if no such iterator is found.
1184 // Note: std::ranges::search_n(R1&& r1,...) returns a range, rather than an
1185 // iterator. For simplicitly we match std::search_n's return type instead.
1186 //
1187 // Complexity: At most `size(range)` applications of the corresponding predicate
1188 // and projection.
1189 //
1190 // Reference: https://wg21.link/alg.search#:~:text=ranges::search_n(R
1191 template <typename Range,
1192           typename Size,
1193           typename T,
1194           typename Pred = ranges::equal_to,
1195           typename Proj = std::identity,
1196           typename = internal::range_category_t<Range>>
1197 constexpr auto search_n(Range&& range,
1198                         Size count,
1199                         const T& value,
1200                         Pred pred = {},
1201                         Proj proj = {}) {
1202   return ranges::search_n(ranges::begin(range), ranges::end(range), count,
1203                           value, std::move(pred), std::move(proj));
1204 }
1205 
1206 // [alg.modifying.operations] Mutating sequence operations
1207 // Reference: https://wg21.link/alg.modifying.operations
1208 
1209 // [alg.copy] Copy
1210 // Reference: https://wg21.link/alg.copy
1211 
1212 // Let N be `last - first`.
1213 //
1214 // Preconditions: `result` is not in the range `[first, last)`.
1215 //
1216 // Effects: Copies elements in the range `[first, last)` into the range
1217 // `[result, result + N)` starting from `first` and proceeding to `last`. For
1218 // each non-negative integer `n < N` , performs `*(result + n) = *(first + n)`.
1219 //
1220 // Returns: `result + N`
1221 //
1222 // Complexity: Exactly `N` assignments.
1223 //
1224 // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy(I
1225 template <typename InputIterator,
1226           typename OutputIterator,
1227           typename = internal::iterator_category_t<InputIterator>,
1228           typename = internal::iterator_category_t<OutputIterator>>
copy(InputIterator first,InputIterator last,OutputIterator result)1229 constexpr auto copy(InputIterator first,
1230                     InputIterator last,
1231                     OutputIterator result) {
1232   return std::copy(first, last, result);
1233 }
1234 
1235 // Let N be `size(range)`.
1236 //
1237 // Preconditions: `result` is not in `range`.
1238 //
1239 // Effects: Copies elements in `range` into the range `[result, result + N)`
1240 // starting from `begin(range)` and proceeding to `end(range)`. For each
1241 // non-negative integer `n < N` , performs
1242 // *(result + n) = *(begin(range) + n)`.
1243 //
1244 // Returns: `result + N`
1245 //
1246 // Complexity: Exactly `N` assignments.
1247 //
1248 // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy(R
1249 template <typename Range,
1250           typename OutputIterator,
1251           typename = internal::range_category_t<Range>,
1252           typename = internal::iterator_category_t<OutputIterator>>
copy(Range && range,OutputIterator result)1253 constexpr auto copy(Range&& range, OutputIterator result) {
1254   return ranges::copy(ranges::begin(range), ranges::end(range), result);
1255 }
1256 
1257 // Let `N` be `max(0, n)`.
1258 //
1259 // Mandates: The type `Size` is convertible to an integral type.
1260 //
1261 // Effects: For each non-negative integer `i < N`, performs
1262 // `*(result + i) = *(first + i)`.
1263 //
1264 // Returns: `result + N`
1265 //
1266 // Complexity: Exactly `N` assignments.
1267 //
1268 // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy_n
1269 template <typename InputIterator,
1270           typename Size,
1271           typename OutputIterator,
1272           typename = internal::iterator_category_t<InputIterator>,
1273           typename = internal::iterator_category_t<OutputIterator>>
copy_n(InputIterator first,Size n,OutputIterator result)1274 constexpr auto copy_n(InputIterator first, Size n, OutputIterator result) {
1275   return std::copy_n(first, n, result);
1276 }
1277 
1278 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`, and `N` be the number
1279 // of iterators `i` in the range `[first, last)` for which the condition `E(i)`
1280 // holds.
1281 //
1282 // Preconditions: The ranges `[first, last)` and
1283 // `[result, result + (last - first))` do not overlap.
1284 //
1285 // Effects: Copies all of the elements referred to by the iterator `i` in the
1286 // range `[first, last)` for which `E(i)` is true.
1287 //
1288 // Returns: `result + N`
1289 //
1290 // Complexity: Exactly `last - first` applications of the corresponding
1291 // predicate and any projection.
1292 //
1293 // Remarks: Stable.
1294 //
1295 // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy_if(I
1296 template <typename InputIterator,
1297           typename OutputIterator,
1298           typename Pred,
1299           typename Proj = std::identity,
1300           typename = internal::iterator_category_t<InputIterator>,
1301           typename = internal::iterator_category_t<OutputIterator>>
1302 constexpr auto copy_if(InputIterator first,
1303                        InputIterator last,
1304                        OutputIterator result,
1305                        Pred pred,
1306                        Proj proj = {}) {
1307   return std::copy_if(first, last, result,
1308                       internal::ProjectedUnaryPredicate(pred, proj));
1309 }
1310 
1311 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`, and `N` be the number
1312 // of iterators `i` in `range` for which the condition `E(i)` holds.
1313 //
1314 // Preconditions: `range`  and `[result, result + size(range))` do not overlap.
1315 //
1316 // Effects: Copies all of the elements referred to by the iterator `i` in
1317 // `range` for which `E(i)` is true.
1318 //
1319 // Returns: `result + N`
1320 //
1321 // Complexity: Exactly `size(range)` applications of the corresponding predicate
1322 // and any projection.
1323 //
1324 // Remarks: Stable.
1325 //
1326 // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy_if(R
1327 template <typename Range,
1328           typename OutputIterator,
1329           typename Pred,
1330           typename Proj = std::identity,
1331           typename = internal::range_category_t<Range>,
1332           typename = internal::iterator_category_t<OutputIterator>>
1333 constexpr auto copy_if(Range&& range,
1334                        OutputIterator result,
1335                        Pred pred,
1336                        Proj proj = {}) {
1337   return ranges::copy_if(ranges::begin(range), ranges::end(range), result,
1338                          std::move(pred), std::move(proj));
1339 }
1340 
1341 // Let `N` be `last - first`.
1342 //
1343 // Preconditions: `result` is not in the range `(first, last]`.
1344 //
1345 // Effects: Copies elements in the range `[first, last)` into the range
1346 // `[result - N, result)` starting from `last - 1` and proceeding to `first`.
1347 // For each positive integer `n ≤ N`, performs `*(result - n) = *(last - n)`.
1348 //
1349 // Returns: `result - N`
1350 //
1351 // Complexity: Exactly `N` assignments.
1352 //
1353 // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy_backward(I1
1354 template <typename BidirectionalIterator1,
1355           typename BidirectionalIterator2,
1356           typename = internal::iterator_category_t<BidirectionalIterator1>,
1357           typename = internal::iterator_category_t<BidirectionalIterator2>>
copy_backward(BidirectionalIterator1 first,BidirectionalIterator1 last,BidirectionalIterator2 result)1358 constexpr auto copy_backward(BidirectionalIterator1 first,
1359                              BidirectionalIterator1 last,
1360                              BidirectionalIterator2 result) {
1361   return std::copy_backward(first, last, result);
1362 }
1363 
1364 // Let `N` be `size(range)`.
1365 //
1366 // Preconditions: `result` is not in the range `(begin(range), end(range)]`.
1367 //
1368 // Effects: Copies elements in `range` into the range `[result - N, result)`
1369 // starting from `end(range) - 1` and proceeding to `begin(range)`. For each
1370 // positive integer `n ≤ N`, performs `*(result - n) = *(end(range) - n)`.
1371 //
1372 // Returns: `result - N`
1373 //
1374 // Complexity: Exactly `N` assignments.
1375 //
1376 // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy_backward(R
1377 template <typename Range,
1378           typename BidirectionalIterator,
1379           typename = internal::range_category_t<Range>,
1380           typename = internal::iterator_category_t<BidirectionalIterator>>
copy_backward(Range && range,BidirectionalIterator result)1381 constexpr auto copy_backward(Range&& range, BidirectionalIterator result) {
1382   return ranges::copy_backward(ranges::begin(range), ranges::end(range),
1383                                result);
1384 }
1385 
1386 // [alg.move] Move
1387 // Reference: https://wg21.link/alg.move
1388 
1389 // Let `E(n)` be `std::move(*(first + n))`.
1390 //
1391 // Let `N` be `last - first`.
1392 //
1393 // Preconditions: `result` is not in the range `[first, last)`.
1394 //
1395 // Effects: Moves elements in the range `[first, last)` into the range `[result,
1396 // result + N)` starting from `first` and proceeding to `last`. For each
1397 // non-negative integer `n < N`, performs `*(result + n) = E(n)`.
1398 //
1399 // Returns: `result + N`
1400 //
1401 // Complexity: Exactly `N` assignments.
1402 //
1403 // Reference: https://wg21.link/alg.move#:~:text=ranges::move(I
1404 template <typename InputIterator,
1405           typename OutputIterator,
1406           typename = internal::iterator_category_t<InputIterator>,
1407           typename = internal::iterator_category_t<OutputIterator>>
move(InputIterator first,InputIterator last,OutputIterator result)1408 constexpr auto move(InputIterator first,
1409                     InputIterator last,
1410                     OutputIterator result) {
1411   return std::move(first, last, result);
1412 }
1413 
1414 // Let `E(n)` be `std::move(*(begin(range) + n))`.
1415 //
1416 // Let `N` be `size(range)`.
1417 //
1418 // Preconditions: `result` is not in `range`.
1419 //
1420 // Effects: Moves elements in `range` into the range `[result, result + N)`
1421 // starting from `begin(range)` and proceeding to `end(range)`. For each
1422 // non-negative integer `n < N`, performs `*(result + n) = E(n)`.
1423 //
1424 // Returns: `result + N`
1425 //
1426 // Complexity: Exactly `N` assignments.
1427 //
1428 // Reference: https://wg21.link/alg.move#:~:text=ranges::move(R
1429 template <typename Range,
1430           typename OutputIterator,
1431           typename = internal::range_category_t<Range>,
1432           typename = internal::iterator_category_t<OutputIterator>>
move(Range && range,OutputIterator result)1433 constexpr auto move(Range&& range, OutputIterator result) {
1434   return ranges::move(ranges::begin(range), ranges::end(range), result);
1435 }
1436 
1437 // Let `E(n)` be `std::move(*(last - n))`.
1438 //
1439 // Let `N` be `last - first`.
1440 //
1441 // Preconditions: `result` is not in the range `(first, last]`.
1442 //
1443 // Effects: Moves elements in the range `[first, last)` into the range
1444 // `[result - N, result)` starting from `last - 1` and proceeding to `first`.
1445 // For each positive integer `n ≤ N`, performs `*(result - n) = E(n)`.
1446 //
1447 // Returns: `result - N`
1448 //
1449 // Complexity: Exactly `N` assignments.
1450 //
1451 // Reference: https://wg21.link/alg.move#:~:text=ranges::move_backward(I1
1452 template <typename BidirectionalIterator1,
1453           typename BidirectionalIterator2,
1454           typename = internal::iterator_category_t<BidirectionalIterator1>,
1455           typename = internal::iterator_category_t<BidirectionalIterator2>>
move_backward(BidirectionalIterator1 first,BidirectionalIterator1 last,BidirectionalIterator2 result)1456 constexpr auto move_backward(BidirectionalIterator1 first,
1457                              BidirectionalIterator1 last,
1458                              BidirectionalIterator2 result) {
1459   return std::move_backward(first, last, result);
1460 }
1461 
1462 // Let `E(n)` be `std::move(*(end(range) - n))`.
1463 //
1464 // Let `N` be `size(range)`.
1465 //
1466 // Preconditions: `result` is not in the range `(begin(range), end(range)]`.
1467 //
1468 // Effects: Moves elements in `range` into the range `[result - N, result)`
1469 // starting from `end(range) - 1` and proceeding to `begin(range)`. For each
1470 // positive integer `n ≤ N`, performs `*(result - n) = E(n)`.
1471 //
1472 // Returns: `result - N`
1473 //
1474 // Complexity: Exactly `N` assignments.
1475 //
1476 // Reference: https://wg21.link/alg.move#:~:text=ranges::move_backward(R
1477 template <typename Range,
1478           typename BidirectionalIterator,
1479           typename = internal::range_category_t<Range>,
1480           typename = internal::iterator_category_t<BidirectionalIterator>>
move_backward(Range && range,BidirectionalIterator result)1481 constexpr auto move_backward(Range&& range, BidirectionalIterator result) {
1482   return ranges::move_backward(ranges::begin(range), ranges::end(range),
1483                                result);
1484 }
1485 
1486 // [alg.swap] Swap
1487 // Reference: https://wg21.link/alg.swap
1488 
1489 // Let `M` be `min(last1 - first1, last2 - first2)`.
1490 //
1491 // Preconditions: The two ranges `[first1, last1)` and `[first2, last2)` do not
1492 // overlap. `*(first1 + n)` is swappable with `*(first2 + n)`.
1493 //
1494 // Effects: For each non-negative integer `n < M` performs
1495 // `swap(*(first1 + n), *(first2 + n))`
1496 //
1497 // Returns: `first2 + M`
1498 //
1499 // Complexity: Exactly `M` swaps.
1500 //
1501 // Reference: https://wg21.link/alg.swap#:~:text=ranges::swap_ranges(I1
1502 template <typename ForwardIterator1,
1503           typename ForwardIterator2,
1504           typename = internal::iterator_category_t<ForwardIterator1>,
1505           typename = internal::iterator_category_t<ForwardIterator2>>
swap_ranges(ForwardIterator1 first1,ForwardIterator1 last1,ForwardIterator2 first2,ForwardIterator2 last2)1506 constexpr auto swap_ranges(ForwardIterator1 first1,
1507                            ForwardIterator1 last1,
1508                            ForwardIterator2 first2,
1509                            ForwardIterator2 last2) {
1510   // std::swap_ranges does not have a `last2` overload. Thus we need to
1511   // adjust `last1` to ensure to not read past `last2`.
1512   last1 = std::next(first1, std::min(std::distance(first1, last1),
1513                                      std::distance(first2, last2)));
1514   return std::swap_ranges(first1, last1, first2);
1515 }
1516 
1517 // Let `M` be `min(size(range1), size(range2))`.
1518 //
1519 // Preconditions: The two ranges `range1` and `range2` do not overlap.
1520 // `*(begin(range1) + n)` is swappable with `*(begin(range2) + n)`.
1521 //
1522 // Effects: For each non-negative integer `n < M` performs
1523 // `swap(*(begin(range1) + n), *(begin(range2) + n))`
1524 //
1525 // Returns: `begin(range2) + M`
1526 //
1527 // Complexity: Exactly `M` swaps.
1528 //
1529 // Reference: https://wg21.link/alg.swap#:~:text=ranges::swap_ranges(R1
1530 template <typename Range1,
1531           typename Range2,
1532           typename = internal::range_category_t<Range1>,
1533           typename = internal::range_category_t<Range2>>
swap_ranges(Range1 && range1,Range2 && range2)1534 constexpr auto swap_ranges(Range1&& range1, Range2&& range2) {
1535   return ranges::swap_ranges(ranges::begin(range1), ranges::end(range1),
1536                              ranges::begin(range2), ranges::end(range2));
1537 }
1538 
1539 // [alg.transform] Transform
1540 // Reference: https://wg21.link/alg.transform
1541 
1542 // Let `N` be `last1 - first1`,
1543 // `E(i)` be `invoke(op, invoke(proj, *(first1 + (i - result))))`.
1544 //
1545 // Preconditions: `op` does not invalidate iterators or subranges, nor modify
1546 // elements in the ranges `[first1, first1 + N]`, and `[result, result + N]`.
1547 //
1548 // Effects: Assigns through every iterator `i` in the range
1549 // `[result, result + N)` a new corresponding value equal to `E(i)`.
1550 //
1551 // Returns: `result + N`
1552 //
1553 // Complexity: Exactly `N` applications of `op` and any projections.
1554 //
1555 // Remarks: result may be equal to `first1`.
1556 //
1557 // Reference: https://wg21.link/alg.transform#:~:text=ranges::transform(I
1558 template <
1559     typename InputIterator,
1560     typename OutputIterator,
1561     typename UnaryOperation,
1562     typename Proj = std::identity,
1563     typename = internal::iterator_category_t<InputIterator>,
1564     typename = internal::iterator_category_t<OutputIterator>,
1565     typename = std::indirect_result_t<UnaryOperation&,
1566                                       std::projected<InputIterator, Proj>>>
1567 constexpr auto transform(InputIterator first1,
1568                          InputIterator last1,
1569                          OutputIterator result,
1570                          UnaryOperation op,
1571                          Proj proj = {}) {
1572   return std::transform(first1, last1, result, [&op, &proj](auto&& arg) {
1573     return std::invoke(op, std::invoke(proj, std::forward<decltype(arg)>(arg)));
1574   });
1575 }
1576 
1577 // Let `N` be `size(range)`,
1578 // `E(i)` be `invoke(op, invoke(proj, *(begin(range) + (i - result))))`.
1579 //
1580 // Preconditions: `op` does not invalidate iterators or subranges, nor modify
1581 // elements in the ranges `[begin(range), end(range)]`, and
1582 // `[result, result + N]`.
1583 //
1584 // Effects: Assigns through every iterator `i` in the range
1585 // `[result, result + N)` a new corresponding value equal to `E(i)`.
1586 //
1587 // Returns: `result + N`
1588 //
1589 // Complexity: Exactly `N` applications of `op` and any projections.
1590 //
1591 // Remarks: result may be equal to `begin(range)`.
1592 //
1593 // Reference: https://wg21.link/alg.transform#:~:text=ranges::transform(R
1594 template <
1595     typename Range,
1596     typename OutputIterator,
1597     typename UnaryOperation,
1598     typename Proj = std::identity,
1599     typename = internal::range_category_t<Range>,
1600     typename = internal::iterator_category_t<OutputIterator>,
1601     typename = std::indirect_result_t<UnaryOperation&,
1602                                       std::projected<iterator_t<Range>, Proj>>>
1603 constexpr auto transform(Range&& range,
1604                          OutputIterator result,
1605                          UnaryOperation op,
1606                          Proj proj = {}) {
1607   return ranges::transform(ranges::begin(range), ranges::end(range), result,
1608                            std::move(op), std::move(proj));
1609 }
1610 
1611 // Let:
1612 // `N` be `min(last1 - first1, last2 - first2)`,
1613 // `E(i)` be `invoke(binary_op, invoke(proj1, *(first1 + (i - result))),
1614 //                              invoke(proj2, *(first2 + (i - result))))`.
1615 //
1616 // Preconditions: `binary_op` does not invalidate iterators or subranges, nor
1617 // modify elements in the ranges `[first1, first1 + N]`, `[first2, first2 + N]`,
1618 // and `[result, result + N]`.
1619 //
1620 // Effects: Assigns through every iterator `i` in the range
1621 // `[result, result + N)` a new corresponding value equal to `E(i)`.
1622 //
1623 // Returns: `result + N`
1624 //
1625 // Complexity: Exactly `N` applications of `binary_op`, and any projections.
1626 //
1627 // Remarks: `result` may be equal to `first1` or `first2`.
1628 //
1629 // Reference: https://wg21.link/alg.transform#:~:text=ranges::transform(I1
1630 template <
1631     typename ForwardIterator1,
1632     typename ForwardIterator2,
1633     typename OutputIterator,
1634     typename BinaryOperation,
1635     typename Proj1 = std::identity,
1636     typename Proj2 = std::identity,
1637     typename = internal::iterator_category_t<ForwardIterator1>,
1638     typename = internal::iterator_category_t<ForwardIterator2>,
1639     typename = internal::iterator_category_t<OutputIterator>,
1640     typename = std::indirect_result_t<BinaryOperation&,
1641                                       std::projected<ForwardIterator1, Proj1>,
1642                                       std::projected<ForwardIterator2, Proj2>>>
1643 constexpr auto transform(ForwardIterator1 first1,
1644                          ForwardIterator1 last1,
1645                          ForwardIterator2 first2,
1646                          ForwardIterator2 last2,
1647                          OutputIterator result,
1648                          BinaryOperation binary_op,
1649                          Proj1 proj1 = {},
1650                          Proj2 proj2 = {}) {
1651   // std::transform does not have a `last2` overload. Thus we need to adjust
1652   // `last1` to ensure to not read past `last2`.
1653   last1 = std::next(first1, std::min(std::distance(first1, last1),
1654                                      std::distance(first2, last2)));
1655   return std::transform(
1656       first1, last1, first2, result,
1657       [&binary_op, &proj1, &proj2](auto&& lhs, auto&& rhs) {
1658         return std::invoke(
1659             binary_op, std::invoke(proj1, std::forward<decltype(lhs)>(lhs)),
1660             std::invoke(proj2, std::forward<decltype(rhs)>(rhs)));
1661       });
1662 }
1663 
1664 // Let:
1665 // `N` be `min(size(range1), size(range2)`,
1666 // `E(i)` be `invoke(binary_op, invoke(proj1, *(begin(range1) + (i - result))),
1667 //                              invoke(proj2, *(begin(range2) + (i - result))))`
1668 //
1669 // Preconditions: `binary_op` does not invalidate iterators or subranges, nor
1670 // modify elements in the ranges `[begin(range1), end(range1)]`,
1671 // `[begin(range2), end(range2)]`, and `[result, result + N]`.
1672 //
1673 // Effects: Assigns through every iterator `i` in the range
1674 // `[result, result + N)` a new corresponding value equal to `E(i)`.
1675 //
1676 // Returns: `result + N`
1677 //
1678 // Complexity: Exactly `N` applications of `binary_op`, and any projections.
1679 //
1680 // Remarks: `result` may be equal to `begin(range1)` or `begin(range2)`.
1681 //
1682 // Reference: https://wg21.link/alg.transform#:~:text=ranges::transform(R1
1683 template <typename Range1,
1684           typename Range2,
1685           typename OutputIterator,
1686           typename BinaryOperation,
1687           typename Proj1 = std::identity,
1688           typename Proj2 = std::identity,
1689           typename = internal::range_category_t<Range1>,
1690           typename = internal::range_category_t<Range2>,
1691           typename = internal::iterator_category_t<OutputIterator>,
1692           typename =
1693               std::indirect_result_t<BinaryOperation&,
1694                                      std::projected<iterator_t<Range1>, Proj1>,
1695                                      std::projected<iterator_t<Range2>, Proj2>>>
1696 constexpr auto transform(Range1&& range1,
1697                          Range2&& range2,
1698                          OutputIterator result,
1699                          BinaryOperation binary_op,
1700                          Proj1 proj1 = {},
1701                          Proj2 proj2 = {}) {
1702   return ranges::transform(ranges::begin(range1), ranges::end(range1),
1703                            ranges::begin(range2), ranges::end(range2), result,
1704                            std::move(binary_op), std::move(proj1),
1705                            std::move(proj2));
1706 }
1707 
1708 // [alg.replace] Replace
1709 // Reference: https://wg21.link/alg.replace
1710 
1711 // Let `E(i)` be `bool(invoke(proj, *i) == old_value)`.
1712 //
1713 // Mandates: `new_value` is writable  to `first`.
1714 //
1715 // Effects: Substitutes elements referred by the iterator `i` in the range
1716 // `[first, last)` with `new_value`, when `E(i)` is true.
1717 //
1718 // Returns: `last`
1719 //
1720 // Complexity: Exactly `last - first` applications of the corresponding
1721 // predicate and any projection.
1722 //
1723 // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace(I
1724 template <typename ForwardIterator,
1725           typename T,
1726           typename Proj = std::identity,
1727           typename = internal::iterator_category_t<ForwardIterator>>
1728 constexpr auto replace(ForwardIterator first,
1729                        ForwardIterator last,
1730                        const T& old_value,
1731                        const T& new_value,
1732                        Proj proj = {}) {
1733   // Note: In order to be able to apply `proj` to each element in [first, last)
1734   // we are dispatching to std::replace_if instead of std::replace.
1735   std::replace_if(
1736       first, last,
1737       [&proj, &old_value](auto&& lhs) {
1738         return std::invoke(proj, std::forward<decltype(lhs)>(lhs)) == old_value;
1739       },
1740       new_value);
1741   return last;
1742 }
1743 
1744 // Let `E(i)` be `bool(invoke(proj, *i) == old_value)`.
1745 //
1746 // Mandates: `new_value` is writable  to `begin(range)`.
1747 //
1748 // Effects: Substitutes elements referred by the iterator `i` in `range` with
1749 // `new_value`, when `E(i)` is true.
1750 //
1751 // Returns: `end(range)`
1752 //
1753 // Complexity: Exactly `size(range)` applications of the corresponding predicate
1754 // and any projection.
1755 //
1756 // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace(R
1757 template <typename Range,
1758           typename T,
1759           typename Proj = std::identity,
1760           typename = internal::range_category_t<Range>>
1761 constexpr auto replace(Range&& range,
1762                        const T& old_value,
1763                        const T& new_value,
1764                        Proj proj = {}) {
1765   return ranges::replace(ranges::begin(range), ranges::end(range), old_value,
1766                          new_value, std::move(proj));
1767 }
1768 
1769 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`.
1770 //
1771 // Mandates: `new_value` is writable  to `first`.
1772 //
1773 // Effects: Substitutes elements referred by the iterator `i` in the range
1774 // `[first, last)` with `new_value`, when `E(i)` is true.
1775 //
1776 // Returns: `last`
1777 //
1778 // Complexity: Exactly `last - first` applications of the corresponding
1779 // predicate and any projection.
1780 //
1781 // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace_if(I
1782 template <typename ForwardIterator,
1783           typename Predicate,
1784           typename T,
1785           typename Proj = std::identity,
1786           typename = internal::iterator_category_t<ForwardIterator>>
1787 constexpr auto replace_if(ForwardIterator first,
1788                           ForwardIterator last,
1789                           Predicate pred,
1790                           const T& new_value,
1791                           Proj proj = {}) {
1792   std::replace_if(first, last, internal::ProjectedUnaryPredicate(pred, proj),
1793                   new_value);
1794   return last;
1795 }
1796 
1797 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`.
1798 //
1799 // Mandates: `new_value` is writable  to `begin(range)`.
1800 //
1801 // Effects: Substitutes elements referred by the iterator `i` in `range` with
1802 // `new_value`, when `E(i)` is true.
1803 //
1804 // Returns: `end(range)`
1805 //
1806 // Complexity: Exactly `size(range)` applications of the corresponding predicate
1807 // and any projection.
1808 //
1809 // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace_if(R
1810 template <typename Range,
1811           typename Predicate,
1812           typename T,
1813           typename Proj = std::identity,
1814           typename = internal::range_category_t<Range>>
1815 constexpr auto replace_if(Range&& range,
1816                           Predicate pred,
1817                           const T& new_value,
1818                           Proj proj = {}) {
1819   return ranges::replace_if(ranges::begin(range), ranges::end(range),
1820                             std::move(pred), new_value, std::move(proj));
1821 }
1822 
1823 // Let `E(i)` be `bool(invoke(proj, *(first + (i - result))) == old_value)`.
1824 //
1825 // Mandates: The results of the expressions `*first` and `new_value` are
1826 // writable  to `result`.
1827 //
1828 // Preconditions: The ranges `[first, last)` and `[result, result + (last -
1829 // first))` do not overlap.
1830 //
1831 // Effects: Assigns through every iterator `i` in the range `[result, result +
1832 // (last - first))` a new corresponding value, `new_value` if `E(i)` is true, or
1833 // `*(first + (i - result))` otherwise.
1834 //
1835 // Returns: `result + (last - first)`.
1836 //
1837 // Complexity: Exactly `last - first` applications of the corresponding
1838 // predicate and any projection.
1839 //
1840 // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace_copy(I
1841 template <typename InputIterator,
1842           typename OutputIterator,
1843           typename T,
1844           typename Proj = std::identity,
1845           typename = internal::iterator_category_t<InputIterator>,
1846           typename = internal::iterator_category_t<OutputIterator>>
1847 constexpr auto replace_copy(InputIterator first,
1848                             InputIterator last,
1849                             OutputIterator result,
1850                             const T& old_value,
1851                             const T& new_value,
1852                             Proj proj = {}) {
1853   // Note: In order to be able to apply `proj` to each element in [first, last)
1854   // we are dispatching to std::replace_copy_if instead of std::replace_copy.
1855   std::replace_copy_if(
1856       first, last, result,
1857       [&proj, &old_value](auto&& lhs) {
1858         return std::invoke(proj, std::forward<decltype(lhs)>(lhs)) == old_value;
1859       },
1860       new_value);
1861   return last;
1862 }
1863 
1864 // Let `E(i)` be
1865 // `bool(invoke(proj, *(begin(range) + (i - result))) == old_value)`.
1866 //
1867 // Mandates: The results of the expressions `*begin(range)` and `new_value` are
1868 // writable  to `result`.
1869 //
1870 // Preconditions: The ranges `range` and `[result, result + size(range))` do not
1871 // overlap.
1872 //
1873 // Effects: Assigns through every iterator `i` in the range `[result, result +
1874 // size(range))` a new corresponding value, `new_value` if `E(i)` is true, or
1875 // `*(begin(range) + (i - result))` otherwise.
1876 //
1877 // Returns: `result + size(range)`.
1878 //
1879 // Complexity: Exactly `size(range)` applications of the corresponding
1880 // predicate and any projection.
1881 //
1882 // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace_copy(R
1883 template <typename Range,
1884           typename OutputIterator,
1885           typename T,
1886           typename Proj = std::identity,
1887           typename = internal::range_category_t<Range>,
1888           typename = internal::iterator_category_t<OutputIterator>>
1889 constexpr auto replace_copy(Range&& range,
1890                             OutputIterator result,
1891                             const T& old_value,
1892                             const T& new_value,
1893                             Proj proj = {}) {
1894   return ranges::replace_copy(ranges::begin(range), ranges::end(range), result,
1895                               old_value, new_value, std::move(proj));
1896 }
1897 
1898 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *(first + (i - result)))))`.
1899 //
1900 // Mandates: The results of the expressions `*first` and `new_value` are
1901 // writable  to `result`.
1902 //
1903 // Preconditions: The ranges `[first, last)` and `[result, result + (last -
1904 // first))` do not overlap.
1905 //
1906 // Effects: Assigns through every iterator `i` in the range `[result, result +
1907 // (last - first))` a new corresponding value, `new_value` if `E(i)` is true, or
1908 // `*(first + (i - result))` otherwise.
1909 //
1910 // Returns: `result + (last - first)`.
1911 //
1912 // Complexity: Exactly `last - first` applications of the corresponding
1913 // predicate and any projection.
1914 //
1915 // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace_copy_if(I
1916 template <typename InputIterator,
1917           typename OutputIterator,
1918           typename Predicate,
1919           typename T,
1920           typename Proj = std::identity,
1921           typename = internal::iterator_category_t<InputIterator>,
1922           typename = internal::iterator_category_t<OutputIterator>>
1923 constexpr auto replace_copy_if(InputIterator first,
1924                                InputIterator last,
1925                                OutputIterator result,
1926                                Predicate pred,
1927                                const T& new_value,
1928                                Proj proj = {}) {
1929   return std::replace_copy_if(first, last, result,
1930                               internal::ProjectedUnaryPredicate(pred, proj),
1931                               new_value);
1932 }
1933 
1934 // Let `E(i)` be
1935 // `bool(invoke(pred, invoke(proj, *(begin(range) + (i - result)))))`.
1936 //
1937 // Mandates: The results of the expressions `*begin(range)` and `new_value` are
1938 // writable  to `result`.
1939 //
1940 // Preconditions: The ranges `range` and `[result, result + size(range))` do not
1941 // overlap.
1942 //
1943 // Effects: Assigns through every iterator `i` in the range `[result, result +
1944 // size(range))` a new corresponding value, `new_value` if `E(i)` is true, or
1945 // `*(begin(range) + (i - result))` otherwise.
1946 //
1947 // Returns: `result + size(range)`.
1948 //
1949 // Complexity: Exactly `size(range)` applications of the corresponding
1950 // predicate and any projection.
1951 //
1952 // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace_copy_if(R
1953 template <typename Range,
1954           typename OutputIterator,
1955           typename Predicate,
1956           typename T,
1957           typename Proj = std::identity,
1958           typename = internal::range_category_t<Range>,
1959           typename = internal::iterator_category_t<OutputIterator>>
1960 constexpr auto replace_copy_if(Range&& range,
1961                                OutputIterator result,
1962                                Predicate pred,
1963                                const T& new_value,
1964                                Proj proj = {}) {
1965   return ranges::replace_copy_if(ranges::begin(range), ranges::end(range),
1966                                  result, pred, new_value, std::move(proj));
1967 }
1968 
1969 // [alg.fill] Fill
1970 // Reference: https://wg21.link/alg.fill
1971 
1972 // Let `N` be `last - first`.
1973 //
1974 // Mandates: The expression `value` is writable to the output iterator.
1975 //
1976 // Effects: Assigns `value` through all the iterators in the range
1977 // `[first, last)`.
1978 //
1979 // Returns: `last`.
1980 //
1981 // Complexity: Exactly `N` assignments.
1982 //
1983 // Reference: https://wg21.link/alg.fill#:~:text=ranges::fill(O
1984 template <typename OutputIterator,
1985           typename T,
1986           typename = internal::iterator_category_t<OutputIterator>>
fill(OutputIterator first,OutputIterator last,const T & value)1987 constexpr auto fill(OutputIterator first, OutputIterator last, const T& value) {
1988   std::fill(first, last, value);
1989   return last;
1990 }
1991 
1992 // Let `N` be `size(range)`.
1993 //
1994 // Mandates: The expression `value` is writable to the output iterator.
1995 //
1996 // Effects: Assigns `value` through all the iterators in `range`.
1997 //
1998 // Returns: `end(range)`.
1999 //
2000 // Complexity: Exactly `N` assignments.
2001 //
2002 // Reference: https://wg21.link/alg.fill#:~:text=ranges::fill(R
2003 template <typename Range,
2004           typename T,
2005           typename = internal::range_category_t<Range>>
fill(Range && range,const T & value)2006 constexpr auto fill(Range&& range, const T& value) {
2007   return ranges::fill(ranges::begin(range), ranges::end(range), value);
2008 }
2009 
2010 // Let `N` be `max(0, n)`.
2011 //
2012 // Mandates: The expression `value` is writable to the output iterator.
2013 // The type `Size` is convertible to an integral type.
2014 //
2015 // Effects: Assigns `value` through all the iterators in `[first, first + N)`.
2016 //
2017 // Returns: `first + N`.
2018 //
2019 // Complexity: Exactly `N` assignments.
2020 //
2021 // Reference: https://wg21.link/alg.fill#:~:text=ranges::fill_n(O
2022 template <typename OutputIterator,
2023           typename Size,
2024           typename T,
2025           typename = internal::iterator_category_t<OutputIterator>>
fill_n(OutputIterator first,Size n,const T & value)2026 constexpr auto fill_n(OutputIterator first, Size n, const T& value) {
2027   return std::fill_n(first, n, value);
2028 }
2029 
2030 // [alg.generate] Generate
2031 // Reference: https://wg21.link/alg.generate
2032 
2033 // Let `N` be `last - first`.
2034 //
2035 // Effects: Assigns the result of successive evaluations of gen() through each
2036 // iterator in the range `[first, last)`.
2037 //
2038 // Returns: `last`.
2039 //
2040 // Complexity: Exactly `N` evaluations of `gen()` and assignments.
2041 //
2042 // Reference: https://wg21.link/alg.generate#:~:text=ranges::generate(O
2043 template <typename OutputIterator,
2044           typename Generator,
2045           typename = internal::iterator_category_t<OutputIterator>>
generate(OutputIterator first,OutputIterator last,Generator gen)2046 constexpr auto generate(OutputIterator first,
2047                         OutputIterator last,
2048                         Generator gen) {
2049   std::generate(first, last, std::move(gen));
2050   return last;
2051 }
2052 
2053 // Let `N` be `size(range)`.
2054 //
2055 // Effects: Assigns the result of successive evaluations of gen() through each
2056 // iterator in `range`.
2057 //
2058 // Returns: `end(range)`.
2059 //
2060 // Complexity: Exactly `N` evaluations of `gen()` and assignments.
2061 //
2062 // Reference: https://wg21.link/alg.generate#:~:text=ranges::generate(R
2063 template <typename Range,
2064           typename Generator,
2065           typename = internal::range_category_t<Range>>
generate(Range && range,Generator gen)2066 constexpr auto generate(Range&& range, Generator gen) {
2067   return ranges::generate(ranges::begin(range), ranges::end(range),
2068                           std::move(gen));
2069 }
2070 
2071 // Let `N` be `max(0, n)`.
2072 //
2073 // Mandates: `Size` is convertible to an integral type.
2074 //
2075 // Effects: Assigns the result of successive evaluations of gen() through each
2076 // iterator in the range `[first, first + N)`.
2077 //
2078 // Returns: `first + N`.
2079 //
2080 // Complexity: Exactly `N` evaluations of `gen()` and assignments.
2081 //
2082 // Reference: https://wg21.link/alg.generate#:~:text=ranges::generate_n(O
2083 template <typename OutputIterator,
2084           typename Size,
2085           typename Generator,
2086           typename = internal::iterator_category_t<OutputIterator>>
generate_n(OutputIterator first,Size n,Generator gen)2087 constexpr auto generate_n(OutputIterator first, Size n, Generator gen) {
2088   return std::generate_n(first, n, std::move(gen));
2089 }
2090 
2091 // [alg.remove] Remove
2092 // Reference: https://wg21.link/alg.remove
2093 
2094 // Let `E(i)` be `bool(invoke(proj, *i) == value)`.
2095 //
2096 // Effects: Eliminates all the elements referred to by iterator `i` in the range
2097 // `[first, last)` for which `E(i)` holds.
2098 //
2099 // Returns: The end of the resulting range.
2100 //
2101 // Remarks: Stable.
2102 //
2103 // Complexity: Exactly `last - first` applications of the corresponding
2104 // predicate and any projection.
2105 //
2106 // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove(I
2107 template <typename ForwardIterator,
2108           typename T,
2109           typename Proj = std::identity,
2110           typename = internal::iterator_category_t<ForwardIterator>>
2111 constexpr auto remove(ForwardIterator first,
2112                       ForwardIterator last,
2113                       const T& value,
2114                       Proj proj = {}) {
2115   // Note: In order to be able to apply `proj` to each element in [first, last)
2116   // we are dispatching to std::remove_if instead of std::remove.
2117   return std::remove_if(first, last, [&proj, &value](auto&& lhs) {
2118     return std::invoke(proj, std::forward<decltype(lhs)>(lhs)) == value;
2119   });
2120 }
2121 
2122 // Let `E(i)` be `bool(invoke(proj, *i) == value)`.
2123 //
2124 // Effects: Eliminates all the elements referred to by iterator `i` in `range`
2125 // for which `E(i)` holds.
2126 //
2127 // Returns: The end of the resulting range.
2128 //
2129 // Remarks: Stable.
2130 //
2131 // Complexity: Exactly `size(range)` applications of the corresponding predicate
2132 // and any projection.
2133 //
2134 // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove(R
2135 template <typename Range,
2136           typename T,
2137           typename Proj = std::identity,
2138           typename = internal::range_category_t<Range>>
2139 constexpr auto remove(Range&& range, const T& value, Proj proj = {}) {
2140   return ranges::remove(ranges::begin(range), ranges::end(range), value,
2141                         std::move(proj));
2142 }
2143 
2144 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`.
2145 //
2146 // Effects: Eliminates all the elements referred to by iterator `i` in the range
2147 // `[first, last)` for which `E(i)` holds.
2148 //
2149 // Returns: The end of the resulting range.
2150 //
2151 // Remarks: Stable.
2152 //
2153 // Complexity: Exactly `last - first` applications of the corresponding
2154 // predicate and any projection.
2155 //
2156 // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove_if(I
2157 template <typename ForwardIterator,
2158           typename Predicate,
2159           typename Proj = std::identity,
2160           typename = internal::iterator_category_t<ForwardIterator>>
2161 constexpr auto remove_if(ForwardIterator first,
2162                          ForwardIterator last,
2163                          Predicate pred,
2164                          Proj proj = {}) {
2165   return std::remove_if(first, last,
2166                         internal::ProjectedUnaryPredicate(pred, proj));
2167 }
2168 
2169 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`.
2170 //
2171 // Effects: Eliminates all the elements referred to by iterator `i` in `range`.
2172 //
2173 // Returns: The end of the resulting range.
2174 //
2175 // Remarks: Stable.
2176 //
2177 // Complexity: Exactly `size(range)` applications of the corresponding predicate
2178 // and any projection.
2179 //
2180 // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove_if(R
2181 template <typename Range,
2182           typename Predicate,
2183           typename Proj = std::identity,
2184           typename = internal::range_category_t<Range>>
2185 constexpr auto remove_if(Range&& range, Predicate pred, Proj proj = {}) {
2186   return ranges::remove_if(ranges::begin(range), ranges::end(range),
2187                            std::move(pred), std::move(proj));
2188 }
2189 
2190 // Let `E(i)` be `bool(invoke(proj, *i) == value)`.
2191 //
2192 // Let `N` be the number of elements in `[first, last)` for which `E(i)` is
2193 // false.
2194 //
2195 // Mandates: `*first` is writable to `result`.
2196 //
2197 // Preconditions: The ranges `[first, last)` and `[result, result + (last -
2198 // first))` do not overlap.
2199 //
2200 // Effects: Copies all the elements referred to by the iterator `i` in the range
2201 // `[first, last)` for which `E(i)` is false.
2202 //
2203 // Returns: `result + N`.
2204 //
2205 // Complexity: Exactly `last - first` applications of the corresponding
2206 // predicate and any projection.
2207 //
2208 // Remarks: Stable.
2209 //
2210 // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove_copy(I
2211 template <typename InputIterator,
2212           typename OutputIterator,
2213           typename T,
2214           typename Proj = std::identity,
2215           typename = internal::iterator_category_t<InputIterator>,
2216           typename = internal::iterator_category_t<OutputIterator>>
2217 constexpr auto remove_copy(InputIterator first,
2218                            InputIterator last,
2219                            OutputIterator result,
2220                            const T& value,
2221                            Proj proj = {}) {
2222   // Note: In order to be able to apply `proj` to each element in [first, last)
2223   // we are dispatching to std::remove_copy_if instead of std::remove_copy.
2224   return std::remove_copy_if(first, last, result, [&proj, &value](auto&& lhs) {
2225     return std::invoke(proj, std::forward<decltype(lhs)>(lhs)) == value;
2226   });
2227 }
2228 
2229 // Let `E(i)` be `bool(invoke(proj, *i) == value)`.
2230 //
2231 // Let `N` be the number of elements in `range` for which `E(i)` is false.
2232 //
2233 // Mandates: `*begin(range)` is writable to `result`.
2234 //
2235 // Preconditions: The ranges `range` and `[result, result + size(range))` do not
2236 // overlap.
2237 //
2238 // Effects: Copies all the elements referred to by the iterator `i` in `range`
2239 //  for which `E(i)` is false.
2240 //
2241 // Returns: `result + N`.
2242 //
2243 // Complexity: Exactly `size(range)` applications of the corresponding
2244 // predicate and any projection.
2245 //
2246 // Remarks: Stable.
2247 //
2248 // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove_copy(R
2249 template <typename Range,
2250           typename OutputIterator,
2251           typename T,
2252           typename Proj = std::identity,
2253           typename = internal::range_category_t<Range>,
2254           typename = internal::iterator_category_t<OutputIterator>>
2255 constexpr auto remove_copy(Range&& range,
2256                            OutputIterator result,
2257                            const T& value,
2258                            Proj proj = {}) {
2259   return ranges::remove_copy(ranges::begin(range), ranges::end(range), result,
2260                              value, std::move(proj));
2261 }
2262 
2263 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`.
2264 //
2265 // Let `N` be the number of elements in `[first, last)` for which `E(i)` is
2266 // false.
2267 //
2268 // Mandates: `*first` is writable to `result`.
2269 //
2270 // Preconditions: The ranges `[first, last)` and `[result, result + (last -
2271 // first))` do not overlap.
2272 //
2273 // Effects: Copies all the elements referred to by the iterator `i` in the range
2274 // `[first, last)` for which `E(i)` is false.
2275 //
2276 // Returns: `result + N`.
2277 //
2278 // Complexity: Exactly `last - first` applications of the corresponding
2279 // predicate and any projection.
2280 //
2281 // Remarks: Stable.
2282 //
2283 // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove_copy_if(I
2284 template <typename InputIterator,
2285           typename OutputIterator,
2286           typename Pred,
2287           typename Proj = std::identity,
2288           typename = internal::iterator_category_t<InputIterator>,
2289           typename = internal::iterator_category_t<OutputIterator>>
2290 constexpr auto remove_copy_if(InputIterator first,
2291                               InputIterator last,
2292                               OutputIterator result,
2293                               Pred pred,
2294                               Proj proj = {}) {
2295   return std::remove_copy_if(first, last, result,
2296                              internal::ProjectedUnaryPredicate(pred, proj));
2297 }
2298 
2299 // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`.
2300 //
2301 // Let `N` be the number of elements in `range` for which `E(i)` is false.
2302 //
2303 // Mandates: `*begin(range)` is writable to `result`.
2304 //
2305 // Preconditions: The ranges `range` and `[result, result + size(range))` do not
2306 // overlap.
2307 //
2308 // Effects: Copies all the elements referred to by the iterator `i` in `range`
2309 //  for which `E(i)` is false.
2310 //
2311 // Returns: `result + N`.
2312 //
2313 // Complexity: Exactly `size(range)` applications of the corresponding
2314 // predicate and any projection.
2315 //
2316 // Remarks: Stable.
2317 //
2318 // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove_copy(R
2319 template <typename Range,
2320           typename OutputIterator,
2321           typename Pred,
2322           typename Proj = std::identity,
2323           typename = internal::range_category_t<Range>,
2324           typename = internal::iterator_category_t<OutputIterator>>
2325 constexpr auto remove_copy_if(Range&& range,
2326                               OutputIterator result,
2327                               Pred pred,
2328                               Proj proj = {}) {
2329   return ranges::remove_copy_if(ranges::begin(range), ranges::end(range),
2330                                 result, std::move(pred), std::move(proj));
2331 }
2332 
2333 // [alg.unique] Unique
2334 // Reference: https://wg21.link/alg.unique
2335 
2336 // Let `E(i)` be `bool(invoke(comp, invoke(proj, *(i - 1)), invoke(proj, *i)))`.
2337 //
2338 // Effects: For a nonempty range, eliminates all but the first element from
2339 // every consecutive group of equivalent elements referred to by the iterator
2340 // `i` in the range `[first + 1, last)` for which `E(i)` is true.
2341 //
2342 // Returns: The end of the resulting range.
2343 //
2344 // Complexity: For nonempty ranges, exactly `(last - first) - 1` applications of
2345 // the corresponding predicate and no more than twice as many applications of
2346 // any projection.
2347 //
2348 // Reference: https://wg21.link/alg.unique#:~:text=ranges::unique(I
2349 template <
2350     typename ForwardIterator,
2351     typename Comp = ranges::equal_to,
2352     typename Proj = std::identity,
2353     typename = internal::iterator_category_t<ForwardIterator>,
2354     typename = std::indirect_result_t<Comp&,
2355                                       std::projected<ForwardIterator, Proj>,
2356                                       std::projected<ForwardIterator, Proj>>>
2357 constexpr auto unique(ForwardIterator first,
2358                       ForwardIterator last,
2359                       Comp comp = {},
2360                       Proj proj = {}) {
2361   return std::unique(first, last,
2362                      internal::ProjectedBinaryPredicate(comp, proj, proj));
2363 }
2364 
2365 // Let `E(i)` be `bool(invoke(comp, invoke(proj, *(i - 1)), invoke(proj, *i)))`.
2366 //
2367 // Effects: For a nonempty range, eliminates all but the first element from
2368 // every consecutive group of equivalent elements referred to by the iterator
2369 // `i` in the range `[begin(range) + 1, end(range))` for which `E(i)` is true.
2370 //
2371 // Returns: The end of the resulting range.
2372 //
2373 // Complexity: For nonempty ranges, exactly `size(range) - 1` applications of
2374 // the corresponding predicate and no more than twice as many applications of
2375 // any projection.
2376 //
2377 // Reference: https://wg21.link/alg.unique#:~:text=ranges::unique(R
2378 template <
2379     typename Range,
2380     typename Comp = ranges::equal_to,
2381     typename Proj = std::identity,
2382     typename = internal::range_category_t<Range>,
2383     typename = std::indirect_result_t<Comp&,
2384                                       std::projected<iterator_t<Range>, Proj>,
2385                                       std::projected<iterator_t<Range>, Proj>>>
2386 constexpr auto unique(Range&& range, Comp comp = {}, Proj proj = {}) {
2387   return ranges::unique(ranges::begin(range), ranges::end(range),
2388                         std::move(comp), std::move(proj));
2389 }
2390 
2391 // Let `E(i)` be `bool(invoke(comp, invoke(proj, *i), invoke(proj, *(i - 1))))`.
2392 //
2393 // Mandates: `*first` is writable to `result`.
2394 //
2395 // Preconditions: The ranges `[first, last)` and
2396 // `[result, result + (last - first))` do not overlap.
2397 //
2398 // Effects: Copies only the first element from every consecutive group of equal
2399 // elements referred to by the iterator `i` in the range `[first, last)` for
2400 // which `E(i)` holds.
2401 //
2402 // Returns: `result + N`.
2403 //
2404 // Complexity: Exactly `last - first - 1` applications of the corresponding
2405 // predicate and no more than twice as many applications of any projection.
2406 //
2407 // Reference: https://wg21.link/alg.unique#:~:text=ranges::unique_copy(I
2408 template <typename ForwardIterator,
2409           typename OutputIterator,
2410           typename Comp = ranges::equal_to,
2411           typename Proj = std::identity,
2412           typename = internal::iterator_category_t<ForwardIterator>,
2413           typename = internal::iterator_category_t<OutputIterator>>
2414 constexpr auto unique_copy(ForwardIterator first,
2415                            ForwardIterator last,
2416                            OutputIterator result,
2417                            Comp comp = {},
2418                            Proj proj = {}) {
2419   return std::unique_copy(first, last, result,
2420                           internal::ProjectedBinaryPredicate(comp, proj, proj));
2421 }
2422 
2423 // Let `E(i)` be `bool(invoke(comp, invoke(proj, *i), invoke(proj, *(i - 1))))`.
2424 //
2425 // Mandates: `*begin(range)` is writable to `result`.
2426 //
2427 // Preconditions: The ranges `range` and `[result, result + size(range))` do not
2428 // overlap.
2429 //
2430 // Effects: Copies only the first element from every consecutive group of equal
2431 // elements referred to by the iterator `i` in `range` for which `E(i)` holds.
2432 //
2433 // Returns: `result + N`.
2434 //
2435 // Complexity: Exactly `size(range) - 1` applications of the corresponding
2436 // predicate and no more than twice as many applications of any projection.
2437 //
2438 // Reference: https://wg21.link/alg.unique#:~:text=ranges::unique_copy(R
2439 template <typename Range,
2440           typename OutputIterator,
2441           typename Comp = ranges::equal_to,
2442           typename Proj = std::identity,
2443           typename = internal::range_category_t<Range>,
2444           typename = internal::iterator_category_t<OutputIterator>>
2445 constexpr auto unique_copy(Range&& range,
2446                            OutputIterator result,
2447                            Comp comp = {},
2448                            Proj proj = {}) {
2449   return ranges::unique_copy(ranges::begin(range), ranges::end(range), result,
2450                              std::move(comp), std::move(proj));
2451 }
2452 
2453 // [alg.reverse] Reverse
2454 // Reference: https://wg21.link/alg.reverse
2455 
2456 // Effects: For each non-negative integer `i < (last - first) / 2`, applies
2457 // `std::iter_swap` to all pairs of iterators `first + i, (last - i) - 1`.
2458 //
2459 // Returns: `last`.
2460 //
2461 // Complexity: Exactly `(last - first)/2` swaps.
2462 //
2463 // Reference: https://wg21.link/alg.reverse#:~:text=ranges::reverse(I
2464 template <typename BidirectionalIterator,
2465           typename = internal::iterator_category_t<BidirectionalIterator>>
reverse(BidirectionalIterator first,BidirectionalIterator last)2466 constexpr auto reverse(BidirectionalIterator first,
2467                        BidirectionalIterator last) {
2468   std::reverse(first, last);
2469   return last;
2470 }
2471 
2472 // Effects: For each non-negative integer `i < size(range) / 2`, applies
2473 // `std::iter_swap` to all pairs of iterators
2474 // `begin(range) + i, (end(range) - i) - 1`.
2475 //
2476 // Returns: `end(range)`.
2477 //
2478 // Complexity: Exactly `size(range)/2` swaps.
2479 //
2480 // Reference: https://wg21.link/alg.reverse#:~:text=ranges::reverse(R
2481 template <typename Range, typename = internal::range_category_t<Range>>
reverse(Range && range)2482 constexpr auto reverse(Range&& range) {
2483   return ranges::reverse(ranges::begin(range), ranges::end(range));
2484 }
2485 
2486 // Let `N` be `last - first`.
2487 //
2488 // Preconditions: The ranges `[first, last)` and `[result, result + N)` do not
2489 // overlap.
2490 //
2491 // Effects: Copies the range `[first, last)` to the range `[result, result + N)`
2492 // such that for every non-negative integer `i < N` the following assignment
2493 // takes place: `*(result + N - 1 - i) = *(first + i)`.
2494 //
2495 // Returns: `result + N`.
2496 //
2497 // Complexity: Exactly `N` assignments.
2498 //
2499 // Reference: https://wg21.link/alg.reverse#:~:text=ranges::reverse_copy(I
2500 template <typename BidirectionalIterator,
2501           typename OutputIterator,
2502           typename = internal::iterator_category_t<BidirectionalIterator>,
2503           typename = internal::iterator_category_t<OutputIterator>>
reverse_copy(BidirectionalIterator first,BidirectionalIterator last,OutputIterator result)2504 constexpr auto reverse_copy(BidirectionalIterator first,
2505                             BidirectionalIterator last,
2506                             OutputIterator result) {
2507   return std::reverse_copy(first, last, result);
2508 }
2509 
2510 // Let `N` be `size(range)`.
2511 //
2512 // Preconditions: The ranges `range` and `[result, result + N)` do not
2513 // overlap.
2514 //
2515 // Effects: Copies `range` to the range `[result, result + N)` such that for
2516 // every non-negative integer `i < N` the following assignment takes place:
2517 // `*(result + N - 1 - i) = *(begin(range) + i)`.
2518 //
2519 // Returns: `result + N`.
2520 //
2521 // Complexity: Exactly `N` assignments.
2522 //
2523 // Reference: https://wg21.link/alg.reverse#:~:text=ranges::reverse_copy(R
2524 template <typename Range,
2525           typename OutputIterator,
2526           typename = internal::range_category_t<Range>,
2527           typename = internal::iterator_category_t<OutputIterator>>
reverse_copy(Range && range,OutputIterator result)2528 constexpr auto reverse_copy(Range&& range, OutputIterator result) {
2529   return ranges::reverse_copy(ranges::begin(range), ranges::end(range), result);
2530 }
2531 
2532 // [alg.rotate] Rotate
2533 // Reference: https://wg21.link/alg.rotate
2534 
2535 // Preconditions: `[first, middle)` and `[middle, last)` are valid ranges.
2536 //
2537 // Effects: For each non-negative integer `i < (last - first)`, places the
2538 // element from the position `first + i` into position
2539 // `first + (i + (last - middle)) % (last - first)`.
2540 //
2541 // Returns: `first + (last - middle)`.
2542 //
2543 // Complexity: At most `last - first` swaps.
2544 //
2545 // Reference: https://wg21.link/alg.rotate#:~:text=ranges::rotate(I
2546 template <typename ForwardIterator,
2547           typename = internal::iterator_category_t<ForwardIterator>>
rotate(ForwardIterator first,ForwardIterator middle,ForwardIterator last)2548 constexpr auto rotate(ForwardIterator first,
2549                       ForwardIterator middle,
2550                       ForwardIterator last) {
2551   return std::rotate(first, middle, last);
2552 }
2553 
2554 // Preconditions: `[begin(range), middle)` and `[middle, end(range))` are valid
2555 // ranges.
2556 //
2557 // Effects: For each non-negative integer `i < size(range)`, places the element
2558 // from the position `begin(range) + i` into position
2559 // `begin(range) + (i + (end(range) - middle)) % size(range)`.
2560 //
2561 // Returns: `begin(range) + (end(range) - middle)`.
2562 //
2563 // Complexity: At most `size(range)` swaps.
2564 //
2565 // Reference: https://wg21.link/alg.rotate#:~:text=ranges::rotate(R
2566 template <typename Range, typename = internal::range_category_t<Range>>
rotate(Range && range,iterator_t<Range> middle)2567 constexpr auto rotate(Range&& range, iterator_t<Range> middle) {
2568   return ranges::rotate(ranges::begin(range), middle, ranges::end(range));
2569 }
2570 
2571 // Let `N` be `last - first`.
2572 //
2573 // Preconditions: `[first, middle)` and `[middle, last)` are valid ranges. The
2574 // ranges `[first, last)` and `[result, result + N)` do not overlap.
2575 //
2576 // Effects: Copies the range `[first, last)` to the range `[result, result + N)`
2577 // such that for each non-negative integer `i < N` the following assignment
2578 // takes place: `*(result + i) = *(first + (i + (middle - first)) % N)`.
2579 //
2580 // Returns: `result + N`.
2581 //
2582 // Complexity: Exactly `N` assignments.
2583 //
2584 // Reference: https://wg21.link/alg.rotate#:~:text=ranges::rotate_copy(I
2585 template <typename ForwardIterator,
2586           typename OutputIterator,
2587           typename = internal::iterator_category_t<ForwardIterator>,
2588           typename = internal::iterator_category_t<OutputIterator>>
rotate_copy(ForwardIterator first,ForwardIterator middle,ForwardIterator last,OutputIterator result)2589 constexpr auto rotate_copy(ForwardIterator first,
2590                            ForwardIterator middle,
2591                            ForwardIterator last,
2592                            OutputIterator result) {
2593   return std::rotate_copy(first, middle, last, result);
2594 }
2595 
2596 // Let `N` be `size(range)`.
2597 //
2598 // Preconditions: `[begin(range), middle)` and `[middle, end(range))` are valid
2599 // ranges. The ranges `range` and `[result, result + N)` do not overlap.
2600 //
2601 // Effects: Copies `range` to the range `[result, result + N)` such that for
2602 // each non-negative integer `i < N` the following assignment takes place:
2603 // `*(result + i) = *(begin(range) + (i + (middle - begin(range))) % N)`.
2604 //
2605 // Returns: `result + N`.
2606 //
2607 // Complexity: Exactly `N` assignments.
2608 //
2609 // Reference: https://wg21.link/alg.rotate#:~:text=ranges::rotate_copy(R
2610 template <typename Range,
2611           typename OutputIterator,
2612           typename = internal::range_category_t<Range>,
2613           typename = internal::iterator_category_t<OutputIterator>>
rotate_copy(Range && range,iterator_t<Range> middle,OutputIterator result)2614 constexpr auto rotate_copy(Range&& range,
2615                            iterator_t<Range> middle,
2616                            OutputIterator result) {
2617   return ranges::rotate_copy(ranges::begin(range), middle, ranges::end(range),
2618                              result);
2619 }
2620 
2621 // [alg.random.sample] Sample
2622 // Reference: https://wg21.link/alg.random.sample
2623 
2624 // Currently not implemented due to lack of std::sample in C++14.
2625 // TODO(crbug.com/1071094): Consider implementing a hand-rolled version.
2626 
2627 // [alg.random.shuffle] Shuffle
2628 // Reference: https://wg21.link/alg.random.shuffle
2629 
2630 // Preconditions: The type `std::remove_reference_t<UniformRandomBitGenerator>`
2631 // meets the uniform random bit generator requirements.
2632 //
2633 // Effects: Permutes the elements in the range `[first, last)` such that each
2634 // possible permutation of those elements has equal probability of appearance.
2635 //
2636 // Returns: `last`.
2637 //
2638 // Complexity: Exactly `(last - first) - 1` swaps.
2639 //
2640 // Remarks: To the extent that the implementation of this function makes use of
2641 // random numbers, the object referenced by g shall serve as the
2642 // implementation's source of randomness.
2643 //
2644 // Reference: https://wg21.link/alg.random.shuffle#:~:text=ranges::shuffle(I
2645 template <typename RandomAccessIterator,
2646           typename UniformRandomBitGenerator,
2647           typename = internal::iterator_category_t<RandomAccessIterator>>
shuffle(RandomAccessIterator first,RandomAccessIterator last,UniformRandomBitGenerator && g)2648 constexpr auto shuffle(RandomAccessIterator first,
2649                        RandomAccessIterator last,
2650                        UniformRandomBitGenerator&& g) {
2651   std::shuffle(first, last, std::forward<UniformRandomBitGenerator>(g));
2652   return last;
2653 }
2654 
2655 // Preconditions: The type `std::remove_reference_t<UniformRandomBitGenerator>`
2656 // meets the uniform random bit generator requirements.
2657 //
2658 // Effects: Permutes the elements in `range` such that each possible permutation
2659 // of those elements has equal probability of appearance.
2660 //
2661 // Returns: `end(range)`.
2662 //
2663 // Complexity: Exactly `size(range) - 1` swaps.
2664 //
2665 // Remarks: To the extent that the implementation of this function makes use of
2666 // random numbers, the object referenced by g shall serve as the
2667 // implementation's source of randomness.
2668 //
2669 // Reference: https://wg21.link/alg.random.shuffle#:~:text=ranges::shuffle(R
2670 template <typename Range,
2671           typename UniformRandomBitGenerator,
2672           typename = internal::range_category_t<Range>>
shuffle(Range && range,UniformRandomBitGenerator && g)2673 constexpr auto shuffle(Range&& range, UniformRandomBitGenerator&& g) {
2674   return ranges::shuffle(ranges::begin(range), ranges::end(range),
2675                          std::forward<UniformRandomBitGenerator>(g));
2676 }
2677 
2678 // [alg.nonmodifying] Sorting and related operations
2679 // Reference: https://wg21.link/alg.sorting
2680 
2681 // [alg.sort] Sorting
2682 // Reference: https://wg21.link/alg.sort
2683 
2684 // [sort] sort
2685 // Reference: https://wg21.link/sort
2686 
2687 // Effects: Sorts the elements in the range `[first, last)` with respect to
2688 // `comp` and `proj`.
2689 //
2690 // Returns: `last`.
2691 //
2692 // Complexity: Let `N` be `last - first`. `O(N log N)` comparisons and
2693 // projections.
2694 //
2695 // Reference: https://wg21.link/sort#:~:text=ranges::sort(I
2696 template <typename RandomAccessIterator,
2697           typename Comp = ranges::less,
2698           typename Proj = std::identity,
2699           typename = internal::iterator_category_t<RandomAccessIterator>,
2700           typename = std::indirect_result_t<
2701               Comp&,
2702               std::projected<RandomAccessIterator, Proj>,
2703               std::projected<RandomAccessIterator, Proj>>>
2704 constexpr auto sort(RandomAccessIterator first,
2705                     RandomAccessIterator last,
2706                     Comp comp = {},
2707                     Proj proj = {}) {
2708   std::sort(first, last, internal::ProjectedBinaryPredicate(comp, proj, proj));
2709   return last;
2710 }
2711 
2712 // Effects: Sorts the elements in `range` with respect to `comp` and `proj`.
2713 //
2714 // Returns: `end(range)`.
2715 //
2716 // Complexity: Let `N` be `size(range)`. `O(N log N)` comparisons and
2717 // projections.
2718 //
2719 // Reference: https://wg21.link/sort#:~:text=ranges::sort(R
2720 template <
2721     typename Range,
2722     typename Comp = ranges::less,
2723     typename Proj = std::identity,
2724     typename = internal::range_category_t<Range>,
2725     typename = std::indirect_result_t<Comp&,
2726                                       std::projected<iterator_t<Range>, Proj>,
2727                                       std::projected<iterator_t<Range>, Proj>>>
2728 constexpr auto sort(Range&& range, Comp comp = {}, Proj proj = {}) {
2729   return ranges::sort(ranges::begin(range), ranges::end(range), std::move(comp),
2730                       std::move(proj));
2731 }
2732 
2733 // [stable.sort] stable_sort
2734 // Reference: https://wg21.link/stable.sort
2735 
2736 // Effects: Sorts the elements in the range `[first, last)` with respect to
2737 // `comp` and `proj`.
2738 //
2739 // Returns: `last`.
2740 //
2741 // Complexity: Let `N` be `last - first`. If enough extra memory is available,
2742 // `N log (N)` comparisons. Otherwise, at most `N log^2 (N)` comparisons. In
2743 // either case, twice as many projections as the number of comparisons.
2744 //
2745 // Remarks: Stable.
2746 //
2747 // Reference: https://wg21.link/stable.sort#:~:text=ranges::stable_sort(I
2748 template <typename RandomAccessIterator,
2749           typename Comp = ranges::less,
2750           typename Proj = std::identity,
2751           typename = internal::iterator_category_t<RandomAccessIterator>,
2752           typename = std::indirect_result_t<
2753               Comp&,
2754               std::projected<RandomAccessIterator, Proj>,
2755               std::projected<RandomAccessIterator, Proj>>>
2756 constexpr auto stable_sort(RandomAccessIterator first,
2757                            RandomAccessIterator last,
2758                            Comp comp = {},
2759                            Proj proj = {}) {
2760   std::stable_sort(first, last,
2761                    internal::ProjectedBinaryPredicate(comp, proj, proj));
2762   return last;
2763 }
2764 
2765 // Effects: Sorts the elements in `range` with respect to `comp` and `proj`.
2766 //
2767 // Returns: `end(rang)`.
2768 //
2769 // Complexity: Let `N` be `size(range)`. If enough extra memory is available,
2770 // `N log (N)` comparisons. Otherwise, at most `N log^2 (N)` comparisons. In
2771 // either case, twice as many projections as the number of comparisons.
2772 //
2773 // Remarks: Stable.
2774 //
2775 // Reference: https://wg21.link/stable.sort#:~:text=ranges::stable_sort(R
2776 template <
2777     typename Range,
2778     typename Comp = ranges::less,
2779     typename Proj = std::identity,
2780     typename = internal::range_category_t<Range>,
2781     typename = std::indirect_result_t<Comp&,
2782                                       std::projected<iterator_t<Range>, Proj>,
2783                                       std::projected<iterator_t<Range>, Proj>>>
2784 constexpr auto stable_sort(Range&& range, Comp comp = {}, Proj proj = {}) {
2785   return ranges::stable_sort(ranges::begin(range), ranges::end(range),
2786                              std::move(comp), std::move(proj));
2787 }
2788 
2789 // [partial.sort] partial_sort
2790 // Reference: https://wg21.link/partial.sort
2791 
2792 // Preconditions: `[first, middle)` and `[middle, last)` are valid ranges.
2793 //
2794 // Effects: Places the first `middle - first` elements from the range
2795 // `[first, last)` as sorted with respect to `comp` and `proj` into the range
2796 // `[first, middle)`. The rest of the elements in the range `[middle, last)` are
2797 // placed in an unspecified order.
2798 //
2799 // Returns: `last`.
2800 //
2801 // Complexity: Approximately `(last - first) * log(middle - first)` comparisons,
2802 // and twice as many projections.
2803 //
2804 // Reference: https://wg21.link/partial.sort#:~:text=ranges::partial_sort(I
2805 template <typename RandomAccessIterator,
2806           typename Comp = ranges::less,
2807           typename Proj = std::identity,
2808           typename = internal::iterator_category_t<RandomAccessIterator>,
2809           typename = std::indirect_result_t<
2810               Comp&,
2811               std::projected<RandomAccessIterator, Proj>,
2812               std::projected<RandomAccessIterator, Proj>>>
2813 constexpr auto partial_sort(RandomAccessIterator first,
2814                             RandomAccessIterator middle,
2815                             RandomAccessIterator last,
2816                             Comp comp = {},
2817                             Proj proj = {}) {
2818   std::partial_sort(first, middle, last,
2819                     internal::ProjectedBinaryPredicate(comp, proj, proj));
2820   return last;
2821 }
2822 
2823 // Preconditions: `[begin(range), middle)` and `[middle, end(range))` are valid
2824 // ranges.
2825 //
2826 // Effects: Places the first `middle - begin(range)` elements from `range` as
2827 // sorted with respect to `comp` and `proj` into the range
2828 // `[begin(range), middle)`. The rest of the elements in the range
2829 // `[middle, end(range))` are placed in an unspecified order.
2830 //
2831 // Returns: `end(range)`.
2832 //
2833 // Complexity: Approximately `size(range) * log(middle - begin(range))`
2834 // comparisons, and twice as many projections.
2835 //
2836 // Reference: https://wg21.link/partial.sort#:~:text=ranges::partial_sort(R
2837 template <
2838     typename Range,
2839     typename Comp = ranges::less,
2840     typename Proj = std::identity,
2841     typename = internal::range_category_t<Range>,
2842     typename = std::indirect_result_t<Comp&,
2843                                       std::projected<iterator_t<Range>, Proj>,
2844                                       std::projected<iterator_t<Range>, Proj>>>
2845 constexpr auto partial_sort(Range&& range,
2846                             iterator_t<Range> middle,
2847                             Comp comp = {},
2848                             Proj proj = {}) {
2849   return ranges::partial_sort(ranges::begin(range), middle, ranges::end(range),
2850                               std::move(comp), std::move(proj));
2851 }
2852 
2853 // [partial.sort.copy] partial_sort_copy
2854 // Reference: https://wg21.link/partial.sort.copy
2855 
2856 // Let `N` be `min(last - first, result_last - result_first)`.
2857 //
2858 // Preconditions: For iterators `a1` and `b1` in `[first, last)`, and iterators
2859 // `x2` and `y2` in `[result_first, result_last)`, after evaluating the
2860 // assignment `*y2 = *b1`, let `E` be the value of `bool(invoke(comp,
2861 // invoke(proj1, *a1), invoke(proj2, *y2)))`. Then, after evaluating the
2862 // assignment `*x2 = *a1`, `E` is equal to `bool(invoke(comp, invoke(proj2,
2863 // *x2), invoke(proj2, *y2)))`.
2864 //
2865 // Effects: Places the first `N` elements as sorted with respect to `comp` and
2866 // `proj2` into the range `[result_first, result_first + N)`.
2867 //
2868 // Returns: `result_first + N`.
2869 //
2870 // Complexity: Approximately `(last - first) * log N` comparisons, and twice as
2871 // many projections.
2872 //
2873 // Reference:
2874 // https://wg21.link/partial.sort.copy#:~:text=ranges::partial_sort_copy(I1
2875 template <
2876     typename InputIterator,
2877     typename RandomAccessIterator,
2878     typename Comp = ranges::less,
2879     typename Proj1 = std::identity,
2880     typename Proj2 = std::identity,
2881     typename = internal::iterator_category_t<InputIterator>,
2882     typename = internal::iterator_category_t<RandomAccessIterator>,
2883     typename =
2884         std::indirect_result_t<Comp&,
2885                                std::projected<InputIterator, Proj1>,
2886                                std::projected<RandomAccessIterator, Proj2>>,
2887     typename =
2888         std::indirect_result_t<Comp&,
2889                                std::projected<RandomAccessIterator, Proj2>,
2890                                std::projected<InputIterator, Proj1>>>
2891 constexpr auto partial_sort_copy(InputIterator first,
2892                                  InputIterator last,
2893                                  RandomAccessIterator result_first,
2894                                  RandomAccessIterator result_last,
2895                                  Comp comp = {},
2896                                  Proj1 proj1 = {},
2897                                  Proj2 proj2 = {}) {
2898   // Needs to opt-in to all permutations, since std::partial_sort_copy expects
2899   // comp(proj2(lhs), proj1(rhs)) to compile.
2900   return std::partial_sort_copy(
2901       first, last, result_first, result_last,
2902       internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2));
2903 }
2904 
2905 // Let `N` be `min(size(range), size(result_range))`.
2906 //
2907 // Preconditions: For iterators `a1` and `b1` in `range`, and iterators
2908 // `x2` and `y2` in `result_range`, after evaluating the assignment
2909 // `*y2 = *b1`, let `E` be the value of
2910 // `bool(invoke(comp, invoke(proj1, *a1), invoke(proj2, *y2)))`. Then, after
2911 // evaluating the assignment `*x2 = *a1`, `E` is equal to
2912 // `bool(invoke(comp, invoke(proj2, *x2), invoke(proj2, *y2)))`.
2913 //
2914 // Effects: Places the first `N` elements as sorted with respect to `comp` and
2915 // `proj2` into the range `[begin(result_range), begin(result_range) + N)`.
2916 //
2917 // Returns: `begin(result_range) + N`.
2918 //
2919 // Complexity: Approximately `size(range) * log N` comparisons, and twice as
2920 // many projections.
2921 //
2922 // Reference:
2923 // https://wg21.link/partial.sort.copy#:~:text=ranges::partial_sort_copy(R1
2924 template <typename Range1,
2925           typename Range2,
2926           typename Comp = ranges::less,
2927           typename Proj1 = std::identity,
2928           typename Proj2 = std::identity,
2929           typename = internal::range_category_t<Range1>,
2930           typename = internal::range_category_t<Range2>,
2931           typename =
2932               std::indirect_result_t<Comp&,
2933                                      std::projected<iterator_t<Range1>, Proj1>,
2934                                      std::projected<iterator_t<Range2>, Proj2>>,
2935           typename =
2936               std::indirect_result_t<Comp&,
2937                                      std::projected<iterator_t<Range2>, Proj2>,
2938                                      std::projected<iterator_t<Range1>, Proj1>>>
2939 constexpr auto partial_sort_copy(Range1&& range,
2940                                  Range2&& result_range,
2941                                  Comp comp = {},
2942                                  Proj1 proj1 = {},
2943                                  Proj2 proj2 = {}) {
2944   return ranges::partial_sort_copy(ranges::begin(range), ranges::end(range),
2945                                    ranges::begin(result_range),
2946                                    ranges::end(result_range), std::move(comp),
2947                                    std::move(proj1), std::move(proj2));
2948 }
2949 
2950 // [is.sorted] is_sorted
2951 // Reference: https://wg21.link/is.sorted
2952 
2953 // Returns: The last iterator `i` in `[first, last]` for which the range
2954 // `[first, i)` is sorted with respect to `comp` and `proj`.
2955 //
2956 // Complexity: Linear.
2957 //
2958 // Reference: https://wg21.link/is.sorted#:~:text=ranges::is_sorted_until(I
2959 template <
2960     typename ForwardIterator,
2961     typename Comp = ranges::less,
2962     typename Proj = std::identity,
2963     typename = internal::iterator_category_t<ForwardIterator>,
2964     typename = std::indirect_result_t<Comp&,
2965                                       std::projected<ForwardIterator, Proj>,
2966                                       std::projected<ForwardIterator, Proj>>>
2967 constexpr auto is_sorted_until(ForwardIterator first,
2968                                ForwardIterator last,
2969                                Comp comp = {},
2970                                Proj proj = {}) {
2971   // Implementation inspired by cppreference.com:
2972   // https://en.cppreference.com/w/cpp/algorithm/is_sorted_until
2973   //
2974   // A reimplementation is required, because std::is_sorted_until is not
2975   // constexpr prior to C++20. Once we have C++20, we should switch to standard
2976   // library implementation.
2977   if (first == last)
2978     return last;
2979 
2980   for (ForwardIterator next = first; ++next != last; ++first) {
2981     if (std::invoke(comp, std::invoke(proj, *next),
2982                     std::invoke(proj, *first))) {
2983       return next;
2984     }
2985   }
2986 
2987   return last;
2988 }
2989 
2990 // Returns: The last iterator `i` in `[begin(range), end(range)]` for which the
2991 // range `[begin(range), i)` is sorted with respect to `comp` and `proj`.
2992 //
2993 // Complexity: Linear.
2994 //
2995 // Reference: https://wg21.link/is.sorted#:~:text=ranges::is_sorted_until(R
2996 template <
2997     typename Range,
2998     typename Comp = ranges::less,
2999     typename Proj = std::identity,
3000     typename = internal::range_category_t<Range>,
3001     typename = std::indirect_result_t<Comp&,
3002                                       std::projected<iterator_t<Range>, Proj>,
3003                                       std::projected<iterator_t<Range>, Proj>>>
3004 constexpr auto is_sorted_until(Range&& range, Comp comp = {}, Proj proj = {}) {
3005   return ranges::is_sorted_until(ranges::begin(range), ranges::end(range),
3006                                  std::move(comp), std::move(proj));
3007 }
3008 
3009 // Returns: Whether the range `[first, last)` is sorted with respect to `comp`
3010 // and `proj`.
3011 //
3012 // Complexity: Linear.
3013 //
3014 // Reference: https://wg21.link/is.sorted#:~:text=ranges::is_sorted(I
3015 template <
3016     typename ForwardIterator,
3017     typename Comp = ranges::less,
3018     typename Proj = std::identity,
3019     typename = internal::iterator_category_t<ForwardIterator>,
3020     typename = std::indirect_result_t<Comp&,
3021                                       std::projected<ForwardIterator, Proj>,
3022                                       std::projected<ForwardIterator, Proj>>>
3023 constexpr auto is_sorted(ForwardIterator first,
3024                          ForwardIterator last,
3025                          Comp comp = {},
3026                          Proj proj = {}) {
3027   return ranges::is_sorted_until(first, last, std::move(comp),
3028                                  std::move(proj)) == last;
3029 }
3030 
3031 // Returns: Whether `range` is sorted with respect to `comp` and `proj`.
3032 //
3033 // Complexity: Linear.
3034 //
3035 // Reference: https://wg21.link/is.sorted#:~:text=ranges::is_sorted(R
3036 template <
3037     typename Range,
3038     typename Comp = ranges::less,
3039     typename Proj = std::identity,
3040     typename = internal::range_category_t<Range>,
3041     typename = std::indirect_result_t<Comp&,
3042                                       std::projected<iterator_t<Range>, Proj>,
3043                                       std::projected<iterator_t<Range>, Proj>>>
3044 constexpr auto is_sorted(Range&& range, Comp comp = {}, Proj proj = {}) {
3045   return ranges::is_sorted(ranges::begin(range), ranges::end(range),
3046                            std::move(comp), std::move(proj));
3047 }
3048 
3049 // [alg.nth.element] Nth element
3050 // Reference: https://wg21.link/alg.nth.element
3051 
3052 // Preconditions: `[first, nth)` and `[nth, last)` are valid ranges.
3053 //
3054 // Effects: After `nth_element` the element in the position pointed to by `nth`
3055 // is the element that would be in that position if the whole range were sorted
3056 // with respect to `comp` and `proj`, unless `nth == last`. Also for every
3057 // iterator `i` in the range `[first, nth)` and every iterator `j` in the range
3058 // `[nth, last)` it holds that:
3059 // `bool(invoke(comp, invoke(proj, *j), invoke(proj, *i)))` is false.
3060 //
3061 // Returns: `last`.
3062 //
3063 // Complexity: Linear on average.
3064 //
3065 // Reference: https://wg21.link/alg.nth.element#:~:text=ranges::nth_element(I
3066 template <typename RandomAccessIterator,
3067           typename Comp = ranges::less,
3068           typename Proj = std::identity,
3069           typename = internal::iterator_category_t<RandomAccessIterator>,
3070           typename = std::indirect_result_t<
3071               Comp&,
3072               std::projected<RandomAccessIterator, Proj>,
3073               std::projected<RandomAccessIterator, Proj>>>
3074 constexpr auto nth_element(RandomAccessIterator first,
3075                            RandomAccessIterator nth,
3076                            RandomAccessIterator last,
3077                            Comp comp = {},
3078                            Proj proj = {}) {
3079   std::nth_element(first, nth, last,
3080                    internal::ProjectedBinaryPredicate(comp, proj, proj));
3081   return last;
3082 }
3083 
3084 // Preconditions: `[begin(range), nth)` and `[nth, end(range))` are valid
3085 // ranges.
3086 //
3087 // Effects: After `nth_element` the element in the position pointed to by `nth`
3088 // is the element that would be in that position if the whole range were sorted
3089 // with respect to `comp` and `proj`, unless `nth == end(range)`. Also for every
3090 // iterator `i` in the range `[begin(range), nth)` and every iterator `j` in the
3091 // range `[nth, end(range))` it holds that:
3092 // `bool(invoke(comp, invoke(proj, *j), invoke(proj, *i)))` is false.
3093 //
3094 // Returns: `end(range)`.
3095 //
3096 // Complexity: Linear on average.
3097 //
3098 // Reference: https://wg21.link/alg.nth.element#:~:text=ranges::nth_element(R
3099 template <
3100     typename Range,
3101     typename Comp = ranges::less,
3102     typename Proj = std::identity,
3103     typename = internal::range_category_t<Range>,
3104     typename = std::indirect_result_t<Comp&,
3105                                       std::projected<iterator_t<Range>, Proj>,
3106                                       std::projected<iterator_t<Range>, Proj>>>
3107 constexpr auto nth_element(Range&& range,
3108                            iterator_t<Range> nth,
3109                            Comp comp = {},
3110                            Proj proj = {}) {
3111   return ranges::nth_element(ranges::begin(range), nth, ranges::end(range),
3112                              std::move(comp), std::move(proj));
3113 }
3114 
3115 // [alg.binary.search] Binary search
3116 // Reference: https://wg21.link/alg.binary.search
3117 
3118 // [lower.bound] lower_bound
3119 // Reference: https://wg21.link/lower.bound
3120 
3121 // Preconditions: The elements `e` of `[first, last)` are partitioned with
3122 // respect to the expression `bool(invoke(comp, invoke(proj, e), value))`.
3123 //
3124 // Returns: The furthermost iterator `i` in the range `[first, last]` such that
3125 // for every iterator `j` in the range `[first, i)`,
3126 // `bool(invoke(comp, invoke(proj, *j), value))` is true.
3127 //
3128 // Complexity: At most `log_2(last - first) + O(1)` comparisons and projections.
3129 //
3130 // Reference: https://wg21.link/lower.bound#:~:text=ranges::lower_bound(I
3131 template <typename ForwardIterator,
3132           typename T,
3133           typename Comp = ranges::less,
3134           typename Proj = std::identity,
3135           typename = internal::iterator_category_t<ForwardIterator>>
3136 constexpr auto lower_bound(ForwardIterator first,
3137                            ForwardIterator last,
3138                            const T& value,
3139                            Comp comp = {},
3140                            Proj proj = {}) {
3141   // The second arg is guaranteed to be `value`, so we'll simply apply the
3142   // std::identity projection.
3143   std::identity value_proj;
3144   return std::lower_bound(
3145       first, last, value,
3146       internal::ProjectedBinaryPredicate(comp, proj, value_proj));
3147 }
3148 
3149 // Preconditions: The elements `e` of `range` are partitioned with respect to
3150 // the expression `bool(invoke(comp, invoke(proj, e), value))`.
3151 //
3152 // Returns: The furthermost iterator `i` in the range
3153 // `[begin(range), end(range)]` such that for every iterator `j` in the range
3154 // `[begin(range), i)`, `bool(invoke(comp, invoke(proj, *j), value))` is true.
3155 //
3156 // Complexity: At most `log_2(size(range)) + O(1)` comparisons and projections.
3157 //
3158 // Reference: https://wg21.link/lower.bound#:~:text=ranges::lower_bound(R
3159 template <typename Range,
3160           typename T,
3161           typename Comp = ranges::less,
3162           typename Proj = std::identity,
3163           typename = internal::range_category_t<Range>>
3164 constexpr auto lower_bound(Range&& range,
3165                            const T& value,
3166                            Comp comp = {},
3167                            Proj proj = {}) {
3168   return ranges::lower_bound(ranges::begin(range), ranges::end(range), value,
3169                              std::move(comp), std::move(proj));
3170 }
3171 
3172 // [upper.bound] upper_bound
3173 // Reference: https://wg21.link/upper.bound
3174 
3175 // Preconditions: The elements `e` of `[first, last)` are partitioned with
3176 // respect to the expression `!bool(invoke(comp, value, invoke(proj, e)))`.
3177 //
3178 // Returns: The furthermost iterator `i` in the range `[first, last]` such that
3179 // for every iterator `j` in the range `[first, i)`,
3180 // `!bool(invoke(comp, value, invoke(proj, *j)))` is true.
3181 //
3182 // Complexity: At most `log_2(last - first) + O(1)` comparisons and projections.
3183 //
3184 // Reference: https://wg21.link/upper.bound#:~:text=ranges::upper_bound(I
3185 template <typename ForwardIterator,
3186           typename T,
3187           typename Comp = ranges::less,
3188           typename Proj = std::identity,
3189           typename = internal::iterator_category_t<ForwardIterator>>
3190 constexpr auto upper_bound(ForwardIterator first,
3191                            ForwardIterator last,
3192                            const T& value,
3193                            Comp comp = {},
3194                            Proj proj = {}) {
3195   // The first arg is guaranteed to be `value`, so we'll simply apply the
3196   // std::identity projection.
3197   std::identity value_proj;
3198   return std::upper_bound(
3199       first, last, value,
3200       internal::ProjectedBinaryPredicate(comp, value_proj, proj));
3201 }
3202 
3203 // Preconditions: The elements `e` of `range` are partitioned with
3204 // respect to the expression `!bool(invoke(comp, value, invoke(proj, e)))`.
3205 //
3206 // Returns: The furthermost iterator `i` in the range
3207 // `[begin(range), end(range)]` such that for every iterator `j` in the range
3208 // `[begin(range), i)`, `!bool(invoke(comp, value, invoke(proj, *j)))` is true.
3209 //
3210 // Complexity: At most `log_2(size(range)) + O(1)` comparisons and projections.
3211 //
3212 // Reference: https://wg21.link/upper.bound#:~:text=ranges::upper_bound(R
3213 template <typename Range,
3214           typename T,
3215           typename Comp = ranges::less,
3216           typename Proj = std::identity,
3217           typename = internal::range_category_t<Range>>
3218 constexpr auto upper_bound(Range&& range,
3219                            const T& value,
3220                            Comp comp = {},
3221                            Proj proj = {}) {
3222   return ranges::upper_bound(ranges::begin(range), ranges::end(range), value,
3223                              std::move(comp), std::move(proj));
3224 }
3225 
3226 // [equal.range] equal_range
3227 // Reference: https://wg21.link/equal.range
3228 
3229 // Preconditions: The elements `e` of `[first, last)` are partitioned with
3230 // respect to the expressions `bool(invoke(comp, invoke(proj, e), value))` and
3231 // `!bool(invoke(comp, value, invoke(proj, e)))`.
3232 //
3233 // Returns: `{ranges::lower_bound(first, last, value, comp, proj),
3234 //            ranges::upper_bound(first, last, value, comp, proj)}`.
3235 //
3236 // Complexity: At most 2 ∗ log_2(last - first) + O(1) comparisons and
3237 // projections.
3238 //
3239 // Reference: https://wg21.link/equal.range#:~:text=ranges::equal_range(I
3240 template <typename ForwardIterator,
3241           typename T,
3242           typename Comp = ranges::less,
3243           typename Proj = std::identity,
3244           typename = internal::iterator_category_t<ForwardIterator>>
3245 constexpr auto equal_range(ForwardIterator first,
3246                            ForwardIterator last,
3247                            const T& value,
3248                            Comp comp = {},
3249                            Proj proj = {}) {
3250   // Note: This does not dispatch to std::equal_range, as otherwise it would not
3251   // be possible to prevent applying `proj` to `value`, which can result in
3252   // unintended behavior.
3253   return std::make_pair(ranges::lower_bound(first, last, value, comp, proj),
3254                         ranges::upper_bound(first, last, value, comp, proj));
3255 }
3256 
3257 // Preconditions: The elements `e` of `range` are partitioned with
3258 // respect to the expressions `bool(invoke(comp, invoke(proj, e), value))` and
3259 // `!bool(invoke(comp, value, invoke(proj, e)))`.
3260 //
3261 // Returns: `{ranges::lower_bound(range, value, comp, proj),
3262 //            ranges::upper_bound(range, value, comp, proj)}`.
3263 //
3264 // Complexity: At most 2 ∗ log_2(size(range)) + O(1) comparisons and
3265 // projections.
3266 //
3267 // Reference: https://wg21.link/equal.range#:~:text=ranges::equal_range(R
3268 template <typename Range,
3269           typename T,
3270           typename Comp = ranges::less,
3271           typename Proj = std::identity,
3272           typename = internal::range_category_t<Range>>
3273 constexpr auto equal_range(Range&& range,
3274                            const T& value,
3275                            Comp comp = {},
3276                            Proj proj = {}) {
3277   return ranges::equal_range(ranges::begin(range), ranges::end(range), value,
3278                              std::move(comp), std::move(proj));
3279 }
3280 
3281 // [binary.search] binary_search
3282 // Reference: https://wg21.link/binary.search
3283 
3284 // Preconditions: The elements `e` of `[first, last)` are partitioned with
3285 // respect to the expressions `bool(invoke(comp, invoke(proj, e), value))` and
3286 // `!bool(invoke(comp, value, invoke(proj, e)))`.
3287 //
3288 // Returns: `true` if and only if for some iterator `i` in the range
3289 // `[first, last)`, `!bool(invoke(comp, invoke(proj, *i), value)) &&
3290 //                   !bool(invoke(comp, value, invoke(proj, *i)))` is true.
3291 //
3292 // Complexity: At most `log_2(last - first) + O(1)` comparisons and projections.
3293 //
3294 // Reference: https://wg21.link/binary.search#:~:text=ranges::binary_search(I
3295 template <typename ForwardIterator,
3296           typename T,
3297           typename Comp = ranges::less,
3298           typename Proj = std::identity,
3299           typename = internal::iterator_category_t<ForwardIterator>>
3300 constexpr auto binary_search(ForwardIterator first,
3301                              ForwardIterator last,
3302                              const T& value,
3303                              Comp comp = {},
3304                              Proj proj = {}) {
3305   first = ranges::lower_bound(first, last, value, comp, proj);
3306   return first != last && !std::invoke(comp, value, std::invoke(proj, *first));
3307 }
3308 
3309 // Preconditions: The elements `e` of `range` are partitioned with
3310 // respect to the expressions `bool(invoke(comp, invoke(proj, e), value))` and
3311 // `!bool(invoke(comp, value, invoke(proj, e)))`.
3312 //
3313 // Returns: `true` if and only if for some iterator `i` in `range`
3314 // `!bool(invoke(comp, invoke(proj, *i), value)) &&
3315 //  !bool(invoke(comp, value, invoke(proj, *i)))` is true.
3316 //
3317 // Complexity: At most `log_2(size(range)) + O(1)` comparisons and projections.
3318 //
3319 // Reference: https://wg21.link/binary.search#:~:text=ranges::binary_search(R
3320 template <typename Range,
3321           typename T,
3322           typename Comp = ranges::less,
3323           typename Proj = std::identity,
3324           typename = internal::range_category_t<Range>>
3325 constexpr auto binary_search(Range&& range,
3326                              const T& value,
3327                              Comp comp = {},
3328                              Proj proj = {}) {
3329   return ranges::binary_search(ranges::begin(range), ranges::end(range), value,
3330                                std::move(comp), std::move(proj));
3331 }
3332 
3333 // [alg.partitions] Partitions
3334 // Reference: https://wg21.link/alg.partitions
3335 
3336 // Returns: `true` if and only if the elements `e` of `[first, last)` are
3337 // partitioned with respect to the expression
3338 // `bool(invoke(pred, invoke(proj, e)))`.
3339 //
3340 // Complexity: Linear. At most `last - first` applications of `pred` and `proj`.
3341 //
3342 // Reference: https://wg21.link/alg.partitions#:~:text=ranges::is_partitioned(I
3343 template <typename ForwardIterator,
3344           typename Pred,
3345           typename Proj = std::identity,
3346           typename = internal::iterator_category_t<ForwardIterator>>
3347 constexpr auto is_partitioned(ForwardIterator first,
3348                               ForwardIterator last,
3349                               Pred pred,
3350                               Proj proj = {}) {
3351   return std::is_partitioned(first, last,
3352                              internal::ProjectedUnaryPredicate(pred, proj));
3353 }
3354 
3355 // Returns: `true` if and only if the elements `e` of `range` are partitioned
3356 // with respect to the expression `bool(invoke(pred, invoke(proj, e)))`.
3357 //
3358 // Complexity: Linear. At most `size(range)` applications of `pred` and `proj`.
3359 //
3360 // Reference: https://wg21.link/alg.partitions#:~:text=ranges::is_partitioned(R
3361 template <typename Range,
3362           typename Pred,
3363           typename Proj = std::identity,
3364           typename = internal::range_category_t<Range>>
3365 constexpr auto is_partitioned(Range&& range, Pred pred, Proj proj = {}) {
3366   return ranges::is_partitioned(ranges::begin(range), ranges::end(range),
3367                                 std::move(pred), std::move(proj));
3368 }
3369 
3370 // Let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`.
3371 //
3372 // Effects: Places all the elements `e` in `[first, last)` that satisfy `E(e)`
3373 // before all the elements that do not.
3374 //
3375 // Returns: Let `i` be an iterator such that `E(*j)` is `true` for every
3376 // iterator `j` in `[first, i)` and `false` for every iterator `j` in
3377 // `[i, last)`. Returns: i.
3378 //
3379 // Complexity: Let `N = last - first`:
3380 // Exactly `N` applications of the predicate and projection. At most `N / 2`
3381 // swaps if the type of `first` models `bidirectional_iterator`, and at most `N`
3382 // swaps otherwise.
3383 //
3384 // Reference: https://wg21.link/alg.partitions#:~:text=ranges::partition(I
3385 template <typename ForwardIterator,
3386           typename Pred,
3387           typename Proj = std::identity,
3388           typename = internal::iterator_category_t<ForwardIterator>>
3389 constexpr auto partition(ForwardIterator first,
3390                          ForwardIterator last,
3391                          Pred pred,
3392                          Proj proj = {}) {
3393   return std::partition(first, last,
3394                         internal::ProjectedUnaryPredicate(pred, proj));
3395 }
3396 
3397 // Let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`.
3398 //
3399 // Effects: Places all the elements `e` in `range` that satisfy `E(e)` before
3400 // all the elements that do not.
3401 //
3402 // Returns: Let `i` be an iterator such that `E(*j)` is `true` for every
3403 // iterator `j` in `[begin(range), i)` and `false` for every iterator `j` in
3404 // `[i, last)`. Returns: i.
3405 //
3406 // Complexity: Let `N = size(range)`:
3407 // Exactly `N` applications of the predicate and projection. At most `N / 2`
3408 // swaps if the type of `first` models `bidirectional_iterator`, and at most `N`
3409 // swaps otherwise.
3410 //
3411 // Reference: https://wg21.link/alg.partitions#:~:text=ranges::partition(R
3412 template <typename Range,
3413           typename Pred,
3414           typename Proj = std::identity,
3415           typename = internal::range_category_t<Range>>
3416 constexpr auto partition(Range&& range, Pred pred, Proj proj = {}) {
3417   return ranges::partition(ranges::begin(range), ranges::end(range),
3418                            std::move(pred), std::move(proj));
3419 }
3420 
3421 // Let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`.
3422 //
3423 // Effects: Places all the elements `e` in `[first, last)` that satisfy `E(e)`
3424 // before all the elements that do not. The relative order of the elements in
3425 // both groups is preserved.
3426 //
3427 // Returns: Let `i` be an iterator such that for every iterator `j` in
3428 // `[first, i)`, `E(*j)` is `true`, and for every iterator `j` in the range
3429 // `[i, last)`, `E(*j)` is `false`. Returns: `i`.
3430 //
3431 // Complexity: Let `N = last - first`:
3432 // At most `N log N` swaps, but only `O(N)` swaps if there is enough extra
3433 // memory. Exactly `N` applications of the predicate and projection.
3434 //
3435 // Reference:
3436 // https://wg21.link/alg.partitions#:~:text=ranges::stable_partition(I
3437 template <typename BidirectionalIterator,
3438           typename Pred,
3439           typename Proj = std::identity,
3440           typename = internal::iterator_category_t<BidirectionalIterator>>
3441 constexpr auto stable_partition(BidirectionalIterator first,
3442                                 BidirectionalIterator last,
3443                                 Pred pred,
3444                                 Proj proj = {}) {
3445   return std::stable_partition(first, last,
3446                                internal::ProjectedUnaryPredicate(pred, proj));
3447 }
3448 
3449 // Let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`.
3450 //
3451 // Effects: Places all the elements `e` in `range` that satisfy `E(e)` before
3452 // all the elements that do not. The relative order of the elements in both
3453 // groups is preserved.
3454 //
3455 // Returns: Let `i` be an iterator such that for every iterator `j` in
3456 // `[begin(range), i)`, `E(*j)` is `true`, and for every iterator `j` in the
3457 // range `[i, end(range))`, `E(*j)` is `false`. Returns: `i`.
3458 //
3459 // Complexity: Let `N = size(range)`:
3460 // At most `N log N` swaps, but only `O(N)` swaps if there is enough extra
3461 // memory. Exactly `N` applications of the predicate and projection.
3462 //
3463 // Reference:
3464 // https://wg21.link/alg.partitions#:~:text=ranges::stable_partition(R
3465 template <typename Range,
3466           typename Pred,
3467           typename Proj = std::identity,
3468           typename = internal::range_category_t<Range>>
3469 constexpr auto stable_partition(Range&& range, Pred pred, Proj proj = {}) {
3470   return ranges::stable_partition(ranges::begin(range), ranges::end(range),
3471                                   std::move(pred), std::move(proj));
3472 }
3473 
3474 // Let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`.
3475 //
3476 // Mandates: The expression `*first` is writable to `out_true` and `out_false`.
3477 //
3478 // Preconditions: The input range and output ranges do not overlap.
3479 //
3480 // Effects: For each iterator `i` in `[first, last)`, copies `*i` to the output
3481 // range beginning with `out_true` if `E(*i)` is `true`, or to the output range
3482 // beginning with `out_false` otherwise.
3483 //
3484 // Returns: Let `o1` be the end of the output range beginning at `out_true`, and
3485 // `o2` the end of the output range beginning at `out_false`.
3486 // Returns `{o1, o2}`.
3487 //
3488 // Complexity: Exactly `last - first` applications of `pred` and `proj`.
3489 //
3490 // Reference: https://wg21.link/alg.partitions#:~:text=ranges::partition_copy(I
3491 template <typename InputIterator,
3492           typename OutputIterator1,
3493           typename OutputIterator2,
3494           typename Pred,
3495           typename Proj = std::identity,
3496           typename = internal::iterator_category_t<InputIterator>,
3497           typename = internal::iterator_category_t<OutputIterator1>,
3498           typename = internal::iterator_category_t<OutputIterator2>>
3499 constexpr auto partition_copy(InputIterator first,
3500                               InputIterator last,
3501                               OutputIterator1 out_true,
3502                               OutputIterator2 out_false,
3503                               Pred pred,
3504                               Proj proj = {}) {
3505   return std::partition_copy(first, last, out_true, out_false,
3506                              internal::ProjectedUnaryPredicate(pred, proj));
3507 }
3508 
3509 // Let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`.
3510 //
3511 // Mandates: The expression `*begin(range)` is writable to `out_true` and
3512 // `out_false`.
3513 //
3514 // Preconditions: The input range and output ranges do not overlap.
3515 //
3516 // Effects: For each iterator `i` in `range`, copies `*i` to the output range
3517 // beginning with `out_true` if `E(*i)` is `true`, or to the output range
3518 // beginning with `out_false` otherwise.
3519 //
3520 // Returns: Let `o1` be the end of the output range beginning at `out_true`, and
3521 // `o2` the end of the output range beginning at `out_false`.
3522 // Returns `{o1, o2}`.
3523 //
3524 // Complexity: Exactly `size(range)` applications of `pred` and `proj`.
3525 //
3526 // Reference: https://wg21.link/alg.partitions#:~:text=ranges::partition_copy(R
3527 template <typename Range,
3528           typename OutputIterator1,
3529           typename OutputIterator2,
3530           typename Pred,
3531           typename Proj = std::identity,
3532           typename = internal::range_category_t<Range>,
3533           typename = internal::iterator_category_t<OutputIterator1>,
3534           typename = internal::iterator_category_t<OutputIterator2>>
3535 constexpr auto partition_copy(Range&& range,
3536                               OutputIterator1 out_true,
3537                               OutputIterator2 out_false,
3538                               Pred pred,
3539                               Proj proj = {}) {
3540   return ranges::partition_copy(ranges::begin(range), ranges::end(range),
3541                                 out_true, out_false, std::move(pred),
3542                                 std::move(proj));
3543 }
3544 
3545 // let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`.
3546 //
3547 // Preconditions: The elements `e` of `[first, last)` are partitioned with
3548 // respect to `E(e)`.
3549 //
3550 // Returns: An iterator `mid` such that `E(*i)` is `true` for all iterators `i`
3551 // in `[first, mid)`, and `false` for all iterators `i` in `[mid, last)`.
3552 //
3553 // Complexity: `O(log(last - first))` applications of `pred` and `proj`.
3554 //
3555 // Reference: https://wg21.link/alg.partitions#:~:text=ranges::partition_point(I
3556 template <typename ForwardIterator,
3557           typename Pred,
3558           typename Proj = std::identity,
3559           typename = internal::iterator_category_t<ForwardIterator>>
3560 constexpr auto partition_point(ForwardIterator first,
3561                                ForwardIterator last,
3562                                Pred pred,
3563                                Proj proj = {}) {
3564   return std::partition_point(first, last,
3565                               internal::ProjectedUnaryPredicate(pred, proj));
3566 }
3567 
3568 // let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`.
3569 //
3570 // Preconditions: The elements `e` of `range` are partitioned with respect to
3571 // `E(e)`.
3572 //
3573 // Returns: An iterator `mid` such that `E(*i)` is `true` for all iterators `i`
3574 // in `[begin(range), mid)`, and `false` for all iterators `i` in
3575 // `[mid, end(range))`.
3576 //
3577 // Complexity: `O(log(size(range)))` applications of `pred` and `proj`.
3578 //
3579 // Reference: https://wg21.link/alg.partitions#:~:text=ranges::partition_point(R
3580 template <typename Range,
3581           typename Pred,
3582           typename Proj = std::identity,
3583           typename = internal::range_category_t<Range>>
3584 constexpr auto partition_point(Range&& range, Pred pred, Proj proj = {}) {
3585   return ranges::partition_point(ranges::begin(range), ranges::end(range),
3586                                  std::move(pred), std::move(proj));
3587 }
3588 
3589 // [alg.merge] Merge
3590 // Reference: https://wg21.link/alg.merge
3591 
3592 // Let `N` be `(last1 - first1) + (last2 - first2)`.
3593 //
3594 // Preconditions: The ranges `[first1, last1)` and `[first2, last2)` are sorted
3595 // with respect to `comp` and `proj1` or `proj2`, respectively. The resulting
3596 // range does not overlap with either of the original ranges.
3597 //
3598 // Effects: Copies all the elements of the two ranges `[first1, last1)` and
3599 // `[first2, last2)` into the range `[result, result_last)`, where `result_last`
3600 // is `result + N`. If an element `a` precedes `b` in an input range, `a` is
3601 // copied into the output range before `b`. If `e1` is an element of
3602 // `[first1, last1)` and `e2` of `[first2, last2)`, `e2` is copied into the
3603 // output range before `e1` if and only if
3604 // `bool(invoke(comp, invoke(proj2, e2), invoke(proj1, e1)))` is `true`.
3605 //
3606 // Returns: `result_last`.
3607 //
3608 // Complexity: At most `N - 1` comparisons and applications of each projection.
3609 //
3610 // Remarks: Stable.
3611 //
3612 // Reference: https://wg21.link/alg.merge#:~:text=ranges::merge(I1
3613 template <
3614     typename InputIterator1,
3615     typename InputIterator2,
3616     typename OutputIterator,
3617     typename Comp = ranges::less,
3618     typename Proj1 = std::identity,
3619     typename Proj2 = std::identity,
3620     typename = internal::iterator_category_t<InputIterator1>,
3621     typename = internal::iterator_category_t<InputIterator2>,
3622     typename = internal::iterator_category_t<OutputIterator>,
3623     typename = std::indirect_result_t<Comp&,
3624                                       std::projected<InputIterator1, Proj1>,
3625                                       std::projected<InputIterator2, Proj2>>,
3626     typename = std::indirect_result_t<Comp&,
3627                                       std::projected<InputIterator2, Proj2>,
3628                                       std::projected<InputIterator1, Proj1>>>
3629 constexpr auto merge(InputIterator1 first1,
3630                      InputIterator1 last1,
3631                      InputIterator2 first2,
3632                      InputIterator2 last2,
3633                      OutputIterator result,
3634                      Comp comp = {},
3635                      Proj1 proj1 = {},
3636                      Proj2 proj2 = {}) {
3637   // Needs to opt-in to all permutations, since std::merge expects
3638   // comp(proj2(lhs), proj1(rhs)) to compile.
3639   return std::merge(
3640       first1, last1, first2, last2, result,
3641       internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2));
3642 }
3643 
3644 // Let `N` be `size(range1) + size(range2)`.
3645 //
3646 // Preconditions: The ranges `range1` and `range2` are sorted with respect to
3647 // `comp` and `proj1` or `proj2`, respectively. The resulting range does not
3648 // overlap with either of the original ranges.
3649 //
3650 // Effects: Copies all the elements of the two ranges `range1` and `range2` into
3651 // the range `[result, result_last)`, where `result_last` is `result + N`. If an
3652 // element `a` precedes `b` in an input range, `a` is copied into the output
3653 // range before `b`. If `e1` is an element of `range1` and `e2` of `range2`,
3654 // `e2` is copied into the output range before `e1` if and only if
3655 // `bool(invoke(comp, invoke(proj2, e2), invoke(proj1, e1)))` is `true`.
3656 //
3657 // Returns: `result_last`.
3658 //
3659 // Complexity: At most `N - 1` comparisons and applications of each projection.
3660 //
3661 // Remarks: Stable.
3662 //
3663 // Reference: https://wg21.link/alg.merge#:~:text=ranges::merge(R1
3664 template <typename Range1,
3665           typename Range2,
3666           typename OutputIterator,
3667           typename Comp = ranges::less,
3668           typename Proj1 = std::identity,
3669           typename Proj2 = std::identity,
3670           typename = internal::range_category_t<Range1>,
3671           typename = internal::range_category_t<Range2>,
3672           typename = internal::iterator_category_t<OutputIterator>,
3673           typename =
3674               std::indirect_result_t<Comp&,
3675                                      std::projected<iterator_t<Range1>, Proj1>,
3676                                      std::projected<iterator_t<Range2>, Proj2>>,
3677           typename =
3678               std::indirect_result_t<Comp&,
3679                                      std::projected<iterator_t<Range2>, Proj2>,
3680                                      std::projected<iterator_t<Range1>, Proj1>>>
3681 constexpr auto merge(Range1&& range1,
3682                      Range2&& range2,
3683                      OutputIterator result,
3684                      Comp comp = {},
3685                      Proj1 proj1 = {},
3686                      Proj2 proj2 = {}) {
3687   return ranges::merge(ranges::begin(range1), ranges::end(range1),
3688                        ranges::begin(range2), ranges::end(range2), result,
3689                        std::move(comp), std::move(proj1), std::move(proj2));
3690 }
3691 
3692 // Preconditions: `[first, middle)` and `[middle, last)` are valid ranges sorted
3693 // with respect to `comp` and `proj`.
3694 //
3695 // Effects: Merges two sorted consecutive ranges `[first, middle)` and
3696 // `[middle, last)`, putting the result of the merge into the range
3697 // `[first, last)`. The resulting range is sorted with respect to `comp` and
3698 // `proj`.
3699 //
3700 // Returns: `last`.
3701 //
3702 // Complexity: Let `N = last - first`: If enough additional memory is available,
3703 // exactly `N - 1` comparisons. Otherwise, `O(N log N)` comparisons. In either
3704 // case, twice as many projections as comparisons.
3705 //
3706 // Remarks: Stable.
3707 //
3708 // Reference: https://wg21.link/alg.merge#:~:text=ranges::inplace_merge(I
3709 template <typename BidirectionalIterator,
3710           typename Comp = ranges::less,
3711           typename Proj = std::identity,
3712           typename = internal::iterator_category_t<BidirectionalIterator>>
3713 constexpr auto inplace_merge(BidirectionalIterator first,
3714                              BidirectionalIterator middle,
3715                              BidirectionalIterator last,
3716                              Comp comp = {},
3717                              Proj proj = {}) {
3718   std::inplace_merge(first, middle, last,
3719                      internal::ProjectedBinaryPredicate(comp, proj, proj));
3720   return last;
3721 }
3722 
3723 // Preconditions: `[begin(range), middle)` and `[middle, end(range))` are valid
3724 // ranges sorted with respect to `comp` and `proj`.
3725 //
3726 // Effects: Merges two sorted consecutive ranges `[begin(range), middle)` and
3727 // `[middle, end(range))`, putting the result of the merge into `range`. The
3728 // resulting range is sorted with respect to `comp` and `proj`.
3729 //
3730 // Returns: `end(range)`.
3731 //
3732 // Complexity: Let `N = size(range)`: If enough additional memory is available,
3733 // exactly `N - 1` comparisons. Otherwise, `O(N log N)` comparisons. In either
3734 // case, twice as many projections as comparisons.
3735 //
3736 // Remarks: Stable.
3737 //
3738 // Reference: https://wg21.link/alg.merge#:~:text=ranges::inplace_merge(R
3739 template <typename Range,
3740           typename Comp = ranges::less,
3741           typename Proj = std::identity,
3742           typename = internal::range_category_t<Range>>
3743 constexpr auto inplace_merge(Range&& range,
3744                              iterator_t<Range> middle,
3745                              Comp comp = {},
3746                              Proj proj = {}) {
3747   return ranges::inplace_merge(ranges::begin(range), middle, ranges::end(range),
3748                                std::move(comp), std::move(proj));
3749 }
3750 
3751 // [alg.set.operations] Set operations on sorted structures
3752 // Reference: https://wg21.link/alg.set.operations
3753 
3754 // [includes] includes
3755 // Reference: https://wg21.link/includes
3756 
3757 // Preconditions: The ranges `[first1, last1)` and `[first2, last2)` are sorted
3758 // with respect to `comp` and `proj1` or `proj2`, respectively.
3759 //
3760 // Returns: `true` if and only if `[first2, last2)` is a subsequence of
3761 // `[first1, last1)`.
3762 //
3763 // Complexity: At most `2 * ((last1 - first1) + (last2 - first2)) - 1`
3764 // comparisons and applications of each projection.
3765 //
3766 // Reference: https://wg21.link/includes#:~:text=ranges::includes(I1
3767 template <
3768     typename InputIterator1,
3769     typename InputIterator2,
3770     typename Comp = ranges::less,
3771     typename Proj1 = std::identity,
3772     typename Proj2 = std::identity,
3773     typename = internal::iterator_category_t<InputIterator1>,
3774     typename = internal::iterator_category_t<InputIterator2>,
3775     typename = std::indirect_result_t<Comp&,
3776                                       std::projected<InputIterator1, Proj1>,
3777                                       std::projected<InputIterator2, Proj2>>,
3778     typename = std::indirect_result_t<Comp&,
3779                                       std::projected<InputIterator2, Proj2>,
3780                                       std::projected<InputIterator1, Proj1>>>
3781 constexpr auto includes(InputIterator1 first1,
3782                         InputIterator1 last1,
3783                         InputIterator2 first2,
3784                         InputIterator2 last2,
3785                         Comp comp = {},
3786                         Proj1 proj1 = {},
3787                         Proj2 proj2 = {}) {
3788   DCHECK(ranges::is_sorted(first1, last1, comp, proj1));
3789   DCHECK(ranges::is_sorted(first2, last2, comp, proj2));
3790   // Needs to opt-in to all permutations, since std::includes expects
3791   // comp(proj1(lhs), proj2(rhs)) and comp(proj2(lhs), proj1(rhs)) to compile.
3792   return std::includes(
3793       first1, last1, first2, last2,
3794       internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2));
3795 }
3796 
3797 // Preconditions: The ranges `range1` and `range2` are sorted with respect to
3798 // `comp` and `proj1` or `proj2`, respectively.
3799 //
3800 // Returns: `true` if and only if `range2` is a subsequence of `range1`.
3801 //
3802 // Complexity: At most `2 * (size(range1) + size(range2)) - 1` comparisons and
3803 // applications of each projection.
3804 //
3805 // Reference: https://wg21.link/includes#:~:text=ranges::includes(R1
3806 template <typename Range1,
3807           typename Range2,
3808           typename Comp = ranges::less,
3809           typename Proj1 = std::identity,
3810           typename Proj2 = std::identity,
3811           typename = internal::range_category_t<Range1>,
3812           typename = internal::range_category_t<Range2>,
3813           typename =
3814               std::indirect_result_t<Comp&,
3815                                      std::projected<iterator_t<Range1>, Proj1>,
3816                                      std::projected<iterator_t<Range2>, Proj2>>,
3817           typename =
3818               std::indirect_result_t<Comp&,
3819                                      std::projected<iterator_t<Range2>, Proj2>,
3820                                      std::projected<iterator_t<Range1>, Proj1>>>
3821 constexpr auto includes(Range1&& range1,
3822                         Range2&& range2,
3823                         Comp comp = {},
3824                         Proj1 proj1 = {},
3825                         Proj2 proj2 = {}) {
3826   return ranges::includes(ranges::begin(range1), ranges::end(range1),
3827                           ranges::begin(range2), ranges::end(range2),
3828                           std::move(comp), std::move(proj1), std::move(proj2));
3829 }
3830 
3831 // [set.union] set_union
3832 // Reference: https://wg21.link/set.union
3833 
3834 // Preconditions: The ranges `[first1, last1)` and `[first2, last2)` are sorted
3835 // with respect to `comp` and `proj1` or `proj2`, respectively. The resulting
3836 // range does not overlap with either of the original ranges.
3837 //
3838 // Effects: Constructs a sorted union of the elements from the two ranges; that
3839 // is, the set of elements that are present in one or both of the ranges.
3840 //
3841 // Returns: The end of the constructed range.
3842 //
3843 // Complexity: At most `2 * ((last1 - first1) + (last2 - first2)) - 1`
3844 // comparisons and applications of each projection.
3845 //
3846 // Remarks: Stable. If `[first1, last1)` contains `m` elements that are
3847 // equivalent to each other and `[first2, last2)` contains `n` elements that are
3848 // equivalent to them, then all `m` elements from the first range are copied to
3849 // the output range, in order, and then the final `max(n - m , 0)` elements from
3850 // the second range are copied to the output range, in order.
3851 //
3852 // Reference: https://wg21.link/set.union#:~:text=ranges::set_union(I1
3853 template <
3854     typename InputIterator1,
3855     typename InputIterator2,
3856     typename OutputIterator,
3857     typename Comp = ranges::less,
3858     typename Proj1 = std::identity,
3859     typename Proj2 = std::identity,
3860     typename = internal::iterator_category_t<InputIterator1>,
3861     typename = internal::iterator_category_t<InputIterator2>,
3862     typename = internal::iterator_category_t<OutputIterator>,
3863     typename = std::indirect_result_t<Comp&,
3864                                       std::projected<InputIterator1, Proj1>,
3865                                       std::projected<InputIterator2, Proj2>>,
3866     typename = std::indirect_result_t<Comp&,
3867                                       std::projected<InputIterator2, Proj2>,
3868                                       std::projected<InputIterator1, Proj1>>>
3869 constexpr auto set_union(InputIterator1 first1,
3870                          InputIterator1 last1,
3871                          InputIterator2 first2,
3872                          InputIterator2 last2,
3873                          OutputIterator result,
3874                          Comp comp = {},
3875                          Proj1 proj1 = {},
3876                          Proj2 proj2 = {}) {
3877   // Needs to opt-in to all permutations, since std::set_union expects
3878   // comp(proj1(lhs), proj2(rhs)) and comp(proj2(lhs), proj1(rhs)) to compile.
3879   return std::set_union(
3880       first1, last1, first2, last2, result,
3881       internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2));
3882 }
3883 
3884 // Preconditions: The ranges `range1` and `range2` are sorted with respect to
3885 // `comp` and `proj1` or `proj2`, respectively. The resulting range does not
3886 // overlap with either of the original ranges.
3887 //
3888 // Effects: Constructs a sorted union of the elements from the two ranges; that
3889 // is, the set of elements that are present in one or both of the ranges.
3890 //
3891 // Returns: The end of the constructed range.
3892 //
3893 // Complexity: At most `2 * (size(range1) + size(range2)) - 1` comparisons and
3894 // applications of each projection.
3895 //
3896 // Remarks: Stable. If `range1` contains `m` elements that are equivalent to
3897 // each other and `range2` contains `n` elements that are equivalent to them,
3898 // then all `m` elements from the first range are copied to the output range, in
3899 // order, and then the final `max(n - m , 0)` elements from the second range are
3900 // copied to the output range, in order.
3901 //
3902 // Reference: https://wg21.link/set.union#:~:text=ranges::set_union(R1
3903 template <typename Range1,
3904           typename Range2,
3905           typename OutputIterator,
3906           typename Comp = ranges::less,
3907           typename Proj1 = std::identity,
3908           typename Proj2 = std::identity,
3909           typename = internal::range_category_t<Range1>,
3910           typename = internal::range_category_t<Range2>,
3911           typename = internal::iterator_category_t<OutputIterator>,
3912           typename =
3913               std::indirect_result_t<Comp&,
3914                                      std::projected<iterator_t<Range1>, Proj1>,
3915                                      std::projected<iterator_t<Range2>, Proj2>>,
3916           typename =
3917               std::indirect_result_t<Comp&,
3918                                      std::projected<iterator_t<Range2>, Proj2>,
3919                                      std::projected<iterator_t<Range1>, Proj1>>>
3920 constexpr auto set_union(Range1&& range1,
3921                          Range2&& range2,
3922                          OutputIterator result,
3923                          Comp comp = {},
3924                          Proj1 proj1 = {},
3925                          Proj2 proj2 = {}) {
3926   return ranges::set_union(ranges::begin(range1), ranges::end(range1),
3927                            ranges::begin(range2), ranges::end(range2), result,
3928                            std::move(comp), std::move(proj1), std::move(proj2));
3929 }
3930 
3931 // [set.intersection] set_intersection
3932 // Reference: https://wg21.link/set.intersection
3933 
3934 // Preconditions: The ranges `[first1, last1)` and `[first2, last2)` are sorted
3935 // with respect to `comp` and `proj1` or `proj2`, respectively. The resulting
3936 // range does not overlap with either of the original ranges.
3937 //
3938 // Effects: Constructs a sorted intersection of the elements from the two
3939 // ranges; that is, the set of elements that are present in both of the ranges.
3940 //
3941 // Returns: The end of the constructed range.
3942 //
3943 // Complexity: At most `2 * ((last1 - first1) + (last2 - first2)) - 1`
3944 // comparisons and applications of each projection.
3945 //
3946 // Remarks: Stable. If `[first1, last1)` contains `m` elements that are
3947 // equivalent to each other and `[first2, last2)` contains `n` elements that are
3948 // equivalent to them, the first `min(m, n)` elements are copied from the first
3949 // range to the output range, in order.
3950 //
3951 // Reference:
3952 // https://wg21.link/set.intersection#:~:text=ranges::set_intersection(I1
3953 template <
3954     typename InputIterator1,
3955     typename InputIterator2,
3956     typename OutputIterator,
3957     typename Comp = ranges::less,
3958     typename Proj1 = std::identity,
3959     typename Proj2 = std::identity,
3960     typename = internal::iterator_category_t<InputIterator1>,
3961     typename = internal::iterator_category_t<InputIterator2>,
3962     typename = internal::iterator_category_t<OutputIterator>,
3963     typename = std::indirect_result_t<Comp&,
3964                                       std::projected<InputIterator1, Proj1>,
3965                                       std::projected<InputIterator2, Proj2>>,
3966     typename = std::indirect_result_t<Comp&,
3967                                       std::projected<InputIterator2, Proj2>,
3968                                       std::projected<InputIterator1, Proj1>>>
3969 constexpr auto set_intersection(InputIterator1 first1,
3970                                 InputIterator1 last1,
3971                                 InputIterator2 first2,
3972                                 InputIterator2 last2,
3973                                 OutputIterator result,
3974                                 Comp comp = {},
3975                                 Proj1 proj1 = {},
3976                                 Proj2 proj2 = {}) {
3977   // Needs to opt-in to all permutations, since std::set_intersection expects
3978   // comp(proj1(lhs), proj2(rhs)) and comp(proj2(lhs), proj1(rhs)) to compile.
3979   return std::set_intersection(
3980       first1, last1, first2, last2, result,
3981       internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2));
3982 }
3983 
3984 // Preconditions: The ranges `range1` and `range2` are sorted with respect to
3985 // `comp` and `proj1` or `proj2`, respectively. The resulting range does not
3986 // overlap with either of the original ranges.
3987 //
3988 // Effects: Constructs a sorted intersection of the elements from the two
3989 // ranges; that is, the set of elements that are present in both of the ranges.
3990 //
3991 // Returns: The end of the constructed range.
3992 //
3993 // Complexity: At most `2 * (size(range1) + size(range2)) - 1` comparisons and
3994 // applications of each projection.
3995 //
3996 // Remarks: Stable. If `range1` contains `m` elements that are equivalent to
3997 // each other and `range2` contains `n` elements that are equivalent to them,
3998 // the first `min(m, n)` elements are copied from the first range to the output
3999 // range, in order.
4000 //
4001 // Reference:
4002 // https://wg21.link/set.intersection#:~:text=ranges::set_intersection(R1
4003 template <typename Range1,
4004           typename Range2,
4005           typename OutputIterator,
4006           typename Comp = ranges::less,
4007           typename Proj1 = std::identity,
4008           typename Proj2 = std::identity,
4009           typename = internal::range_category_t<Range1>,
4010           typename = internal::range_category_t<Range2>,
4011           typename = internal::iterator_category_t<OutputIterator>,
4012           typename =
4013               std::indirect_result_t<Comp&,
4014                                      std::projected<iterator_t<Range1>, Proj1>,
4015                                      std::projected<iterator_t<Range2>, Proj2>>,
4016           typename =
4017               std::indirect_result_t<Comp&,
4018                                      std::projected<iterator_t<Range2>, Proj2>,
4019                                      std::projected<iterator_t<Range1>, Proj1>>>
4020 constexpr auto set_intersection(Range1&& range1,
4021                                 Range2&& range2,
4022                                 OutputIterator result,
4023                                 Comp comp = {},
4024                                 Proj1 proj1 = {},
4025                                 Proj2 proj2 = {}) {
4026   return ranges::set_intersection(ranges::begin(range1), ranges::end(range1),
4027                                   ranges::begin(range2), ranges::end(range2),
4028                                   result, std::move(comp), std::move(proj1),
4029                                   std::move(proj2));
4030 }
4031 
4032 // [set.difference] set_difference
4033 // Reference: https://wg21.link/set.difference
4034 
4035 // Preconditions: The ranges `[first1, last1)` and `[first2, last2)` are sorted
4036 // with respect to `comp` and `proj1` or `proj2`, respectively. The resulting
4037 // range does not overlap with either of the original ranges.
4038 //
4039 // Effects: Copies the elements of the range `[first1, last1)` which are not
4040 // present in the range `[first2, last2)` to the range beginning at `result`.
4041 // The elements in the constructed range are sorted.
4042 //
4043 // Returns: The end of the constructed range.
4044 //
4045 // Complexity: At most `2 * ((last1 - first1) + (last2 - first2)) - 1`
4046 // comparisons and applications of each projection.
4047 //
4048 // Remarks: If `[first1, last1)` contains `m` elements that are equivalent to
4049 // each other and `[first2, last2)` contains `n` elements that are equivalent to
4050 // them, the last `max(m - n, 0)` elements from `[first1, last1)` are copied to
4051 // the output range, in order.
4052 //
4053 // Reference:
4054 // https://wg21.link/set.difference#:~:text=ranges::set_difference(I1
4055 template <
4056     typename InputIterator1,
4057     typename InputIterator2,
4058     typename OutputIterator,
4059     typename Comp = ranges::less,
4060     typename Proj1 = std::identity,
4061     typename Proj2 = std::identity,
4062     typename = internal::iterator_category_t<InputIterator1>,
4063     typename = internal::iterator_category_t<InputIterator2>,
4064     typename = internal::iterator_category_t<OutputIterator>,
4065     typename = std::indirect_result_t<Comp&,
4066                                       std::projected<InputIterator1, Proj1>,
4067                                       std::projected<InputIterator2, Proj2>>,
4068     typename = std::indirect_result_t<Comp&,
4069                                       std::projected<InputIterator2, Proj2>,
4070                                       std::projected<InputIterator1, Proj1>>>
4071 constexpr auto set_difference(InputIterator1 first1,
4072                               InputIterator1 last1,
4073                               InputIterator2 first2,
4074                               InputIterator2 last2,
4075                               OutputIterator result,
4076                               Comp comp = {},
4077                               Proj1 proj1 = {},
4078                               Proj2 proj2 = {}) {
4079   // Needs to opt-in to all permutations, since std::set_difference expects
4080   // comp(proj1(lhs), proj2(rhs)) and comp(proj2(lhs), proj1(rhs)) to compile.
4081   return std::set_difference(
4082       first1, last1, first2, last2, result,
4083       internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2));
4084 }
4085 
4086 // Preconditions: The ranges `range1` and `range2` are sorted with respect to
4087 // `comp` and `proj1` or `proj2`, respectively. The resulting range does not
4088 // overlap with either of the original ranges.
4089 //
4090 // Effects: Copies the elements of `range1` which are not present in `range2`
4091 // to the range beginning at `result`. The elements in the constructed range are
4092 // sorted.
4093 //
4094 // Returns: The end of the constructed range.
4095 //
4096 // Complexity: At most `2 * (size(range1) + size(range2)) - 1` comparisons and
4097 // applications of each projection.
4098 //
4099 // Remarks: Stable. If `range1` contains `m` elements that are equivalent to
4100 // each other and `range2` contains `n` elements that are equivalent to them,
4101 // the last `max(m - n, 0)` elements from `range1` are copied to the output
4102 // range, in order.
4103 //
4104 // Reference:
4105 // https://wg21.link/set.difference#:~:text=ranges::set_difference(R1
4106 template <typename Range1,
4107           typename Range2,
4108           typename OutputIterator,
4109           typename Comp = ranges::less,
4110           typename Proj1 = std::identity,
4111           typename Proj2 = std::identity,
4112           typename = internal::range_category_t<Range1>,
4113           typename = internal::range_category_t<Range2>,
4114           typename = internal::iterator_category_t<OutputIterator>,
4115           typename =
4116               std::indirect_result_t<Comp&,
4117                                      std::projected<iterator_t<Range1>, Proj1>,
4118                                      std::projected<iterator_t<Range2>, Proj2>>,
4119           typename =
4120               std::indirect_result_t<Comp&,
4121                                      std::projected<iterator_t<Range2>, Proj2>,
4122                                      std::projected<iterator_t<Range1>, Proj1>>>
4123 constexpr auto set_difference(Range1&& range1,
4124                               Range2&& range2,
4125                               OutputIterator result,
4126                               Comp comp = {},
4127                               Proj1 proj1 = {},
4128                               Proj2 proj2 = {}) {
4129   return ranges::set_difference(ranges::begin(range1), ranges::end(range1),
4130                                 ranges::begin(range2), ranges::end(range2),
4131                                 result, std::move(comp), std::move(proj1),
4132                                 std::move(proj2));
4133 }
4134 
4135 // [set.symmetric.difference] set_symmetric_difference
4136 // Reference: https://wg21.link/set.symmetric.difference
4137 
4138 // Preconditions: The ranges `[first1, last1)` and `[first2, last2)` are sorted
4139 // with respect to `comp` and `proj1` or `proj2`, respectively. The resulting
4140 // range does not overlap with either of the original ranges.
4141 //
4142 // Effects: Copies the elements of the range `[first1, last1)` that are not
4143 // present in the range `[first2, last2)`, and the elements of the range
4144 // `[first2, last2)` that are not present in the range `[first1, last1)` to the
4145 // range beginning at `result`. The elements in the constructed range are
4146 // sorted.
4147 //
4148 // Returns: The end of the constructed range.
4149 //
4150 // Complexity: At most `2 * ((last1 - first1) + (last2 - first2)) - 1`
4151 // comparisons and applications of each projection.
4152 //
4153 // Remarks: Stable. If `[first1, last1)` contains `m` elements that are
4154 // equivalent to each other and `[first2, last2)` contains `n` elements that are
4155 // equivalent to them, then `|m - n|` of those elements shall be copied to the
4156 // output range: the last `m - n` of these elements from `[first1, last1)` if
4157 // `m > n`, and the last `n - m` of these elements from `[first2, last2)` if
4158 // `m < n`. In either case, the elements are copied in order.
4159 //
4160 // Reference:
4161 // https://wg21.link/set.symmetric.difference#:~:text=set_symmetric_difference(I1
4162 template <
4163     typename InputIterator1,
4164     typename InputIterator2,
4165     typename OutputIterator,
4166     typename Comp = ranges::less,
4167     typename Proj1 = std::identity,
4168     typename Proj2 = std::identity,
4169     typename = internal::iterator_category_t<InputIterator1>,
4170     typename = internal::iterator_category_t<InputIterator2>,
4171     typename = internal::iterator_category_t<OutputIterator>,
4172     typename = std::indirect_result_t<Comp&,
4173                                       std::projected<InputIterator1, Proj1>,
4174                                       std::projected<InputIterator2, Proj2>>,
4175     typename = std::indirect_result_t<Comp&,
4176                                       std::projected<InputIterator2, Proj2>,
4177                                       std::projected<InputIterator1, Proj1>>>
4178 constexpr auto set_symmetric_difference(InputIterator1 first1,
4179                                         InputIterator1 last1,
4180                                         InputIterator2 first2,
4181                                         InputIterator2 last2,
4182                                         OutputIterator result,
4183                                         Comp comp = {},
4184                                         Proj1 proj1 = {},
4185                                         Proj2 proj2 = {}) {
4186   // Needs to opt-in to all permutations, since std::set_symmetric_difference
4187   // expects comp(proj1(lhs), proj2(rhs)) and comp(proj2(lhs), proj1(rhs)) to
4188   // compile.
4189   return std::set_symmetric_difference(
4190       first1, last1, first2, last2, result,
4191       internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2));
4192 }
4193 
4194 // Preconditions: The ranges `range1` and `range2` are sorted with respect to
4195 // `comp` and `proj1` or `proj2`, respectively. The resulting range does not
4196 // overlap with either of the original ranges.
4197 //
4198 // Effects: Copies the elements of `range1` that are not present in `range2`,
4199 // and the elements of `range2` that are not present in `range1` to the range
4200 // beginning at `result`. The elements in the constructed range are sorted.
4201 //
4202 // Returns: The end of the constructed range.
4203 //
4204 // Complexity: At most `2 * (size(range1) + size(range2)) - 1` comparisons and
4205 // applications of each projection.
4206 //
4207 // Remarks: Stable. If `range1` contains `m` elements that are equivalent to
4208 // each other and `range2` contains `n` elements that are equivalent to them,
4209 // then `|m - n|` of those elements shall be copied to the output range: the
4210 // last `m - n` of these elements from `range1` if `m > n`, and the last `n - m`
4211 // of these elements from `range2` if `m < n`. In either case, the elements are
4212 // copied in order.
4213 //
4214 // Reference:
4215 // https://wg21.link/set.symmetric.difference#:~:text=set_symmetric_difference(R1
4216 template <typename Range1,
4217           typename Range2,
4218           typename OutputIterator,
4219           typename Comp = ranges::less,
4220           typename Proj1 = std::identity,
4221           typename Proj2 = std::identity,
4222           typename = internal::range_category_t<Range1>,
4223           typename = internal::range_category_t<Range2>,
4224           typename = internal::iterator_category_t<OutputIterator>,
4225           typename =
4226               std::indirect_result_t<Comp&,
4227                                      std::projected<iterator_t<Range1>, Proj1>,
4228                                      std::projected<iterator_t<Range2>, Proj2>>,
4229           typename =
4230               std::indirect_result_t<Comp&,
4231                                      std::projected<iterator_t<Range2>, Proj2>,
4232                                      std::projected<iterator_t<Range1>, Proj1>>>
4233 constexpr auto set_symmetric_difference(Range1&& range1,
4234                                         Range2&& range2,
4235                                         OutputIterator result,
4236                                         Comp comp = {},
4237                                         Proj1 proj1 = {},
4238                                         Proj2 proj2 = {}) {
4239   return ranges::set_symmetric_difference(
4240       ranges::begin(range1), ranges::end(range1), ranges::begin(range2),
4241       ranges::end(range2), result, std::move(comp), std::move(proj1),
4242       std::move(proj2));
4243 }
4244 
4245 // [alg.heap.operations] Heap operations
4246 // Reference: https://wg21.link/alg.heap.operations
4247 
4248 // [push.heap] push_heap
4249 // Reference: https://wg21.link/push.heap
4250 
4251 // Preconditions: The range `[first, last - 1)` is a valid heap with respect to
4252 // `comp` and `proj`.
4253 //
4254 // Effects: Places the value in the location `last - 1` into the resulting heap
4255 // `[first, last)`.
4256 //
4257 // Returns: `last`.
4258 //
4259 // Complexity: At most `log(last - first)` comparisons and twice as many
4260 // projections.
4261 //
4262 // Reference: https://wg21.link/push.heap#:~:text=ranges::push_heap(I
4263 template <typename RandomAccessIterator,
4264           typename Comp = ranges::less,
4265           typename Proj = std::identity,
4266           typename = internal::iterator_category_t<RandomAccessIterator>,
4267           typename = std::indirect_result_t<
4268               Comp&,
4269               std::projected<RandomAccessIterator, Proj>,
4270               std::projected<RandomAccessIterator, Proj>>>
4271 constexpr auto push_heap(RandomAccessIterator first,
4272                          RandomAccessIterator last,
4273                          Comp comp = {},
4274                          Proj proj = {}) {
4275   std::push_heap(first, last,
4276                  internal::ProjectedBinaryPredicate(comp, proj, proj));
4277   return last;
4278 }
4279 
4280 // Preconditions: The range `[begin(range), end(range) - 1)` is a valid heap
4281 // with respect to `comp` and `proj`.
4282 //
4283 // Effects: Places the value in the location `end(range) - 1` into the resulting
4284 // heap `range`.
4285 //
4286 // Returns: `end(range)`.
4287 //
4288 // Complexity: At most `log(size(range))` comparisons and twice as many
4289 // projections.
4290 //
4291 // Reference: https://wg21.link/push.heap#:~:text=ranges::push_heap(R
4292 template <
4293     typename Range,
4294     typename Comp = ranges::less,
4295     typename Proj = std::identity,
4296     typename = internal::range_category_t<Range>,
4297     typename = std::indirect_result_t<Comp&,
4298                                       std::projected<iterator_t<Range>, Proj>,
4299                                       std::projected<iterator_t<Range>, Proj>>>
4300 constexpr auto push_heap(Range&& range, Comp comp = {}, Proj proj = {}) {
4301   return ranges::push_heap(ranges::begin(range), ranges::end(range),
4302                            std::move(comp), std::move(proj));
4303 }
4304 
4305 // [pop.heap] pop_heap
4306 // Reference: https://wg21.link/pop.heap
4307 
4308 // Preconditions: The range `[first, last)` is a valid non-empty heap with
4309 // respect to `comp` and `proj`.
4310 //
4311 // Effects: Swaps the value in the location `first` with the value in the
4312 // location `last - 1` and makes `[first, last - 1)` into a heap with respect to
4313 // `comp` and `proj`.
4314 //
4315 // Returns: `last`.
4316 //
4317 // Complexity: At most `2 log(last - first)` comparisons and twice as many
4318 // projections.
4319 //
4320 // Reference: https://wg21.link/pop.heap#:~:text=ranges::pop_heap(I
4321 template <typename RandomAccessIterator,
4322           typename Comp = ranges::less,
4323           typename Proj = std::identity,
4324           typename = internal::iterator_category_t<RandomAccessIterator>,
4325           typename = std::indirect_result_t<
4326               Comp&,
4327               std::projected<RandomAccessIterator, Proj>,
4328               std::projected<RandomAccessIterator, Proj>>>
4329 constexpr auto pop_heap(RandomAccessIterator first,
4330                         RandomAccessIterator last,
4331                         Comp comp = {},
4332                         Proj proj = {}) {
4333   std::pop_heap(first, last,
4334                 internal::ProjectedBinaryPredicate(comp, proj, proj));
4335   return last;
4336 }
4337 
4338 // Preconditions: `range` is a valid non-empty heap with respect to `comp` and
4339 // `proj`.
4340 //
4341 // Effects: Swaps the value in the location `begin(range)` with the value in the
4342 // location `end(range) - 1` and makes `[begin(range), end(range) - 1)` into a
4343 // heap with respect to `comp` and `proj`.
4344 //
4345 // Returns: `end(range)`.
4346 //
4347 // Complexity: At most `2 log(size(range))` comparisons and twice as many
4348 // projections.
4349 //
4350 // Reference: https://wg21.link/pop.heap#:~:text=ranges::pop_heap(R
4351 template <
4352     typename Range,
4353     typename Comp = ranges::less,
4354     typename Proj = std::identity,
4355     typename = internal::range_category_t<Range>,
4356     typename = std::indirect_result_t<Comp&,
4357                                       std::projected<iterator_t<Range>, Proj>,
4358                                       std::projected<iterator_t<Range>, Proj>>>
4359 constexpr auto pop_heap(Range&& range, Comp comp = {}, Proj proj = {}) {
4360   return ranges::pop_heap(ranges::begin(range), ranges::end(range),
4361                           std::move(comp), std::move(proj));
4362 }
4363 
4364 // [make.heap] make_heap
4365 // Reference: https://wg21.link/make.heap
4366 
4367 // Effects: Constructs a heap with respect to `comp` and `proj` out of the range
4368 // `[first, last)`.
4369 //
4370 // Returns: `last`.
4371 //
4372 // Complexity: At most `3 * (last - first)` comparisons and twice as many
4373 // projections.
4374 //
4375 // Reference: https://wg21.link/make.heap#:~:text=ranges::make_heap(I
4376 template <typename RandomAccessIterator,
4377           typename Comp = ranges::less,
4378           typename Proj = std::identity,
4379           typename = internal::iterator_category_t<RandomAccessIterator>,
4380           typename = std::indirect_result_t<
4381               Comp&,
4382               std::projected<RandomAccessIterator, Proj>,
4383               std::projected<RandomAccessIterator, Proj>>>
4384 constexpr auto make_heap(RandomAccessIterator first,
4385                          RandomAccessIterator last,
4386                          Comp comp = {},
4387                          Proj proj = {}) {
4388   std::make_heap(first, last,
4389                  internal::ProjectedBinaryPredicate(comp, proj, proj));
4390   return last;
4391 }
4392 
4393 // Effects: Constructs a heap with respect to `comp` and `proj` out of `range`.
4394 //
4395 // Returns: `end(range)`.
4396 //
4397 // Complexity: At most `3 * size(range)` comparisons and twice as many
4398 // projections.
4399 //
4400 // Reference: https://wg21.link/make.heap#:~:text=ranges::make_heap(R
4401 template <
4402     typename Range,
4403     typename Comp = ranges::less,
4404     typename Proj = std::identity,
4405     typename = internal::range_category_t<Range>,
4406     typename = std::indirect_result_t<Comp&,
4407                                       std::projected<iterator_t<Range>, Proj>,
4408                                       std::projected<iterator_t<Range>, Proj>>>
4409 constexpr auto make_heap(Range&& range, Comp comp = {}, Proj proj = {}) {
4410   return ranges::make_heap(ranges::begin(range), ranges::end(range),
4411                            std::move(comp), std::move(proj));
4412 }
4413 
4414 // [sort.heap] sort_heap
4415 // Reference: https://wg21.link/sort.heap
4416 
4417 // Preconditions: The range `[first, last)` is a valid heap with respect to
4418 // `comp` and `proj`.
4419 //
4420 // Effects: Sorts elements in the heap `[first, last)` with respect to `comp`
4421 // and `proj`.
4422 //
4423 // Returns: `last`.
4424 //
4425 // Complexity: At most `2 N log N` comparisons, where `N = last - first`, and
4426 // twice as many projections.
4427 //
4428 // Reference: https://wg21.link/sort.heap#:~:text=ranges::sort_heap(I
4429 template <typename RandomAccessIterator,
4430           typename Comp = ranges::less,
4431           typename Proj = std::identity,
4432           typename = internal::iterator_category_t<RandomAccessIterator>,
4433           typename = std::indirect_result_t<
4434               Comp&,
4435               std::projected<RandomAccessIterator, Proj>,
4436               std::projected<RandomAccessIterator, Proj>>>
4437 constexpr auto sort_heap(RandomAccessIterator first,
4438                          RandomAccessIterator last,
4439                          Comp comp = {},
4440                          Proj proj = {}) {
4441   std::sort_heap(first, last,
4442                  internal::ProjectedBinaryPredicate(comp, proj, proj));
4443   return last;
4444 }
4445 
4446 // Preconditions: `range` is a valid heap with respect to `comp` and `proj`.
4447 //
4448 // Effects: Sorts elements in the heap `range` with respect to `comp` and
4449 // `proj`.
4450 //
4451 // Returns: `end(range)`.
4452 //
4453 // Complexity: At most `2 N log N` comparisons, where `N = size(range)`, and
4454 // twice as many projections.
4455 //
4456 // Reference: https://wg21.link/sort.heap#:~:text=ranges::sort_heap(R
4457 template <
4458     typename Range,
4459     typename Comp = ranges::less,
4460     typename Proj = std::identity,
4461     typename = internal::range_category_t<Range>,
4462     typename = std::indirect_result_t<Comp&,
4463                                       std::projected<iterator_t<Range>, Proj>,
4464                                       std::projected<iterator_t<Range>, Proj>>>
4465 constexpr auto sort_heap(Range&& range, Comp comp = {}, Proj proj = {}) {
4466   return ranges::sort_heap(ranges::begin(range), ranges::end(range),
4467                            std::move(comp), std::move(proj));
4468 }
4469 
4470 // [is.heap] is_heap
4471 // Reference: https://wg21.link/is.heap
4472 
4473 // Returns: Whether the range `[first, last)` is a heap with respect to `comp`
4474 // and `proj`.
4475 //
4476 // Complexity: Linear.
4477 //
4478 // Reference: https://wg21.link/is.heap#:~:text=ranges::is_heap(I
4479 template <typename RandomAccessIterator,
4480           typename Comp = ranges::less,
4481           typename Proj = std::identity,
4482           typename = internal::iterator_category_t<RandomAccessIterator>,
4483           typename = std::indirect_result_t<
4484               Comp&,
4485               std::projected<RandomAccessIterator, Proj>,
4486               std::projected<RandomAccessIterator, Proj>>>
4487 constexpr auto is_heap(RandomAccessIterator first,
4488                        RandomAccessIterator last,
4489                        Comp comp = {},
4490                        Proj proj = {}) {
4491   return std::is_heap(first, last,
4492                       internal::ProjectedBinaryPredicate(comp, proj, proj));
4493 }
4494 
4495 // Returns: Whether `range` is a heap with respect to `comp` and `proj`.
4496 //
4497 // Complexity: Linear.
4498 //
4499 // Reference: https://wg21.link/is.heap#:~:text=ranges::is_heap(R
4500 template <
4501     typename Range,
4502     typename Comp = ranges::less,
4503     typename Proj = std::identity,
4504     typename = internal::range_category_t<Range>,
4505     typename = std::indirect_result_t<Comp&,
4506                                       std::projected<iterator_t<Range>, Proj>,
4507                                       std::projected<iterator_t<Range>, Proj>>>
4508 constexpr auto is_heap(Range&& range, Comp comp = {}, Proj proj = {}) {
4509   return ranges::is_heap(ranges::begin(range), ranges::end(range),
4510                          std::move(comp), std::move(proj));
4511 }
4512 
4513 // Returns: The last iterator `i` in `[first, last]` for which the range
4514 // `[first, i)` is a heap with respect to `comp` and `proj`.
4515 //
4516 // Complexity: Linear.
4517 //
4518 // Reference: https://wg21.link/is.heap#:~:text=ranges::is_heap_until(I
4519 template <typename RandomAccessIterator,
4520           typename Comp = ranges::less,
4521           typename Proj = std::identity,
4522           typename = internal::iterator_category_t<RandomAccessIterator>,
4523           typename = std::indirect_result_t<
4524               Comp&,
4525               std::projected<RandomAccessIterator, Proj>,
4526               std::projected<RandomAccessIterator, Proj>>>
4527 constexpr auto is_heap_until(RandomAccessIterator first,
4528                              RandomAccessIterator last,
4529                              Comp comp = {},
4530                              Proj proj = {}) {
4531   return std::is_heap_until(
4532       first, last, internal::ProjectedBinaryPredicate(comp, proj, proj));
4533 }
4534 
4535 // Returns: The last iterator `i` in `[begin(range), end(range)]` for which the
4536 // range `[begin(range), i)` is a heap with respect to `comp` and `proj`.
4537 //
4538 // Complexity: Linear.
4539 //
4540 // Reference: https://wg21.link/is.heap#:~:text=ranges::is_heap_until(R
4541 template <
4542     typename Range,
4543     typename Comp = ranges::less,
4544     typename Proj = std::identity,
4545     typename = internal::range_category_t<Range>,
4546     typename = std::indirect_result_t<Comp&,
4547                                       std::projected<iterator_t<Range>, Proj>,
4548                                       std::projected<iterator_t<Range>, Proj>>>
4549 constexpr auto is_heap_until(Range&& range, Comp comp = {}, Proj proj = {}) {
4550   return ranges::is_heap_until(ranges::begin(range), ranges::end(range),
4551                                std::move(comp), std::move(proj));
4552 }
4553 
4554 // [alg.min.max] Minimum and maximum
4555 // Reference: https://wg21.link/alg.min.max
4556 
4557 // Returns: The smaller value. Returns the first argument when the arguments are
4558 // equivalent.
4559 //
4560 // Complexity: Exactly one comparison and two applications of the projection, if
4561 // any.
4562 //
4563 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::min
4564 template <typename T,
4565           typename Comp = ranges::less,
4566           typename Proj = std::identity>
4567 constexpr const T& min(const T& a, const T& b, Comp comp = {}, Proj proj = {}) {
4568   return std::invoke(comp, std::invoke(proj, b), std::invoke(proj, a)) ? b : a;
4569 }
4570 
4571 // Preconditions: `!empty(ilist)`.
4572 //
4573 // Returns: The smallest value in the input range. Returns a copy of the
4574 // leftmost element when several elements are equivalent to the smallest.
4575 //
4576 // Complexity: Exactly `size(ilist) - 1` comparisons and twice as many
4577 // applications of the projection, if any.
4578 //
4579 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::min(initializer_list
4580 template <typename T,
4581           typename Comp = ranges::less,
4582           typename Proj = std::identity>
4583 constexpr T min(std::initializer_list<T> ilist,
4584                 Comp comp = {},
4585                 Proj proj = {}) {
4586   return *std::min_element(
4587       ilist.begin(), ilist.end(),
4588       internal::ProjectedBinaryPredicate(comp, proj, proj));
4589 }
4590 
4591 // Preconditions: `!empty(range)`.
4592 //
4593 // Returns: The smallest value in the input range. Returns a copy of the
4594 // leftmost element when several elements are equivalent to the smallest.
4595 //
4596 // Complexity: Exactly `size(range) - 1` comparisons and twice as many
4597 // applications of the projection, if any.
4598 //
4599 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::min(R
4600 template <typename Range,
4601           typename Comp = ranges::less,
4602           typename Proj = std::identity,
4603           typename = internal::range_category_t<Range>>
4604 constexpr auto min(Range&& range, Comp comp = {}, Proj proj = {}) {
4605   return *std::min_element(
4606       ranges::begin(range), ranges::end(range),
4607       internal::ProjectedBinaryPredicate(comp, proj, proj));
4608 }
4609 
4610 // Returns: The larger value. Returns the first argument when the arguments are
4611 // equivalent.
4612 //
4613 // Complexity: Exactly one comparison and two applications of the projection, if
4614 // any.
4615 //
4616 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::max
4617 template <typename T,
4618           typename Comp = ranges::less,
4619           typename Proj = std::identity>
4620 constexpr const T& max(const T& a, const T& b, Comp comp = {}, Proj proj = {}) {
4621   return std::invoke(comp, std::invoke(proj, a), std::invoke(proj, b)) ? b : a;
4622 }
4623 
4624 // Preconditions: `!empty(ilist)`.
4625 //
4626 // Returns: The largest value in the input range. Returns a copy of the leftmost
4627 // element when several elements are equivalent to the largest.
4628 //
4629 // Complexity: Exactly `size(ilist) - 1` comparisons and twice as many
4630 // applications of the projection, if any.
4631 //
4632 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::max(initializer_list
4633 template <typename T,
4634           typename Comp = ranges::less,
4635           typename Proj = std::identity>
4636 constexpr T max(std::initializer_list<T> ilist,
4637                 Comp comp = {},
4638                 Proj proj = {}) {
4639   return *std::max_element(
4640       ilist.begin(), ilist.end(),
4641       internal::ProjectedBinaryPredicate(comp, proj, proj));
4642 }
4643 
4644 // Preconditions: `!empty(range)`.
4645 //
4646 // Returns: The largest value in the input range. Returns a copy of the leftmost
4647 // element when several elements are equivalent to the smallest.
4648 //
4649 // Complexity: Exactly `size(range) - 1` comparisons and twice as many
4650 // applications of the projection, if any.
4651 //
4652 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::max(R
4653 template <typename Range,
4654           typename Comp = ranges::less,
4655           typename Proj = std::identity,
4656           typename = internal::range_category_t<Range>>
4657 constexpr auto max(Range&& range, Comp comp = {}, Proj proj = {}) {
4658   return *std::max_element(
4659       ranges::begin(range), ranges::end(range),
4660       internal::ProjectedBinaryPredicate(comp, proj, proj));
4661 }
4662 
4663 // Returns: `{b, a}` if `b` is smaller than `a`, and `{a, b}` otherwise.
4664 //
4665 // Complexity: Exactly one comparison and two applications of the projection, if
4666 // any.
4667 //
4668 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::minmax
4669 template <typename T,
4670           typename Comp = ranges::less,
4671           typename Proj = std::identity>
4672 constexpr auto minmax(const T& a, const T& b, Comp comp = {}, Proj proj = {}) {
4673   return std::minmax(a, b,
4674                      internal::ProjectedBinaryPredicate(comp, proj, proj));
4675 }
4676 
4677 // Preconditions: `!empty(ilist)`.
4678 //
4679 // Returns: Let `X` be the return type. Returns `X{x, y}`, where `x` is a copy
4680 // of the leftmost element with the smallest value and `y` a copy of the
4681 // rightmost element with the largest value in the input range.
4682 //
4683 // Complexity: At most `(3/2) size(ilist)` applications of the corresponding
4684 // predicate and twice as many applications of the projection, if any.
4685 //
4686 // Reference:
4687 // https://wg21.link/alg.min.max#:~:text=ranges::minmax(initializer_list
4688 template <typename T,
4689           typename Comp = ranges::less,
4690           typename Proj = std::identity>
4691 constexpr auto minmax(std::initializer_list<T> ilist,
4692                       Comp comp = {},
4693                       Proj proj = {}) {
4694   auto it =
4695       std::minmax_element(ranges::begin(ilist), ranges::end(ilist),
4696                           internal::ProjectedBinaryPredicate(comp, proj, proj));
4697   return std::pair<T, T>{*it.first, *it.second};
4698 }
4699 
4700 // Preconditions: `!empty(range)`.
4701 //
4702 // Returns: Let `X` be the return type. Returns `X{x, y}`, where `x` is a copy
4703 // of the leftmost element with the smallest value and `y` a copy of the
4704 // rightmost element with the largest value in the input range.
4705 //
4706 // Complexity: At most `(3/2) size(range)` applications of the corresponding
4707 // predicate and twice as many applications of the projection, if any.
4708 //
4709 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::minmax(R
4710 template <typename Range,
4711           typename Comp = ranges::less,
4712           typename Proj = std::identity,
4713           typename = internal::range_category_t<Range>>
4714 constexpr auto minmax(Range&& range, Comp comp = {}, Proj proj = {}) {
4715   using T = range_value_t<Range>;
4716   auto it =
4717       std::minmax_element(ranges::begin(range), ranges::end(range),
4718                           internal::ProjectedBinaryPredicate(comp, proj, proj));
4719   return std::pair<T, T>{*it.first, *it.second};
4720 }
4721 
4722 // Returns: The first iterator i in the range `[first, last)` such that for
4723 // every iterator `j` in the range `[first, last)`,
4724 // `bool(invoke(comp, invoke(proj, *j), invoke(proj, *i)))` is `false`. Returns
4725 // `last` if `first == last`.
4726 //
4727 // Complexity: Exactly `max(last - first - 1, 0)` comparisons and twice as
4728 // many projections.
4729 //
4730 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::min_element(I
4731 template <
4732     typename ForwardIterator,
4733     typename Comp = ranges::less,
4734     typename Proj = std::identity,
4735     typename = internal::iterator_category_t<ForwardIterator>,
4736     typename = std::indirect_result_t<Comp&,
4737                                       std::projected<ForwardIterator, Proj>,
4738                                       std::projected<ForwardIterator, Proj>>>
4739 constexpr auto min_element(ForwardIterator first,
4740                            ForwardIterator last,
4741                            Comp comp = {},
4742                            Proj proj = {}) {
4743   return std::min_element(first, last,
4744                           internal::ProjectedBinaryPredicate(comp, proj, proj));
4745 }
4746 
4747 // Returns: The first iterator i in `range` such that for every iterator `j` in
4748 // `range`, `bool(invoke(comp, invoke(proj, *j), invoke(proj, *i)))` is `false`.
4749 // Returns `end(range)` if `empty(range)`.
4750 //
4751 // Complexity: Exactly `max(size(range) - 1, 0)` comparisons and twice as many
4752 // projections.
4753 //
4754 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::min_element(R
4755 template <
4756     typename Range,
4757     typename Comp = ranges::less,
4758     typename Proj = std::identity,
4759     typename = internal::range_category_t<Range>,
4760     typename = std::indirect_result_t<Comp&,
4761                                       std::projected<iterator_t<Range>, Proj>,
4762                                       std::projected<iterator_t<Range>, Proj>>>
4763 constexpr auto min_element(Range&& range, Comp comp = {}, Proj proj = {}) {
4764   return ranges::min_element(ranges::begin(range), ranges::end(range),
4765                              std::move(comp), std::move(proj));
4766 }
4767 
4768 // Returns: The first iterator i in the range `[first, last)` such that for
4769 // every iterator `j` in the range `[first, last)`,
4770 // `bool(invoke(comp, invoke(proj, *i), invoke(proj, *j)))` is `false`.
4771 // Returns `last` if `first == last`.
4772 //
4773 // Complexity: Exactly `max(last - first - 1, 0)` comparisons and twice as
4774 // many projections.
4775 //
4776 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::max_element(I
4777 template <
4778     typename ForwardIterator,
4779     typename Comp = ranges::less,
4780     typename Proj = std::identity,
4781     typename = internal::iterator_category_t<ForwardIterator>,
4782     typename = std::indirect_result_t<Comp&,
4783                                       std::projected<ForwardIterator, Proj>,
4784                                       std::projected<ForwardIterator, Proj>>>
4785 constexpr auto max_element(ForwardIterator first,
4786                            ForwardIterator last,
4787                            Comp comp = {},
4788                            Proj proj = {}) {
4789   return std::max_element(first, last,
4790                           internal::ProjectedBinaryPredicate(comp, proj, proj));
4791 }
4792 
4793 // Returns: The first iterator i in `range` such that for every iterator `j`
4794 // in `range`, `bool(invoke(comp, invoke(proj, *j), invoke(proj, *j)))` is
4795 // `false`. Returns `end(range)` if `empty(range)`.
4796 //
4797 // Complexity: Exactly `max(size(range) - 1, 0)` comparisons and twice as many
4798 // projections.
4799 //
4800 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::max_element(R
4801 template <
4802     typename Range,
4803     typename Comp = ranges::less,
4804     typename Proj = std::identity,
4805     typename = internal::range_category_t<Range>,
4806     typename = std::indirect_result_t<Comp&,
4807                                       std::projected<iterator_t<Range>, Proj>,
4808                                       std::projected<iterator_t<Range>, Proj>>>
4809 constexpr auto max_element(Range&& range, Comp comp = {}, Proj proj = {}) {
4810   return ranges::max_element(ranges::begin(range), ranges::end(range),
4811                              std::move(comp), std::move(proj));
4812 }
4813 
4814 // Returns: `{first, first}` if `[first, last)` is empty, otherwise `{m, M}`,
4815 // where `m` is the first iterator in `[first, last)` such that no iterator in
4816 // the range refers to a smaller element, and where `M` is the last iterator
4817 // in
4818 // `[first, last)` such that no iterator in the range refers to a larger
4819 // element.
4820 //
4821 // Complexity: Let `N` be `last - first`. At most `max(3/2 (N − 1), 0)`
4822 // comparisons and twice as many applications of the projection, if any.
4823 //
4824 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::minmax_element(I
4825 template <
4826     typename ForwardIterator,
4827     typename Comp = ranges::less,
4828     typename Proj = std::identity,
4829     typename = internal::iterator_category_t<ForwardIterator>,
4830     typename = std::indirect_result_t<Comp&,
4831                                       std::projected<ForwardIterator, Proj>,
4832                                       std::projected<ForwardIterator, Proj>>>
4833 constexpr auto minmax_element(ForwardIterator first,
4834                               ForwardIterator last,
4835                               Comp comp = {},
4836                               Proj proj = {}) {
4837   return std::minmax_element(
4838       first, last, internal::ProjectedBinaryPredicate(comp, proj, proj));
4839 }
4840 
4841 // Returns: `{begin(range), begin(range)}` if `range` is empty, otherwise
4842 // `{m, M}`, where `m` is the first iterator in `range` such that no iterator
4843 // in the range refers to a smaller element, and where `M` is the last
4844 // iterator in `range` such that no iterator in the range refers to a larger
4845 // element.
4846 //
4847 // Complexity: Let `N` be `size(range)`. At most `max(3/2 (N − 1), 0)`
4848 // comparisons and twice as many applications of the projection, if any.
4849 //
4850 // Reference: https://wg21.link/alg.min.max#:~:text=ranges::minmax_element(R
4851 template <
4852     typename Range,
4853     typename Comp = ranges::less,
4854     typename Proj = std::identity,
4855     typename = internal::range_category_t<Range>,
4856     typename = std::indirect_result_t<Comp&,
4857                                       std::projected<iterator_t<Range>, Proj>,
4858                                       std::projected<iterator_t<Range>, Proj>>>
4859 constexpr auto minmax_element(Range&& range, Comp comp = {}, Proj proj = {}) {
4860   return ranges::minmax_element(ranges::begin(range), ranges::end(range),
4861                                 std::move(comp), std::move(proj));
4862 }
4863 
4864 // [alg.clamp] Bounded value
4865 // Reference: https://wg21.link/alg.clamp
4866 
4867 // Preconditions: `bool(invoke(comp, invoke(proj, hi), invoke(proj, lo)))` is
4868 // `false`.
4869 //
4870 // Returns: `lo` if `bool(invoke(comp, invoke(proj, v), invoke(proj, lo)))` is
4871 // `true`, `hi` if `bool(invoke(comp, invoke(proj, hi), invoke(proj, v)))` is
4872 // `true`, otherwise `v`.
4873 //
4874 // Complexity: At most two comparisons and three applications of the
4875 // projection.
4876 //
4877 // Reference: https://wg21.link/alg.clamp#:~:text=ranges::clamp
4878 template <typename T,
4879           typename Comp = ranges::less,
4880           typename Proj = std::identity>
4881 constexpr const T& clamp(const T& v,
4882                          const T& lo,
4883                          const T& hi,
4884                          Comp comp = {},
4885                          Proj proj = {}) {
4886   auto&& projected_v = std::invoke(proj, v);
4887   if (std::invoke(comp, projected_v, std::invoke(proj, lo))) {
4888     return lo;
4889   }
4890 
4891   return std::invoke(comp, std::invoke(proj, hi), projected_v) ? hi : v;
4892 }
4893 
4894 // [alg.lex.comparison] Lexicographical comparison
4895 // Reference: https://wg21.link/alg.lex.comparison
4896 
4897 // Returns: `true` if and only if the sequence of elements defined by the range
4898 // `[first1, last1)` is lexicographically less than the sequence of elements
4899 // defined by the range `[first2, last2)`.
4900 //
4901 // Complexity: At most `2 min(last1 - first1, last2 - first2)` applications of
4902 // the corresponding comparison and each projection, if any.
4903 //
4904 // Remarks: If two sequences have the same number of elements and their
4905 // corresponding elements (if any) are equivalent, then neither sequence is
4906 // lexicographically less than the other. If one sequence is a proper prefix of
4907 // the other, then the shorter sequence is lexicographically less than the
4908 // longer sequence. Otherwise, the lexicographical comparison of the sequences
4909 // yields the same result as the comparison of the first corresponding pair of
4910 // elements that are not equivalent.
4911 //
4912 // Reference:
4913 // https://wg21.link/alg.lex.comparison#:~:text=lexicographical_compare(I1
4914 template <
4915     typename ForwardIterator1,
4916     typename ForwardIterator2,
4917     typename Comp = ranges::less,
4918     typename Proj1 = std::identity,
4919     typename Proj2 = std::identity,
4920     typename = internal::iterator_category_t<ForwardIterator1>,
4921     typename = internal::iterator_category_t<ForwardIterator2>,
4922     typename = std::indirect_result_t<Comp&,
4923                                       std::projected<ForwardIterator1, Proj1>,
4924                                       std::projected<ForwardIterator2, Proj2>>,
4925     typename = std::indirect_result_t<Comp&,
4926                                       std::projected<ForwardIterator2, Proj2>,
4927                                       std::projected<ForwardIterator1, Proj1>>>
4928 constexpr bool lexicographical_compare(ForwardIterator1 first1,
4929                                        ForwardIterator1 last1,
4930                                        ForwardIterator2 first2,
4931                                        ForwardIterator2 last2,
4932                                        Comp comp = {},
4933                                        Proj1 proj1 = {},
4934                                        Proj2 proj2 = {}) {
4935   for (; first1 != last1 && first2 != last2; ++first1, ++first2) {
4936     auto&& projected_first1 = std::invoke(proj1, *first1);
4937     auto&& projected_first2 = std::invoke(proj2, *first2);
4938     if (std::invoke(comp, projected_first1, projected_first2)) {
4939       return true;
4940     }
4941     if (std::invoke(comp, projected_first2, projected_first1)) {
4942       return false;
4943     }
4944   }
4945 
4946   // `first2 != last2` is equivalent to `first1 == last1 && first2 != last2`
4947   // here, since we broke out of the loop above.
4948   return first2 != last2;
4949 }
4950 
4951 // Returns: `true` if and only if the sequence of elements defined by `range1`
4952 //  is lexicographically less than the sequence of elements defined by `range2`.
4953 //
4954 // Complexity: At most `2 min(size(range1), size(range2))` applications of the
4955 // corresponding comparison and each projection, if any.
4956 //
4957 // Remarks: If two sequences have the same number of elements and their
4958 // corresponding elements (if any) are equivalent, then neither sequence is
4959 // lexicographically less than the other. If one sequence is a proper prefix of
4960 // the other, then the shorter sequence is lexicographically less than the
4961 // longer sequence. Otherwise, the lexicographical comparison of the sequences
4962 // yields the same result as the comparison of the first corresponding pair of
4963 // elements that are not equivalent.
4964 //
4965 // Reference:
4966 // https://wg21.link/alg.lex.comparison#:~:text=lexicographical_compare(R1
4967 template <typename Range1,
4968           typename Range2,
4969           typename Comp = ranges::less,
4970           typename Proj1 = std::identity,
4971           typename Proj2 = std::identity,
4972           typename = internal::range_category_t<Range1>,
4973           typename = internal::range_category_t<Range2>,
4974           typename =
4975               std::indirect_result_t<Comp&,
4976                                      std::projected<iterator_t<Range1>, Proj1>,
4977                                      std::projected<iterator_t<Range2>, Proj2>>,
4978           typename =
4979               std::indirect_result_t<Comp&,
4980                                      std::projected<iterator_t<Range2>, Proj2>,
4981                                      std::projected<iterator_t<Range1>, Proj1>>>
4982 constexpr bool lexicographical_compare(Range1&& range1,
4983                                        Range2&& range2,
4984                                        Comp comp = {},
4985                                        Proj1 proj1 = {},
4986                                        Proj2 proj2 = {}) {
4987   return ranges::lexicographical_compare(
4988       ranges::begin(range1), ranges::end(range1), ranges::begin(range2),
4989       ranges::end(range2), std::move(comp), std::move(proj1), std::move(proj2));
4990 }
4991 
4992 // [alg.permutation.generators] Permutation generators
4993 // Reference: https://wg21.link/alg.permutation.generators
4994 
4995 // Effects: Takes a sequence defined by the range `[first, last)` and transforms
4996 // it into the next permutation. The next permutation is found by assuming that
4997 // the set of all permutations is lexicographically sorted with respect to
4998 // `comp` and `proj`. If no such permutation exists, transforms the sequence
4999 // into the first permutation; that is, the ascendingly-sorted one.
5000 //
5001 // Returns: `true` if a next permutation was found and otherwise `false`.
5002 //
5003 // Complexity: At most `(last - first) / 2` swaps.
5004 //
5005 // Reference:
5006 // https://wg21.link/alg.permutation.generators#:~:text=next_permutation(I
5007 template <typename BidirectionalIterator,
5008           typename Comp = ranges::less,
5009           typename Proj = std::identity,
5010           typename = internal::iterator_category_t<BidirectionalIterator>,
5011           typename = std::indirect_result_t<
5012               Comp&,
5013               std::projected<BidirectionalIterator, Proj>,
5014               std::projected<BidirectionalIterator, Proj>>>
5015 constexpr auto next_permutation(BidirectionalIterator first,
5016                                 BidirectionalIterator last,
5017                                 Comp comp = {},
5018                                 Proj proj = {}) {
5019   return std::next_permutation(
5020       first, last, internal::ProjectedBinaryPredicate(comp, proj, proj));
5021 }
5022 
5023 // Effects: Takes a sequence defined by `range` and transforms it into the next
5024 // permutation. The next permutation is found by assuming that the set of all
5025 // permutations is lexicographically sorted with respect to `comp` and `proj`.
5026 // If no such permutation exists, transforms the sequence into the first
5027 // permutation; that is, the ascendingly-sorted one.
5028 //
5029 // Returns: `true` if a next permutation was found and otherwise `false`.
5030 //
5031 // Complexity: At most `size(range) / 2` swaps.
5032 //
5033 // Reference:
5034 // https://wg21.link/alg.permutation.generators#:~:text=next_permutation(R
5035 template <
5036     typename Range,
5037     typename Comp = ranges::less,
5038     typename Proj = std::identity,
5039     typename = internal::range_category_t<Range>,
5040     typename = std::indirect_result_t<Comp&,
5041                                       std::projected<iterator_t<Range>, Proj>,
5042                                       std::projected<iterator_t<Range>, Proj>>>
5043 constexpr auto next_permutation(Range&& range, Comp comp = {}, Proj proj = {}) {
5044   return ranges::next_permutation(ranges::begin(range), ranges::end(range),
5045                                   std::move(comp), std::move(proj));
5046 }
5047 
5048 // Effects: Takes a sequence defined by the range `[first, last)` and transforms
5049 // it into the previous permutation. The previous permutation is found by
5050 // assuming that the set of all permutations is lexicographically sorted with
5051 // respect to `comp` and `proj`. If no such permutation exists, transforms the
5052 // sequence into the last permutation; that is, the decreasingly-sorted one.
5053 //
5054 // Returns: `true` if a next permutation was found and otherwise `false`.
5055 //
5056 // Complexity: At most `(last - first) / 2` swaps.
5057 //
5058 // Reference:
5059 // https://wg21.link/alg.permutation.generators#:~:text=prev_permutation(I
5060 template <typename BidirectionalIterator,
5061           typename Comp = ranges::less,
5062           typename Proj = std::identity,
5063           typename = internal::iterator_category_t<BidirectionalIterator>,
5064           typename = std::indirect_result_t<
5065               Comp&,
5066               std::projected<BidirectionalIterator, Proj>,
5067               std::projected<BidirectionalIterator, Proj>>>
5068 constexpr auto prev_permutation(BidirectionalIterator first,
5069                                 BidirectionalIterator last,
5070                                 Comp comp = {},
5071                                 Proj proj = {}) {
5072   return std::prev_permutation(
5073       first, last, internal::ProjectedBinaryPredicate(comp, proj, proj));
5074 }
5075 
5076 // Effects: Takes a sequence defined by `range` and transforms it into the
5077 // previous permutation. The previous permutation is found by assuming that the
5078 // set of all permutations is lexicographically sorted with respect to `comp`
5079 // and `proj`. If no such permutation exists, transforms the sequence into the
5080 // last permutation; that is, the decreasingly-sorted one.
5081 //
5082 // Returns: `true` if a previous permutation was found and otherwise `false`.
5083 //
5084 // Complexity: At most `size(range) / 2` swaps.
5085 //
5086 // Reference:
5087 // https://wg21.link/alg.permutation.generators#:~:text=prev_permutation(R
5088 template <
5089     typename Range,
5090     typename Comp = ranges::less,
5091     typename Proj = std::identity,
5092     typename = internal::range_category_t<Range>,
5093     typename = std::indirect_result_t<Comp&,
5094                                       std::projected<iterator_t<Range>, Proj>,
5095                                       std::projected<iterator_t<Range>, Proj>>>
5096 constexpr auto prev_permutation(Range&& range, Comp comp = {}, Proj proj = {}) {
5097   return ranges::prev_permutation(ranges::begin(range), ranges::end(range),
5098                                   std::move(comp), std::move(proj));
5099 }
5100 
5101 }  // namespace ranges
5102 
5103 }  // namespace base
5104 
5105 #endif  // BASE_RANGES_ALGORITHM_H_
5106