tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

algorithm.h (208793B)


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