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