|  | // Copyright 2020 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef BASE_RANGES_ALGORITHM_H_ | 
|  | #define BASE_RANGES_ALGORITHM_H_ | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <initializer_list> | 
|  | #include <iterator> | 
|  | #include <type_traits> | 
|  | #include <utility> | 
|  |  | 
|  | #include "polyfills/base/check.h" | 
|  | #include "base/compiler_specific.h" | 
|  | #include "base/functional/identity.h" | 
|  | #include "base/functional/invoke.h" | 
|  | #include "base/ranges/functional.h" | 
|  | #include "base/ranges/ranges.h" | 
|  | #include "base/template_util.h" | 
|  |  | 
|  | namespace gurl_base { | 
|  |  | 
|  | namespace internal { | 
|  |  | 
|  | // Returns a transformed version of the unary predicate `pred` applying `proj` | 
|  | // to its argument before invoking `pred` on it. | 
|  | // Ensures that the return type of `invoke(pred, ...)` is convertible to bool. | 
|  | template <typename Pred, typename Proj> | 
|  | constexpr auto ProjectedUnaryPredicate(Pred& pred, Proj& proj) noexcept { | 
|  | return [&pred, &proj](auto&& arg) -> bool { | 
|  | return gurl_base::invoke(pred, | 
|  | gurl_base::invoke(proj, std::forward<decltype(arg)>(arg))); | 
|  | }; | 
|  | } | 
|  |  | 
|  | // Returns a transformed version of the binary predicate `pred` applying `proj1` | 
|  | // and `proj2` to its arguments before invoking `pred` on them. | 
|  | // | 
|  | // Provides an opt-in to considers all four permutations of projections and | 
|  | // argument types. This is sometimes necessary to allow usage with legacy | 
|  | // non-ranges std:: algorithms that don't support projections. | 
|  | // | 
|  | // These permutations are assigned different priorities to break ambiguities in | 
|  | // case several permutations are possible, e.g. when Proj1 and Proj2 are the | 
|  | // same type. | 
|  | // | 
|  | // Note that even when opting in to using all permutations of projections, | 
|  | // calling code should still ensure that the canonical mapping of {Proj1, Proj2} | 
|  | // to {LHS, RHS} compiles for all members of the range. This can be done by | 
|  | // adding the following constraint: | 
|  | // | 
|  | //   typename = indirect_result_t<Pred&, | 
|  | //                                projected<iterator_t<Range1>, Proj1>, | 
|  | //                                projected<iterator_t<Range2>, Proj2>> | 
|  | // | 
|  | // Ensures that the return type of `invoke(pred, ...)` is convertible to bool. | 
|  | template <typename Pred, typename Proj1, typename Proj2, bool kPermute = false> | 
|  | class BinaryPredicateProjector { | 
|  | public: | 
|  | constexpr BinaryPredicateProjector(Pred& pred, Proj1& proj1, Proj2& proj2) | 
|  | : pred_(pred), proj1_(proj1), proj2_(proj2) {} | 
|  |  | 
|  | private: | 
|  | template <typename ProjT, typename ProjU, typename T, typename U> | 
|  | using InvokeResult = invoke_result_t<Pred&, | 
|  | invoke_result_t<ProjT&, T&&>, | 
|  | invoke_result_t<ProjU&, U&&>>; | 
|  |  | 
|  | template <typename T, typename U, typename = InvokeResult<Proj1, Proj2, T, U>> | 
|  | constexpr std::pair<Proj1&, Proj2&> GetProjs(priority_tag<3>) const { | 
|  | return {proj1_, proj2_}; | 
|  | } | 
|  |  | 
|  | template <typename T, | 
|  | typename U, | 
|  | bool LazyPermute = kPermute, | 
|  | typename = std::enable_if_t<LazyPermute>, | 
|  | typename = InvokeResult<Proj2, Proj1, T, U>> | 
|  | constexpr std::pair<Proj2&, Proj1&> GetProjs(priority_tag<2>) const { | 
|  | return {proj2_, proj1_}; | 
|  | } | 
|  |  | 
|  | template <typename T, | 
|  | typename U, | 
|  | bool LazyPermute = kPermute, | 
|  | typename = std::enable_if_t<LazyPermute>, | 
|  | typename = InvokeResult<Proj1, Proj1, T, U>> | 
|  | constexpr std::pair<Proj1&, Proj1&> GetProjs(priority_tag<1>) const { | 
|  | return {proj1_, proj1_}; | 
|  | } | 
|  |  | 
|  | template <typename T, | 
|  | typename U, | 
|  | bool LazyPermute = kPermute, | 
|  | typename = std::enable_if_t<LazyPermute>, | 
|  | typename = InvokeResult<Proj2, Proj2, T, U>> | 
|  | constexpr std::pair<Proj2&, Proj2&> GetProjs(priority_tag<0>) const { | 
|  | return {proj2_, proj2_}; | 
|  | } | 
|  |  | 
|  | public: | 
|  | template <typename T, typename U> | 
|  | constexpr bool operator()(T&& lhs, U&& rhs) const { | 
|  | auto projs = GetProjs<T, U>(priority_tag<3>()); | 
|  | return gurl_base::invoke(pred_, gurl_base::invoke(projs.first, std::forward<T>(lhs)), | 
|  | gurl_base::invoke(projs.second, std::forward<U>(rhs))); | 
|  | } | 
|  |  | 
|  | private: | 
|  | Pred& pred_; | 
|  | Proj1& proj1_; | 
|  | Proj2& proj2_; | 
|  | }; | 
|  |  | 
|  | // Small wrappers around BinaryPredicateProjector to make the calling side more | 
|  | // readable. | 
|  | template <typename Pred, typename Proj1, typename Proj2> | 
|  | constexpr auto ProjectedBinaryPredicate(Pred& pred, | 
|  | Proj1& proj1, | 
|  | Proj2& proj2) noexcept { | 
|  | return BinaryPredicateProjector<Pred, Proj1, Proj2>(pred, proj1, proj2); | 
|  | } | 
|  |  | 
|  | template <typename Pred, typename Proj1, typename Proj2> | 
|  | constexpr auto PermutedProjectedBinaryPredicate(Pred& pred, | 
|  | Proj1& proj1, | 
|  | Proj2& proj2) noexcept { | 
|  | return BinaryPredicateProjector<Pred, Proj1, Proj2, true>(pred, proj1, proj2); | 
|  | } | 
|  |  | 
|  | // This alias is used below to restrict iterator based APIs to types for which | 
|  | // `iterator_category` and the pre-increment and post-increment operators are | 
|  | // defined. This is required in situations where otherwise an undesired overload | 
|  | // would be chosen, e.g. copy_if. In spirit this is similar to C++20's | 
|  | // std::input_or_output_iterator, a concept that each iterator should satisfy. | 
|  | template <typename Iter, | 
|  | typename = decltype(++std::declval<Iter&>()), | 
|  | typename = decltype(std::declval<Iter&>()++)> | 
|  | using iterator_category_t = | 
|  | typename std::iterator_traits<Iter>::iterator_category; | 
|  |  | 
|  | // This alias is used below to restrict range based APIs to types for which | 
|  | // `iterator_category_t` is defined for the underlying iterator. This is | 
|  | // required in situations where otherwise an undesired overload would be chosen, | 
|  | // e.g. transform. In spirit this is similar to C++20's std::ranges::range, a | 
|  | // concept that each range should satisfy. | 
|  | template <typename Range> | 
|  | using range_category_t = iterator_category_t<ranges::iterator_t<Range>>; | 
|  |  | 
|  | }  // namespace internal | 
|  |  | 
|  | namespace ranges { | 
|  |  | 
|  | // C++14 implementation of std::ranges::in_fun_result. | 
|  | // | 
|  | // Reference: https://wg21.link/algorithms.results#:~:text=in_fun_result | 
|  | template <typename I, typename F> | 
|  | struct in_fun_result { | 
|  | NO_UNIQUE_ADDRESS I in; | 
|  | NO_UNIQUE_ADDRESS F fun; | 
|  |  | 
|  | template <typename I2, | 
|  | typename F2, | 
|  | std::enable_if_t<std::is_convertible<const I&, I2>{} && | 
|  | std::is_convertible<const F&, F2>{}>> | 
|  | constexpr operator in_fun_result<I2, F2>() const& { | 
|  | return {in, fun}; | 
|  | } | 
|  |  | 
|  | template <typename I2, | 
|  | typename F2, | 
|  | std::enable_if_t<std::is_convertible<I, I2>{} && | 
|  | std::is_convertible<F, F2>{}>> | 
|  | constexpr operator in_fun_result<I2, F2>() && { | 
|  | return {std::move(in), std::move(fun)}; | 
|  | } | 
|  | }; | 
|  |  | 
|  | // TODO(crbug.com/1071094): Implement the other result types. | 
|  |  | 
|  | // [alg.nonmodifying] Non-modifying sequence operations | 
|  | // Reference: https://wg21.link/alg.nonmodifying | 
|  |  | 
|  | // [alg.all.of] All of | 
|  | // Reference: https://wg21.link/alg.all.of | 
|  |  | 
|  | // Let `E(i)` be `invoke(pred, invoke(proj, *i))`. | 
|  | // | 
|  | // Returns: `false` if `E(i)` is `false` for some iterator `i` in the range | 
|  | // `[first, last)`, and `true` otherwise. | 
|  | // | 
|  | // Complexity: At most `last - first` applications of the predicate and any | 
|  | // projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.all.of#:~:text=ranges::all_of(I | 
|  | template <typename InputIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>> | 
|  | constexpr bool all_of(InputIterator first, | 
|  | InputIterator last, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | for (; first != last; ++first) { | 
|  | if (!gurl_base::invoke(pred, gurl_base::invoke(proj, *first))) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `invoke(pred, invoke(proj, *i))`. | 
|  | // | 
|  | // Returns: `false` if `E(i)` is `false` for some iterator `i` in `range`, and | 
|  | // `true` otherwise. | 
|  | // | 
|  | // Complexity: At most `size(range)` applications of the predicate and any | 
|  | // projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.all.of#:~:text=ranges::all_of(R | 
|  | template <typename Range, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr bool all_of(Range&& range, Pred pred, Proj proj = {}) { | 
|  | return ranges::all_of(ranges::begin(range), ranges::end(range), | 
|  | std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.any.of] Any of | 
|  | // Reference: https://wg21.link/alg.any.of | 
|  |  | 
|  | // Let `E(i)` be `invoke(pred, invoke(proj, *i))`. | 
|  | // | 
|  | // Returns: `true` if `E(i)` is `true` for some iterator `i` in the range | 
|  | // `[first, last)`, and `false` otherwise. | 
|  | // | 
|  | // Complexity: At most `last - first` applications of the predicate and any | 
|  | // projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.any.of#:~:text=ranges::any_of(I | 
|  | template <typename InputIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>> | 
|  | constexpr bool any_of(InputIterator first, | 
|  | InputIterator last, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | for (; first != last; ++first) { | 
|  | if (gurl_base::invoke(pred, gurl_base::invoke(proj, *first))) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `invoke(pred, invoke(proj, *i))`. | 
|  | // | 
|  | // Returns: `true` if `E(i)` is `true` for some iterator `i` in `range`, and | 
|  | // `false` otherwise. | 
|  | // | 
|  | // Complexity: At most `size(range)` applications of the predicate and any | 
|  | // projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.any.of#:~:text=ranges::any_of(R | 
|  | template <typename Range, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr bool any_of(Range&& range, Pred pred, Proj proj = {}) { | 
|  | return ranges::any_of(ranges::begin(range), ranges::end(range), | 
|  | std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.none.of] None of | 
|  | // Reference: https://wg21.link/alg.none.of | 
|  |  | 
|  | // Let `E(i)` be `invoke(pred, invoke(proj, *i))`. | 
|  | // | 
|  | // Returns: `false` if `E(i)` is `true` for some iterator `i` in the range | 
|  | // `[first, last)`, and `true` otherwise. | 
|  | // | 
|  | // Complexity: At most `last - first` applications of the predicate and any | 
|  | // projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.none.of#:~:text=ranges::none_of(I | 
|  | template <typename InputIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>> | 
|  | constexpr bool none_of(InputIterator first, | 
|  | InputIterator last, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | for (; first != last; ++first) { | 
|  | if (gurl_base::invoke(pred, gurl_base::invoke(proj, *first))) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `invoke(pred, invoke(proj, *i))`. | 
|  | // | 
|  | // Returns: `false` if `E(i)` is `true` for some iterator `i` in `range`, and | 
|  | // `true` otherwise. | 
|  | // | 
|  | // Complexity: At most `size(range)` applications of the predicate and any | 
|  | // projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.none.of#:~:text=ranges::none_of(R | 
|  | template <typename Range, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr bool none_of(Range&& range, Pred pred, Proj proj = {}) { | 
|  | return ranges::none_of(ranges::begin(range), ranges::end(range), | 
|  | std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.foreach] For each | 
|  | // Reference: https://wg21.link/alg.foreach | 
|  |  | 
|  | // Reference: https://wg21.link/algorithm.syn#:~:text=for_each_result | 
|  | template <typename I, typename F> | 
|  | using for_each_result = in_fun_result<I, F>; | 
|  |  | 
|  | // Effects: Calls `invoke(f, invoke(proj, *i))` for every iterator `i` in the | 
|  | // range `[first, last)`, starting from `first` and proceeding to `last - 1`. | 
|  | // | 
|  | // Returns: `{last, std::move(f)}`. | 
|  | // | 
|  | // Complexity: Applies `f` and `proj` exactly `last - first` times. | 
|  | // | 
|  | // Remarks: If `f` returns a result, the result is ignored. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.foreach#:~:text=ranges::for_each(I | 
|  | template <typename InputIterator, | 
|  | typename Fun, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>> | 
|  | constexpr auto for_each(InputIterator first, | 
|  | InputIterator last, | 
|  | Fun f, | 
|  | Proj proj = {}) { | 
|  | for (; first != last; ++first) | 
|  | gurl_base::invoke(f, gurl_base::invoke(proj, *first)); | 
|  | return for_each_result<InputIterator, Fun>{first, std::move(f)}; | 
|  | } | 
|  |  | 
|  | // Effects: Calls `invoke(f, invoke(proj, *i))` for every iterator `i` in the | 
|  | // range `range`, starting from `begin(range)` and proceeding to `end(range) - | 
|  | // 1`. | 
|  | // | 
|  | // Returns: `{last, std::move(f)}`. | 
|  | // | 
|  | // Complexity: Applies `f` and `proj` exactly `size(range)` times. | 
|  | // | 
|  | // Remarks: If `f` returns a result, the result is ignored. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.foreach#:~:text=ranges::for_each(R | 
|  | template <typename Range, | 
|  | typename Fun, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto for_each(Range&& range, Fun f, Proj proj = {}) { | 
|  | return ranges::for_each(ranges::begin(range), ranges::end(range), | 
|  | std::move(f), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Reference: https://wg21.link/algorithm.syn#:~:text=for_each_n_result | 
|  | template <typename I, typename F> | 
|  | using for_each_n_result = in_fun_result<I, F>; | 
|  |  | 
|  | // Preconditions: `n >= 0` is `true`. | 
|  | // | 
|  | // Effects: Calls `invoke(f, invoke(proj, *i))` for every iterator `i` in the | 
|  | // range `[first, first + n)` in order. | 
|  | // | 
|  | // Returns: `{first + n, std::move(f)}`. | 
|  | // | 
|  | // Remarks: If `f` returns a result, the result is ignored. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.foreach#:~:text=ranges::for_each_n | 
|  | template <typename InputIterator, | 
|  | typename Size, | 
|  | typename Fun, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>> | 
|  | constexpr auto for_each_n(InputIterator first, Size n, Fun f, Proj proj = {}) { | 
|  | while (n > 0) { | 
|  | gurl_base::invoke(f, gurl_base::invoke(proj, *first)); | 
|  | ++first; | 
|  | --n; | 
|  | } | 
|  |  | 
|  | return for_each_n_result<InputIterator, Fun>{first, std::move(f)}; | 
|  | } | 
|  |  | 
|  | // [alg.find] Find | 
|  | // Reference: https://wg21.link/alg.find | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(proj, *i) == value)`. | 
|  | // | 
|  | // Returns: The first iterator `i` in the range `[first, last)` for which `E(i)` | 
|  | // is `true`. Returns `last` if no such iterator is found. | 
|  | // | 
|  | // Complexity: At most `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.find#:~:text=ranges::find(I | 
|  | template <typename InputIterator, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>> | 
|  | constexpr auto find(InputIterator first, | 
|  | InputIterator last, | 
|  | const T& value, | 
|  | Proj proj = {}) { | 
|  | for (; first != last; ++first) { | 
|  | if (gurl_base::invoke(proj, *first) == value) | 
|  | break; | 
|  | } | 
|  |  | 
|  | return first; | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(proj, *i) == value)`. | 
|  | // | 
|  | // Returns: The first iterator `i` in `range` for which `E(i)` is `true`. | 
|  | // Returns `end(range)` if no such iterator is found. | 
|  | // | 
|  | // Complexity: At most `size(range)` applications of the corresponding predicate | 
|  | // and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.find#:~:text=ranges::find(R | 
|  | template <typename Range, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto find(Range&& range, const T& value, Proj proj = {}) { | 
|  | return ranges::find(ranges::begin(range), ranges::end(range), value, | 
|  | std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`. | 
|  | // | 
|  | // Returns: The first iterator `i` in the range `[first, last)` for which `E(i)` | 
|  | // is `true`. Returns `last` if no such iterator is found. | 
|  | // | 
|  | // Complexity: At most `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.find#:~:text=ranges::find_if(I | 
|  | template <typename InputIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>> | 
|  | constexpr auto find_if(InputIterator first, | 
|  | InputIterator last, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | return std::find_if(first, last, | 
|  | internal::ProjectedUnaryPredicate(pred, proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`. | 
|  | // | 
|  | // Returns: The first iterator `i` in `range` for which `E(i)` is `true`. | 
|  | // Returns `end(range)` if no such iterator is found. | 
|  | // | 
|  | // Complexity: At most `size(range)` applications of the corresponding predicate | 
|  | // and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.find#:~:text=ranges::find_if(R | 
|  | template <typename Range, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto find_if(Range&& range, Pred pred, Proj proj = {}) { | 
|  | return ranges::find_if(ranges::begin(range), ranges::end(range), | 
|  | std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(!invoke(pred, invoke(proj, *i)))`. | 
|  | // | 
|  | // Returns: The first iterator `i` in the range `[first, last)` for which `E(i)` | 
|  | // is `true`. Returns `last` if no such iterator is found. | 
|  | // | 
|  | // Complexity: At most `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.find#:~:text=ranges::find_if_not(I | 
|  | template <typename InputIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>> | 
|  | constexpr auto find_if_not(InputIterator first, | 
|  | InputIterator last, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | return std::find_if_not(first, last, | 
|  | internal::ProjectedUnaryPredicate(pred, proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(!invoke(pred, invoke(proj, *i)))`. | 
|  | // | 
|  | // Returns: The first iterator `i` in `range` for which `E(i)` is `true`. | 
|  | // Returns `end(range)` if no such iterator is found. | 
|  | // | 
|  | // Complexity: At most `size(range)` applications of the corresponding predicate | 
|  | // and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.find#:~:text=ranges::find_if_not(R | 
|  | template <typename Range, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto find_if_not(Range&& range, Pred pred, Proj proj = {}) { | 
|  | return ranges::find_if_not(ranges::begin(range), ranges::end(range), | 
|  | std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.find.end] Find end | 
|  | // Reference: https://wg21.link/alg.find.end | 
|  |  | 
|  | // Let: | 
|  | // - `E(i,n)` be `invoke(pred, invoke(proj1, *(i + n)), | 
|  | //                             invoke(proj2, *(first2 + n)))` | 
|  | // | 
|  | // - `i` be `last1` if `[first2, last2)` is empty, or if | 
|  | //   `(last2 - first2) > (last1 - first1)` is `true`, or if there is no iterator | 
|  | //   in the range `[first1, last1 - (last2 - first2))` such that for every | 
|  | //   non-negative integer `n < (last2 - first2)`, `E(i,n)` is `true`. Otherwise | 
|  | //   `i` is the last such iterator in `[first1, last1 - (last2 - first2))`. | 
|  | // | 
|  | // Returns: `i` | 
|  | // Note: std::ranges::find_end(I1 first1,...) returns a range, rather than an | 
|  | // iterator. For simplicitly we match std::find_end's return type instead. | 
|  | // | 
|  | // Complexity: | 
|  | // At most `(last2 - first2) * (last1 - first1 - (last2 - first2) + 1)` | 
|  | // applications of the corresponding predicate and any projections. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.find.end#:~:text=ranges::find_end(I1 | 
|  | template <typename ForwardIterator1, | 
|  | typename ForwardIterator2, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator1>, | 
|  | typename = internal::iterator_category_t<ForwardIterator2>, | 
|  | typename = indirect_result_t<Pred&, | 
|  | projected<ForwardIterator1, Proj1>, | 
|  | projected<ForwardIterator2, Proj2>>> | 
|  | constexpr auto find_end(ForwardIterator1 first1, | 
|  | ForwardIterator1 last1, | 
|  | ForwardIterator2 first2, | 
|  | ForwardIterator2 last2, | 
|  | Pred pred = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return std::find_end(first1, last1, first2, last2, | 
|  | internal::ProjectedBinaryPredicate(pred, proj1, proj2)); | 
|  | } | 
|  |  | 
|  | // Let: | 
|  | // - `E(i,n)` be `invoke(pred, invoke(proj1, *(i + n)), | 
|  | //                             invoke(proj2, *(first2 + n)))` | 
|  | // | 
|  | // - `i` be `end(range1)` if `range2` is empty, or if | 
|  | //   `size(range2) > size(range1)` is `true`, or if there is no iterator in the | 
|  | //   range `[begin(range1), end(range1) - size(range2))` such that for every | 
|  | //   non-negative integer `n < size(range2)`, `E(i,n)` is `true`. Otherwise `i` | 
|  | //   is the last such iterator in `[begin(range1), end(range1) - size(range2))`. | 
|  | // | 
|  | // Returns: `i` | 
|  | // Note: std::ranges::find_end(R1&& r1,...) returns a range, rather than an | 
|  | // iterator. For simplicitly we match std::find_end's return type instead. | 
|  | // | 
|  | // Complexity: At most `size(range2) * (size(range1) - size(range2) + 1)` | 
|  | // applications of the corresponding predicate and any projections. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.find.end#:~:text=ranges::find_end(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = indirect_result_t<Pred&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>> | 
|  | constexpr auto find_end(Range1&& range1, | 
|  | Range2&& range2, | 
|  | Pred pred = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::find_end(ranges::begin(range1), ranges::end(range1), | 
|  | ranges::begin(range2), ranges::end(range2), | 
|  | std::move(pred), std::move(proj1), std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // [alg.find.first.of] Find first | 
|  | // Reference: https://wg21.link/alg.find.first.of | 
|  |  | 
|  | // Let `E(i,j)` be `bool(invoke(pred, invoke(proj1, *i), invoke(proj2, *j)))`. | 
|  | // | 
|  | // Effects: Finds an element that matches one of a set of values. | 
|  | // | 
|  | // Returns: The first iterator `i` in the range `[first1, last1)` such that for | 
|  | // some iterator `j` in the range `[first2, last2)` `E(i,j)` holds. Returns | 
|  | // `last1` if `[first2, last2)` is empty or if no such iterator is found. | 
|  | // | 
|  | // Complexity: At most `(last1 - first1) * (last2 - first2)` applications of the | 
|  | // corresponding predicate and any projections. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.find.first.of#:~:text=ranges::find_first_of(I1 | 
|  | template <typename ForwardIterator1, | 
|  | typename ForwardIterator2, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator1>, | 
|  | typename = internal::iterator_category_t<ForwardIterator2>, | 
|  | typename = indirect_result_t<Pred&, | 
|  | projected<ForwardIterator1, Proj1>, | 
|  | projected<ForwardIterator2, Proj2>>> | 
|  | constexpr auto find_first_of(ForwardIterator1 first1, | 
|  | ForwardIterator1 last1, | 
|  | ForwardIterator2 first2, | 
|  | ForwardIterator2 last2, | 
|  | Pred pred = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return std::find_first_of( | 
|  | first1, last1, first2, last2, | 
|  | internal::ProjectedBinaryPredicate(pred, proj1, proj2)); | 
|  | } | 
|  |  | 
|  | // Let `E(i,j)` be `bool(invoke(pred, invoke(proj1, *i), invoke(proj2, *j)))`. | 
|  | // | 
|  | // Effects: Finds an element that matches one of a set of values. | 
|  | // | 
|  | // Returns: The first iterator `i` in `range1` such that for some iterator `j` | 
|  | // in `range2` `E(i,j)` holds. Returns `end(range1)` if `range2` is empty or if | 
|  | // no such iterator is found. | 
|  | // | 
|  | // Complexity: At most `size(range1) * size(range2)` applications of the | 
|  | // corresponding predicate and any projections. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.find.first.of#:~:text=ranges::find_first_of(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = indirect_result_t<Pred&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>> | 
|  | constexpr auto find_first_of(Range1&& range1, | 
|  | Range2&& range2, | 
|  | Pred pred = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::find_first_of( | 
|  | ranges::begin(range1), ranges::end(range1), ranges::begin(range2), | 
|  | ranges::end(range2), std::move(pred), std::move(proj1), std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // [alg.adjacent.find] Adjacent find | 
|  | // Reference: https://wg21.link/alg.adjacent.find | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i), invoke(proj, *(i + 1))))`. | 
|  | // | 
|  | // Returns: The first iterator `i` such that both `i` and `i + 1` are in the | 
|  | // range `[first, last)` for which `E(i)` holds. Returns `last` if no such | 
|  | // iterator is found. | 
|  | // | 
|  | // Complexity: Exactly `min((i - first) + 1, (last - first) - 1)` applications | 
|  | // of the corresponding predicate, where `i` is `adjacent_find`'s return value. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.adjacent.find#:~:text=ranges::adjacent_find(I | 
|  | template <typename ForwardIterator, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto adjacent_find(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | Pred pred = {}, | 
|  | Proj proj = {}) { | 
|  | // Implementation inspired by cppreference.com: | 
|  | // https://en.cppreference.com/w/cpp/algorithm/adjacent_find | 
|  | // | 
|  | // A reimplementation is required, because std::adjacent_find is not constexpr | 
|  | // prior to C++20. Once we have C++20, we should switch to standard library | 
|  | // implementation. | 
|  | if (first == last) | 
|  | return last; | 
|  |  | 
|  | for (ForwardIterator next = first; ++next != last; ++first) { | 
|  | if (gurl_base::invoke(pred, gurl_base::invoke(proj, *first), | 
|  | gurl_base::invoke(proj, *next))) { | 
|  | return first; | 
|  | } | 
|  | } | 
|  |  | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i), invoke(proj, *(i + 1))))`. | 
|  | // | 
|  | // Returns: The first iterator `i` such that both `i` and `i + 1` are in the | 
|  | // range `range` for which `E(i)` holds. Returns `end(range)` if no such | 
|  | // iterator is found. | 
|  | // | 
|  | // Complexity: Exactly `min((i - begin(range)) + 1, size(range) - 1)` | 
|  | // applications of the corresponding predicate, where `i` is `adjacent_find`'s | 
|  | // return value. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.adjacent.find#:~:text=ranges::adjacent_find(R | 
|  | template <typename Range, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto adjacent_find(Range&& range, Pred pred = {}, Proj proj = {}) { | 
|  | return ranges::adjacent_find(ranges::begin(range), ranges::end(range), | 
|  | std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.count] Count | 
|  | // Reference: https://wg21.link/alg.count | 
|  |  | 
|  | // Let `E(i)` be `invoke(proj, *i) == value`. | 
|  | // | 
|  | // Effects: Returns the number of iterators `i` in the range `[first, last)` for | 
|  | // which `E(i)` holds. | 
|  | // | 
|  | // Complexity: Exactly `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.count#:~:text=ranges::count(I | 
|  | template <typename InputIterator, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>> | 
|  | constexpr auto count(InputIterator first, | 
|  | InputIterator last, | 
|  | const T& value, | 
|  | Proj proj = {}) { | 
|  | // Note: In order to be able to apply `proj` to each element in [first, last) | 
|  | // we are dispatching to std::count_if instead of std::count. | 
|  | return std::count_if(first, last, [&proj, &value](auto&& lhs) { | 
|  | return gurl_base::invoke(proj, std::forward<decltype(lhs)>(lhs)) == value; | 
|  | }); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `invoke(proj, *i) == value`. | 
|  | // | 
|  | // Effects: Returns the number of iterators `i` in `range` for which `E(i)` | 
|  | // holds. | 
|  | // | 
|  | // Complexity: Exactly `size(range)` applications of the corresponding predicate | 
|  | // and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.count#:~:text=ranges::count(R | 
|  | template <typename Range, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto count(Range&& range, const T& value, Proj proj = {}) { | 
|  | return ranges::count(ranges::begin(range), ranges::end(range), value, | 
|  | std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`. | 
|  | // | 
|  | // Effects: Returns the number of iterators `i` in the range `[first, last)` for | 
|  | // which `E(i)` holds. | 
|  | // | 
|  | // Complexity: Exactly `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.count#:~:text=ranges::count_if(I | 
|  | template <typename InputIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>> | 
|  | constexpr auto count_if(InputIterator first, | 
|  | InputIterator last, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | return std::count_if(first, last, | 
|  | internal::ProjectedUnaryPredicate(pred, proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`. | 
|  | // | 
|  | // Effects: Returns the number of iterators `i` in `range` for which `E(i)` | 
|  | // holds. | 
|  | // | 
|  | // Complexity: Exactly `size(range)` applications of the corresponding predicate | 
|  | // and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.count#:~:text=ranges::count_if(R | 
|  | template <typename Range, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto count_if(Range&& range, Pred pred, Proj proj = {}) { | 
|  | return ranges::count_if(ranges::begin(range), ranges::end(range), | 
|  | std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [mismatch] Mismatch | 
|  | // Reference: https://wg21.link/mismatch | 
|  |  | 
|  | // Let `E(n)` be `!invoke(pred, invoke(proj1, *(first1 + n)), | 
|  | //                              invoke(proj2, *(first2 + n)))`. | 
|  | // | 
|  | // Let `N` be `min(last1 - first1, last2 - first2)`. | 
|  | // | 
|  | // Returns: `{ first1 + n, first2 + n }`, where `n` is the smallest integer in | 
|  | // `[0, N)` such that `E(n)` holds, or `N` if no such integer exists. | 
|  | // | 
|  | // Complexity: At most `N` applications of the corresponding predicate and any | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/mismatch#:~:text=ranges::mismatch(I1 | 
|  | template <typename ForwardIterator1, | 
|  | typename ForwardIterator2, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator1>, | 
|  | typename = internal::iterator_category_t<ForwardIterator2>, | 
|  | typename = indirect_result_t<Pred&, | 
|  | projected<ForwardIterator1, Proj1>, | 
|  | projected<ForwardIterator2, Proj2>>> | 
|  | constexpr auto mismatch(ForwardIterator1 first1, | 
|  | ForwardIterator1 last1, | 
|  | ForwardIterator2 first2, | 
|  | ForwardIterator2 last2, | 
|  | Pred pred = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return std::mismatch(first1, last1, first2, last2, | 
|  | internal::ProjectedBinaryPredicate(pred, proj1, proj2)); | 
|  | } | 
|  |  | 
|  | // Let `E(n)` be `!invoke(pred, invoke(proj1, *(begin(range1) + n)), | 
|  | //                              invoke(proj2, *(begin(range2) + n)))`. | 
|  | // | 
|  | // Let `N` be `min(size(range1), size(range2))`. | 
|  | // | 
|  | // Returns: `{ begin(range1) + n, begin(range2) + n }`, where `n` is the | 
|  | // smallest integer in `[0, N)` such that `E(n)` holds, or `N` if no such | 
|  | // integer exists. | 
|  | // | 
|  | // Complexity: At most `N` applications of the corresponding predicate and any | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/mismatch#:~:text=ranges::mismatch(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = indirect_result_t<Pred&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>> | 
|  | constexpr auto mismatch(Range1&& range1, | 
|  | Range2&& range2, | 
|  | Pred pred = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::mismatch(ranges::begin(range1), ranges::end(range1), | 
|  | ranges::begin(range2), ranges::end(range2), | 
|  | std::move(pred), std::move(proj1), std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // [alg.equal] Equal | 
|  | // Reference: https://wg21.link/alg.equal | 
|  |  | 
|  | // Let `E(i)` be | 
|  | //   `invoke(pred, invoke(proj1, *i), invoke(proj2, *(first2 + (i - first1))))`. | 
|  | // | 
|  | // Returns: If `last1 - first1 != last2 - first2`, return `false.` Otherwise | 
|  | // return `true` if `E(i)` holds for every iterator `i` in the range `[first1, | 
|  | // last1)`. Otherwise, returns `false`. | 
|  | // | 
|  | // Complexity: If the types of `first1`, `last1`, `first2`, and `last2` meet the | 
|  | // `RandomAccessIterator` requirements and `last1 - first1 != last2 - first2`, | 
|  | // then no applications of the corresponding predicate and each projection; | 
|  | // otherwise, at most `min(last1 - first1, last2 - first2)` applications of the | 
|  | // corresponding predicate and any projections. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.equal#:~:text=ranges::equal(I1 | 
|  | template <typename ForwardIterator1, | 
|  | typename ForwardIterator2, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator1>, | 
|  | typename = internal::iterator_category_t<ForwardIterator2>, | 
|  | typename = indirect_result_t<Pred&, | 
|  | projected<ForwardIterator1, Proj1>, | 
|  | projected<ForwardIterator2, Proj2>>> | 
|  | constexpr bool equal(ForwardIterator1 first1, | 
|  | ForwardIterator1 last1, | 
|  | ForwardIterator2 first2, | 
|  | ForwardIterator2 last2, | 
|  | Pred pred = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | if (gurl_base::is_constant_evaluated()) { | 
|  | for (; first1 != last1 && first2 != last2; ++first1, ++first2) { | 
|  | if (!gurl_base::invoke(pred, gurl_base::invoke(proj1, *first1), | 
|  | gurl_base::invoke(proj2, *first2))) { | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | return first1 == last1 && first2 == last2; | 
|  | } | 
|  |  | 
|  | return std::equal(first1, last1, first2, last2, | 
|  | internal::ProjectedBinaryPredicate(pred, proj1, proj2)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be | 
|  | //   `invoke(pred, invoke(proj1, *i), | 
|  | //                 invoke(proj2, *(begin(range2) + (i - begin(range1)))))`. | 
|  | // | 
|  | // Returns: If `size(range1) != size(range2)`, return `false.` Otherwise return | 
|  | // `true` if `E(i)` holds for every iterator `i` in `range1`. Otherwise, returns | 
|  | // `false`. | 
|  | // | 
|  | // Complexity: If the types of `begin(range1)`, `end(range1)`, `begin(range2)`, | 
|  | // and `end(range2)` meet the `RandomAccessIterator` requirements and | 
|  | // `size(range1) != size(range2)`, then no applications of the corresponding | 
|  | // predicate and each projection; | 
|  | // otherwise, at most `min(size(range1), size(range2))` applications of the | 
|  | // corresponding predicate and any projections. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.equal#:~:text=ranges::equal(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = indirect_result_t<Pred&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>> | 
|  | constexpr bool equal(Range1&& range1, | 
|  | Range2&& range2, | 
|  | Pred pred = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::equal(ranges::begin(range1), ranges::end(range1), | 
|  | ranges::begin(range2), ranges::end(range2), | 
|  | std::move(pred), std::move(proj1), std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // [alg.is.permutation] Is permutation | 
|  | // Reference: https://wg21.link/alg.is.permutation | 
|  |  | 
|  | // Returns: If `last1 - first1 != last2 - first2`, return `false`. Otherwise | 
|  | // return `true` if there exists a permutation of the elements in the range | 
|  | // `[first2, last2)`, bounded by `[pfirst, plast)`, such that | 
|  | // `ranges::equal(first1, last1, pfirst, plast, pred, proj, proj)` returns | 
|  | // `true`; otherwise, returns `false`. | 
|  | // | 
|  | // Complexity: No applications of the corresponding predicate if | 
|  | // ForwardIterator1 and ForwardIterator2 meet the requirements of random access | 
|  | // iterators and `last1 - first1 != last2 - first2`. Otherwise, exactly | 
|  | // `last1 - first1` applications of the corresponding predicate and projections | 
|  | // if `ranges::equal(first1, last1, first2, last2, pred, proj, proj)` would | 
|  | // return true; | 
|  | // otherwise, at worst `O(N^2)`, where `N` has the value `last1 - first1`. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.is.permutation#:~:text=ranges::is_permutation(I1 | 
|  | template <typename ForwardIterator1, | 
|  | typename ForwardIterator2, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator1>, | 
|  | typename = internal::iterator_category_t<ForwardIterator2>, | 
|  | typename = indirect_result_t<Pred&, | 
|  | projected<ForwardIterator1, Proj1>, | 
|  | projected<ForwardIterator2, Proj2>>> | 
|  | constexpr bool is_permutation(ForwardIterator1 first1, | 
|  | ForwardIterator1 last1, | 
|  | ForwardIterator2 first2, | 
|  | ForwardIterator2 last2, | 
|  | Pred pred = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | // Needs to opt-in to all permutations, since std::is_permutation expects | 
|  | // pred(proj1(lhs), proj1(rhs)) to compile. | 
|  | return std::is_permutation( | 
|  | first1, last1, first2, last2, | 
|  | internal::PermutedProjectedBinaryPredicate(pred, proj1, proj2)); | 
|  | } | 
|  |  | 
|  | // Returns: If `size(range1) != size(range2)`, return `false`. Otherwise return | 
|  | // `true` if there exists a permutation of the elements in `range2`, bounded by | 
|  | // `[pbegin, pend)`, such that | 
|  | // `ranges::equal(range1, [pbegin, pend), pred, proj, proj)` returns `true`; | 
|  | // otherwise, returns `false`. | 
|  | // | 
|  | // Complexity: No applications of the corresponding predicate if Range1 and | 
|  | // Range2 meet the requirements of random access ranges and | 
|  | // `size(range1) != size(range2)`. Otherwise, exactly `size(range1)` | 
|  | // applications of the corresponding predicate and projections if | 
|  | // `ranges::equal(range1, range2, pred, proj, proj)` would return true; | 
|  | // otherwise, at worst `O(N^2)`, where `N` has the value `size(range1)`. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.is.permutation#:~:text=ranges::is_permutation(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = indirect_result_t<Pred&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>> | 
|  | constexpr bool is_permutation(Range1&& range1, | 
|  | Range2&& range2, | 
|  | Pred pred = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::is_permutation( | 
|  | ranges::begin(range1), ranges::end(range1), ranges::begin(range2), | 
|  | ranges::end(range2), std::move(pred), std::move(proj1), std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // [alg.search] Search | 
|  | // Reference: https://wg21.link/alg.search | 
|  |  | 
|  | // Returns: `i`, where `i` is the first iterator in the range | 
|  | // `[first1, last1 - (last2 - first2))` such that for every non-negative integer | 
|  | // `n` less than `last2 - first2` the condition | 
|  | // `bool(invoke(pred, invoke(proj1, *(i + n)), invoke(proj2, *(first2 + n))))` | 
|  | // is `true`. | 
|  | // Returns `last1` if no such iterator exists. | 
|  | // Note: std::ranges::search(I1 first1,...) returns a range, rather than an | 
|  | // iterator. For simplicitly we match std::search's return type instead. | 
|  | // | 
|  | // Complexity: At most `(last1 - first1) * (last2 - first2)` applications of the | 
|  | // corresponding predicate and projections. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.search#:~:text=ranges::search(I1 | 
|  | template <typename ForwardIterator1, | 
|  | typename ForwardIterator2, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator1>, | 
|  | typename = internal::iterator_category_t<ForwardIterator2>, | 
|  | typename = indirect_result_t<Pred&, | 
|  | projected<ForwardIterator1, Proj1>, | 
|  | projected<ForwardIterator2, Proj2>>> | 
|  | constexpr auto search(ForwardIterator1 first1, | 
|  | ForwardIterator1 last1, | 
|  | ForwardIterator2 first2, | 
|  | ForwardIterator2 last2, | 
|  | Pred pred = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return std::search(first1, last1, first2, last2, | 
|  | internal::ProjectedBinaryPredicate(pred, proj1, proj2)); | 
|  | } | 
|  |  | 
|  | // Returns: `i`, where `i` is the first iterator in the range | 
|  | // `[begin(range1), end(range1) - size(range2))` such that for every | 
|  | // non-negative integer `n` less than `size(range2)` the condition | 
|  | // `bool(invoke(pred, invoke(proj1, *(i + n)), | 
|  | //                    invoke(proj2, *(begin(range2) + n))))` is `true`. | 
|  | // Returns `end(range1)` if no such iterator exists. | 
|  | // Note: std::ranges::search(R1&& r1,...) returns a range, rather than an | 
|  | // iterator. For simplicitly we match std::search's return type instead. | 
|  | // | 
|  | // Complexity: At most `size(range1) * size(range2)` applications of the | 
|  | // corresponding predicate and projections. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.search#:~:text=ranges::search(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = indirect_result_t<Pred&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>> | 
|  | constexpr auto search(Range1&& range1, | 
|  | Range2&& range2, | 
|  | Pred pred = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::search(ranges::begin(range1), ranges::end(range1), | 
|  | ranges::begin(range2), ranges::end(range2), | 
|  | std::move(pred), std::move(proj1), std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // Mandates: The type `Size` is convertible to an integral type. | 
|  | // | 
|  | // Returns: `i` where `i` is the first iterator in the range | 
|  | // `[first, last - count)` such that for every non-negative integer `n` less | 
|  | // than `count`, the following condition holds: | 
|  | // `invoke(pred, invoke(proj, *(i + n)), value)`. | 
|  | // Returns `last` if no such iterator is found. | 
|  | // Note: std::ranges::search_n(I1 first1,...) returns a range, rather than an | 
|  | // iterator. For simplicitly we match std::search_n's return type instead. | 
|  | // | 
|  | // Complexity: At most `last - first` applications of the corresponding | 
|  | // predicate and projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.search#:~:text=ranges::search_n(I | 
|  | template <typename ForwardIterator, | 
|  | typename Size, | 
|  | typename T, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto search_n(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | Size count, | 
|  | const T& value, | 
|  | Pred pred = {}, | 
|  | Proj proj = {}) { | 
|  | // The second arg is guaranteed to be `value`, so we'll simply apply the | 
|  | // identity projection. | 
|  | identity value_proj; | 
|  | return std::search_n( | 
|  | first, last, count, value, | 
|  | internal::ProjectedBinaryPredicate(pred, proj, value_proj)); | 
|  | } | 
|  |  | 
|  | // Mandates: The type `Size` is convertible to an integral type. | 
|  | // | 
|  | // Returns: `i` where `i` is the first iterator in the range | 
|  | // `[begin(range), end(range) - count)` such that for every non-negative integer | 
|  | // `n` less than `count`, the following condition holds: | 
|  | // `invoke(pred, invoke(proj, *(i + n)), value)`. | 
|  | // Returns `end(arnge)` if no such iterator is found. | 
|  | // Note: std::ranges::search_n(R1&& r1,...) returns a range, rather than an | 
|  | // iterator. For simplicitly we match std::search_n's return type instead. | 
|  | // | 
|  | // Complexity: At most `size(range)` applications of the corresponding predicate | 
|  | // and projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.search#:~:text=ranges::search_n(R | 
|  | template <typename Range, | 
|  | typename Size, | 
|  | typename T, | 
|  | typename Pred = ranges::equal_to, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto search_n(Range&& range, | 
|  | Size count, | 
|  | const T& value, | 
|  | Pred pred = {}, | 
|  | Proj proj = {}) { | 
|  | return ranges::search_n(ranges::begin(range), ranges::end(range), count, | 
|  | value, std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.modifying.operations] Mutating sequence operations | 
|  | // Reference: https://wg21.link/alg.modifying.operations | 
|  |  | 
|  | // [alg.copy] Copy | 
|  | // Reference: https://wg21.link/alg.copy | 
|  |  | 
|  | // Let N be `last - first`. | 
|  | // | 
|  | // Preconditions: `result` is not in the range `[first, last)`. | 
|  | // | 
|  | // Effects: Copies elements in the range `[first, last)` into the range | 
|  | // `[result, result + N)` starting from `first` and proceeding to `last`. For | 
|  | // each non-negative integer `n < N` , performs `*(result + n) = *(first + n)`. | 
|  | // | 
|  | // Returns: `result + N` | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy(I | 
|  | template <typename InputIterator, | 
|  | typename OutputIterator, | 
|  | typename = internal::iterator_category_t<InputIterator>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto copy(InputIterator first, | 
|  | InputIterator last, | 
|  | OutputIterator result) { | 
|  | return std::copy(first, last, result); | 
|  | } | 
|  |  | 
|  | // Let N be `size(range)`. | 
|  | // | 
|  | // Preconditions: `result` is not in `range`. | 
|  | // | 
|  | // Effects: Copies elements in `range` into the range `[result, result + N)` | 
|  | // starting from `begin(range)` and proceeding to `end(range)`. For each | 
|  | // non-negative integer `n < N` , performs | 
|  | // *(result + n) = *(begin(range) + n)`. | 
|  | // | 
|  | // Returns: `result + N` | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy(R | 
|  | template <typename Range, | 
|  | typename OutputIterator, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto copy(Range&& range, OutputIterator result) { | 
|  | return ranges::copy(ranges::begin(range), ranges::end(range), result); | 
|  | } | 
|  |  | 
|  | // Let `N` be `max(0, n)`. | 
|  | // | 
|  | // Mandates: The type `Size` is convertible to an integral type. | 
|  | // | 
|  | // Effects: For each non-negative integer `i < N`, performs | 
|  | // `*(result + i) = *(first + i)`. | 
|  | // | 
|  | // Returns: `result + N` | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy_n | 
|  | template <typename InputIterator, | 
|  | typename Size, | 
|  | typename OutputIterator, | 
|  | typename = internal::iterator_category_t<InputIterator>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto copy_n(InputIterator first, Size n, OutputIterator result) { | 
|  | return std::copy_n(first, n, result); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`, and `N` be the number | 
|  | // of iterators `i` in the range `[first, last)` for which the condition `E(i)` | 
|  | // holds. | 
|  | // | 
|  | // Preconditions: The ranges `[first, last)` and | 
|  | // `[result, result + (last - first))` do not overlap. | 
|  | // | 
|  | // Effects: Copies all of the elements referred to by the iterator `i` in the | 
|  | // range `[first, last)` for which `E(i)` is true. | 
|  | // | 
|  | // Returns: `result + N` | 
|  | // | 
|  | // Complexity: Exactly `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy_if(I | 
|  | template <typename InputIterator, | 
|  | typename OutputIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto copy_if(InputIterator first, | 
|  | InputIterator last, | 
|  | OutputIterator result, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | return std::copy_if(first, last, result, | 
|  | internal::ProjectedUnaryPredicate(pred, proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`, and `N` be the number | 
|  | // of iterators `i` in `range` for which the condition `E(i)` holds. | 
|  | // | 
|  | // Preconditions: `range`  and `[result, result + size(range))` do not overlap. | 
|  | // | 
|  | // Effects: Copies all of the elements referred to by the iterator `i` in | 
|  | // `range` for which `E(i)` is true. | 
|  | // | 
|  | // Returns: `result + N` | 
|  | // | 
|  | // Complexity: Exactly `size(range)` applications of the corresponding predicate | 
|  | // and any projection. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy_if(R | 
|  | template <typename Range, | 
|  | typename OutputIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto copy_if(Range&& range, | 
|  | OutputIterator result, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | return ranges::copy_if(ranges::begin(range), ranges::end(range), result, | 
|  | std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `N` be `last - first`. | 
|  | // | 
|  | // Preconditions: `result` is not in the range `(first, last]`. | 
|  | // | 
|  | // Effects: Copies elements in the range `[first, last)` into the range | 
|  | // `[result - N, result)` starting from `last - 1` and proceeding to `first`. | 
|  | // For each positive integer `n ≤ N`, performs `*(result - n) = *(last - n)`. | 
|  | // | 
|  | // Returns: `result - N` | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy_backward(I1 | 
|  | template <typename BidirectionalIterator1, | 
|  | typename BidirectionalIterator2, | 
|  | typename = internal::iterator_category_t<BidirectionalIterator1>, | 
|  | typename = internal::iterator_category_t<BidirectionalIterator2>> | 
|  | constexpr auto copy_backward(BidirectionalIterator1 first, | 
|  | BidirectionalIterator1 last, | 
|  | BidirectionalIterator2 result) { | 
|  | return std::copy_backward(first, last, result); | 
|  | } | 
|  |  | 
|  | // Let `N` be `size(range)`. | 
|  | // | 
|  | // Preconditions: `result` is not in the range `(begin(range), end(range)]`. | 
|  | // | 
|  | // Effects: Copies elements in `range` into the range `[result - N, result)` | 
|  | // starting from `end(range) - 1` and proceeding to `begin(range)`. For each | 
|  | // positive integer `n ≤ N`, performs `*(result - n) = *(end(range) - n)`. | 
|  | // | 
|  | // Returns: `result - N` | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.copy#:~:text=ranges::copy_backward(R | 
|  | template <typename Range, | 
|  | typename BidirectionalIterator, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<BidirectionalIterator>> | 
|  | constexpr auto copy_backward(Range&& range, BidirectionalIterator result) { | 
|  | return ranges::copy_backward(ranges::begin(range), ranges::end(range), | 
|  | result); | 
|  | } | 
|  |  | 
|  | // [alg.move] Move | 
|  | // Reference: https://wg21.link/alg.move | 
|  |  | 
|  | // Let `E(n)` be `std::move(*(first + n))`. | 
|  | // | 
|  | // Let `N` be `last - first`. | 
|  | // | 
|  | // Preconditions: `result` is not in the range `[first, last)`. | 
|  | // | 
|  | // Effects: Moves elements in the range `[first, last)` into the range `[result, | 
|  | // result + N)` starting from `first` and proceeding to `last`. For each | 
|  | // non-negative integer `n < N`, performs `*(result + n) = E(n)`. | 
|  | // | 
|  | // Returns: `result + N` | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.move#:~:text=ranges::move(I | 
|  | template <typename InputIterator, | 
|  | typename OutputIterator, | 
|  | typename = internal::iterator_category_t<InputIterator>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto move(InputIterator first, | 
|  | InputIterator last, | 
|  | OutputIterator result) { | 
|  | return std::move(first, last, result); | 
|  | } | 
|  |  | 
|  | // Let `E(n)` be `std::move(*(begin(range) + n))`. | 
|  | // | 
|  | // Let `N` be `size(range)`. | 
|  | // | 
|  | // Preconditions: `result` is not in `range`. | 
|  | // | 
|  | // Effects: Moves elements in `range` into the range `[result, result + N)` | 
|  | // starting from `begin(range)` and proceeding to `end(range)`. For each | 
|  | // non-negative integer `n < N`, performs `*(result + n) = E(n)`. | 
|  | // | 
|  | // Returns: `result + N` | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.move#:~:text=ranges::move(R | 
|  | template <typename Range, | 
|  | typename OutputIterator, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto move(Range&& range, OutputIterator result) { | 
|  | return ranges::move(ranges::begin(range), ranges::end(range), result); | 
|  | } | 
|  |  | 
|  | // Let `E(n)` be `std::move(*(last - n))`. | 
|  | // | 
|  | // Let `N` be `last - first`. | 
|  | // | 
|  | // Preconditions: `result` is not in the range `(first, last]`. | 
|  | // | 
|  | // Effects: Moves elements in the range `[first, last)` into the range | 
|  | // `[result - N, result)` starting from `last - 1` and proceeding to `first`. | 
|  | // For each positive integer `n ≤ N`, performs `*(result - n) = E(n)`. | 
|  | // | 
|  | // Returns: `result - N` | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.move#:~:text=ranges::move_backward(I1 | 
|  | template <typename BidirectionalIterator1, | 
|  | typename BidirectionalIterator2, | 
|  | typename = internal::iterator_category_t<BidirectionalIterator1>, | 
|  | typename = internal::iterator_category_t<BidirectionalIterator2>> | 
|  | constexpr auto move_backward(BidirectionalIterator1 first, | 
|  | BidirectionalIterator1 last, | 
|  | BidirectionalIterator2 result) { | 
|  | return std::move_backward(first, last, result); | 
|  | } | 
|  |  | 
|  | // Let `E(n)` be `std::move(*(end(range) - n))`. | 
|  | // | 
|  | // Let `N` be `size(range)`. | 
|  | // | 
|  | // Preconditions: `result` is not in the range `(begin(range), end(range)]`. | 
|  | // | 
|  | // Effects: Moves elements in `range` into the range `[result - N, result)` | 
|  | // starting from `end(range) - 1` and proceeding to `begin(range)`. For each | 
|  | // positive integer `n ≤ N`, performs `*(result - n) = E(n)`. | 
|  | // | 
|  | // Returns: `result - N` | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.move#:~:text=ranges::move_backward(R | 
|  | template <typename Range, | 
|  | typename BidirectionalIterator, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<BidirectionalIterator>> | 
|  | constexpr auto move_backward(Range&& range, BidirectionalIterator result) { | 
|  | return ranges::move_backward(ranges::begin(range), ranges::end(range), | 
|  | result); | 
|  | } | 
|  |  | 
|  | // [alg.swap] Swap | 
|  | // Reference: https://wg21.link/alg.swap | 
|  |  | 
|  | // Let `M` be `min(last1 - first1, last2 - first2)`. | 
|  | // | 
|  | // Preconditions: The two ranges `[first1, last1)` and `[first2, last2)` do not | 
|  | // overlap. `*(first1 + n)` is swappable with `*(first2 + n)`. | 
|  | // | 
|  | // Effects: For each non-negative integer `n < M` performs | 
|  | // `swap(*(first1 + n), *(first2 + n))` | 
|  | // | 
|  | // Returns: `first2 + M` | 
|  | // | 
|  | // Complexity: Exactly `M` swaps. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.swap#:~:text=ranges::swap_ranges(I1 | 
|  | template <typename ForwardIterator1, | 
|  | typename ForwardIterator2, | 
|  | typename = internal::iterator_category_t<ForwardIterator1>, | 
|  | typename = internal::iterator_category_t<ForwardIterator2>> | 
|  | constexpr auto swap_ranges(ForwardIterator1 first1, | 
|  | ForwardIterator1 last1, | 
|  | ForwardIterator2 first2, | 
|  | ForwardIterator2 last2) { | 
|  | // std::swap_ranges does not have a `last2` overload. Thus we need to | 
|  | // adjust `last1` to ensure to not read past `last2`. | 
|  | last1 = std::next(first1, std::min(std::distance(first1, last1), | 
|  | std::distance(first2, last2))); | 
|  | return std::swap_ranges(first1, last1, first2); | 
|  | } | 
|  |  | 
|  | // Let `M` be `min(size(range1), size(range2))`. | 
|  | // | 
|  | // Preconditions: The two ranges `range1` and `range2` do not overlap. | 
|  | // `*(begin(range1) + n)` is swappable with `*(begin(range2) + n)`. | 
|  | // | 
|  | // Effects: For each non-negative integer `n < M` performs | 
|  | // `swap(*(begin(range1) + n), *(begin(range2) + n))` | 
|  | // | 
|  | // Returns: `begin(range2) + M` | 
|  | // | 
|  | // Complexity: Exactly `M` swaps. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.swap#:~:text=ranges::swap_ranges(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>> | 
|  | constexpr auto swap_ranges(Range1&& range1, Range2&& range2) { | 
|  | return ranges::swap_ranges(ranges::begin(range1), ranges::end(range1), | 
|  | ranges::begin(range2), ranges::end(range2)); | 
|  | } | 
|  |  | 
|  | // [alg.transform] Transform | 
|  | // Reference: https://wg21.link/alg.transform | 
|  |  | 
|  | // Let `N` be `last1 - first1`, | 
|  | // `E(i)` be `invoke(op, invoke(proj, *(first1 + (i - result))))`. | 
|  | // | 
|  | // Preconditions: `op` does not invalidate iterators or subranges, nor modify | 
|  | // elements in the ranges `[first1, first1 + N]`, and `[result, result + N]`. | 
|  | // | 
|  | // Effects: Assigns through every iterator `i` in the range | 
|  | // `[result, result + N)` a new corresponding value equal to `E(i)`. | 
|  | // | 
|  | // Returns: `result + N` | 
|  | // | 
|  | // Complexity: Exactly `N` applications of `op` and any projections. | 
|  | // | 
|  | // Remarks: result may be equal to `first1`. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.transform#:~:text=ranges::transform(I | 
|  | template <typename InputIterator, | 
|  | typename OutputIterator, | 
|  | typename UnaryOperation, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<UnaryOperation&, | 
|  | projected<InputIterator, Proj>>> | 
|  | constexpr auto transform(InputIterator first1, | 
|  | InputIterator last1, | 
|  | OutputIterator result, | 
|  | UnaryOperation op, | 
|  | Proj proj = {}) { | 
|  | return std::transform(first1, last1, result, [&op, &proj](auto&& arg) { | 
|  | return gurl_base::invoke(op, | 
|  | gurl_base::invoke(proj, std::forward<decltype(arg)>(arg))); | 
|  | }); | 
|  | } | 
|  |  | 
|  | // Let `N` be `size(range)`, | 
|  | // `E(i)` be `invoke(op, invoke(proj, *(begin(range) + (i - result))))`. | 
|  | // | 
|  | // Preconditions: `op` does not invalidate iterators or subranges, nor modify | 
|  | // elements in the ranges `[begin(range), end(range)]`, and | 
|  | // `[result, result + N]`. | 
|  | // | 
|  | // Effects: Assigns through every iterator `i` in the range | 
|  | // `[result, result + N)` a new corresponding value equal to `E(i)`. | 
|  | // | 
|  | // Returns: `result + N` | 
|  | // | 
|  | // Complexity: Exactly `N` applications of `op` and any projections. | 
|  | // | 
|  | // Remarks: result may be equal to `begin(range)`. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.transform#:~:text=ranges::transform(R | 
|  | template <typename Range, | 
|  | typename OutputIterator, | 
|  | typename UnaryOperation, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<UnaryOperation&, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto transform(Range&& range, | 
|  | OutputIterator result, | 
|  | UnaryOperation op, | 
|  | Proj proj = {}) { | 
|  | return ranges::transform(ranges::begin(range), ranges::end(range), result, | 
|  | std::move(op), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let: | 
|  | // `N` be `min(last1 - first1, last2 - first2)`, | 
|  | // `E(i)` be `invoke(binary_op, invoke(proj1, *(first1 + (i - result))), | 
|  | //                              invoke(proj2, *(first2 + (i - result))))`. | 
|  | // | 
|  | // Preconditions: `binary_op` does not invalidate iterators or subranges, nor | 
|  | // modify elements in the ranges `[first1, first1 + N]`, `[first2, first2 + N]`, | 
|  | // and `[result, result + N]`. | 
|  | // | 
|  | // Effects: Assigns through every iterator `i` in the range | 
|  | // `[result, result + N)` a new corresponding value equal to `E(i)`. | 
|  | // | 
|  | // Returns: `result + N` | 
|  | // | 
|  | // Complexity: Exactly `N` applications of `binary_op`, and any projections. | 
|  | // | 
|  | // Remarks: `result` may be equal to `first1` or `first2`. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.transform#:~:text=ranges::transform(I1 | 
|  | template <typename ForwardIterator1, | 
|  | typename ForwardIterator2, | 
|  | typename OutputIterator, | 
|  | typename BinaryOperation, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator1>, | 
|  | typename = internal::iterator_category_t<ForwardIterator2>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<BinaryOperation&, | 
|  | projected<ForwardIterator1, Proj1>, | 
|  | projected<ForwardIterator2, Proj2>>> | 
|  | constexpr auto transform(ForwardIterator1 first1, | 
|  | ForwardIterator1 last1, | 
|  | ForwardIterator2 first2, | 
|  | ForwardIterator2 last2, | 
|  | OutputIterator result, | 
|  | BinaryOperation binary_op, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | // std::transform does not have a `last2` overload. Thus we need to adjust | 
|  | // `last1` to ensure to not read past `last2`. | 
|  | last1 = std::next(first1, std::min(std::distance(first1, last1), | 
|  | std::distance(first2, last2))); | 
|  | return std::transform( | 
|  | first1, last1, first2, result, | 
|  | [&binary_op, &proj1, &proj2](auto&& lhs, auto&& rhs) { | 
|  | return gurl_base::invoke( | 
|  | binary_op, gurl_base::invoke(proj1, std::forward<decltype(lhs)>(lhs)), | 
|  | gurl_base::invoke(proj2, std::forward<decltype(rhs)>(rhs))); | 
|  | }); | 
|  | } | 
|  |  | 
|  | // Let: | 
|  | // `N` be `min(size(range1), size(range2)`, | 
|  | // `E(i)` be `invoke(binary_op, invoke(proj1, *(begin(range1) + (i - result))), | 
|  | //                              invoke(proj2, *(begin(range2) + (i - result))))` | 
|  | // | 
|  | // Preconditions: `binary_op` does not invalidate iterators or subranges, nor | 
|  | // modify elements in the ranges `[begin(range1), end(range1)]`, | 
|  | // `[begin(range2), end(range2)]`, and `[result, result + N]`. | 
|  | // | 
|  | // Effects: Assigns through every iterator `i` in the range | 
|  | // `[result, result + N)` a new corresponding value equal to `E(i)`. | 
|  | // | 
|  | // Returns: `result + N` | 
|  | // | 
|  | // Complexity: Exactly `N` applications of `binary_op`, and any projections. | 
|  | // | 
|  | // Remarks: `result` may be equal to `begin(range1)` or `begin(range2)`. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.transform#:~:text=ranges::transform(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename OutputIterator, | 
|  | typename BinaryOperation, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<BinaryOperation&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>> | 
|  | constexpr auto transform(Range1&& range1, | 
|  | Range2&& range2, | 
|  | OutputIterator result, | 
|  | BinaryOperation binary_op, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::transform(ranges::begin(range1), ranges::end(range1), | 
|  | ranges::begin(range2), ranges::end(range2), result, | 
|  | std::move(binary_op), std::move(proj1), | 
|  | std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // [alg.replace] Replace | 
|  | // Reference: https://wg21.link/alg.replace | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(proj, *i) == old_value)`. | 
|  | // | 
|  | // Mandates: `new_value` is writable  to `first`. | 
|  | // | 
|  | // Effects: Substitutes elements referred by the iterator `i` in the range | 
|  | // `[first, last)` with `new_value`, when `E(i)` is true. | 
|  | // | 
|  | // Returns: `last` | 
|  | // | 
|  | // Complexity: Exactly `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace(I | 
|  | template <typename ForwardIterator, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto replace(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | const T& old_value, | 
|  | const T& new_value, | 
|  | Proj proj = {}) { | 
|  | // Note: In order to be able to apply `proj` to each element in [first, last) | 
|  | // we are dispatching to std::replace_if instead of std::replace. | 
|  | std::replace_if( | 
|  | first, last, | 
|  | [&proj, &old_value](auto&& lhs) { | 
|  | return gurl_base::invoke(proj, std::forward<decltype(lhs)>(lhs)) == | 
|  | old_value; | 
|  | }, | 
|  | new_value); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(proj, *i) == old_value)`. | 
|  | // | 
|  | // Mandates: `new_value` is writable  to `begin(range)`. | 
|  | // | 
|  | // Effects: Substitutes elements referred by the iterator `i` in `range` with | 
|  | // `new_value`, when `E(i)` is true. | 
|  | // | 
|  | // Returns: `end(range)` | 
|  | // | 
|  | // Complexity: Exactly `size(range)` applications of the corresponding predicate | 
|  | // and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace(R | 
|  | template <typename Range, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto replace(Range&& range, | 
|  | const T& old_value, | 
|  | const T& new_value, | 
|  | Proj proj = {}) { | 
|  | return ranges::replace(ranges::begin(range), ranges::end(range), old_value, | 
|  | new_value, std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`. | 
|  | // | 
|  | // Mandates: `new_value` is writable  to `first`. | 
|  | // | 
|  | // Effects: Substitutes elements referred by the iterator `i` in the range | 
|  | // `[first, last)` with `new_value`, when `E(i)` is true. | 
|  | // | 
|  | // Returns: `last` | 
|  | // | 
|  | // Complexity: Exactly `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace_if(I | 
|  | template <typename ForwardIterator, | 
|  | typename Predicate, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto replace_if(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | Predicate pred, | 
|  | const T& new_value, | 
|  | Proj proj = {}) { | 
|  | std::replace_if(first, last, internal::ProjectedUnaryPredicate(pred, proj), | 
|  | new_value); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`. | 
|  | // | 
|  | // Mandates: `new_value` is writable  to `begin(range)`. | 
|  | // | 
|  | // Effects: Substitutes elements referred by the iterator `i` in `range` with | 
|  | // `new_value`, when `E(i)` is true. | 
|  | // | 
|  | // Returns: `end(range)` | 
|  | // | 
|  | // Complexity: Exactly `size(range)` applications of the corresponding predicate | 
|  | // and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace_if(R | 
|  | template <typename Range, | 
|  | typename Predicate, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto replace_if(Range&& range, | 
|  | Predicate pred, | 
|  | const T& new_value, | 
|  | Proj proj = {}) { | 
|  | return ranges::replace_if(ranges::begin(range), ranges::end(range), | 
|  | std::move(pred), new_value, std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(proj, *(first + (i - result))) == old_value)`. | 
|  | // | 
|  | // Mandates: The results of the expressions `*first` and `new_value` are | 
|  | // writable  to `result`. | 
|  | // | 
|  | // Preconditions: The ranges `[first, last)` and `[result, result + (last - | 
|  | // first))` do not overlap. | 
|  | // | 
|  | // Effects: Assigns through every iterator `i` in the range `[result, result + | 
|  | // (last - first))` a new corresponding value, `new_value` if `E(i)` is true, or | 
|  | // `*(first + (i - result))` otherwise. | 
|  | // | 
|  | // Returns: `result + (last - first)`. | 
|  | // | 
|  | // Complexity: Exactly `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace_copy(I | 
|  | template <typename InputIterator, | 
|  | typename OutputIterator, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto replace_copy(InputIterator first, | 
|  | InputIterator last, | 
|  | OutputIterator result, | 
|  | const T& old_value, | 
|  | const T& new_value, | 
|  | Proj proj = {}) { | 
|  | // Note: In order to be able to apply `proj` to each element in [first, last) | 
|  | // we are dispatching to std::replace_copy_if instead of std::replace_copy. | 
|  | std::replace_copy_if( | 
|  | first, last, result, | 
|  | [&proj, &old_value](auto&& lhs) { | 
|  | return gurl_base::invoke(proj, std::forward<decltype(lhs)>(lhs)) == | 
|  | old_value; | 
|  | }, | 
|  | new_value); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be | 
|  | // `bool(invoke(proj, *(begin(range) + (i - result))) == old_value)`. | 
|  | // | 
|  | // Mandates: The results of the expressions `*begin(range)` and `new_value` are | 
|  | // writable  to `result`. | 
|  | // | 
|  | // Preconditions: The ranges `range` and `[result, result + size(range))` do not | 
|  | // overlap. | 
|  | // | 
|  | // Effects: Assigns through every iterator `i` in the range `[result, result + | 
|  | // size(range))` a new corresponding value, `new_value` if `E(i)` is true, or | 
|  | // `*(begin(range) + (i - result))` otherwise. | 
|  | // | 
|  | // Returns: `result + size(range)`. | 
|  | // | 
|  | // Complexity: Exactly `size(range)` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace_copy(R | 
|  | template <typename Range, | 
|  | typename OutputIterator, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto replace_copy(Range&& range, | 
|  | OutputIterator result, | 
|  | const T& old_value, | 
|  | const T& new_value, | 
|  | Proj proj = {}) { | 
|  | return ranges::replace_copy(ranges::begin(range), ranges::end(range), result, | 
|  | old_value, new_value, std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *(first + (i - result)))))`. | 
|  | // | 
|  | // Mandates: The results of the expressions `*first` and `new_value` are | 
|  | // writable  to `result`. | 
|  | // | 
|  | // Preconditions: The ranges `[first, last)` and `[result, result + (last - | 
|  | // first))` do not overlap. | 
|  | // | 
|  | // Effects: Assigns through every iterator `i` in the range `[result, result + | 
|  | // (last - first))` a new corresponding value, `new_value` if `E(i)` is true, or | 
|  | // `*(first + (i - result))` otherwise. | 
|  | // | 
|  | // Returns: `result + (last - first)`. | 
|  | // | 
|  | // Complexity: Exactly `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace_copy_if(I | 
|  | template <typename InputIterator, | 
|  | typename OutputIterator, | 
|  | typename Predicate, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto replace_copy_if(InputIterator first, | 
|  | InputIterator last, | 
|  | OutputIterator result, | 
|  | Predicate pred, | 
|  | const T& new_value, | 
|  | Proj proj = {}) { | 
|  | return std::replace_copy_if(first, last, result, | 
|  | internal::ProjectedUnaryPredicate(pred, proj), | 
|  | new_value); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be | 
|  | // `bool(invoke(pred, invoke(proj, *(begin(range) + (i - result)))))`. | 
|  | // | 
|  | // Mandates: The results of the expressions `*begin(range)` and `new_value` are | 
|  | // writable  to `result`. | 
|  | // | 
|  | // Preconditions: The ranges `range` and `[result, result + size(range))` do not | 
|  | // overlap. | 
|  | // | 
|  | // Effects: Assigns through every iterator `i` in the range `[result, result + | 
|  | // size(range))` a new corresponding value, `new_value` if `E(i)` is true, or | 
|  | // `*(begin(range) + (i - result))` otherwise. | 
|  | // | 
|  | // Returns: `result + size(range)`. | 
|  | // | 
|  | // Complexity: Exactly `size(range)` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.replace#:~:text=ranges::replace_copy_if(R | 
|  | template <typename Range, | 
|  | typename OutputIterator, | 
|  | typename Predicate, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto replace_copy_if(Range&& range, | 
|  | OutputIterator result, | 
|  | Predicate pred, | 
|  | const T& new_value, | 
|  | Proj proj = {}) { | 
|  | return ranges::replace_copy_if(ranges::begin(range), ranges::end(range), | 
|  | result, pred, new_value, std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.fill] Fill | 
|  | // Reference: https://wg21.link/alg.fill | 
|  |  | 
|  | // Let `N` be `last - first`. | 
|  | // | 
|  | // Mandates: The expression `value` is writable to the output iterator. | 
|  | // | 
|  | // Effects: Assigns `value` through all the iterators in the range | 
|  | // `[first, last)`. | 
|  | // | 
|  | // Returns: `last`. | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.fill#:~:text=ranges::fill(O | 
|  | template <typename OutputIterator, | 
|  | typename T, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto fill(OutputIterator first, OutputIterator last, const T& value) { | 
|  | std::fill(first, last, value); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Let `N` be `size(range)`. | 
|  | // | 
|  | // Mandates: The expression `value` is writable to the output iterator. | 
|  | // | 
|  | // Effects: Assigns `value` through all the iterators in `range`. | 
|  | // | 
|  | // Returns: `end(range)`. | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.fill#:~:text=ranges::fill(R | 
|  | template <typename Range, | 
|  | typename T, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto fill(Range&& range, const T& value) { | 
|  | return ranges::fill(ranges::begin(range), ranges::end(range), value); | 
|  | } | 
|  |  | 
|  | // Let `N` be `max(0, n)`. | 
|  | // | 
|  | // Mandates: The expression `value` is writable to the output iterator. | 
|  | // The type `Size` is convertible to an integral type. | 
|  | // | 
|  | // Effects: Assigns `value` through all the iterators in `[first, first + N)`. | 
|  | // | 
|  | // Returns: `first + N`. | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.fill#:~:text=ranges::fill_n(O | 
|  | template <typename OutputIterator, | 
|  | typename Size, | 
|  | typename T, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto fill_n(OutputIterator first, Size n, const T& value) { | 
|  | return std::fill_n(first, n, value); | 
|  | } | 
|  |  | 
|  | // [alg.generate] Generate | 
|  | // Reference: https://wg21.link/alg.generate | 
|  |  | 
|  | // Let `N` be `last - first`. | 
|  | // | 
|  | // Effects: Assigns the result of successive evaluations of gen() through each | 
|  | // iterator in the range `[first, last)`. | 
|  | // | 
|  | // Returns: `last`. | 
|  | // | 
|  | // Complexity: Exactly `N` evaluations of `gen()` and assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.generate#:~:text=ranges::generate(O | 
|  | template <typename OutputIterator, | 
|  | typename Generator, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto generate(OutputIterator first, | 
|  | OutputIterator last, | 
|  | Generator gen) { | 
|  | std::generate(first, last, std::move(gen)); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Let `N` be `size(range)`. | 
|  | // | 
|  | // Effects: Assigns the result of successive evaluations of gen() through each | 
|  | // iterator in `range`. | 
|  | // | 
|  | // Returns: `end(range)`. | 
|  | // | 
|  | // Complexity: Exactly `N` evaluations of `gen()` and assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.generate#:~:text=ranges::generate(R | 
|  | template <typename Range, | 
|  | typename Generator, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto generate(Range&& range, Generator gen) { | 
|  | return ranges::generate(ranges::begin(range), ranges::end(range), | 
|  | std::move(gen)); | 
|  | } | 
|  |  | 
|  | // Let `N` be `max(0, n)`. | 
|  | // | 
|  | // Mandates: `Size` is convertible to an integral type. | 
|  | // | 
|  | // Effects: Assigns the result of successive evaluations of gen() through each | 
|  | // iterator in the range `[first, first + N)`. | 
|  | // | 
|  | // Returns: `first + N`. | 
|  | // | 
|  | // Complexity: Exactly `N` evaluations of `gen()` and assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.generate#:~:text=ranges::generate_n(O | 
|  | template <typename OutputIterator, | 
|  | typename Size, | 
|  | typename Generator, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto generate_n(OutputIterator first, Size n, Generator gen) { | 
|  | return std::generate_n(first, n, std::move(gen)); | 
|  | } | 
|  |  | 
|  | // [alg.remove] Remove | 
|  | // Reference: https://wg21.link/alg.remove | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(proj, *i) == value)`. | 
|  | // | 
|  | // Effects: Eliminates all the elements referred to by iterator `i` in the range | 
|  | // `[first, last)` for which `E(i)` holds. | 
|  | // | 
|  | // Returns: The end of the resulting range. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Complexity: Exactly `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove(I | 
|  | template <typename ForwardIterator, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto remove(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | const T& value, | 
|  | Proj proj = {}) { | 
|  | // Note: In order to be able to apply `proj` to each element in [first, last) | 
|  | // we are dispatching to std::remove_if instead of std::remove. | 
|  | return std::remove_if(first, last, [&proj, &value](auto&& lhs) { | 
|  | return gurl_base::invoke(proj, std::forward<decltype(lhs)>(lhs)) == value; | 
|  | }); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(proj, *i) == value)`. | 
|  | // | 
|  | // Effects: Eliminates all the elements referred to by iterator `i` in `range` | 
|  | // for which `E(i)` holds. | 
|  | // | 
|  | // Returns: The end of the resulting range. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Complexity: Exactly `size(range)` applications of the corresponding predicate | 
|  | // and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove(R | 
|  | template <typename Range, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto remove(Range&& range, const T& value, Proj proj = {}) { | 
|  | return ranges::remove(ranges::begin(range), ranges::end(range), value, | 
|  | std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`. | 
|  | // | 
|  | // Effects: Eliminates all the elements referred to by iterator `i` in the range | 
|  | // `[first, last)` for which `E(i)` holds. | 
|  | // | 
|  | // Returns: The end of the resulting range. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Complexity: Exactly `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove_if(I | 
|  | template <typename ForwardIterator, | 
|  | typename Predicate, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto remove_if(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | Predicate pred, | 
|  | Proj proj = {}) { | 
|  | return std::remove_if(first, last, | 
|  | internal::ProjectedUnaryPredicate(pred, proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`. | 
|  | // | 
|  | // Effects: Eliminates all the elements referred to by iterator `i` in `range`. | 
|  | // | 
|  | // Returns: The end of the resulting range. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Complexity: Exactly `size(range)` applications of the corresponding predicate | 
|  | // and any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove_if(R | 
|  | template <typename Range, | 
|  | typename Predicate, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto remove_if(Range&& range, Predicate pred, Proj proj = {}) { | 
|  | return ranges::remove_if(ranges::begin(range), ranges::end(range), | 
|  | std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(proj, *i) == value)`. | 
|  | // | 
|  | // Let `N` be the number of elements in `[first, last)` for which `E(i)` is | 
|  | // false. | 
|  | // | 
|  | // Mandates: `*first` is writable to `result`. | 
|  | // | 
|  | // Preconditions: The ranges `[first, last)` and `[result, result + (last - | 
|  | // first))` do not overlap. | 
|  | // | 
|  | // Effects: Copies all the elements referred to by the iterator `i` in the range | 
|  | // `[first, last)` for which `E(i)` is false. | 
|  | // | 
|  | // Returns: `result + N`. | 
|  | // | 
|  | // Complexity: Exactly `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove_copy(I | 
|  | template <typename InputIterator, | 
|  | typename OutputIterator, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto remove_copy(InputIterator first, | 
|  | InputIterator last, | 
|  | OutputIterator result, | 
|  | const T& value, | 
|  | Proj proj = {}) { | 
|  | // Note: In order to be able to apply `proj` to each element in [first, last) | 
|  | // we are dispatching to std::remove_copy_if instead of std::remove_copy. | 
|  | return std::remove_copy_if(first, last, result, [&proj, &value](auto&& lhs) { | 
|  | return gurl_base::invoke(proj, std::forward<decltype(lhs)>(lhs)) == value; | 
|  | }); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(proj, *i) == value)`. | 
|  | // | 
|  | // Let `N` be the number of elements in `range` for which `E(i)` is false. | 
|  | // | 
|  | // Mandates: `*begin(range)` is writable to `result`. | 
|  | // | 
|  | // Preconditions: The ranges `range` and `[result, result + size(range))` do not | 
|  | // overlap. | 
|  | // | 
|  | // Effects: Copies all the elements referred to by the iterator `i` in `range` | 
|  | //  for which `E(i)` is false. | 
|  | // | 
|  | // Returns: `result + N`. | 
|  | // | 
|  | // Complexity: Exactly `size(range)` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove_copy(R | 
|  | template <typename Range, | 
|  | typename OutputIterator, | 
|  | typename T, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto remove_copy(Range&& range, | 
|  | OutputIterator result, | 
|  | const T& value, | 
|  | Proj proj = {}) { | 
|  | return ranges::remove_copy(ranges::begin(range), ranges::end(range), result, | 
|  | value, std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`. | 
|  | // | 
|  | // Let `N` be the number of elements in `[first, last)` for which `E(i)` is | 
|  | // false. | 
|  | // | 
|  | // Mandates: `*first` is writable to `result`. | 
|  | // | 
|  | // Preconditions: The ranges `[first, last)` and `[result, result + (last - | 
|  | // first))` do not overlap. | 
|  | // | 
|  | // Effects: Copies all the elements referred to by the iterator `i` in the range | 
|  | // `[first, last)` for which `E(i)` is false. | 
|  | // | 
|  | // Returns: `result + N`. | 
|  | // | 
|  | // Complexity: Exactly `last - first` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove_copy_if(I | 
|  | template <typename InputIterator, | 
|  | typename OutputIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto remove_copy_if(InputIterator first, | 
|  | InputIterator last, | 
|  | OutputIterator result, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | return std::remove_copy_if(first, last, result, | 
|  | internal::ProjectedUnaryPredicate(pred, proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(pred, invoke(proj, *i)))`. | 
|  | // | 
|  | // Let `N` be the number of elements in `range` for which `E(i)` is false. | 
|  | // | 
|  | // Mandates: `*begin(range)` is writable to `result`. | 
|  | // | 
|  | // Preconditions: The ranges `range` and `[result, result + size(range))` do not | 
|  | // overlap. | 
|  | // | 
|  | // Effects: Copies all the elements referred to by the iterator `i` in `range` | 
|  | //  for which `E(i)` is false. | 
|  | // | 
|  | // Returns: `result + N`. | 
|  | // | 
|  | // Complexity: Exactly `size(range)` applications of the corresponding | 
|  | // predicate and any projection. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.remove#:~:text=ranges::remove_copy(R | 
|  | template <typename Range, | 
|  | typename OutputIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto remove_copy_if(Range&& range, | 
|  | OutputIterator result, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | return ranges::remove_copy_if(ranges::begin(range), ranges::end(range), | 
|  | result, std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.unique] Unique | 
|  | // Reference: https://wg21.link/alg.unique | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(comp, invoke(proj, *(i - 1)), invoke(proj, *i)))`. | 
|  | // | 
|  | // Effects: For a nonempty range, eliminates all but the first element from | 
|  | // every consecutive group of equivalent elements referred to by the iterator | 
|  | // `i` in the range `[first + 1, last)` for which `E(i)` is true. | 
|  | // | 
|  | // Returns: The end of the resulting range. | 
|  | // | 
|  | // Complexity: For nonempty ranges, exactly `(last - first) - 1` applications of | 
|  | // the corresponding predicate and no more than twice as many applications of | 
|  | // any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.unique#:~:text=ranges::unique(I | 
|  | template <typename ForwardIterator, | 
|  | typename Comp = ranges::equal_to, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<ForwardIterator, Proj>, | 
|  | projected<ForwardIterator, Proj>>> | 
|  | constexpr auto unique(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return std::unique(first, last, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(comp, invoke(proj, *(i - 1)), invoke(proj, *i)))`. | 
|  | // | 
|  | // Effects: For a nonempty range, eliminates all but the first element from | 
|  | // every consecutive group of equivalent elements referred to by the iterator | 
|  | // `i` in the range `[begin(range) + 1, end(range))` for which `E(i)` is true. | 
|  | // | 
|  | // Returns: The end of the resulting range. | 
|  | // | 
|  | // Complexity: For nonempty ranges, exactly `size(range) - 1` applications of | 
|  | // the corresponding predicate and no more than twice as many applications of | 
|  | // any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.unique#:~:text=ranges::unique(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::equal_to, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto unique(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::unique(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(comp, invoke(proj, *i), invoke(proj, *(i - 1))))`. | 
|  | // | 
|  | // Mandates: `*first` is writable to `result`. | 
|  | // | 
|  | // Preconditions: The ranges `[first, last)` and | 
|  | // `[result, result + (last - first))` do not overlap. | 
|  | // | 
|  | // Effects: Copies only the first element from every consecutive group of equal | 
|  | // elements referred to by the iterator `i` in the range `[first, last)` for | 
|  | // which `E(i)` holds. | 
|  | // | 
|  | // Returns: `result + N`. | 
|  | // | 
|  | // Complexity: Exactly `last - first - 1` applications of the corresponding | 
|  | // predicate and no more than twice as many applications of any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.unique#:~:text=ranges::unique_copy(I | 
|  | template <typename ForwardIterator, | 
|  | typename OutputIterator, | 
|  | typename Comp = ranges::equal_to, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto unique_copy(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | OutputIterator result, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return std::unique_copy(first, last, result, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(i)` be `bool(invoke(comp, invoke(proj, *i), invoke(proj, *(i - 1))))`. | 
|  | // | 
|  | // Mandates: `*begin(range)` is writable to `result`. | 
|  | // | 
|  | // Preconditions: The ranges `range` and `[result, result + size(range))` do not | 
|  | // overlap. | 
|  | // | 
|  | // Effects: Copies only the first element from every consecutive group of equal | 
|  | // elements referred to by the iterator `i` in `range` for which `E(i)` holds. | 
|  | // | 
|  | // Returns: `result + N`. | 
|  | // | 
|  | // Complexity: Exactly `size(range) - 1` applications of the corresponding | 
|  | // predicate and no more than twice as many applications of any projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.unique#:~:text=ranges::unique_copy(R | 
|  | template <typename Range, | 
|  | typename OutputIterator, | 
|  | typename Comp = ranges::equal_to, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto unique_copy(Range&& range, | 
|  | OutputIterator result, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return ranges::unique_copy(ranges::begin(range), ranges::end(range), result, | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.reverse] Reverse | 
|  | // Reference: https://wg21.link/alg.reverse | 
|  |  | 
|  | // Effects: For each non-negative integer `i < (last - first) / 2`, applies | 
|  | // `std::iter_swap` to all pairs of iterators `first + i, (last - i) - 1`. | 
|  | // | 
|  | // Returns: `last`. | 
|  | // | 
|  | // Complexity: Exactly `(last - first)/2` swaps. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.reverse#:~:text=ranges::reverse(I | 
|  | template <typename BidirectionalIterator, | 
|  | typename = internal::iterator_category_t<BidirectionalIterator>> | 
|  | constexpr auto reverse(BidirectionalIterator first, | 
|  | BidirectionalIterator last) { | 
|  | std::reverse(first, last); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Effects: For each non-negative integer `i < size(range) / 2`, applies | 
|  | // `std::iter_swap` to all pairs of iterators | 
|  | // `begin(range) + i, (end(range) - i) - 1`. | 
|  | // | 
|  | // Returns: `end(range)`. | 
|  | // | 
|  | // Complexity: Exactly `size(range)/2` swaps. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.reverse#:~:text=ranges::reverse(R | 
|  | template <typename Range, typename = internal::range_category_t<Range>> | 
|  | constexpr auto reverse(Range&& range) { | 
|  | return ranges::reverse(ranges::begin(range), ranges::end(range)); | 
|  | } | 
|  |  | 
|  | // Let `N` be `last - first`. | 
|  | // | 
|  | // Preconditions: The ranges `[first, last)` and `[result, result + N)` do not | 
|  | // overlap. | 
|  | // | 
|  | // Effects: Copies the range `[first, last)` to the range `[result, result + N)` | 
|  | // such that for every non-negative integer `i < N` the following assignment | 
|  | // takes place: `*(result + N - 1 - i) = *(first + i)`. | 
|  | // | 
|  | // Returns: `result + N`. | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.reverse#:~:text=ranges::reverse_copy(I | 
|  | template <typename BidirectionalIterator, | 
|  | typename OutputIterator, | 
|  | typename = internal::iterator_category_t<BidirectionalIterator>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto reverse_copy(BidirectionalIterator first, | 
|  | BidirectionalIterator last, | 
|  | OutputIterator result) { | 
|  | return std::reverse_copy(first, last, result); | 
|  | } | 
|  |  | 
|  | // Let `N` be `size(range)`. | 
|  | // | 
|  | // Preconditions: The ranges `range` and `[result, result + N)` do not | 
|  | // overlap. | 
|  | // | 
|  | // Effects: Copies `range` to the range `[result, result + N)` such that for | 
|  | // every non-negative integer `i < N` the following assignment takes place: | 
|  | // `*(result + N - 1 - i) = *(begin(range) + i)`. | 
|  | // | 
|  | // Returns: `result + N`. | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.reverse#:~:text=ranges::reverse_copy(R | 
|  | template <typename Range, | 
|  | typename OutputIterator, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto reverse_copy(Range&& range, OutputIterator result) { | 
|  | return ranges::reverse_copy(ranges::begin(range), ranges::end(range), result); | 
|  | } | 
|  |  | 
|  | // [alg.rotate] Rotate | 
|  | // Reference: https://wg21.link/alg.rotate | 
|  |  | 
|  | // Preconditions: `[first, middle)` and `[middle, last)` are valid ranges. | 
|  | // | 
|  | // Effects: For each non-negative integer `i < (last - first)`, places the | 
|  | // element from the position `first + i` into position | 
|  | // `first + (i + (last - middle)) % (last - first)`. | 
|  | // | 
|  | // Returns: `first + (last - middle)`. | 
|  | // | 
|  | // Complexity: At most `last - first` swaps. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.rotate#:~:text=ranges::rotate(I | 
|  | template <typename ForwardIterator, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto rotate(ForwardIterator first, | 
|  | ForwardIterator middle, | 
|  | ForwardIterator last) { | 
|  | return std::rotate(first, middle, last); | 
|  | } | 
|  |  | 
|  | // Preconditions: `[begin(range), middle)` and `[middle, end(range))` are valid | 
|  | // ranges. | 
|  | // | 
|  | // Effects: For each non-negative integer `i < size(range)`, places the element | 
|  | // from the position `begin(range) + i` into position | 
|  | // `begin(range) + (i + (end(range) - middle)) % size(range)`. | 
|  | // | 
|  | // Returns: `begin(range) + (end(range) - middle)`. | 
|  | // | 
|  | // Complexity: At most `size(range)` swaps. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.rotate#:~:text=ranges::rotate(R | 
|  | template <typename Range, typename = internal::range_category_t<Range>> | 
|  | constexpr auto rotate(Range&& range, iterator_t<Range> middle) { | 
|  | return ranges::rotate(ranges::begin(range), middle, ranges::end(range)); | 
|  | } | 
|  |  | 
|  | // Let `N` be `last - first`. | 
|  | // | 
|  | // Preconditions: `[first, middle)` and `[middle, last)` are valid ranges. The | 
|  | // ranges `[first, last)` and `[result, result + N)` do not overlap. | 
|  | // | 
|  | // Effects: Copies the range `[first, last)` to the range `[result, result + N)` | 
|  | // such that for each non-negative integer `i < N` the following assignment | 
|  | // takes place: `*(result + i) = *(first + (i + (middle - first)) % N)`. | 
|  | // | 
|  | // Returns: `result + N`. | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.rotate#:~:text=ranges::rotate_copy(I | 
|  | template <typename ForwardIterator, | 
|  | typename OutputIterator, | 
|  | typename = internal::iterator_category_t<ForwardIterator>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto rotate_copy(ForwardIterator first, | 
|  | ForwardIterator middle, | 
|  | ForwardIterator last, | 
|  | OutputIterator result) { | 
|  | return std::rotate_copy(first, middle, last, result); | 
|  | } | 
|  |  | 
|  | // Let `N` be `size(range)`. | 
|  | // | 
|  | // Preconditions: `[begin(range), middle)` and `[middle, end(range))` are valid | 
|  | // ranges. The ranges `range` and `[result, result + N)` do not overlap. | 
|  | // | 
|  | // Effects: Copies `range` to the range `[result, result + N)` such that for | 
|  | // each non-negative integer `i < N` the following assignment takes place: | 
|  | // `*(result + i) = *(begin(range) + (i + (middle - begin(range))) % N)`. | 
|  | // | 
|  | // Returns: `result + N`. | 
|  | // | 
|  | // Complexity: Exactly `N` assignments. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.rotate#:~:text=ranges::rotate_copy(R | 
|  | template <typename Range, | 
|  | typename OutputIterator, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<OutputIterator>> | 
|  | constexpr auto rotate_copy(Range&& range, | 
|  | iterator_t<Range> middle, | 
|  | OutputIterator result) { | 
|  | return ranges::rotate_copy(ranges::begin(range), middle, ranges::end(range), | 
|  | result); | 
|  | } | 
|  |  | 
|  | // [alg.random.sample] Sample | 
|  | // Reference: https://wg21.link/alg.random.sample | 
|  |  | 
|  | // Currently not implemented due to lack of std::sample in C++14. | 
|  | // TODO(crbug.com/1071094): Consider implementing a hand-rolled version. | 
|  |  | 
|  | // [alg.random.shuffle] Shuffle | 
|  | // Reference: https://wg21.link/alg.random.shuffle | 
|  |  | 
|  | // Preconditions: The type `std::remove_reference_t<UniformRandomBitGenerator>` | 
|  | // meets the uniform random bit generator requirements. | 
|  | // | 
|  | // Effects: Permutes the elements in the range `[first, last)` such that each | 
|  | // possible permutation of those elements has equal probability of appearance. | 
|  | // | 
|  | // Returns: `last`. | 
|  | // | 
|  | // Complexity: Exactly `(last - first) - 1` swaps. | 
|  | // | 
|  | // Remarks: To the extent that the implementation of this function makes use of | 
|  | // random numbers, the object referenced by g shall serve as the | 
|  | // implementation's source of randomness. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.random.shuffle#:~:text=ranges::shuffle(I | 
|  | template <typename RandomAccessIterator, | 
|  | typename UniformRandomBitGenerator, | 
|  | typename = internal::iterator_category_t<RandomAccessIterator>> | 
|  | constexpr auto shuffle(RandomAccessIterator first, | 
|  | RandomAccessIterator last, | 
|  | UniformRandomBitGenerator&& g) { | 
|  | std::shuffle(first, last, std::forward<UniformRandomBitGenerator>(g)); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Preconditions: The type `std::remove_reference_t<UniformRandomBitGenerator>` | 
|  | // meets the uniform random bit generator requirements. | 
|  | // | 
|  | // Effects: Permutes the elements in `range` such that each possible permutation | 
|  | // of those elements has equal probability of appearance. | 
|  | // | 
|  | // Returns: `end(range)`. | 
|  | // | 
|  | // Complexity: Exactly `size(range) - 1` swaps. | 
|  | // | 
|  | // Remarks: To the extent that the implementation of this function makes use of | 
|  | // random numbers, the object referenced by g shall serve as the | 
|  | // implementation's source of randomness. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.random.shuffle#:~:text=ranges::shuffle(R | 
|  | template <typename Range, | 
|  | typename UniformRandomBitGenerator, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto shuffle(Range&& range, UniformRandomBitGenerator&& g) { | 
|  | return ranges::shuffle(ranges::begin(range), ranges::end(range), | 
|  | std::forward<UniformRandomBitGenerator>(g)); | 
|  | } | 
|  |  | 
|  | // [alg.nonmodifying] Sorting and related operations | 
|  | // Reference: https://wg21.link/alg.sorting | 
|  |  | 
|  | // [alg.sort] Sorting | 
|  | // Reference: https://wg21.link/alg.sort | 
|  |  | 
|  | // [sort] sort | 
|  | // Reference: https://wg21.link/sort | 
|  |  | 
|  | // Effects: Sorts the elements in the range `[first, last)` with respect to | 
|  | // `comp` and `proj`. | 
|  | // | 
|  | // Returns: `last`. | 
|  | // | 
|  | // Complexity: Let `N` be `last - first`. `O(N log N)` comparisons and | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/sort#:~:text=ranges::sort(I | 
|  | template <typename RandomAccessIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<RandomAccessIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<RandomAccessIterator, Proj>, | 
|  | projected<RandomAccessIterator, Proj>>> | 
|  | constexpr auto sort(RandomAccessIterator first, | 
|  | RandomAccessIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | std::sort(first, last, internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Effects: Sorts the elements in `range` with respect to `comp` and `proj`. | 
|  | // | 
|  | // Returns: `end(range)`. | 
|  | // | 
|  | // Complexity: Let `N` be `size(range)`. `O(N log N)` comparisons and | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/sort#:~:text=ranges::sort(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto sort(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::sort(ranges::begin(range), ranges::end(range), std::move(comp), | 
|  | std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [stable.sort] stable_sort | 
|  | // Reference: https://wg21.link/stable.sort | 
|  |  | 
|  | // Effects: Sorts the elements in the range `[first, last)` with respect to | 
|  | // `comp` and `proj`. | 
|  | // | 
|  | // Returns: `last`. | 
|  | // | 
|  | // Complexity: Let `N` be `last - first`. If enough extra memory is available, | 
|  | // `N log (N)` comparisons. Otherwise, at most `N log^2 (N)` comparisons. In | 
|  | // either case, twice as many projections as the number of comparisons. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Reference: https://wg21.link/stable.sort#:~:text=ranges::stable_sort(I | 
|  | template <typename RandomAccessIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<RandomAccessIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<RandomAccessIterator, Proj>, | 
|  | projected<RandomAccessIterator, Proj>>> | 
|  | constexpr auto stable_sort(RandomAccessIterator first, | 
|  | RandomAccessIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | std::stable_sort(first, last, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Effects: Sorts the elements in `range` with respect to `comp` and `proj`. | 
|  | // | 
|  | // Returns: `end(rang)`. | 
|  | // | 
|  | // Complexity: Let `N` be `size(range)`. If enough extra memory is available, | 
|  | // `N log (N)` comparisons. Otherwise, at most `N log^2 (N)` comparisons. In | 
|  | // either case, twice as many projections as the number of comparisons. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Reference: https://wg21.link/stable.sort#:~:text=ranges::stable_sort(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto stable_sort(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::stable_sort(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [partial.sort] partial_sort | 
|  | // Reference: https://wg21.link/partial.sort | 
|  |  | 
|  | // Preconditions: `[first, middle)` and `[middle, last)` are valid ranges. | 
|  | // | 
|  | // Effects: Places the first `middle - first` elements from the range | 
|  | // `[first, last)` as sorted with respect to `comp` and `proj` into the range | 
|  | // `[first, middle)`. The rest of the elements in the range `[middle, last)` are | 
|  | // placed in an unspecified order. | 
|  | // | 
|  | // Returns: `last`. | 
|  | // | 
|  | // Complexity: Approximately `(last - first) * log(middle - first)` comparisons, | 
|  | // and twice as many projections. | 
|  | // | 
|  | // Reference: https://wg21.link/partial.sort#:~:text=ranges::partial_sort(I | 
|  | template <typename RandomAccessIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<RandomAccessIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<RandomAccessIterator, Proj>, | 
|  | projected<RandomAccessIterator, Proj>>> | 
|  | constexpr auto partial_sort(RandomAccessIterator first, | 
|  | RandomAccessIterator middle, | 
|  | RandomAccessIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | std::partial_sort(first, middle, last, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Preconditions: `[begin(range), middle)` and `[middle, end(range))` are valid | 
|  | // ranges. | 
|  | // | 
|  | // Effects: Places the first `middle - begin(range)` elements from `range` as | 
|  | // sorted with respect to `comp` and `proj` into the range | 
|  | // `[begin(range), middle)`. The rest of the elements in the range | 
|  | // `[middle, end(range))` are placed in an unspecified order. | 
|  | // | 
|  | // Returns: `end(range)`. | 
|  | // | 
|  | // Complexity: Approximately `size(range) * log(middle - begin(range))` | 
|  | // comparisons, and twice as many projections. | 
|  | // | 
|  | // Reference: https://wg21.link/partial.sort#:~:text=ranges::partial_sort(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto partial_sort(Range&& range, | 
|  | iterator_t<Range> middle, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return ranges::partial_sort(ranges::begin(range), middle, ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [partial.sort.copy] partial_sort_copy | 
|  | // Reference: https://wg21.link/partial.sort.copy | 
|  |  | 
|  | // Let `N` be `min(last - first, result_last - result_first)`. | 
|  | // | 
|  | // Preconditions: For iterators `a1` and `b1` in `[first, last)`, and iterators | 
|  | // `x2` and `y2` in `[result_first, result_last)`, after evaluating the | 
|  | // assignment `*y2 = *b1`, let `E` be the value of `bool(invoke(comp, | 
|  | // invoke(proj1, *a1), invoke(proj2, *y2)))`. Then, after evaluating the | 
|  | // assignment `*x2 = *a1`, `E` is equal to `bool(invoke(comp, invoke(proj2, | 
|  | // *x2), invoke(proj2, *y2)))`. | 
|  | // | 
|  | // Effects: Places the first `N` elements as sorted with respect to `comp` and | 
|  | // `proj2` into the range `[result_first, result_first + N)`. | 
|  | // | 
|  | // Returns: `result_first + N`. | 
|  | // | 
|  | // Complexity: Approximately `(last - first) * log N` comparisons, and twice as | 
|  | // many projections. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/partial.sort.copy#:~:text=ranges::partial_sort_copy(I1 | 
|  | template <typename InputIterator, | 
|  | typename RandomAccessIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>, | 
|  | typename = internal::iterator_category_t<RandomAccessIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<InputIterator, Proj1>, | 
|  | projected<RandomAccessIterator, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<RandomAccessIterator, Proj2>, | 
|  | projected<InputIterator, Proj1>>> | 
|  | constexpr auto partial_sort_copy(InputIterator first, | 
|  | InputIterator last, | 
|  | RandomAccessIterator result_first, | 
|  | RandomAccessIterator result_last, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | // Needs to opt-in to all permutations, since std::partial_sort_copy expects | 
|  | // comp(proj2(lhs), proj1(rhs)) to compile. | 
|  | return std::partial_sort_copy( | 
|  | first, last, result_first, result_last, | 
|  | internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2)); | 
|  | } | 
|  |  | 
|  | // Let `N` be `min(size(range), size(result_range))`. | 
|  | // | 
|  | // Preconditions: For iterators `a1` and `b1` in `range`, and iterators | 
|  | // `x2` and `y2` in `result_range`, after evaluating the assignment | 
|  | // `*y2 = *b1`, let `E` be the value of | 
|  | // `bool(invoke(comp, invoke(proj1, *a1), invoke(proj2, *y2)))`. Then, after | 
|  | // evaluating the assignment `*x2 = *a1`, `E` is equal to | 
|  | // `bool(invoke(comp, invoke(proj2, *x2), invoke(proj2, *y2)))`. | 
|  | // | 
|  | // Effects: Places the first `N` elements as sorted with respect to `comp` and | 
|  | // `proj2` into the range `[begin(result_range), begin(result_range) + N)`. | 
|  | // | 
|  | // Returns: `begin(result_range) + N`. | 
|  | // | 
|  | // Complexity: Approximately `size(range) * log N` comparisons, and twice as | 
|  | // many projections. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/partial.sort.copy#:~:text=ranges::partial_sort_copy(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range2>, Proj2>, | 
|  | projected<iterator_t<Range1>, Proj1>>> | 
|  | constexpr auto partial_sort_copy(Range1&& range, | 
|  | Range2&& result_range, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::partial_sort_copy(ranges::begin(range), ranges::end(range), | 
|  | ranges::begin(result_range), | 
|  | ranges::end(result_range), std::move(comp), | 
|  | std::move(proj1), std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // [is.sorted] is_sorted | 
|  | // Reference: https://wg21.link/is.sorted | 
|  |  | 
|  | // Returns: The last iterator `i` in `[first, last]` for which the range | 
|  | // `[first, i)` is sorted with respect to `comp` and `proj`. | 
|  | // | 
|  | // Complexity: Linear. | 
|  | // | 
|  | // Reference: https://wg21.link/is.sorted#:~:text=ranges::is_sorted_until(I | 
|  | template <typename ForwardIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<ForwardIterator, Proj>, | 
|  | projected<ForwardIterator, Proj>>> | 
|  | constexpr auto is_sorted_until(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | // Implementation inspired by cppreference.com: | 
|  | // https://en.cppreference.com/w/cpp/algorithm/is_sorted_until | 
|  | // | 
|  | // A reimplementation is required, because std::is_sorted_until is not | 
|  | // constexpr prior to C++20. Once we have C++20, we should switch to standard | 
|  | // library implementation. | 
|  | if (first == last) | 
|  | return last; | 
|  |  | 
|  | for (ForwardIterator next = first; ++next != last; ++first) { | 
|  | if (gurl_base::invoke(comp, gurl_base::invoke(proj, *next), | 
|  | gurl_base::invoke(proj, *first))) { | 
|  | return next; | 
|  | } | 
|  | } | 
|  |  | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Returns: The last iterator `i` in `[begin(range), end(range)]` for which the | 
|  | // range `[begin(range), i)` is sorted with respect to `comp` and `proj`. | 
|  | // | 
|  | // Complexity: Linear. | 
|  | // | 
|  | // Reference: https://wg21.link/is.sorted#:~:text=ranges::is_sorted_until(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto is_sorted_until(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::is_sorted_until(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Returns: Whether the range `[first, last)` is sorted with respect to `comp` | 
|  | // and `proj`. | 
|  | // | 
|  | // Complexity: Linear. | 
|  | // | 
|  | // Reference: https://wg21.link/is.sorted#:~:text=ranges::is_sorted(I | 
|  | template <typename ForwardIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<ForwardIterator, Proj>, | 
|  | projected<ForwardIterator, Proj>>> | 
|  | constexpr auto is_sorted(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return ranges::is_sorted_until(first, last, std::move(comp), | 
|  | std::move(proj)) == last; | 
|  | } | 
|  |  | 
|  | // Returns: Whether `range` is sorted with respect to `comp` and `proj`. | 
|  | // | 
|  | // Complexity: Linear. | 
|  | // | 
|  | // Reference: https://wg21.link/is.sorted#:~:text=ranges::is_sorted(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto is_sorted(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::is_sorted(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.nth.element] Nth element | 
|  | // Reference: https://wg21.link/alg.nth.element | 
|  |  | 
|  | // Preconditions: `[first, nth)` and `[nth, last)` are valid ranges. | 
|  | // | 
|  | // Effects: After `nth_element` the element in the position pointed to by `nth` | 
|  | // is the element that would be in that position if the whole range were sorted | 
|  | // with respect to `comp` and `proj`, unless `nth == last`. Also for every | 
|  | // iterator `i` in the range `[first, nth)` and every iterator `j` in the range | 
|  | // `[nth, last)` it holds that: | 
|  | // `bool(invoke(comp, invoke(proj, *j), invoke(proj, *i)))` is false. | 
|  | // | 
|  | // Returns: `last`. | 
|  | // | 
|  | // Complexity: Linear on average. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.nth.element#:~:text=ranges::nth_element(I | 
|  | template <typename RandomAccessIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<RandomAccessIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<RandomAccessIterator, Proj>, | 
|  | projected<RandomAccessIterator, Proj>>> | 
|  | constexpr auto nth_element(RandomAccessIterator first, | 
|  | RandomAccessIterator nth, | 
|  | RandomAccessIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | std::nth_element(first, nth, last, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Preconditions: `[begin(range), nth)` and `[nth, end(range))` are valid | 
|  | // ranges. | 
|  | // | 
|  | // Effects: After `nth_element` the element in the position pointed to by `nth` | 
|  | // is the element that would be in that position if the whole range were sorted | 
|  | // with respect to `comp` and `proj`, unless `nth == end(range)`. Also for every | 
|  | // iterator `i` in the range `[begin(range), nth)` and every iterator `j` in the | 
|  | // range `[nth, end(range))` it holds that: | 
|  | // `bool(invoke(comp, invoke(proj, *j), invoke(proj, *i)))` is false. | 
|  | // | 
|  | // Returns: `end(range)`. | 
|  | // | 
|  | // Complexity: Linear on average. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.nth.element#:~:text=ranges::nth_element(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto nth_element(Range&& range, | 
|  | iterator_t<Range> nth, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return ranges::nth_element(ranges::begin(range), nth, ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.binary.search] Binary search | 
|  | // Reference: https://wg21.link/alg.binary.search | 
|  |  | 
|  | // [lower.bound] lower_bound | 
|  | // Reference: https://wg21.link/lower.bound | 
|  |  | 
|  | // Preconditions: The elements `e` of `[first, last)` are partitioned with | 
|  | // respect to the expression `bool(invoke(comp, invoke(proj, e), value))`. | 
|  | // | 
|  | // Returns: The furthermost iterator `i` in the range `[first, last]` such that | 
|  | // for every iterator `j` in the range `[first, i)`, | 
|  | // `bool(invoke(comp, invoke(proj, *j), value))` is true. | 
|  | // | 
|  | // Complexity: At most `log_2(last - first) + O(1)` comparisons and projections. | 
|  | // | 
|  | // Reference: https://wg21.link/lower.bound#:~:text=ranges::lower_bound(I | 
|  | template <typename ForwardIterator, | 
|  | typename T, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto lower_bound(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | const T& value, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | // The second arg is guaranteed to be `value`, so we'll simply apply the | 
|  | // identity projection. | 
|  | identity value_proj; | 
|  | return std::lower_bound( | 
|  | first, last, value, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, value_proj)); | 
|  | } | 
|  |  | 
|  | // Preconditions: The elements `e` of `range` are partitioned with respect to | 
|  | // the expression `bool(invoke(comp, invoke(proj, e), value))`. | 
|  | // | 
|  | // Returns: The furthermost iterator `i` in the range | 
|  | // `[begin(range), end(range)]` such that for every iterator `j` in the range | 
|  | // `[begin(range), i)`, `bool(invoke(comp, invoke(proj, *j), value))` is true. | 
|  | // | 
|  | // Complexity: At most `log_2(size(range)) + O(1)` comparisons and projections. | 
|  | // | 
|  | // Reference: https://wg21.link/lower.bound#:~:text=ranges::lower_bound(R | 
|  | template <typename Range, | 
|  | typename T, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto lower_bound(Range&& range, | 
|  | const T& value, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return ranges::lower_bound(ranges::begin(range), ranges::end(range), value, | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [upper.bound] upper_bound | 
|  | // Reference: https://wg21.link/upper.bound | 
|  |  | 
|  | // Preconditions: The elements `e` of `[first, last)` are partitioned with | 
|  | // respect to the expression `!bool(invoke(comp, value, invoke(proj, e)))`. | 
|  | // | 
|  | // Returns: The furthermost iterator `i` in the range `[first, last]` such that | 
|  | // for every iterator `j` in the range `[first, i)`, | 
|  | // `!bool(invoke(comp, value, invoke(proj, *j)))` is true. | 
|  | // | 
|  | // Complexity: At most `log_2(last - first) + O(1)` comparisons and projections. | 
|  | // | 
|  | // Reference: https://wg21.link/upper.bound#:~:text=ranges::upper_bound(I | 
|  | template <typename ForwardIterator, | 
|  | typename T, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto upper_bound(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | const T& value, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | // The first arg is guaranteed to be `value`, so we'll simply apply the | 
|  | // identity projection. | 
|  | identity value_proj; | 
|  | return std::upper_bound( | 
|  | first, last, value, | 
|  | internal::ProjectedBinaryPredicate(comp, value_proj, proj)); | 
|  | } | 
|  |  | 
|  | // Preconditions: The elements `e` of `range` are partitioned with | 
|  | // respect to the expression `!bool(invoke(comp, value, invoke(proj, e)))`. | 
|  | // | 
|  | // Returns: The furthermost iterator `i` in the range | 
|  | // `[begin(range), end(range)]` such that for every iterator `j` in the range | 
|  | // `[begin(range), i)`, `!bool(invoke(comp, value, invoke(proj, *j)))` is true. | 
|  | // | 
|  | // Complexity: At most `log_2(size(range)) + O(1)` comparisons and projections. | 
|  | // | 
|  | // Reference: https://wg21.link/upper.bound#:~:text=ranges::upper_bound(R | 
|  | template <typename Range, | 
|  | typename T, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto upper_bound(Range&& range, | 
|  | const T& value, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return ranges::upper_bound(ranges::begin(range), ranges::end(range), value, | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [equal.range] equal_range | 
|  | // Reference: https://wg21.link/equal.range | 
|  |  | 
|  | // Preconditions: The elements `e` of `[first, last)` are partitioned with | 
|  | // respect to the expressions `bool(invoke(comp, invoke(proj, e), value))` and | 
|  | // `!bool(invoke(comp, value, invoke(proj, e)))`. | 
|  | // | 
|  | // Returns: `{ranges::lower_bound(first, last, value, comp, proj), | 
|  | //            ranges::upper_bound(first, last, value, comp, proj)}`. | 
|  | // | 
|  | // Complexity: At most 2 ∗ log_2(last - first) + O(1) comparisons and | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/equal.range#:~:text=ranges::equal_range(I | 
|  | template <typename ForwardIterator, | 
|  | typename T, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto equal_range(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | const T& value, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | // Note: This does not dispatch to std::equal_range, as otherwise it would not | 
|  | // be possible to prevent applying `proj` to `value`, which can result in | 
|  | // unintended behavior. | 
|  | return std::make_pair(ranges::lower_bound(first, last, value, comp, proj), | 
|  | ranges::upper_bound(first, last, value, comp, proj)); | 
|  | } | 
|  |  | 
|  | // Preconditions: The elements `e` of `range` are partitioned with | 
|  | // respect to the expressions `bool(invoke(comp, invoke(proj, e), value))` and | 
|  | // `!bool(invoke(comp, value, invoke(proj, e)))`. | 
|  | // | 
|  | // Returns: `{ranges::lower_bound(range, value, comp, proj), | 
|  | //            ranges::upper_bound(range, value, comp, proj)}`. | 
|  | // | 
|  | // Complexity: At most 2 ∗ log_2(size(range)) + O(1) comparisons and | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/equal.range#:~:text=ranges::equal_range(R | 
|  | template <typename Range, | 
|  | typename T, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto equal_range(Range&& range, | 
|  | const T& value, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return ranges::equal_range(ranges::begin(range), ranges::end(range), value, | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [binary.search] binary_search | 
|  | // Reference: https://wg21.link/binary.search | 
|  |  | 
|  | // Preconditions: The elements `e` of `[first, last)` are partitioned with | 
|  | // respect to the expressions `bool(invoke(comp, invoke(proj, e), value))` and | 
|  | // `!bool(invoke(comp, value, invoke(proj, e)))`. | 
|  | // | 
|  | // Returns: `true` if and only if for some iterator `i` in the range | 
|  | // `[first, last)`, `!bool(invoke(comp, invoke(proj, *i), value)) && | 
|  | //                   !bool(invoke(comp, value, invoke(proj, *i)))` is true. | 
|  | // | 
|  | // Complexity: At most `log_2(last - first) + O(1)` comparisons and projections. | 
|  | // | 
|  | // Reference: https://wg21.link/binary.search#:~:text=ranges::binary_search(I | 
|  | template <typename ForwardIterator, | 
|  | typename T, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto binary_search(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | const T& value, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | first = ranges::lower_bound(first, last, value, comp, proj); | 
|  | return first != last && | 
|  | !gurl_base::invoke(comp, value, gurl_base::invoke(proj, *first)); | 
|  | } | 
|  |  | 
|  | // Preconditions: The elements `e` of `range` are partitioned with | 
|  | // respect to the expressions `bool(invoke(comp, invoke(proj, e), value))` and | 
|  | // `!bool(invoke(comp, value, invoke(proj, e)))`. | 
|  | // | 
|  | // Returns: `true` if and only if for some iterator `i` in `range` | 
|  | // `!bool(invoke(comp, invoke(proj, *i), value)) && | 
|  | //  !bool(invoke(comp, value, invoke(proj, *i)))` is true. | 
|  | // | 
|  | // Complexity: At most `log_2(size(range)) + O(1)` comparisons and projections. | 
|  | // | 
|  | // Reference: https://wg21.link/binary.search#:~:text=ranges::binary_search(R | 
|  | template <typename Range, | 
|  | typename T, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto binary_search(Range&& range, | 
|  | const T& value, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return ranges::binary_search(ranges::begin(range), ranges::end(range), value, | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.partitions] Partitions | 
|  | // Reference: https://wg21.link/alg.partitions | 
|  |  | 
|  | // Returns: `true` if and only if the elements `e` of `[first, last)` are | 
|  | // partitioned with respect to the expression | 
|  | // `bool(invoke(pred, invoke(proj, e)))`. | 
|  | // | 
|  | // Complexity: Linear. At most `last - first` applications of `pred` and `proj`. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.partitions#:~:text=ranges::is_partitioned(I | 
|  | template <typename ForwardIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto is_partitioned(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | return std::is_partitioned(first, last, | 
|  | internal::ProjectedUnaryPredicate(pred, proj)); | 
|  | } | 
|  |  | 
|  | // Returns: `true` if and only if the elements `e` of `range` are partitioned | 
|  | // with respect to the expression `bool(invoke(pred, invoke(proj, e)))`. | 
|  | // | 
|  | // Complexity: Linear. At most `size(range)` applications of `pred` and `proj`. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.partitions#:~:text=ranges::is_partitioned(R | 
|  | template <typename Range, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto is_partitioned(Range&& range, Pred pred, Proj proj = {}) { | 
|  | return ranges::is_partitioned(ranges::begin(range), ranges::end(range), | 
|  | std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`. | 
|  | // | 
|  | // Effects: Places all the elements `e` in `[first, last)` that satisfy `E(e)` | 
|  | // before all the elements that do not. | 
|  | // | 
|  | // Returns: Let `i` be an iterator such that `E(*j)` is `true` for every | 
|  | // iterator `j` in `[first, i)` and `false` for every iterator `j` in | 
|  | // `[i, last)`. Returns: i. | 
|  | // | 
|  | // Complexity: Let `N = last - first`: | 
|  | // Exactly `N` applications of the predicate and projection. At most `N / 2` | 
|  | // swaps if the type of `first` models `bidirectional_iterator`, and at most `N` | 
|  | // swaps otherwise. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.partitions#:~:text=ranges::partition(I | 
|  | template <typename ForwardIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto partition(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | return std::partition(first, last, | 
|  | internal::ProjectedUnaryPredicate(pred, proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`. | 
|  | // | 
|  | // Effects: Places all the elements `e` in `range` that satisfy `E(e)` before | 
|  | // all the elements that do not. | 
|  | // | 
|  | // Returns: Let `i` be an iterator such that `E(*j)` is `true` for every | 
|  | // iterator `j` in `[begin(range), i)` and `false` for every iterator `j` in | 
|  | // `[i, last)`. Returns: i. | 
|  | // | 
|  | // Complexity: Let `N = size(range)`: | 
|  | // Exactly `N` applications of the predicate and projection. At most `N / 2` | 
|  | // swaps if the type of `first` models `bidirectional_iterator`, and at most `N` | 
|  | // swaps otherwise. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.partitions#:~:text=ranges::partition(R | 
|  | template <typename Range, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto partition(Range&& range, Pred pred, Proj proj = {}) { | 
|  | return ranges::partition(ranges::begin(range), ranges::end(range), | 
|  | std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`. | 
|  | // | 
|  | // Effects: Places all the elements `e` in `[first, last)` that satisfy `E(e)` | 
|  | // before all the elements that do not. The relative order of the elements in | 
|  | // both groups is preserved. | 
|  | // | 
|  | // Returns: Let `i` be an iterator such that for every iterator `j` in | 
|  | // `[first, i)`, `E(*j)` is `true`, and for every iterator `j` in the range | 
|  | // `[i, last)`, `E(*j)` is `false`. Returns: `i`. | 
|  | // | 
|  | // Complexity: Let `N = last - first`: | 
|  | // At most `N log N` swaps, but only `O(N)` swaps if there is enough extra | 
|  | // memory. Exactly `N` applications of the predicate and projection. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.partitions#:~:text=ranges::stable_partition(I | 
|  | template <typename BidirectionalIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<BidirectionalIterator>> | 
|  | constexpr auto stable_partition(BidirectionalIterator first, | 
|  | BidirectionalIterator last, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | return std::stable_partition(first, last, | 
|  | internal::ProjectedUnaryPredicate(pred, proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`. | 
|  | // | 
|  | // Effects: Places all the elements `e` in `range` that satisfy `E(e)` before | 
|  | // all the elements that do not. The relative order of the elements in both | 
|  | // groups is preserved. | 
|  | // | 
|  | // Returns: Let `i` be an iterator such that for every iterator `j` in | 
|  | // `[begin(range), i)`, `E(*j)` is `true`, and for every iterator `j` in the | 
|  | // range `[i, end(range))`, `E(*j)` is `false`. Returns: `i`. | 
|  | // | 
|  | // Complexity: Let `N = size(range)`: | 
|  | // At most `N log N` swaps, but only `O(N)` swaps if there is enough extra | 
|  | // memory. Exactly `N` applications of the predicate and projection. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.partitions#:~:text=ranges::stable_partition(R | 
|  | template <typename Range, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto stable_partition(Range&& range, Pred pred, Proj proj = {}) { | 
|  | return ranges::stable_partition(ranges::begin(range), ranges::end(range), | 
|  | std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`. | 
|  | // | 
|  | // Mandates: The expression `*first` is writable to `out_true` and `out_false`. | 
|  | // | 
|  | // Preconditions: The input range and output ranges do not overlap. | 
|  | // | 
|  | // Effects: For each iterator `i` in `[first, last)`, copies `*i` to the output | 
|  | // range beginning with `out_true` if `E(*i)` is `true`, or to the output range | 
|  | // beginning with `out_false` otherwise. | 
|  | // | 
|  | // Returns: Let `o1` be the end of the output range beginning at `out_true`, and | 
|  | // `o2` the end of the output range beginning at `out_false`. | 
|  | // Returns `{o1, o2}`. | 
|  | // | 
|  | // Complexity: Exactly `last - first` applications of `pred` and `proj`. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.partitions#:~:text=ranges::partition_copy(I | 
|  | template <typename InputIterator, | 
|  | typename OutputIterator1, | 
|  | typename OutputIterator2, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<InputIterator>, | 
|  | typename = internal::iterator_category_t<OutputIterator1>, | 
|  | typename = internal::iterator_category_t<OutputIterator2>> | 
|  | constexpr auto partition_copy(InputIterator first, | 
|  | InputIterator last, | 
|  | OutputIterator1 out_true, | 
|  | OutputIterator2 out_false, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | return std::partition_copy(first, last, out_true, out_false, | 
|  | internal::ProjectedUnaryPredicate(pred, proj)); | 
|  | } | 
|  |  | 
|  | // Let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`. | 
|  | // | 
|  | // Mandates: The expression `*begin(range)` is writable to `out_true` and | 
|  | // `out_false`. | 
|  | // | 
|  | // Preconditions: The input range and output ranges do not overlap. | 
|  | // | 
|  | // Effects: For each iterator `i` in `range`, copies `*i` to the output range | 
|  | // beginning with `out_true` if `E(*i)` is `true`, or to the output range | 
|  | // beginning with `out_false` otherwise. | 
|  | // | 
|  | // Returns: Let `o1` be the end of the output range beginning at `out_true`, and | 
|  | // `o2` the end of the output range beginning at `out_false`. | 
|  | // Returns `{o1, o2}`. | 
|  | // | 
|  | // Complexity: Exactly `size(range)` applications of `pred` and `proj`. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.partitions#:~:text=ranges::partition_copy(R | 
|  | template <typename Range, | 
|  | typename OutputIterator1, | 
|  | typename OutputIterator2, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = internal::iterator_category_t<OutputIterator1>, | 
|  | typename = internal::iterator_category_t<OutputIterator2>> | 
|  | constexpr auto partition_copy(Range&& range, | 
|  | OutputIterator1 out_true, | 
|  | OutputIterator2 out_false, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | return ranges::partition_copy(ranges::begin(range), ranges::end(range), | 
|  | out_true, out_false, std::move(pred), | 
|  | std::move(proj)); | 
|  | } | 
|  |  | 
|  | // let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`. | 
|  | // | 
|  | // Preconditions: The elements `e` of `[first, last)` are partitioned with | 
|  | // respect to `E(e)`. | 
|  | // | 
|  | // Returns: An iterator `mid` such that `E(*i)` is `true` for all iterators `i` | 
|  | // in `[first, mid)`, and `false` for all iterators `i` in `[mid, last)`. | 
|  | // | 
|  | // Complexity: `O(log(last - first))` applications of `pred` and `proj`. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.partitions#:~:text=ranges::partition_point(I | 
|  | template <typename ForwardIterator, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>> | 
|  | constexpr auto partition_point(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | Pred pred, | 
|  | Proj proj = {}) { | 
|  | return std::partition_point(first, last, | 
|  | internal::ProjectedUnaryPredicate(pred, proj)); | 
|  | } | 
|  |  | 
|  | // let `E(x)` be `bool(invoke(pred, invoke(proj, x)))`. | 
|  | // | 
|  | // Preconditions: The elements `e` of `range` are partitioned with respect to | 
|  | // `E(e)`. | 
|  | // | 
|  | // Returns: An iterator `mid` such that `E(*i)` is `true` for all iterators `i` | 
|  | // in `[begin(range), mid)`, and `false` for all iterators `i` in | 
|  | // `[mid, end(range))`. | 
|  | // | 
|  | // Complexity: `O(log(size(range)))` applications of `pred` and `proj`. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.partitions#:~:text=ranges::partition_point(R | 
|  | template <typename Range, | 
|  | typename Pred, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto partition_point(Range&& range, Pred pred, Proj proj = {}) { | 
|  | return ranges::partition_point(ranges::begin(range), ranges::end(range), | 
|  | std::move(pred), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.merge] Merge | 
|  | // Reference: https://wg21.link/alg.merge | 
|  |  | 
|  | // Let `N` be `(last1 - first1) + (last2 - first2)`. | 
|  | // | 
|  | // Preconditions: The ranges `[first1, last1)` and `[first2, last2)` are sorted | 
|  | // with respect to `comp` and `proj1` or `proj2`, respectively. The resulting | 
|  | // range does not overlap with either of the original ranges. | 
|  | // | 
|  | // Effects: Copies all the elements of the two ranges `[first1, last1)` and | 
|  | // `[first2, last2)` into the range `[result, result_last)`, where `result_last` | 
|  | // is `result + N`. If an element `a` precedes `b` in an input range, `a` is | 
|  | // copied into the output range before `b`. If `e1` is an element of | 
|  | // `[first1, last1)` and `e2` of `[first2, last2)`, `e2` is copied into the | 
|  | // output range before `e1` if and only if | 
|  | // `bool(invoke(comp, invoke(proj2, e2), invoke(proj1, e1)))` is `true`. | 
|  | // | 
|  | // Returns: `result_last`. | 
|  | // | 
|  | // Complexity: At most `N - 1` comparisons and applications of each projection. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.merge#:~:text=ranges::merge(I1 | 
|  | template <typename InputIterator1, | 
|  | typename InputIterator2, | 
|  | typename OutputIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<InputIterator1>, | 
|  | typename = internal::iterator_category_t<InputIterator2>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<InputIterator1, Proj1>, | 
|  | projected<InputIterator2, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<InputIterator2, Proj2>, | 
|  | projected<InputIterator1, Proj1>>> | 
|  | constexpr auto merge(InputIterator1 first1, | 
|  | InputIterator1 last1, | 
|  | InputIterator2 first2, | 
|  | InputIterator2 last2, | 
|  | OutputIterator result, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | // Needs to opt-in to all permutations, since std::merge expects | 
|  | // comp(proj2(lhs), proj1(rhs)) to compile. | 
|  | return std::merge( | 
|  | first1, last1, first2, last2, result, | 
|  | internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2)); | 
|  | } | 
|  |  | 
|  | // Let `N` be `size(range1) + size(range2)`. | 
|  | // | 
|  | // Preconditions: The ranges `range1` and `range2` are sorted with respect to | 
|  | // `comp` and `proj1` or `proj2`, respectively. The resulting range does not | 
|  | // overlap with either of the original ranges. | 
|  | // | 
|  | // Effects: Copies all the elements of the two ranges `range1` and `range2` into | 
|  | // the range `[result, result_last)`, where `result_last` is `result + N`. If an | 
|  | // element `a` precedes `b` in an input range, `a` is copied into the output | 
|  | // range before `b`. If `e1` is an element of `range1` and `e2` of `range2`, | 
|  | // `e2` is copied into the output range before `e1` if and only if | 
|  | // `bool(invoke(comp, invoke(proj2, e2), invoke(proj1, e1)))` is `true`. | 
|  | // | 
|  | // Returns: `result_last`. | 
|  | // | 
|  | // Complexity: At most `N - 1` comparisons and applications of each projection. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.merge#:~:text=ranges::merge(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename OutputIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range2>, Proj2>, | 
|  | projected<iterator_t<Range1>, Proj1>>> | 
|  | constexpr auto merge(Range1&& range1, | 
|  | Range2&& range2, | 
|  | OutputIterator result, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::merge(ranges::begin(range1), ranges::end(range1), | 
|  | ranges::begin(range2), ranges::end(range2), result, | 
|  | std::move(comp), std::move(proj1), std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // Preconditions: `[first, middle)` and `[middle, last)` are valid ranges sorted | 
|  | // with respect to `comp` and `proj`. | 
|  | // | 
|  | // Effects: Merges two sorted consecutive ranges `[first, middle)` and | 
|  | // `[middle, last)`, putting the result of the merge into the range | 
|  | // `[first, last)`. The resulting range is sorted with respect to `comp` and | 
|  | // `proj`. | 
|  | // | 
|  | // Returns: `last`. | 
|  | // | 
|  | // Complexity: Let `N = last - first`: If enough additional memory is available, | 
|  | // exactly `N - 1` comparisons. Otherwise, `O(N log N)` comparisons. In either | 
|  | // case, twice as many projections as comparisons. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.merge#:~:text=ranges::inplace_merge(I | 
|  | template <typename BidirectionalIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<BidirectionalIterator>> | 
|  | constexpr auto inplace_merge(BidirectionalIterator first, | 
|  | BidirectionalIterator middle, | 
|  | BidirectionalIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | std::inplace_merge(first, middle, last, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Preconditions: `[begin(range), middle)` and `[middle, end(range))` are valid | 
|  | // ranges sorted with respect to `comp` and `proj`. | 
|  | // | 
|  | // Effects: Merges two sorted consecutive ranges `[begin(range), middle)` and | 
|  | // `[middle, end(range))`, putting the result of the merge into `range`. The | 
|  | // resulting range is sorted with respect to `comp` and `proj`. | 
|  | // | 
|  | // Returns: `end(range)`. | 
|  | // | 
|  | // Complexity: Let `N = size(range)`: If enough additional memory is available, | 
|  | // exactly `N - 1` comparisons. Otherwise, `O(N log N)` comparisons. In either | 
|  | // case, twice as many projections as comparisons. | 
|  | // | 
|  | // Remarks: Stable. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.merge#:~:text=ranges::inplace_merge(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto inplace_merge(Range&& range, | 
|  | iterator_t<Range> middle, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return ranges::inplace_merge(ranges::begin(range), middle, ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.set.operations] Set operations on sorted structures | 
|  | // Reference: https://wg21.link/alg.set.operations | 
|  |  | 
|  | // [includes] includes | 
|  | // Reference: https://wg21.link/includes | 
|  |  | 
|  | // Preconditions: The ranges `[first1, last1)` and `[first2, last2)` are sorted | 
|  | // with respect to `comp` and `proj1` or `proj2`, respectively. | 
|  | // | 
|  | // Returns: `true` if and only if `[first2, last2)` is a subsequence of | 
|  | // `[first1, last1)`. | 
|  | // | 
|  | // Complexity: At most `2 * ((last1 - first1) + (last2 - first2)) - 1` | 
|  | // comparisons and applications of each projection. | 
|  | // | 
|  | // Reference: https://wg21.link/includes#:~:text=ranges::includes(I1 | 
|  | template <typename InputIterator1, | 
|  | typename InputIterator2, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<InputIterator1>, | 
|  | typename = internal::iterator_category_t<InputIterator2>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<InputIterator1, Proj1>, | 
|  | projected<InputIterator2, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<InputIterator2, Proj2>, | 
|  | projected<InputIterator1, Proj1>>> | 
|  | constexpr auto includes(InputIterator1 first1, | 
|  | InputIterator1 last1, | 
|  | InputIterator2 first2, | 
|  | InputIterator2 last2, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | GURL_DCHECK(ranges::is_sorted(first1, last1, comp, proj1)); | 
|  | GURL_DCHECK(ranges::is_sorted(first2, last2, comp, proj2)); | 
|  | // Needs to opt-in to all permutations, since std::includes expects | 
|  | // comp(proj1(lhs), proj2(rhs)) and comp(proj2(lhs), proj1(rhs)) to compile. | 
|  | return std::includes( | 
|  | first1, last1, first2, last2, | 
|  | internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2)); | 
|  | } | 
|  |  | 
|  | // Preconditions: The ranges `range1` and `range2` are sorted with respect to | 
|  | // `comp` and `proj1` or `proj2`, respectively. | 
|  | // | 
|  | // Returns: `true` if and only if `range2` is a subsequence of `range1`. | 
|  | // | 
|  | // Complexity: At most `2 * (size(range1) + size(range2)) - 1` comparisons and | 
|  | // applications of each projection. | 
|  | // | 
|  | // Reference: https://wg21.link/includes#:~:text=ranges::includes(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range2>, Proj2>, | 
|  | projected<iterator_t<Range1>, Proj1>>> | 
|  | constexpr auto includes(Range1&& range1, | 
|  | Range2&& range2, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::includes(ranges::begin(range1), ranges::end(range1), | 
|  | ranges::begin(range2), ranges::end(range2), | 
|  | std::move(comp), std::move(proj1), std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // [set.union] set_union | 
|  | // Reference: https://wg21.link/set.union | 
|  |  | 
|  | // Preconditions: The ranges `[first1, last1)` and `[first2, last2)` are sorted | 
|  | // with respect to `comp` and `proj1` or `proj2`, respectively. The resulting | 
|  | // range does not overlap with either of the original ranges. | 
|  | // | 
|  | // Effects: Constructs a sorted union of the elements from the two ranges; that | 
|  | // is, the set of elements that are present in one or both of the ranges. | 
|  | // | 
|  | // Returns: The end of the constructed range. | 
|  | // | 
|  | // Complexity: At most `2 * ((last1 - first1) + (last2 - first2)) - 1` | 
|  | // comparisons and applications of each projection. | 
|  | // | 
|  | // Remarks: Stable. If `[first1, last1)` contains `m` elements that are | 
|  | // equivalent to each other and `[first2, last2)` contains `n` elements that are | 
|  | // equivalent to them, then all `m` elements from the first range are copied to | 
|  | // the output range, in order, and then the final `max(n - m , 0)` elements from | 
|  | // the second range are copied to the output range, in order. | 
|  | // | 
|  | // Reference: https://wg21.link/set.union#:~:text=ranges::set_union(I1 | 
|  | template <typename InputIterator1, | 
|  | typename InputIterator2, | 
|  | typename OutputIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<InputIterator1>, | 
|  | typename = internal::iterator_category_t<InputIterator2>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<InputIterator1, Proj1>, | 
|  | projected<InputIterator2, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<InputIterator2, Proj2>, | 
|  | projected<InputIterator1, Proj1>>> | 
|  | constexpr auto set_union(InputIterator1 first1, | 
|  | InputIterator1 last1, | 
|  | InputIterator2 first2, | 
|  | InputIterator2 last2, | 
|  | OutputIterator result, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | // Needs to opt-in to all permutations, since std::set_union expects | 
|  | // comp(proj1(lhs), proj2(rhs)) and comp(proj2(lhs), proj1(rhs)) to compile. | 
|  | return std::set_union( | 
|  | first1, last1, first2, last2, result, | 
|  | internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2)); | 
|  | } | 
|  |  | 
|  | // Preconditions: The ranges `range1` and `range2` are sorted with respect to | 
|  | // `comp` and `proj1` or `proj2`, respectively. The resulting range does not | 
|  | // overlap with either of the original ranges. | 
|  | // | 
|  | // Effects: Constructs a sorted union of the elements from the two ranges; that | 
|  | // is, the set of elements that are present in one or both of the ranges. | 
|  | // | 
|  | // Returns: The end of the constructed range. | 
|  | // | 
|  | // Complexity: At most `2 * (size(range1) + size(range2)) - 1` comparisons and | 
|  | // applications of each projection. | 
|  | // | 
|  | // Remarks: Stable. If `range1` contains `m` elements that are equivalent to | 
|  | // each other and `range2` contains `n` elements that are equivalent to them, | 
|  | // then all `m` elements from the first range are copied to the output range, in | 
|  | // order, and then the final `max(n - m , 0)` elements from the second range are | 
|  | // copied to the output range, in order. | 
|  | // | 
|  | // Reference: https://wg21.link/set.union#:~:text=ranges::set_union(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename OutputIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range2>, Proj2>, | 
|  | projected<iterator_t<Range1>, Proj1>>> | 
|  | constexpr auto set_union(Range1&& range1, | 
|  | Range2&& range2, | 
|  | OutputIterator result, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::set_union(ranges::begin(range1), ranges::end(range1), | 
|  | ranges::begin(range2), ranges::end(range2), result, | 
|  | std::move(comp), std::move(proj1), std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // [set.intersection] set_intersection | 
|  | // Reference: https://wg21.link/set.intersection | 
|  |  | 
|  | // Preconditions: The ranges `[first1, last1)` and `[first2, last2)` are sorted | 
|  | // with respect to `comp` and `proj1` or `proj2`, respectively. The resulting | 
|  | // range does not overlap with either of the original ranges. | 
|  | // | 
|  | // Effects: Constructs a sorted intersection of the elements from the two | 
|  | // ranges; that is, the set of elements that are present in both of the ranges. | 
|  | // | 
|  | // Returns: The end of the constructed range. | 
|  | // | 
|  | // Complexity: At most `2 * ((last1 - first1) + (last2 - first2)) - 1` | 
|  | // comparisons and applications of each projection. | 
|  | // | 
|  | // Remarks: Stable. If `[first1, last1)` contains `m` elements that are | 
|  | // equivalent to each other and `[first2, last2)` contains `n` elements that are | 
|  | // equivalent to them, the first `min(m, n)` elements are copied from the first | 
|  | // range to the output range, in order. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/set.intersection#:~:text=ranges::set_intersection(I1 | 
|  | template <typename InputIterator1, | 
|  | typename InputIterator2, | 
|  | typename OutputIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<InputIterator1>, | 
|  | typename = internal::iterator_category_t<InputIterator2>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<InputIterator1, Proj1>, | 
|  | projected<InputIterator2, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<InputIterator2, Proj2>, | 
|  | projected<InputIterator1, Proj1>>> | 
|  | constexpr auto set_intersection(InputIterator1 first1, | 
|  | InputIterator1 last1, | 
|  | InputIterator2 first2, | 
|  | InputIterator2 last2, | 
|  | OutputIterator result, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | // Needs to opt-in to all permutations, since std::set_intersection expects | 
|  | // comp(proj1(lhs), proj2(rhs)) and comp(proj2(lhs), proj1(rhs)) to compile. | 
|  | return std::set_intersection( | 
|  | first1, last1, first2, last2, result, | 
|  | internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2)); | 
|  | } | 
|  |  | 
|  | // Preconditions: The ranges `range1` and `range2` are sorted with respect to | 
|  | // `comp` and `proj1` or `proj2`, respectively. The resulting range does not | 
|  | // overlap with either of the original ranges. | 
|  | // | 
|  | // Effects: Constructs a sorted intersection of the elements from the two | 
|  | // ranges; that is, the set of elements that are present in both of the ranges. | 
|  | // | 
|  | // Returns: The end of the constructed range. | 
|  | // | 
|  | // Complexity: At most `2 * (size(range1) + size(range2)) - 1` comparisons and | 
|  | // applications of each projection. | 
|  | // | 
|  | // Remarks: Stable. If `range1` contains `m` elements that are equivalent to | 
|  | // each other and `range2` contains `n` elements that are equivalent to them, | 
|  | // the first `min(m, n)` elements are copied from the first range to the output | 
|  | // range, in order. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/set.intersection#:~:text=ranges::set_intersection(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename OutputIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range2>, Proj2>, | 
|  | projected<iterator_t<Range1>, Proj1>>> | 
|  | constexpr auto set_intersection(Range1&& range1, | 
|  | Range2&& range2, | 
|  | OutputIterator result, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::set_intersection(ranges::begin(range1), ranges::end(range1), | 
|  | ranges::begin(range2), ranges::end(range2), | 
|  | result, std::move(comp), std::move(proj1), | 
|  | std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // [set.difference] set_difference | 
|  | // Reference: https://wg21.link/set.difference | 
|  |  | 
|  | // Preconditions: The ranges `[first1, last1)` and `[first2, last2)` are sorted | 
|  | // with respect to `comp` and `proj1` or `proj2`, respectively. The resulting | 
|  | // range does not overlap with either of the original ranges. | 
|  | // | 
|  | // Effects: Copies the elements of the range `[first1, last1)` which are not | 
|  | // present in the range `[first2, last2)` to the range beginning at `result`. | 
|  | // The elements in the constructed range are sorted. | 
|  | // | 
|  | // Returns: The end of the constructed range. | 
|  | // | 
|  | // Complexity: At most `2 * ((last1 - first1) + (last2 - first2)) - 1` | 
|  | // comparisons and applications of each projection. | 
|  | // | 
|  | // Remarks: If `[first1, last1)` contains `m` elements that are equivalent to | 
|  | // each other and `[first2, last2)` contains `n` elements that are equivalent to | 
|  | // them, the last `max(m - n, 0)` elements from `[first1, last1)` are copied to | 
|  | // the output range, in order. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/set.difference#:~:text=ranges::set_difference(I1 | 
|  | template <typename InputIterator1, | 
|  | typename InputIterator2, | 
|  | typename OutputIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<InputIterator1>, | 
|  | typename = internal::iterator_category_t<InputIterator2>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<InputIterator1, Proj1>, | 
|  | projected<InputIterator2, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<InputIterator2, Proj2>, | 
|  | projected<InputIterator1, Proj1>>> | 
|  | constexpr auto set_difference(InputIterator1 first1, | 
|  | InputIterator1 last1, | 
|  | InputIterator2 first2, | 
|  | InputIterator2 last2, | 
|  | OutputIterator result, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | // Needs to opt-in to all permutations, since std::set_difference expects | 
|  | // comp(proj1(lhs), proj2(rhs)) and comp(proj2(lhs), proj1(rhs)) to compile. | 
|  | return std::set_difference( | 
|  | first1, last1, first2, last2, result, | 
|  | internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2)); | 
|  | } | 
|  |  | 
|  | // Preconditions: The ranges `range1` and `range2` are sorted with respect to | 
|  | // `comp` and `proj1` or `proj2`, respectively. The resulting range does not | 
|  | // overlap with either of the original ranges. | 
|  | // | 
|  | // Effects: Copies the elements of `range1` which are not present in `range2` | 
|  | // to the range beginning at `result`. The elements in the constructed range are | 
|  | // sorted. | 
|  | // | 
|  | // Returns: The end of the constructed range. | 
|  | // | 
|  | // Complexity: At most `2 * (size(range1) + size(range2)) - 1` comparisons and | 
|  | // applications of each projection. | 
|  | // | 
|  | // Remarks: Stable. If `range1` contains `m` elements that are equivalent to | 
|  | // each other and `range2` contains `n` elements that are equivalent to them, | 
|  | // the last `max(m - n, 0)` elements from `range1` are copied to the output | 
|  | // range, in order. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/set.difference#:~:text=ranges::set_difference(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename OutputIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range2>, Proj2>, | 
|  | projected<iterator_t<Range1>, Proj1>>> | 
|  | constexpr auto set_difference(Range1&& range1, | 
|  | Range2&& range2, | 
|  | OutputIterator result, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::set_difference(ranges::begin(range1), ranges::end(range1), | 
|  | ranges::begin(range2), ranges::end(range2), | 
|  | result, std::move(comp), std::move(proj1), | 
|  | std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // [set.symmetric.difference] set_symmetric_difference | 
|  | // Reference: https://wg21.link/set.symmetric.difference | 
|  |  | 
|  | // Preconditions: The ranges `[first1, last1)` and `[first2, last2)` are sorted | 
|  | // with respect to `comp` and `proj1` or `proj2`, respectively. The resulting | 
|  | // range does not overlap with either of the original ranges. | 
|  | // | 
|  | // Effects: Copies the elements of the range `[first1, last1)` that are not | 
|  | // present in the range `[first2, last2)`, and the elements of the range | 
|  | // `[first2, last2)` that are not present in the range `[first1, last1)` to the | 
|  | // range beginning at `result`. The elements in the constructed range are | 
|  | // sorted. | 
|  | // | 
|  | // Returns: The end of the constructed range. | 
|  | // | 
|  | // Complexity: At most `2 * ((last1 - first1) + (last2 - first2)) - 1` | 
|  | // comparisons and applications of each projection. | 
|  | // | 
|  | // Remarks: Stable. If `[first1, last1)` contains `m` elements that are | 
|  | // equivalent to each other and `[first2, last2)` contains `n` elements that are | 
|  | // equivalent to them, then `|m - n|` of those elements shall be copied to the | 
|  | // output range: the last `m - n` of these elements from `[first1, last1)` if | 
|  | // `m > n`, and the last `n - m` of these elements from `[first2, last2)` if | 
|  | // `m < n`. In either case, the elements are copied in order. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/set.symmetric.difference#:~:text=set_symmetric_difference(I1 | 
|  | template <typename InputIterator1, | 
|  | typename InputIterator2, | 
|  | typename OutputIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<InputIterator1>, | 
|  | typename = internal::iterator_category_t<InputIterator2>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<InputIterator1, Proj1>, | 
|  | projected<InputIterator2, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<InputIterator2, Proj2>, | 
|  | projected<InputIterator1, Proj1>>> | 
|  | constexpr auto set_symmetric_difference(InputIterator1 first1, | 
|  | InputIterator1 last1, | 
|  | InputIterator2 first2, | 
|  | InputIterator2 last2, | 
|  | OutputIterator result, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | // Needs to opt-in to all permutations, since std::set_symmetric_difference | 
|  | // expects comp(proj1(lhs), proj2(rhs)) and comp(proj2(lhs), proj1(rhs)) to | 
|  | // compile. | 
|  | return std::set_symmetric_difference( | 
|  | first1, last1, first2, last2, result, | 
|  | internal::PermutedProjectedBinaryPredicate(comp, proj1, proj2)); | 
|  | } | 
|  |  | 
|  | // Preconditions: The ranges `range1` and `range2` are sorted with respect to | 
|  | // `comp` and `proj1` or `proj2`, respectively. The resulting range does not | 
|  | // overlap with either of the original ranges. | 
|  | // | 
|  | // Effects: Copies the elements of `range1` that are not present in `range2`, | 
|  | // and the elements of `range2` that are not present in `range1` to the range | 
|  | // beginning at `result`. The elements in the constructed range are sorted. | 
|  | // | 
|  | // Returns: The end of the constructed range. | 
|  | // | 
|  | // Complexity: At most `2 * (size(range1) + size(range2)) - 1` comparisons and | 
|  | // applications of each projection. | 
|  | // | 
|  | // Remarks: Stable. If `range1` contains `m` elements that are equivalent to | 
|  | // each other and `range2` contains `n` elements that are equivalent to them, | 
|  | // then `|m - n|` of those elements shall be copied to the output range: the | 
|  | // last `m - n` of these elements from `range1` if `m > n`, and the last `n - m` | 
|  | // of these elements from `range2` if `m < n`. In either case, the elements are | 
|  | // copied in order. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/set.symmetric.difference#:~:text=set_symmetric_difference(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename OutputIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = internal::iterator_category_t<OutputIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range2>, Proj2>, | 
|  | projected<iterator_t<Range1>, Proj1>>> | 
|  | constexpr auto set_symmetric_difference(Range1&& range1, | 
|  | Range2&& range2, | 
|  | OutputIterator result, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::set_symmetric_difference( | 
|  | ranges::begin(range1), ranges::end(range1), ranges::begin(range2), | 
|  | ranges::end(range2), result, std::move(comp), std::move(proj1), | 
|  | std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // [alg.heap.operations] Heap operations | 
|  | // Reference: https://wg21.link/alg.heap.operations | 
|  |  | 
|  | // [push.heap] push_heap | 
|  | // Reference: https://wg21.link/push.heap | 
|  |  | 
|  | // Preconditions: The range `[first, last - 1)` is a valid heap with respect to | 
|  | // `comp` and `proj`. | 
|  | // | 
|  | // Effects: Places the value in the location `last - 1` into the resulting heap | 
|  | // `[first, last)`. | 
|  | // | 
|  | // Returns: `last`. | 
|  | // | 
|  | // Complexity: At most `log(last - first)` comparisons and twice as many | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/push.heap#:~:text=ranges::push_heap(I | 
|  | template <typename RandomAccessIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<RandomAccessIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<RandomAccessIterator, Proj>, | 
|  | projected<RandomAccessIterator, Proj>>> | 
|  | constexpr auto push_heap(RandomAccessIterator first, | 
|  | RandomAccessIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | std::push_heap(first, last, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Preconditions: The range `[begin(range), end(range) - 1)` is a valid heap | 
|  | // with respect to `comp` and `proj`. | 
|  | // | 
|  | // Effects: Places the value in the location `end(range) - 1` into the resulting | 
|  | // heap `range`. | 
|  | // | 
|  | // Returns: `end(range)`. | 
|  | // | 
|  | // Complexity: At most `log(size(range))` comparisons and twice as many | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/push.heap#:~:text=ranges::push_heap(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto push_heap(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::push_heap(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [pop.heap] pop_heap | 
|  | // Reference: https://wg21.link/pop.heap | 
|  |  | 
|  | // Preconditions: The range `[first, last)` is a valid non-empty heap with | 
|  | // respect to `comp` and `proj`. | 
|  | // | 
|  | // Effects: Swaps the value in the location `first` with the value in the | 
|  | // location `last - 1` and makes `[first, last - 1)` into a heap with respect to | 
|  | // `comp` and `proj`. | 
|  | // | 
|  | // Returns: `last`. | 
|  | // | 
|  | // Complexity: At most `2 log(last - first)` comparisons and twice as many | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/pop.heap#:~:text=ranges::pop_heap(I | 
|  | template <typename RandomAccessIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<RandomAccessIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<RandomAccessIterator, Proj>, | 
|  | projected<RandomAccessIterator, Proj>>> | 
|  | constexpr auto pop_heap(RandomAccessIterator first, | 
|  | RandomAccessIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | std::pop_heap(first, last, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Preconditions: `range` is a valid non-empty heap with respect to `comp` and | 
|  | // `proj`. | 
|  | // | 
|  | // Effects: Swaps the value in the location `begin(range)` with the value in the | 
|  | // location `end(range) - 1` and makes `[begin(range), end(range) - 1)` into a | 
|  | // heap with respect to `comp` and `proj`. | 
|  | // | 
|  | // Returns: `end(range)`. | 
|  | // | 
|  | // Complexity: At most `2 log(size(range))` comparisons and twice as many | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/pop.heap#:~:text=ranges::pop_heap(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto pop_heap(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::pop_heap(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [make.heap] make_heap | 
|  | // Reference: https://wg21.link/make.heap | 
|  |  | 
|  | // Effects: Constructs a heap with respect to `comp` and `proj` out of the range | 
|  | // `[first, last)`. | 
|  | // | 
|  | // Returns: `last`. | 
|  | // | 
|  | // Complexity: At most `3 * (last - first)` comparisons and twice as many | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/make.heap#:~:text=ranges::make_heap(I | 
|  | template <typename RandomAccessIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<RandomAccessIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<RandomAccessIterator, Proj>, | 
|  | projected<RandomAccessIterator, Proj>>> | 
|  | constexpr auto make_heap(RandomAccessIterator first, | 
|  | RandomAccessIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | std::make_heap(first, last, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Effects: Constructs a heap with respect to `comp` and `proj` out of `range`. | 
|  | // | 
|  | // Returns: `end(range)`. | 
|  | // | 
|  | // Complexity: At most `3 * size(range)` comparisons and twice as many | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/make.heap#:~:text=ranges::make_heap(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto make_heap(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::make_heap(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [sort.heap] sort_heap | 
|  | // Reference: https://wg21.link/sort.heap | 
|  |  | 
|  | // Preconditions: The range `[first, last)` is a valid heap with respect to | 
|  | // `comp` and `proj`. | 
|  | // | 
|  | // Effects: Sorts elements in the heap `[first, last)` with respect to `comp` | 
|  | // and `proj`. | 
|  | // | 
|  | // Returns: `last`. | 
|  | // | 
|  | // Complexity: At most `2 N log N` comparisons, where `N = last - first`, and | 
|  | // twice as many projections. | 
|  | // | 
|  | // Reference: https://wg21.link/sort.heap#:~:text=ranges::sort_heap(I | 
|  | template <typename RandomAccessIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<RandomAccessIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<RandomAccessIterator, Proj>, | 
|  | projected<RandomAccessIterator, Proj>>> | 
|  | constexpr auto sort_heap(RandomAccessIterator first, | 
|  | RandomAccessIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | std::sort_heap(first, last, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | return last; | 
|  | } | 
|  |  | 
|  | // Preconditions: `range` is a valid heap with respect to `comp` and `proj`. | 
|  | // | 
|  | // Effects: Sorts elements in the heap `range` with respect to `comp` and | 
|  | // `proj`. | 
|  | // | 
|  | // Returns: `end(range)`. | 
|  | // | 
|  | // Complexity: At most `2 N log N` comparisons, where `N = size(range)`, and | 
|  | // twice as many projections. | 
|  | // | 
|  | // Reference: https://wg21.link/sort.heap#:~:text=ranges::sort_heap(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto sort_heap(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::sort_heap(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [is.heap] is_heap | 
|  | // Reference: https://wg21.link/is.heap | 
|  |  | 
|  | // Returns: Whether the range `[first, last)` is a heap with respect to `comp` | 
|  | // and `proj`. | 
|  | // | 
|  | // Complexity: Linear. | 
|  | // | 
|  | // Reference: https://wg21.link/is.heap#:~:text=ranges::is_heap(I | 
|  | template <typename RandomAccessIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<RandomAccessIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<RandomAccessIterator, Proj>, | 
|  | projected<RandomAccessIterator, Proj>>> | 
|  | constexpr auto is_heap(RandomAccessIterator first, | 
|  | RandomAccessIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return std::is_heap(first, last, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Returns: Whether `range` is a heap with respect to `comp` and `proj`. | 
|  | // | 
|  | // Complexity: Linear. | 
|  | // | 
|  | // Reference: https://wg21.link/is.heap#:~:text=ranges::is_heap(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto is_heap(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::is_heap(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Returns: The last iterator `i` in `[first, last]` for which the range | 
|  | // `[first, i)` is a heap with respect to `comp` and `proj`. | 
|  | // | 
|  | // Complexity: Linear. | 
|  | // | 
|  | // Reference: https://wg21.link/is.heap#:~:text=ranges::is_heap_until(I | 
|  | template <typename RandomAccessIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<RandomAccessIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<RandomAccessIterator, Proj>, | 
|  | projected<RandomAccessIterator, Proj>>> | 
|  | constexpr auto is_heap_until(RandomAccessIterator first, | 
|  | RandomAccessIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return std::is_heap_until( | 
|  | first, last, internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Returns: The last iterator `i` in `[begin(range), end(range)]` for which the | 
|  | // range `[begin(range), i)` is a heap with respect to `comp` and `proj`. | 
|  | // | 
|  | // Complexity: Linear. | 
|  | // | 
|  | // Reference: https://wg21.link/is.heap#:~:text=ranges::is_heap_until(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto is_heap_until(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::is_heap_until(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.min.max] Minimum and maximum | 
|  | // Reference: https://wg21.link/alg.min.max | 
|  |  | 
|  | // Returns: The smaller value. Returns the first argument when the arguments are | 
|  | // equivalent. | 
|  | // | 
|  | // Complexity: Exactly one comparison and two applications of the projection, if | 
|  | // any. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::min | 
|  | template <typename T, typename Comp = ranges::less, typename Proj = identity> | 
|  | constexpr const T& min(const T& a, const T& b, Comp comp = {}, Proj proj = {}) { | 
|  | return gurl_base::invoke(comp, gurl_base::invoke(proj, b), gurl_base::invoke(proj, a)) ? b | 
|  | : a; | 
|  | } | 
|  |  | 
|  | // Preconditions: `!empty(ilist)`. | 
|  | // | 
|  | // Returns: The smallest value in the input range. Returns a copy of the | 
|  | // leftmost element when several elements are equivalent to the smallest. | 
|  | // | 
|  | // Complexity: Exactly `size(ilist) - 1` comparisons and twice as many | 
|  | // applications of the projection, if any. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::min(initializer_list | 
|  | template <typename T, typename Comp = ranges::less, typename Proj = identity> | 
|  | constexpr T min(std::initializer_list<T> ilist, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return *std::min_element( | 
|  | ilist.begin(), ilist.end(), | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Preconditions: `!empty(range)`. | 
|  | // | 
|  | // Returns: The smallest value in the input range. Returns a copy of the | 
|  | // leftmost element when several elements are equivalent to the smallest. | 
|  | // | 
|  | // Complexity: Exactly `size(range) - 1` comparisons and twice as many | 
|  | // applications of the projection, if any. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::min(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto min(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return *std::min_element( | 
|  | ranges::begin(range), ranges::end(range), | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Returns: The larger value. Returns the first argument when the arguments are | 
|  | // equivalent. | 
|  | // | 
|  | // Complexity: Exactly one comparison and two applications of the projection, if | 
|  | // any. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::max | 
|  | template <typename T, typename Comp = ranges::less, typename Proj = identity> | 
|  | constexpr const T& max(const T& a, const T& b, Comp comp = {}, Proj proj = {}) { | 
|  | return gurl_base::invoke(comp, gurl_base::invoke(proj, a), gurl_base::invoke(proj, b)) ? b | 
|  | : a; | 
|  | } | 
|  |  | 
|  | // Preconditions: `!empty(ilist)`. | 
|  | // | 
|  | // Returns: The largest value in the input range. Returns a copy of the leftmost | 
|  | // element when several elements are equivalent to the largest. | 
|  | // | 
|  | // Complexity: Exactly `size(ilist) - 1` comparisons and twice as many | 
|  | // applications of the projection, if any. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::max(initializer_list | 
|  | template <typename T, typename Comp = ranges::less, typename Proj = identity> | 
|  | constexpr T max(std::initializer_list<T> ilist, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return *std::max_element( | 
|  | ilist.begin(), ilist.end(), | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Preconditions: `!empty(range)`. | 
|  | // | 
|  | // Returns: The largest value in the input range. Returns a copy of the leftmost | 
|  | // element when several elements are equivalent to the smallest. | 
|  | // | 
|  | // Complexity: Exactly `size(range) - 1` comparisons and twice as many | 
|  | // applications of the projection, if any. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::max(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto max(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return *std::max_element( | 
|  | ranges::begin(range), ranges::end(range), | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Returns: `{b, a}` if `b` is smaller than `a`, and `{a, b}` otherwise. | 
|  | // | 
|  | // Complexity: Exactly one comparison and two applications of the projection, if | 
|  | // any. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::minmax | 
|  | template <typename T, typename Comp = ranges::less, typename Proj = identity> | 
|  | constexpr auto minmax(const T& a, const T& b, Comp comp = {}, Proj proj = {}) { | 
|  | return std::minmax(a, b, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Preconditions: `!empty(ilist)`. | 
|  | // | 
|  | // Returns: Let `X` be the return type. Returns `X{x, y}`, where `x` is a copy | 
|  | // of the leftmost element with the smallest value and `y` a copy of the | 
|  | // rightmost element with the largest value in the input range. | 
|  | // | 
|  | // Complexity: At most `(3/2) size(ilist)` applications of the corresponding | 
|  | // predicate and twice as many applications of the projection, if any. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.min.max#:~:text=ranges::minmax(initializer_list | 
|  | template <typename T, typename Comp = ranges::less, typename Proj = identity> | 
|  | constexpr auto minmax(std::initializer_list<T> ilist, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | auto it = | 
|  | std::minmax_element(ranges::begin(ilist), ranges::end(ilist), | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | return std::pair<T, T>{*it.first, *it.second}; | 
|  | } | 
|  |  | 
|  | // Preconditions: `!empty(range)`. | 
|  | // | 
|  | // Returns: Let `X` be the return type. Returns `X{x, y}`, where `x` is a copy | 
|  | // of the leftmost element with the smallest value and `y` a copy of the | 
|  | // rightmost element with the largest value in the input range. | 
|  | // | 
|  | // Complexity: At most `(3/2) size(range)` applications of the corresponding | 
|  | // predicate and twice as many applications of the projection, if any. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::minmax(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>> | 
|  | constexpr auto minmax(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | using T = range_value_t<Range>; | 
|  | auto it = | 
|  | std::minmax_element(ranges::begin(range), ranges::end(range), | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | return std::pair<T, T>{*it.first, *it.second}; | 
|  | } | 
|  |  | 
|  | // Returns: The first iterator i in the range `[first, last)` such that for | 
|  | // every iterator `j` in the range `[first, last)`, | 
|  | // `bool(invoke(comp, invoke(proj, *j), invoke(proj, *i)))` is `false`. Returns | 
|  | // `last` if `first == last`. | 
|  | // | 
|  | // Complexity: Exactly `max(last - first - 1, 0)` comparisons and twice as | 
|  | // many projections. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::min_element(I | 
|  | template <typename ForwardIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<ForwardIterator, Proj>, | 
|  | projected<ForwardIterator, Proj>>> | 
|  | constexpr auto min_element(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return std::min_element(first, last, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Returns: The first iterator i in `range` such that for every iterator `j` in | 
|  | // `range`, `bool(invoke(comp, invoke(proj, *j), invoke(proj, *i)))` is `false`. | 
|  | // Returns `end(range)` if `empty(range)`. | 
|  | // | 
|  | // Complexity: Exactly `max(size(range) - 1, 0)` comparisons and twice as many | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::min_element(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto min_element(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::min_element(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Returns: The first iterator i in the range `[first, last)` such that for | 
|  | // every iterator `j` in the range `[first, last)`, | 
|  | // `bool(invoke(comp, invoke(proj, *i), invoke(proj, *j)))` is `false`. | 
|  | // Returns `last` if `first == last`. | 
|  | // | 
|  | // Complexity: Exactly `max(last - first - 1, 0)` comparisons and twice as | 
|  | // many projections. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::max_element(I | 
|  | template <typename ForwardIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<ForwardIterator, Proj>, | 
|  | projected<ForwardIterator, Proj>>> | 
|  | constexpr auto max_element(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return std::max_element(first, last, | 
|  | internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Returns: The first iterator i in `range` such that for every iterator `j` | 
|  | // in `range`, `bool(invoke(comp, invoke(proj, *j), invoke(proj, *j)))` is | 
|  | // `false`. Returns `end(range)` if `empty(range)`. | 
|  | // | 
|  | // Complexity: Exactly `max(size(range) - 1, 0)` comparisons and twice as many | 
|  | // projections. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::max_element(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto max_element(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::max_element(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Returns: `{first, first}` if `[first, last)` is empty, otherwise `{m, M}`, | 
|  | // where `m` is the first iterator in `[first, last)` such that no iterator in | 
|  | // the range refers to a smaller element, and where `M` is the last iterator | 
|  | // in | 
|  | // `[first, last)` such that no iterator in the range refers to a larger | 
|  | // element. | 
|  | // | 
|  | // Complexity: Let `N` be `last - first`. At most `max(3/2 (N − 1), 0)` | 
|  | // comparisons and twice as many applications of the projection, if any. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::minmax_element(I | 
|  | template <typename ForwardIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<ForwardIterator, Proj>, | 
|  | projected<ForwardIterator, Proj>>> | 
|  | constexpr auto minmax_element(ForwardIterator first, | 
|  | ForwardIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return std::minmax_element( | 
|  | first, last, internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Returns: `{begin(range), begin(range)}` if `range` is empty, otherwise | 
|  | // `{m, M}`, where `m` is the first iterator in `range` such that no iterator | 
|  | // in the range refers to a smaller element, and where `M` is the last | 
|  | // iterator in `range` such that no iterator in the range refers to a larger | 
|  | // element. | 
|  | // | 
|  | // Complexity: Let `N` be `size(range)`. At most `max(3/2 (N − 1), 0)` | 
|  | // comparisons and twice as many applications of the projection, if any. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.min.max#:~:text=ranges::minmax_element(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto minmax_element(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::minmax_element(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // [alg.clamp] Bounded value | 
|  | // Reference: https://wg21.link/alg.clamp | 
|  |  | 
|  | // Preconditions: `bool(invoke(comp, invoke(proj, hi), invoke(proj, lo)))` is | 
|  | // `false`. | 
|  | // | 
|  | // Returns: `lo` if `bool(invoke(comp, invoke(proj, v), invoke(proj, lo)))` is | 
|  | // `true`, `hi` if `bool(invoke(comp, invoke(proj, hi), invoke(proj, v)))` is | 
|  | // `true`, otherwise `v`. | 
|  | // | 
|  | // Complexity: At most two comparisons and three applications of the | 
|  | // projection. | 
|  | // | 
|  | // Reference: https://wg21.link/alg.clamp#:~:text=ranges::clamp | 
|  | template <typename T, typename Comp = ranges::less, typename Proj = identity> | 
|  | constexpr const T& clamp(const T& v, | 
|  | const T& lo, | 
|  | const T& hi, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | auto&& projected_v = gurl_base::invoke(proj, v); | 
|  | if (gurl_base::invoke(comp, projected_v, gurl_base::invoke(proj, lo))) | 
|  | return lo; | 
|  |  | 
|  | return gurl_base::invoke(comp, gurl_base::invoke(proj, hi), projected_v) ? hi : v; | 
|  | } | 
|  |  | 
|  | // [alg.lex.comparison] Lexicographical comparison | 
|  | // Reference: https://wg21.link/alg.lex.comparison | 
|  |  | 
|  | // Returns: `true` if and only if the sequence of elements defined by the range | 
|  | // `[first1, last1)` is lexicographically less than the sequence of elements | 
|  | // defined by the range `[first2, last2)`. | 
|  | // | 
|  | // Complexity: At most `2 min(last1 - first1, last2 - first2)` applications of | 
|  | // the corresponding comparison and each projection, if any. | 
|  | // | 
|  | // Remarks: If two sequences have the same number of elements and their | 
|  | // corresponding elements (if any) are equivalent, then neither sequence is | 
|  | // lexicographically less than the other. If one sequence is a proper prefix of | 
|  | // the other, then the shorter sequence is lexicographically less than the | 
|  | // longer sequence. Otherwise, the lexicographical comparison of the sequences | 
|  | // yields the same result as the comparison of the first corresponding pair of | 
|  | // elements that are not equivalent. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.lex.comparison#:~:text=lexicographical_compare(I1 | 
|  | template <typename ForwardIterator1, | 
|  | typename ForwardIterator2, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::iterator_category_t<ForwardIterator1>, | 
|  | typename = internal::iterator_category_t<ForwardIterator2>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<ForwardIterator1, Proj1>, | 
|  | projected<ForwardIterator2, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<ForwardIterator2, Proj2>, | 
|  | projected<ForwardIterator1, Proj1>>> | 
|  | constexpr bool lexicographical_compare(ForwardIterator1 first1, | 
|  | ForwardIterator1 last1, | 
|  | ForwardIterator2 first2, | 
|  | ForwardIterator2 last2, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | for (; first1 != last1 && first2 != last2; ++first1, ++first2) { | 
|  | auto&& projected_first1 = gurl_base::invoke(proj1, *first1); | 
|  | auto&& projected_first2 = gurl_base::invoke(proj2, *first2); | 
|  | if (gurl_base::invoke(comp, projected_first1, projected_first2)) | 
|  | return true; | 
|  | if (gurl_base::invoke(comp, projected_first2, projected_first1)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // `first2 != last2` is equivalent to `first1 == last1 && first2 != last2` | 
|  | // here, since we broke out of the loop above. | 
|  | return first2 != last2; | 
|  | } | 
|  |  | 
|  | // Returns: `true` if and only if the sequence of elements defined by `range1` | 
|  | //  is lexicographically less than the sequence of elements defined by `range2`. | 
|  | // | 
|  | // Complexity: At most `2 min(size(range1), size(range2))` applications of the | 
|  | // corresponding comparison and each projection, if any. | 
|  | // | 
|  | // Remarks: If two sequences have the same number of elements and their | 
|  | // corresponding elements (if any) are equivalent, then neither sequence is | 
|  | // lexicographically less than the other. If one sequence is a proper prefix of | 
|  | // the other, then the shorter sequence is lexicographically less than the | 
|  | // longer sequence. Otherwise, the lexicographical comparison of the sequences | 
|  | // yields the same result as the comparison of the first corresponding pair of | 
|  | // elements that are not equivalent. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.lex.comparison#:~:text=lexicographical_compare(R1 | 
|  | template <typename Range1, | 
|  | typename Range2, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj1 = identity, | 
|  | typename Proj2 = identity, | 
|  | typename = internal::range_category_t<Range1>, | 
|  | typename = internal::range_category_t<Range2>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range1>, Proj1>, | 
|  | projected<iterator_t<Range2>, Proj2>>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range2>, Proj2>, | 
|  | projected<iterator_t<Range1>, Proj1>>> | 
|  | constexpr bool lexicographical_compare(Range1&& range1, | 
|  | Range2&& range2, | 
|  | Comp comp = {}, | 
|  | Proj1 proj1 = {}, | 
|  | Proj2 proj2 = {}) { | 
|  | return ranges::lexicographical_compare( | 
|  | ranges::begin(range1), ranges::end(range1), ranges::begin(range2), | 
|  | ranges::end(range2), std::move(comp), std::move(proj1), std::move(proj2)); | 
|  | } | 
|  |  | 
|  | // [alg.permutation.generators] Permutation generators | 
|  | // Reference: https://wg21.link/alg.permutation.generators | 
|  |  | 
|  | // Effects: Takes a sequence defined by the range `[first, last)` and transforms | 
|  | // it into the next permutation. The next permutation is found by assuming that | 
|  | // the set of all permutations is lexicographically sorted with respect to | 
|  | // `comp` and `proj`. If no such permutation exists, transforms the sequence | 
|  | // into the first permutation; that is, the ascendingly-sorted one. | 
|  | // | 
|  | // Returns: `true` if a next permutation was found and otherwise `false`. | 
|  | // | 
|  | // Complexity: At most `(last - first) / 2` swaps. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.permutation.generators#:~:text=next_permutation(I | 
|  | template <typename BidirectionalIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<BidirectionalIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<BidirectionalIterator, Proj>, | 
|  | projected<BidirectionalIterator, Proj>>> | 
|  | constexpr auto next_permutation(BidirectionalIterator first, | 
|  | BidirectionalIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return std::next_permutation( | 
|  | first, last, internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Effects: Takes a sequence defined by `range` and transforms it into the next | 
|  | // permutation. The next permutation is found by assuming that the set of all | 
|  | // permutations is lexicographically sorted with respect to `comp` and `proj`. | 
|  | // If no such permutation exists, transforms the sequence into the first | 
|  | // permutation; that is, the ascendingly-sorted one. | 
|  | // | 
|  | // Returns: `true` if a next permutation was found and otherwise `false`. | 
|  | // | 
|  | // Complexity: At most `size(range) / 2` swaps. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.permutation.generators#:~:text=next_permutation(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto next_permutation(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::next_permutation(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | // Effects: Takes a sequence defined by the range `[first, last)` and transforms | 
|  | // it into the previous permutation. The previous permutation is found by | 
|  | // assuming that the set of all permutations is lexicographically sorted with | 
|  | // respect to `comp` and `proj`. If no such permutation exists, transforms the | 
|  | // sequence into the last permutation; that is, the decreasingly-sorted one. | 
|  | // | 
|  | // Returns: `true` if a next permutation was found and otherwise `false`. | 
|  | // | 
|  | // Complexity: At most `(last - first) / 2` swaps. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.permutation.generators#:~:text=prev_permutation(I | 
|  | template <typename BidirectionalIterator, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::iterator_category_t<BidirectionalIterator>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<BidirectionalIterator, Proj>, | 
|  | projected<BidirectionalIterator, Proj>>> | 
|  | constexpr auto prev_permutation(BidirectionalIterator first, | 
|  | BidirectionalIterator last, | 
|  | Comp comp = {}, | 
|  | Proj proj = {}) { | 
|  | return std::prev_permutation( | 
|  | first, last, internal::ProjectedBinaryPredicate(comp, proj, proj)); | 
|  | } | 
|  |  | 
|  | // Effects: Takes a sequence defined by `range` and transforms it into the | 
|  | // previous permutation. The previous permutation is found by assuming that the | 
|  | // set of all permutations is lexicographically sorted with respect to `comp` | 
|  | // and `proj`. If no such permutation exists, transforms the sequence into the | 
|  | // last permutation; that is, the decreasingly-sorted one. | 
|  | // | 
|  | // Returns: `true` if a previous permutation was found and otherwise `false`. | 
|  | // | 
|  | // Complexity: At most `size(range) / 2` swaps. | 
|  | // | 
|  | // Reference: | 
|  | // https://wg21.link/alg.permutation.generators#:~:text=prev_permutation(R | 
|  | template <typename Range, | 
|  | typename Comp = ranges::less, | 
|  | typename Proj = identity, | 
|  | typename = internal::range_category_t<Range>, | 
|  | typename = indirect_result_t<Comp&, | 
|  | projected<iterator_t<Range>, Proj>, | 
|  | projected<iterator_t<Range>, Proj>>> | 
|  | constexpr auto prev_permutation(Range&& range, Comp comp = {}, Proj proj = {}) { | 
|  | return ranges::prev_permutation(ranges::begin(range), ranges::end(range), | 
|  | std::move(comp), std::move(proj)); | 
|  | } | 
|  |  | 
|  | }  // namespace ranges | 
|  |  | 
|  | }  // namespace base | 
|  |  | 
|  | #endif  // BASE_RANGES_ALGORITHM_H_ |