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