chromium/chromium-86-use-range-based...

6649 lines
278 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

diff -up chromium-86.0.4240.111/base/callback_list.h.a61fb57e chromium-86.0.4240.111/base/callback_list.h
--- chromium-86.0.4240.111/base/callback_list.h.a61fb57e 2020-10-20 20:14:17.000000000 -0400
+++ chromium-86.0.4240.111/base/callback_list.h 2020-10-21 17:11:20.000228716 -0400
@@ -5,7 +5,6 @@
#ifndef BASE_CALLBACK_LIST_H_
#define BASE_CALLBACK_LIST_H_
-#include <algorithm>
#include <list>
#include <memory>
#include <utility>
@@ -17,6 +16,7 @@
#include "base/check.h"
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
// OVERVIEW:
@@ -163,8 +163,8 @@ class CallbackListBase {
// Returns whether the list of registered callbacks is empty (from an external
// perspective -- meaning no remaining callbacks are live).
bool empty() const {
- return std::all_of(callbacks_.cbegin(), callbacks_.cend(),
- [](const auto& callback) { return callback.is_null(); });
+ return ranges::all_of(
+ callbacks_, [](const auto& callback) { return callback.is_null(); });
}
// Calls all registered callbacks that are not canceled beforehand. If any
diff -up chromium-86.0.4240.111/base/command_line.cc.a61fb57e chromium-86.0.4240.111/base/command_line.cc
--- chromium-86.0.4240.111/base/command_line.cc.a61fb57e 2020-10-20 20:14:17.000000000 -0400
+++ chromium-86.0.4240.111/base/command_line.cc 2020-10-21 17:11:20.000228716 -0400
@@ -4,13 +4,13 @@
#include "base/command_line.h"
-#include <algorithm>
#include <ostream>
#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/notreached.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "base/strings/strcat.h"
#include "base/strings/string_split.h"
@@ -411,8 +411,7 @@ CommandLine::StringVector CommandLine::G
// Gather all arguments after the last switch (may include kSwitchTerminator).
StringVector args(argv_.begin() + begin_args_, argv_.end());
// Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?)
- auto switch_terminator =
- std::find(args.begin(), args.end(), kSwitchTerminator);
+ auto switch_terminator = ranges::find(args, kSwitchTerminator);
if (switch_terminator != args.end())
args.erase(switch_terminator);
return args;
diff -up chromium-86.0.4240.111/base/containers/checked_range_unittest.cc.a61fb57e chromium-86.0.4240.111/base/containers/checked_range_unittest.cc
--- chromium-86.0.4240.111/base/containers/checked_range_unittest.cc.a61fb57e 2020-10-20 20:14:17.000000000 -0400
+++ chromium-86.0.4240.111/base/containers/checked_range_unittest.cc 2020-10-21 17:11:20.001228724 -0400
@@ -8,6 +8,7 @@
#include <initializer_list>
#include <type_traits>
+#include "base/ranges/algorithm.h"
#include "base/strings/string_piece.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -151,9 +152,9 @@ TEST(CheckedContiguousRange, Mutable_Dat
std::vector<int> vector = {3, 1, 4, 2, 5};
CheckedContiguousRange<std::vector<int>> range(vector);
- EXPECT_FALSE(std::is_sorted(vector.begin(), vector.end()));
+ EXPECT_FALSE(ranges::is_sorted(vector));
std::sort(range.data(), range.data() + range.size());
- EXPECT_TRUE(std::is_sorted(vector.begin(), vector.end()));
+ EXPECT_TRUE(ranges::is_sorted(vector));
}
TEST(CheckedContiguousRange, DataSizeEmpty_Constexpr) {
diff -up chromium-86.0.4240.111/base/containers/circular_deque.h.a61fb57e chromium-86.0.4240.111/base/containers/circular_deque.h
--- chromium-86.0.4240.111/base/containers/circular_deque.h.a61fb57e 2020-10-20 20:14:17.000000000 -0400
+++ chromium-86.0.4240.111/base/containers/circular_deque.h 2020-10-21 17:11:20.001228724 -0400
@@ -14,6 +14,7 @@
#include "base/check_op.h"
#include "base/containers/vector_buffer.h"
#include "base/macros.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "base/template_util.h"
@@ -1097,7 +1098,7 @@ class circular_deque {
// Implementations of base::Erase[If] (see base/stl_util.h).
template <class T, class Value>
size_t Erase(circular_deque<T>& container, const Value& value) {
- auto it = std::remove(container.begin(), container.end(), value);
+ auto it = ranges::remove(container, value);
size_t removed = std::distance(it, container.end());
container.erase(it, container.end());
return removed;
@@ -1105,7 +1106,7 @@ size_t Erase(circular_deque<T>& containe
template <class T, class Predicate>
size_t EraseIf(circular_deque<T>& container, Predicate pred) {
- auto it = std::remove_if(container.begin(), container.end(), pred);
+ auto it = ranges::remove_if(container, pred);
size_t removed = std::distance(it, container.end());
container.erase(it, container.end());
return removed;
diff -up chromium-86.0.4240.111/base/containers/flat_map_unittest.cc.a61fb57e chromium-86.0.4240.111/base/containers/flat_map_unittest.cc
--- chromium-86.0.4240.111/base/containers/flat_map_unittest.cc.a61fb57e 2020-10-20 20:14:17.000000000 -0400
+++ chromium-86.0.4240.111/base/containers/flat_map_unittest.cc 2020-10-21 17:11:20.001228724 -0400
@@ -8,6 +8,7 @@
#include <vector>
#include "base/macros.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string_piece.h"
#include "base/test/move_only_int.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -214,7 +215,7 @@ TEST(FlatMap, InsertOrAssignMoveOnlyKey)
base::flat_map<MoveOnlyInt, int> map;
for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) {
map.insert_or_assign(MoveOnlyInt(i), i);
- EXPECT_TRUE(std::is_sorted(map.begin(), map.end()));
+ EXPECT_TRUE(ranges::is_sorted(map));
}
}
@@ -249,7 +250,7 @@ TEST(FlatMap, InsertOrAssignMoveOnlyKeyW
base::flat_map<MoveOnlyInt, int> map;
for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) {
map.insert_or_assign(map.end(), MoveOnlyInt(i), i);
- EXPECT_TRUE(std::is_sorted(map.begin(), map.end()));
+ EXPECT_TRUE(ranges::is_sorted(map));
}
}
@@ -294,7 +295,7 @@ TEST(FlatMap, TryEmplaceMoveOnlyKey) {
base::flat_map<MoveOnlyInt, int> map;
for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) {
map.try_emplace(MoveOnlyInt(i), i);
- EXPECT_TRUE(std::is_sorted(map.begin(), map.end()));
+ EXPECT_TRUE(ranges::is_sorted(map));
}
}
@@ -340,7 +341,7 @@ TEST(FlatMap, TryEmplaceMoveOnlyKeyWithH
base::flat_map<MoveOnlyInt, int> map;
for (int i : {3, 1, 5, 6, 8, 7, 0, 9, 4, 2}) {
map.try_emplace(map.end(), MoveOnlyInt(i), i);
- EXPECT_TRUE(std::is_sorted(map.begin(), map.end()));
+ EXPECT_TRUE(ranges::is_sorted(map));
}
}
diff -up chromium-86.0.4240.111/base/containers/flat_tree.h.a61fb57e chromium-86.0.4240.111/base/containers/flat_tree.h
--- chromium-86.0.4240.111/base/containers/flat_tree.h.a61fb57e 2020-10-20 20:14:17.000000000 -0400
+++ chromium-86.0.4240.111/base/containers/flat_tree.h 2020-10-21 17:11:20.002228733 -0400
@@ -11,6 +11,7 @@
#include <utility>
#include <vector>
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "base/template_util.h"
@@ -753,11 +754,10 @@ template <class Key, class Value, class
void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::replace(
underlying_type&& body) {
// Ensure that |body| is sorted and has no repeated elements.
- DCHECK(std::is_sorted(body.begin(), body.end(), value_comp()));
- DCHECK(std::adjacent_find(body.begin(), body.end(),
- [this](const auto& lhs, const auto& rhs) {
- return !value_comp()(lhs, rhs);
- }) == body.end());
+ DCHECK(ranges::is_sorted(body, value_comp()));
+ DCHECK(ranges::adjacent_find(body, [this](const auto& lhs, const auto& rhs) {
+ return !value_comp()(lhs, rhs);
+ }) == body.end());
impl_.body_ = std::move(body);
}
@@ -883,7 +883,7 @@ auto flat_tree<Key, Value, GetKeyFromVal
const KeyTypeOrK<K>& key_ref = key;
KeyValueCompare key_value(impl_.get_key_comp());
- return std::lower_bound(begin(), end(), key_ref, key_value);
+ return ranges::lower_bound(*this, key_ref, key_value);
}
template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
@@ -904,7 +904,7 @@ auto flat_tree<Key, Value, GetKeyFromVal
const KeyTypeOrK<K>& key_ref = key;
KeyValueCompare key_value(impl_.get_key_comp());
- return std::upper_bound(begin(), end(), key_ref, key_value);
+ return ranges::upper_bound(*this, key_ref, key_value);
}
// ----------------------------------------------------------------------------
@@ -978,7 +978,7 @@ size_t EraseIf(
base::internal::flat_tree<Key, Value, GetKeyFromValue, KeyCompare>&
container,
Predicate pred) {
- auto it = std::remove_if(container.begin(), container.end(), pred);
+ auto it = ranges::remove_if(container, pred);
size_t removed = std::distance(it, container.end());
container.erase(it, container.end());
return removed;
diff -up chromium-86.0.4240.111/base/containers/flat_tree_unittest.cc.a61fb57e chromium-86.0.4240.111/base/containers/flat_tree_unittest.cc
--- chromium-86.0.4240.111/base/containers/flat_tree_unittest.cc.a61fb57e 2020-10-20 20:14:17.000000000 -0400
+++ chromium-86.0.4240.111/base/containers/flat_tree_unittest.cc 2020-10-21 17:11:20.003228742 -0400
@@ -35,6 +35,7 @@
#include <string>
#include <vector>
+#include "base/ranges/algorithm.h"
#include "base/template_util.h"
#include "base/test/move_only_int.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -218,8 +219,8 @@ TEST(FlatTree, Stability) {
Tree cont({{0, 0}, {1, 0}, {0, 1}, {2, 0}, {0, 2}, {1, 1}});
auto AllOfSecondsAreZero = [&cont] {
- return std::all_of(cont.begin(), cont.end(),
- [](const Pair& elem) { return elem.second == 0; });
+ return ranges::all_of(cont,
+ [](const Pair& elem) { return elem.second == 0; });
};
EXPECT_TRUE(AllOfSecondsAreZero()) << "constructor should be stable";
@@ -975,11 +976,11 @@ TEST(FlatTree, EraseEndDeath) {
TEST(FlatTree, KeyComp) {
ReversedTree cont({1, 2, 3, 4, 5});
- EXPECT_TRUE(std::is_sorted(cont.begin(), cont.end(), cont.key_comp()));
+ EXPECT_TRUE(ranges::is_sorted(cont, cont.key_comp()));
int new_elements[] = {6, 7, 8, 9, 10};
std::copy(std::begin(new_elements), std::end(new_elements),
std::inserter(cont, cont.end()));
- EXPECT_TRUE(std::is_sorted(cont.begin(), cont.end(), cont.key_comp()));
+ EXPECT_TRUE(ranges::is_sorted(cont, cont.key_comp()));
}
// value_compare value_comp() const
@@ -987,11 +988,11 @@ TEST(FlatTree, KeyComp) {
TEST(FlatTree, ValueComp) {
ReversedTree cont({1, 2, 3, 4, 5});
- EXPECT_TRUE(std::is_sorted(cont.begin(), cont.end(), cont.value_comp()));
+ EXPECT_TRUE(ranges::is_sorted(cont, cont.value_comp()));
int new_elements[] = {6, 7, 8, 9, 10};
std::copy(std::begin(new_elements), std::end(new_elements),
std::inserter(cont, cont.end()));
- EXPECT_TRUE(std::is_sorted(cont.begin(), cont.end(), cont.value_comp()));
+ EXPECT_TRUE(ranges::is_sorted(cont, cont.value_comp()));
}
// ----------------------------------------------------------------------------
diff -up chromium-86.0.4240.111/base/containers/span_unittest.cc.a61fb57e chromium-86.0.4240.111/base/containers/span_unittest.cc
--- chromium-86.0.4240.111/base/containers/span_unittest.cc.a61fb57e 2020-10-20 20:14:17.000000000 -0400
+++ chromium-86.0.4240.111/base/containers/span_unittest.cc 2020-10-21 17:11:20.003228742 -0400
@@ -6,7 +6,6 @@
#include <stdint.h>
-#include <algorithm>
#include <iterator>
#include <memory>
#include <string>
@@ -14,6 +13,7 @@
#include <vector>
#include "base/containers/checked_iterators.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -1382,7 +1382,7 @@ TEST(SpanTest, Sort) {
int array[] = {5, 4, 3, 2, 1};
span<int> dynamic_span = array;
- std::sort(dynamic_span.begin(), dynamic_span.end());
+ ranges::sort(dynamic_span);
EXPECT_THAT(array, ElementsAre(1, 2, 3, 4, 5));
std::sort(dynamic_span.rbegin(), dynamic_span.rend());
EXPECT_THAT(array, ElementsAre(5, 4, 3, 2, 1));
@@ -1390,7 +1390,7 @@ TEST(SpanTest, Sort) {
span<int, 5> static_span = array;
std::sort(static_span.rbegin(), static_span.rend(), std::greater<>());
EXPECT_THAT(array, ElementsAre(1, 2, 3, 4, 5));
- std::sort(static_span.begin(), static_span.end(), std::greater<>());
+ ranges::sort(static_span, std::greater<>());
EXPECT_THAT(array, ElementsAre(5, 4, 3, 2, 1));
}
diff -up chromium-86.0.4240.111/base/containers/unique_ptr_adapters_unittest.cc.a61fb57e chromium-86.0.4240.111/base/containers/unique_ptr_adapters_unittest.cc
--- chromium-86.0.4240.111/base/containers/unique_ptr_adapters_unittest.cc.a61fb57e 2020-10-20 20:14:17.000000000 -0400
+++ chromium-86.0.4240.111/base/containers/unique_ptr_adapters_unittest.cc 2020-10-21 17:11:20.004228750 -0400
@@ -4,10 +4,10 @@
#include "base/containers/unique_ptr_adapters.h"
-#include <algorithm>
#include <memory>
#include <vector>
+#include "base/ranges/algorithm.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -76,19 +76,19 @@ TEST(UniquePtrMatcherTest, Basic) {
v.push_back(std::move(foo_ptr2));
{
- auto iter = std::find_if(v.begin(), v.end(), UniquePtrMatcher<Foo>(foo1));
+ auto iter = ranges::find_if(v, UniquePtrMatcher<Foo>(foo1));
ASSERT_TRUE(iter != v.end());
EXPECT_EQ(foo1, iter->get());
}
{
- auto iter = std::find_if(v.begin(), v.end(), UniquePtrMatcher<Foo>(foo2));
+ auto iter = ranges::find_if(v, UniquePtrMatcher<Foo>(foo2));
ASSERT_TRUE(iter != v.end());
EXPECT_EQ(foo2, iter->get());
}
{
- auto iter = std::find_if(v.begin(), v.end(), MatchesUniquePtr(foo2));
+ auto iter = ranges::find_if(v, MatchesUniquePtr(foo2));
ASSERT_TRUE(iter != v.end());
EXPECT_EQ(foo2, iter->get());
}
@@ -110,22 +110,19 @@ TEST(UniquePtrMatcherTest, Deleter) {
v.push_back(std::move(foo_ptr2));
{
- auto iter = std::find_if(v.begin(), v.end(),
- UniquePtrMatcher<Foo, TestDeleter>(foo1));
+ auto iter = ranges::find_if(v, UniquePtrMatcher<Foo, TestDeleter>(foo1));
ASSERT_TRUE(iter != v.end());
EXPECT_EQ(foo1, iter->get());
}
{
- auto iter = std::find_if(v.begin(), v.end(),
- UniquePtrMatcher<Foo, TestDeleter>(foo2));
+ auto iter = ranges::find_if(v, UniquePtrMatcher<Foo, TestDeleter>(foo2));
ASSERT_TRUE(iter != v.end());
EXPECT_EQ(foo2, iter->get());
}
{
- auto iter = std::find_if(v.begin(), v.end(),
- MatchesUniquePtr<Foo, TestDeleter>(foo2));
+ auto iter = ranges::find_if(v, MatchesUniquePtr<Foo, TestDeleter>(foo2));
ASSERT_TRUE(iter != v.end());
EXPECT_EQ(foo2, iter->get());
}
diff -up chromium-86.0.4240.111/base/debug/activity_analyzer.cc.a61fb57e chromium-86.0.4240.111/base/debug/activity_analyzer.cc
--- chromium-86.0.4240.111/base/debug/activity_analyzer.cc.a61fb57e 2020-10-20 20:14:17.000000000 -0400
+++ chromium-86.0.4240.111/base/debug/activity_analyzer.cc 2020-10-21 17:11:20.004228750 -0400
@@ -4,7 +4,6 @@
#include "base/debug/activity_analyzer.h"
-#include <algorithm>
#include <utility>
#include "base/check_op.h"
@@ -14,6 +13,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
@@ -398,7 +398,7 @@ void GlobalActivityAnalyzer::PrepareAllA
}
// Reverse the list of PIDs so that they get popped in the order found.
- std::reverse(process_ids_.begin(), process_ids_.end());
+ ranges::reverse(process_ids_);
}
} // namespace debug
diff -up chromium-86.0.4240.111/base/debug/task_trace.cc.a61fb57e chromium-86.0.4240.111/base/debug/task_trace.cc
--- chromium-86.0.4240.111/base/debug/task_trace.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/debug/task_trace.cc 2020-10-21 17:11:20.004228750 -0400
@@ -4,13 +4,13 @@
#include "base/debug/task_trace.h"
+#include "base/ranges/algorithm.h"
#include "build/build_config.h"
#if defined(OS_ANDROID)
#include <android/log.h>
#endif // OS_ANDROID
-#include <algorithm>
#include <iostream>
#include <sstream>
@@ -55,8 +55,7 @@ TaskTrace::TaskTrace() {
return;
std::array<const void*, PendingTask::kTaskBacktraceLength + 1> task_trace;
task_trace[0] = current_task->posted_from.program_counter();
- std::copy(current_task->task_backtrace.begin(),
- current_task->task_backtrace.end(), task_trace.begin() + 1);
+ ranges::copy(current_task->task_backtrace, task_trace.begin() + 1);
size_t length = 0;
while (length < task_trace.size() && task_trace[length])
++length;
diff -up chromium-86.0.4240.111/base/feature_list_unittest.cc.a61fb57e chromium-86.0.4240.111/base/feature_list_unittest.cc
--- chromium-86.0.4240.111/base/feature_list_unittest.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/feature_list_unittest.cc 2020-10-21 17:11:20.005228759 -0400
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include <algorithm>
#include <utility>
#include <vector>
@@ -14,6 +13,7 @@
#include "base/memory/read_only_shared_memory_region.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/persistent_memory_allocator.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
@@ -39,7 +39,7 @@ struct Feature kFeatureOffByDefault {
std::string SortFeatureListString(const std::string& feature_list) {
std::vector<base::StringPiece> features =
FeatureList::SplitFeatureListString(feature_list);
- std::sort(features.begin(), features.end());
+ ranges::sort(features);
return JoinString(features, ",");
}
diff -up chromium-86.0.4240.111/base/hash/sha1_perftest.cc.a61fb57e chromium-86.0.4240.111/base/hash/sha1_perftest.cc
--- chromium-86.0.4240.111/base/hash/sha1_perftest.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/hash/sha1_perftest.cc 2020-10-21 17:11:20.005228759 -0400
@@ -6,11 +6,11 @@
#include <stddef.h>
#include <stdint.h>
-#include <algorithm>
#include <string>
#include <vector>
#include "base/rand_util.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
@@ -48,7 +48,7 @@ void Timing(const size_t len) {
utime[i] = TimeTicks::Now() - start;
total_test_time += utime[i];
}
- std::sort(utime.begin(), utime.end());
+ ranges::sort(utime);
}
reporter.AddResult(kMetricRuntime, total_test_time.InMicrosecondsF());
@@ -67,8 +67,8 @@ void Timing(const size_t len) {
// Convert to a comma-separated string so we can report every data point.
std::vector<std::string> rate_strings(utime.size());
- std::transform(utime.cbegin(), utime.cend(), rate_strings.begin(),
- [rate](const auto& t) { return NumberToString(rate(t)); });
+ ranges::transform(utime, rate_strings.begin(),
+ [rate](const auto& t) { return NumberToString(rate(t)); });
reporter.AddResultList(kMetricThroughput, JoinString(rate_strings, ","));
}
diff -up chromium-86.0.4240.111/base/i18n/break_iterator_unittest.cc.a61fb57e chromium-86.0.4240.111/base/i18n/break_iterator_unittest.cc
--- chromium-86.0.4240.111/base/i18n/break_iterator_unittest.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/i18n/break_iterator_unittest.cc 2020-10-21 17:11:20.006228768 -0400
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <vector>
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
@@ -414,8 +415,7 @@ TEST(BreakIteratorTest, IsSentenceBounda
sentence_breaks.push_back(24);
sentence_breaks.push_back(42);
for (size_t i = 0; i < str.size(); i++) {
- if (std::find(sentence_breaks.begin(), sentence_breaks.end(), i) !=
- sentence_breaks.end()) {
+ if (ranges::find(sentence_breaks, i) != sentence_breaks.end()) {
EXPECT_TRUE(iter.IsSentenceBoundary(i)) << " at index=" << i;
} else {
EXPECT_FALSE(iter.IsSentenceBoundary(i)) << " at index=" << i;
diff -up chromium-86.0.4240.111/base/json/json_parser.cc.a61fb57e chromium-86.0.4240.111/base/json/json_parser.cc
--- chromium-86.0.4240.111/base/json/json_parser.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/json/json_parser.cc 2020-10-21 17:11:20.006228768 -0400
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
@@ -441,7 +442,7 @@ Optional<Value> JSONParser::ConsumeDicti
ConsumeChar(); // Closing '}'.
// Reverse |dict_storage| to keep the last of elements with the same key in
// the input.
- std::reverse(dict_storage.begin(), dict_storage.end());
+ ranges::reverse(dict_storage);
return Value(Value::DictStorage(std::move(dict_storage)));
}
diff -up chromium-86.0.4240.111/base/memory/platform_shared_memory_region_unittest.cc.a61fb57e chromium-86.0.4240.111/base/memory/platform_shared_memory_region_unittest.cc
--- chromium-86.0.4240.111/base/memory/platform_shared_memory_region_unittest.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/memory/platform_shared_memory_region_unittest.cc 2020-10-21 17:11:20.006228768 -0400
@@ -7,6 +7,7 @@
#include "base/check.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/process/process_metrics.h"
+#include "base/ranges/algorithm.h"
#include "base/system/sys_info.h"
#include "base/test/gtest_util.h"
#include "base/test/test_shared_memory_util.h"
@@ -250,11 +251,10 @@ void CheckReadOnlyMapProtection(void* ad
ASSERT_TRUE(base::debug::ReadProcMaps(&proc_maps));
std::vector<base::debug::MappedMemoryRegion> regions;
ASSERT_TRUE(base::debug::ParseProcMaps(proc_maps, &regions));
- auto it =
- std::find_if(regions.begin(), regions.end(),
- [addr](const base::debug::MappedMemoryRegion& region) {
- return region.start == reinterpret_cast<uintptr_t>(addr);
- });
+ auto it = ranges::find_if(
+ regions, [addr](const base::debug::MappedMemoryRegion& region) {
+ return region.start == reinterpret_cast<uintptr_t>(addr);
+ });
ASSERT_TRUE(it != regions.end());
// PROT_READ may imply PROT_EXEC on some architectures, so just check that
// permissions don't contain PROT_WRITE bit.
diff -up chromium-86.0.4240.111/base/memory/shared_memory_mapping_unittest.cc.a61fb57e chromium-86.0.4240.111/base/memory/shared_memory_mapping_unittest.cc
--- chromium-86.0.4240.111/base/memory/shared_memory_mapping_unittest.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/memory/shared_memory_mapping_unittest.cc 2020-10-21 17:11:20.007228776 -0400
@@ -6,12 +6,12 @@
#include <stdint.h>
-#include <algorithm>
#include <limits>
#include "base/containers/span.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/writable_shared_memory_region.h"
+#include "base/ranges/algorithm.h"
#include "base/test/metrics/histogram_tester.h"
#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -67,7 +67,7 @@ TEST_F(SharedMemoryMappingTest, SpanWith
span<const uint32_t> read_span = read_mapping_.GetMemoryAsSpan<uint32_t>();
ASSERT_EQ(2u, read_span.size());
- std::fill(write_span.begin(), write_span.end(), 0);
+ ranges::fill(write_span, 0);
EXPECT_EQ(0u, read_span[0]);
EXPECT_EQ(0u, read_span[1]);
@@ -92,7 +92,7 @@ TEST_F(SharedMemoryMappingTest, SpanWith
span<const uint32_t> read_span_2 = read_mapping_.GetMemoryAsSpan<uint32_t>(1);
ASSERT_EQ(1u, read_span_2.size());
- std::fill(write_span.begin(), write_span.end(), 0);
+ ranges::fill(write_span, 0);
EXPECT_EQ(0u, read_span[0]);
EXPECT_EQ(0u, read_span[1]);
EXPECT_EQ(0u, read_span_2[0]);
@@ -103,7 +103,7 @@ TEST_F(SharedMemoryMappingTest, SpanWith
EXPECT_EQ(0x08070605u, read_span[1]);
EXPECT_EQ(0x04030201u, read_span_2[0]);
- std::fill(write_span_2.begin(), write_span_2.end(), 0);
+ ranges::fill(write_span_2, 0);
EXPECT_EQ(0u, read_span[0]);
EXPECT_EQ(0x08070605u, read_span[1]);
EXPECT_EQ(0u, read_span_2[0]);
diff -up chromium-86.0.4240.111/base/metrics/histogram.cc.a61fb57e chromium-86.0.4240.111/base/metrics/histogram.cc
--- chromium-86.0.4240.111/base/metrics/histogram.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/metrics/histogram.cc 2020-10-21 17:11:20.008228785 -0400
@@ -13,7 +13,6 @@
#include <limits.h>
#include <math.h>
-#include <algorithm>
#include <string>
#include <utility>
@@ -29,6 +28,7 @@
#include "base/metrics/sample_vector.h"
#include "base/metrics/statistics_recorder.h"
#include "base/pickle.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -1248,8 +1248,8 @@ class CustomHistogram::Factory : public
std::vector<int> ranges = *custom_ranges_;
ranges.push_back(0); // Ensure we have a zero value.
ranges.push_back(HistogramBase::kSampleType_MAX);
- std::sort(ranges.begin(), ranges.end());
- ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
+ ranges::sort(ranges);
+ ranges.erase(ranges::unique(ranges), ranges.end());
BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
for (uint32_t i = 0; i < ranges.size(); i++) {
diff -up chromium-86.0.4240.111/base/metrics/statistics_recorder.cc.a61fb57e chromium-86.0.4240.111/base/metrics/statistics_recorder.cc
--- chromium-86.0.4240.111/base/metrics/statistics_recorder.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/metrics/statistics_recorder.cc 2020-10-21 17:11:20.008228785 -0400
@@ -16,6 +16,7 @@
#include "base/metrics/metrics_hashes.h"
#include "base/metrics/persistent_histogram_allocator.h"
#include "base/metrics/record_histogram_checker.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
@@ -366,7 +367,7 @@ StatisticsRecorder::Histograms Statistic
// static
StatisticsRecorder::Histograms StatisticsRecorder::Sort(Histograms histograms) {
- std::sort(histograms.begin(), histograms.end(), &HistogramNameLesser);
+ ranges::sort(histograms, &HistogramNameLesser);
return histograms;
}
@@ -376,12 +377,12 @@ StatisticsRecorder::Histograms Statistic
const std::string& query) {
// Need a C-string query for comparisons against C-string histogram name.
const char* const query_string = query.c_str();
- histograms.erase(std::remove_if(histograms.begin(), histograms.end(),
- [query_string](const HistogramBase* const h) {
- return !strstr(h->histogram_name(),
- query_string);
- }),
- histograms.end());
+ histograms.erase(
+ ranges::remove_if(histograms,
+ [query_string](const HistogramBase* const h) {
+ return !strstr(h->histogram_name(), query_string);
+ }),
+ histograms.end());
return histograms;
}
@@ -389,10 +390,11 @@ StatisticsRecorder::Histograms Statistic
StatisticsRecorder::Histograms StatisticsRecorder::NonPersistent(
Histograms histograms) {
histograms.erase(
- std::remove_if(histograms.begin(), histograms.end(),
- [](const HistogramBase* const h) {
- return (h->flags() & HistogramBase::kIsPersistent) != 0;
- }),
+ ranges::remove_if(histograms,
+ [](const HistogramBase* const h) {
+ return (h->flags() & HistogramBase::kIsPersistent) !=
+ 0;
+ }),
histograms.end());
return histograms;
}
diff -up chromium-86.0.4240.111/base/observer_list.h.a61fb57e chromium-86.0.4240.111/base/observer_list.h
--- chromium-86.0.4240.111/base/observer_list.h.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/observer_list.h 2020-10-21 17:11:20.009228794 -0400
@@ -18,6 +18,7 @@
#include "base/macros.h"
#include "base/notreached.h"
#include "base/observer_list_internal.h"
+#include "base/ranges/algorithm.h"
#include "base/sequence_checker.h"
#include "base/stl_util.h"
@@ -279,9 +280,8 @@ class ObserverList {
// not in this list.
void RemoveObserver(const ObserverType* obs) {
DCHECK(obs);
- const auto it =
- std::find_if(observers_.begin(), observers_.end(),
- [obs](const auto& o) { return o.IsEqual(obs); });
+ const auto it = ranges::find_if(
+ observers_, [obs](const auto& o) { return o.IsEqual(obs); });
if (it == observers_.end())
return;
@@ -300,9 +300,9 @@ class ObserverList {
// probably DCHECK, but some client code currently does pass null.
if (obs == nullptr)
return false;
- return std::find_if(observers_.begin(), observers_.end(),
- [obs](const auto& o) { return o.IsEqual(obs); }) !=
- observers_.end();
+ return ranges::find_if(observers_, [obs](const auto& o) {
+ return o.IsEqual(obs);
+ }) != observers_.end();
}
// Removes all the observers from this list.
diff -up chromium-86.0.4240.111/base/process/process_metrics_unittest.cc.a61fb57e chromium-86.0.4240.111/base/process/process_metrics_unittest.cc
--- chromium-86.0.4240.111/base/process/process_metrics_unittest.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/process/process_metrics_unittest.cc 2020-10-21 17:11:20.009228794 -0400
@@ -19,6 +19,7 @@
#include "base/macros.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/memory/writable_shared_memory_region.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -781,13 +782,13 @@ TEST(ProcessMetricsTestLinux, GetCumulat
// Should have at least the test runner thread and the thread spawned above.
EXPECT_GE(prev_thread_times.size(), 2u);
- EXPECT_TRUE(std::any_of(
- prev_thread_times.begin(), prev_thread_times.end(),
+ EXPECT_TRUE(ranges::any_of(
+ prev_thread_times,
[&thread1](const std::pair<PlatformThreadId, base::TimeDelta>& entry) {
return entry.first == thread1.GetThreadId();
}));
- EXPECT_TRUE(std::any_of(
- prev_thread_times.begin(), prev_thread_times.end(),
+ EXPECT_TRUE(ranges::any_of(
+ prev_thread_times,
[](const std::pair<PlatformThreadId, base::TimeDelta>& entry) {
return entry.first == base::PlatformThread::CurrentId();
}));
@@ -803,16 +804,16 @@ TEST(ProcessMetricsTestLinux, GetCumulat
// The stopped thread may still be reported until the kernel cleans it up.
EXPECT_GE(prev_thread_times.size(), 1u);
- EXPECT_TRUE(std::any_of(
- current_thread_times.begin(), current_thread_times.end(),
+ EXPECT_TRUE(ranges::any_of(
+ current_thread_times,
[](const std::pair<PlatformThreadId, base::TimeDelta>& entry) {
return entry.first == base::PlatformThread::CurrentId();
}));
// Reported times should not decrease.
for (const auto& entry : current_thread_times) {
- auto prev_it = std::find_if(
- prev_thread_times.begin(), prev_thread_times.end(),
+ auto prev_it = ranges::find_if(
+ prev_thread_times,
[&entry](
const std::pair<PlatformThreadId, base::TimeDelta>& prev_entry) {
return entry.first == prev_entry.first;
@@ -862,8 +863,8 @@ TEST(ProcessMetricsTestLinux, GetPerThre
// Reported times should not decrease.
for (const auto& entry : current_thread_times) {
- auto prev_it = std::find_if(
- prev_thread_times.begin(), prev_thread_times.end(),
+ auto prev_it = ranges::find_if(
+ prev_thread_times,
[&entry](const ProcessMetrics::ThreadTimeInState& prev_entry) {
return entry.thread_id == prev_entry.thread_id &&
entry.core_type == prev_entry.core_type &&
diff -up chromium-86.0.4240.111/base/profiler/arm_cfi_table.cc.a61fb57e chromium-86.0.4240.111/base/profiler/arm_cfi_table.cc
--- chromium-86.0.4240.111/base/profiler/arm_cfi_table.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/profiler/arm_cfi_table.cc 2020-10-21 17:11:20.009228794 -0400
@@ -4,7 +4,7 @@
#include "base/profiler/arm_cfi_table.h"
-#include <algorithm>
+#include "base/ranges/algorithm.h"
namespace base {
@@ -91,8 +91,7 @@ Optional<ArmCFITable::FrameEntry> ArmCFI
// Find the required function address in UNW_INDEX as the last function lower
// or equal to |address| (the value right before the result of upper_bound(),
// if any).
- auto func_it = std::upper_bound(function_addresses_.begin(),
- function_addresses_.end(), address);
+ auto func_it = ranges::upper_bound(function_addresses_, address);
// If no function comes before |address|, no CFI entry is returned.
if (func_it == function_addresses_.begin())
return nullopt;
@@ -157,4 +156,4 @@ Optional<ArmCFITable::FrameEntry> ArmCFI
return last_frame_entry;
}
-} // namespace base
\ No newline at end of file
+} // namespace base
diff -up chromium-86.0.4240.111/base/profiler/metadata_recorder_unittest.cc.a61fb57e chromium-86.0.4240.111/base/profiler/metadata_recorder_unittest.cc
--- chromium-86.0.4240.111/base/profiler/metadata_recorder_unittest.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/profiler/metadata_recorder_unittest.cc 2020-10-21 17:11:20.010228802 -0400
@@ -4,6 +4,7 @@
#include "base/profiler/metadata_recorder.h"
+#include "base/ranges/algorithm.h"
#include "base/test/gtest_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -213,7 +214,7 @@ TEST(MetadataRecorderTest, ReclaimInacti
}
MetadataRecorder::ItemArray items_arr;
- std::copy(items_set.begin(), items_set.end(), items_arr.begin());
+ ranges::copy(items_set, items_arr.begin());
MetadataRecorder::ItemArray recorder_items;
size_t recorder_item_count =
diff -up chromium-86.0.4240.111/base/profiler/module_cache.cc.a61fb57e chromium-86.0.4240.111/base/profiler/module_cache.cc
--- chromium-86.0.4240.111/base/profiler/module_cache.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/profiler/module_cache.cc 2020-10-21 17:11:20.010228802 -0400
@@ -4,10 +4,11 @@
#include "base/profiler/module_cache.h"
-#include <algorithm>
#include <iterator>
#include <utility>
+#include "base/ranges/algorithm.h"
+
namespace base {
namespace {
diff -up chromium-86.0.4240.111/base/profiler/stack_sampler_impl.cc.a61fb57e chromium-86.0.4240.111/base/profiler/stack_sampler_impl.cc
--- chromium-86.0.4240.111/base/profiler/stack_sampler_impl.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/profiler/stack_sampler_impl.cc 2020-10-21 17:11:20.010228802 -0400
@@ -16,6 +16,7 @@
#include "base/profiler/stack_copier.h"
#include "base/profiler/suspendable_thread_delegate.h"
#include "base/profiler/unwinder.h"
+#include "base/ranges/algorithm.h"
#include "build/build_config.h"
// IMPORTANT NOTE: Some functions within this implementation are invoked while
@@ -161,11 +162,10 @@ std::vector<Frame> StackSamplerImpl::Wal
do {
// Choose an authoritative unwinder for the current module. Use the first
// unwinder that thinks it can unwind from the current frame.
- auto unwinder =
- std::find_if(unwinders.begin(), unwinders.end(),
- [&stack](const std::unique_ptr<Unwinder>& unwinder) {
- return unwinder->CanUnwindFrom(stack.back());
- });
+ auto unwinder = ranges::find_if(
+ unwinders, [&stack](const std::unique_ptr<Unwinder>& unwinder) {
+ return unwinder->CanUnwindFrom(stack.back());
+ });
if (unwinder == unwinders.end())
return stack;
diff -up chromium-86.0.4240.111/base/profiler/stack_sampling_profiler_unittest.cc.a61fb57e chromium-86.0.4240.111/base/profiler/stack_sampling_profiler_unittest.cc
--- chromium-86.0.4240.111/base/profiler/stack_sampling_profiler_unittest.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/profiler/stack_sampling_profiler_unittest.cc 2020-10-21 17:11:20.011228811 -0400
@@ -5,7 +5,6 @@
#include <stddef.h>
#include <stdint.h>
-#include <algorithm>
#include <cstdlib>
#include <memory>
#include <set>
@@ -25,6 +24,7 @@
#include "base/profiler/stack_sampling_profiler.h"
#include "base/profiler/stack_sampling_profiler_test_util.h"
#include "base/profiler/unwinder.h"
+#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/scoped_native_library.h"
#include "base/stl_util.h"
@@ -269,10 +269,10 @@ size_t WaitForSamplingComplete(
const std::vector<std::unique_ptr<TestProfilerInfo>>& infos) {
// Map unique_ptrs to something that WaitMany can accept.
std::vector<WaitableEvent*> sampling_completed_rawptrs(infos.size());
- std::transform(infos.begin(), infos.end(), sampling_completed_rawptrs.begin(),
- [](const std::unique_ptr<TestProfilerInfo>& info) {
- return &info.get()->completed;
- });
+ ranges::transform(infos, sampling_completed_rawptrs.begin(),
+ [](const std::unique_ptr<TestProfilerInfo>& info) {
+ return &info.get()->completed;
+ });
// Wait for one profiler to finish.
return WaitableEvent::WaitMany(sampling_completed_rawptrs.data(),
sampling_completed_rawptrs.size());
diff -up chromium-86.0.4240.111/base/ranges/algorithm.h.a61fb57e chromium-86.0.4240.111/base/ranges/algorithm.h
--- chromium-86.0.4240.111/base/ranges/algorithm.h.a61fb57e 2020-10-21 17:44:59.179014291 -0400
+++ chromium-86.0.4240.111/base/ranges/algorithm.h 2020-10-21 17:43:40.094374195 -0400
@@ -0,0 +1,4965 @@
+// 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 "base/ranges/functional.h"
+#include "base/ranges/ranges.h"
+#include "base/stl_util.h"
+#include "base/template_util.h"
+
+namespace 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 base::invoke(pred,
+ 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 base::invoke(pred_, base::invoke(projs.first, std::forward<T>(lhs)),
+ 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. Note the because C++14
+// lacks the `no_unique_address` attribute it is commented out.
+//
+// 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 (!base::invoke(pred, 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 (base::invoke(pred, 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 (base::invoke(pred, 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)
+ base::invoke(f, 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) {
+ base::invoke(f, 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 = {}) {
+ // Note: In order to be able to apply `proj` to each element in [first, last)
+ // we are dispatching to std::find_if instead of std::find.
+ return std::find_if(first, last, [&proj, &value](auto&& lhs) {
+ return base::invoke(proj, std::forward<decltype(lhs)>(lhs)) == value;
+ });
+}
+
+// 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 = {}) {
+ return std::adjacent_find(
+ first, last, internal::ProjectedBinaryPredicate(pred, proj, proj));
+}
+
+// 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 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 = {}) {
+ 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 base::invoke(op,
+ 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 base::invoke(
+ binary_op, base::invoke(proj1, std::forward<decltype(lhs)>(lhs)),
+ 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 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 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 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 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: 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 std::is_sorted(first, last,
+ internal::ProjectedBinaryPredicate(comp, proj, proj));
+}
+
+// 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));
+}
+
+// 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 = {}) {
+ return std::is_sorted_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 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));
+}
+
+// [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 &&
+ !base::invoke(comp, value, 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 = {}) {
+ // 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 log(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 log(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 base::invoke(comp, base::invoke(proj, b), 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 base::invoke(comp, base::invoke(proj, a), 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 = base::invoke(proj, v);
+ if (base::invoke(comp, projected_v, base::invoke(proj, lo)))
+ return lo;
+
+ return base::invoke(comp, 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 = base::invoke(proj1, *first1);
+ auto&& projected_first2 = base::invoke(proj2, *first2);
+ if (base::invoke(comp, projected_first1, projected_first2))
+ return true;
+ if (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_
diff -up chromium-86.0.4240.111/base/ranges/functional.h.a61fb57e chromium-86.0.4240.111/base/ranges/functional.h
--- chromium-86.0.4240.111/base/ranges/functional.h.a61fb57e 2020-10-21 17:45:04.573057952 -0400
+++ chromium-86.0.4240.111/base/ranges/functional.h 2020-10-21 17:44:05.320578383 -0400
@@ -0,0 +1,32 @@
+// 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_FUNCTIONAL_H_
+#define BASE_RANGES_FUNCTIONAL_H_
+
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+namespace base {
+
+namespace ranges {
+
+// Simplified implementations of C++20's std::ranges comparison function
+// objects. As opposed to the std::ranges implementation, these versions do not
+// constrain the passed-in types.
+//
+// Reference: https://wg21.link/range.cmp
+using equal_to = std::equal_to<>;
+using not_equal_to = std::not_equal_to<>;
+using greater = std::greater<>;
+using less = std::less<>;
+using greater_equal = std::greater_equal<>;
+using less_equal = std::less_equal<>;
+
+} // namespace ranges
+
+} // namespace base
+
+#endif // BASE_RANGES_FUNCTIONAL_H_
diff -up chromium-86.0.4240.111/base/ranges/ranges.h.a61fb57e chromium-86.0.4240.111/base/ranges/ranges.h
--- chromium-86.0.4240.111/base/ranges/ranges.h.a61fb57e 2020-10-21 17:45:13.828132866 -0400
+++ chromium-86.0.4240.111/base/ranges/ranges.h 2020-10-21 17:44:37.950842465 -0400
@@ -0,0 +1,140 @@
+// 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_RANGES_H_
+#define BASE_RANGES_RANGES_H_
+
+#include <array>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+
+#include "base/template_util.h"
+
+namespace base {
+
+namespace internal {
+
+// Overload for C array.
+template <typename T, size_t N>
+constexpr T* begin(T (&array)[N], priority_tag<2>) {
+ return array;
+}
+
+// Overload for mutable std::array. Required since std::array::begin is not
+// constexpr prior to C++17. Needs to dispatch to the const overload since only
+// const operator[] is constexpr in C++14.
+template <typename T, size_t N>
+constexpr T* begin(std::array<T, N>& array, priority_tag<2> tag) {
+ return const_cast<T*>(begin(const_cast<const std::array<T, N>&>(array), tag));
+}
+
+// Overload for const std::array. Required since std::array::begin is not
+// constexpr prior to C++17.
+template <typename T, size_t N>
+constexpr const T* begin(const std::array<T, N>& array, priority_tag<2>) {
+ return N != 0 ? &array[0] : nullptr;
+}
+
+// Generic container overload.
+template <typename Range>
+constexpr auto begin(Range&& range, priority_tag<1>)
+ -> decltype(std::forward<Range>(range).begin()) {
+ return std::forward<Range>(range).begin();
+}
+
+// Overload for free begin() function.
+template <typename Range>
+constexpr auto begin(Range&& range, priority_tag<0>)
+ -> decltype(begin(std::forward<Range>(range))) {
+ return begin(std::forward<Range>(range));
+}
+
+// Overload for C array.
+template <typename T, size_t N>
+constexpr T* end(T (&array)[N], priority_tag<2>) {
+ return array + N;
+}
+
+// Overload for mutable std::array. Required since std::array::end is not
+// constexpr prior to C++17. Needs to dispatch to the const overload since only
+// const operator[] is constexpr in C++14.
+template <typename T, size_t N>
+constexpr T* end(std::array<T, N>& array, priority_tag<2> tag) {
+ return const_cast<T*>(end(const_cast<const std::array<T, N>&>(array), tag));
+}
+
+// Overload for const std::array. Required since std::array::end is not
+// constexpr prior to C++17.
+template <typename T, size_t N>
+constexpr const T* end(const std::array<T, N>& array, priority_tag<2>) {
+ return N != 0 ? (&array[0]) + N : nullptr;
+}
+
+// Generic container overload.
+template <typename Range>
+constexpr auto end(Range&& range, priority_tag<1>)
+ -> decltype(std::forward<Range>(range).end()) {
+ return std::forward<Range>(range).end();
+}
+
+// Overload for free end() function.
+template <typename Range>
+constexpr auto end(Range&& range, priority_tag<0>)
+ -> decltype(end(std::forward<Range>(range))) {
+ return end(std::forward<Range>(range));
+}
+
+} // namespace internal
+
+namespace ranges {
+
+// Simplified implementation of C++20's std::ranges::begin.
+// As opposed to std::ranges::begin, this implementation does does not check
+// whether begin() returns an iterator and does not inhibit ADL.
+//
+// The trailing return type and dispatch to the internal implementation is
+// necessary to be SFINAE friendly.
+//
+// Reference: https://wg21.link/range.access.begin
+template <typename Range>
+constexpr auto begin(Range&& range) noexcept
+ -> decltype(internal::begin(std::forward<Range>(range),
+ internal::priority_tag<2>())) {
+ return internal::begin(std::forward<Range>(range),
+ internal::priority_tag<2>());
+}
+
+// Simplified implementation of C++20's std::ranges::end.
+// As opposed to std::ranges::end, this implementation does does not check
+// whether end() returns an iterator and does not inhibit ADL.
+//
+// The trailing return type and dispatch to the internal implementation is
+// necessary to be SFINAE friendly.
+//
+// Reference: - https://wg21.link/range.access.end
+template <typename Range>
+constexpr auto end(Range&& range) noexcept
+ -> decltype(internal::end(std::forward<Range>(range),
+ internal::priority_tag<2>())) {
+ return internal::end(std::forward<Range>(range), internal::priority_tag<2>());
+}
+
+// Implementation of C++20's std::ranges::iterator_t.
+//
+// Reference: https://wg21.link/ranges.syn#:~:text=iterator_t
+template <typename Range>
+using iterator_t = decltype(ranges::begin(std::declval<Range&>()));
+
+// Implementation of C++20's std::ranges::range_value_t.
+//
+// Reference: https://wg21.link/ranges.syn#:~:text=range_value_t
+template <typename Range>
+using range_value_t = iter_value_t<iterator_t<Range>>;
+
+} // namespace ranges
+
+} // namespace base
+
+#endif // BASE_RANGES_RANGES_H_
diff -up chromium-86.0.4240.111/base/sampling_heap_profiler/poisson_allocation_sampler.cc.a61fb57e chromium-86.0.4240.111/base/sampling_heap_profiler/poisson_allocation_sampler.cc
--- chromium-86.0.4240.111/base/sampling_heap_profiler/poisson_allocation_sampler.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/sampling_heap_profiler/poisson_allocation_sampler.cc 2020-10-21 17:11:20.011228811 -0400
@@ -4,7 +4,6 @@
#include "base/sampling_heap_profiler/poisson_allocation_sampler.h"
-#include <algorithm>
#include <atomic>
#include <cmath>
#include <memory>
@@ -17,6 +16,7 @@
#include "base/no_destructor.h"
#include "base/partition_alloc_buildflags.h"
#include "base/rand_util.h"
+#include "base/ranges/algorithm.h"
#include "build/build_config.h"
#if defined(OS_APPLE) || defined(OS_ANDROID)
@@ -557,8 +557,7 @@ void PoissonAllocationSampler::SuppressR
void PoissonAllocationSampler::AddSamplesObserver(SamplesObserver* observer) {
ScopedMuteThreadSamples no_reentrancy_scope;
AutoLock lock(mutex_);
- DCHECK(std::find(observers_.begin(), observers_.end(), observer) ==
- observers_.end());
+ DCHECK(ranges::find(observers_, observer) == observers_.end());
observers_.push_back(observer);
InstallAllocatorHooksOnce();
g_running = !observers_.empty();
@@ -568,7 +567,7 @@ void PoissonAllocationSampler::RemoveSam
SamplesObserver* observer) {
ScopedMuteThreadSamples no_reentrancy_scope;
AutoLock lock(mutex_);
- auto it = std::find(observers_.begin(), observers_.end(), observer);
+ auto it = ranges::find(observers_, observer);
DCHECK(it != observers_.end());
observers_.erase(it);
g_running = !observers_.empty();
diff -up chromium-86.0.4240.111/base/scoped_observer.h.a61fb57e chromium-86.0.4240.111/base/scoped_observer.h
--- chromium-86.0.4240.111/base/scoped_observer.h.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/scoped_observer.h 2020-10-21 17:11:20.011228811 -0400
@@ -7,11 +7,11 @@
#include <stddef.h>
-#include <algorithm>
#include <vector>
#include "base/check.h"
#include "base/macros.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
// ScopedObserver is used to keep track of the set of sources an object has
@@ -56,7 +56,7 @@ class ScopedObserver {
// Remove the object passed to the constructor as an observer from |source|.
void Remove(Source* source) {
- auto it = std::find(sources_.begin(), sources_.end(), source);
+ auto it = base::ranges::find(sources_, source);
DCHECK(it != sources_.end());
sources_.erase(it);
(source->*RemoveObsFn)(observer_);
diff -up chromium-86.0.4240.111/base/strings/abseil_string_conversions.cc.a61fb57e chromium-86.0.4240.111/base/strings/abseil_string_conversions.cc
--- chromium-86.0.4240.111/base/strings/abseil_string_conversions.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/strings/abseil_string_conversions.cc 2020-10-21 17:11:20.012228820 -0400
@@ -4,10 +4,10 @@
#include "base/strings/abseil_string_conversions.h"
-#include <algorithm>
#include <vector>
#include "base/containers/span.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string_piece.h"
#include "third_party/abseil-cpp/absl/strings/string_view.h"
@@ -16,16 +16,14 @@ namespace base {
std::vector<absl::string_view> StringPiecesToStringViews(
span<const StringPiece> pieces) {
std::vector<absl::string_view> views(pieces.size());
- std::transform(pieces.begin(), pieces.end(), views.begin(),
- &StringPieceToStringView);
+ ranges::transform(pieces, views.begin(), &StringPieceToStringView);
return views;
}
std::vector<StringPiece> StringViewsToStringPieces(
span<const absl::string_view> views) {
std::vector<StringPiece> pieces(views.size());
- std::transform(views.begin(), views.end(), pieces.begin(),
- &StringViewToStringPiece);
+ ranges::transform(views, pieces.begin(), &StringViewToStringPiece);
return pieces;
}
diff -up chromium-86.0.4240.111/base/strings/string_util_internal.h.a61fb57e chromium-86.0.4240.111/base/strings/string_util_internal.h
--- chromium-86.0.4240.111/base/strings/string_util_internal.h.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/strings/string_util_internal.h 2020-10-21 17:11:20.012228820 -0400
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "base/notreached.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string_piece.h"
#include "base/third_party/icu/icu_utf.h"
@@ -578,8 +579,7 @@ StringType DoReplaceStringPlaceholders(
ReplacementOffset r_offset(index,
static_cast<int>(formatted.size()));
r_offsets.insert(
- std::upper_bound(r_offsets.begin(), r_offsets.end(), r_offset,
- &CompareParameter),
+ ranges::upper_bound(r_offsets, r_offset, &CompareParameter),
r_offset);
}
if (index < substitutions)
diff -up chromium-86.0.4240.111/base/synchronization/waitable_event_posix.cc.a61fb57e chromium-86.0.4240.111/base/synchronization/waitable_event_posix.cc
--- chromium-86.0.4240.111/base/synchronization/waitable_event_posix.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/synchronization/waitable_event_posix.cc 2020-10-21 17:11:20.012228820 -0400
@@ -4,13 +4,13 @@
#include <stddef.h>
-#include <algorithm>
#include <limits>
#include <vector>
#include "base/check_op.h"
#include "base/debug/activity_tracker.h"
#include "base/optional.h"
+#include "base/ranges/algorithm.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
@@ -265,7 +265,7 @@ size_t WaitableEvent::WaitMany(WaitableE
DCHECK_EQ(count, waitables.size());
- sort(waitables.begin(), waitables.end(), cmp_fst_addr);
+ ranges::sort(waitables, cmp_fst_addr);
// The set of waitables must be distinct. Since we have just sorted by
// address, we can check this cheaply by comparing pairs of consecutive
diff -up chromium-86.0.4240.111/base/task/common/checked_lock_impl.cc.a61fb57e chromium-86.0.4240.111/base/task/common/checked_lock_impl.cc
--- chromium-86.0.4240.111/base/task/common/checked_lock_impl.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/task/common/checked_lock_impl.cc 2020-10-21 17:11:20.013228828 -0400
@@ -4,12 +4,12 @@
#include "base/task/common/checked_lock_impl.h"
-#include <algorithm>
#include <unordered_map>
#include <vector>
#include "base/check_op.h"
#include "base/lazy_instance.h"
+#include "base/ranges/algorithm.h"
#include "base/synchronization/condition_variable.h"
#include "base/task/common/checked_lock.h"
#include "base/threading/platform_thread.h"
@@ -44,8 +44,7 @@ class SafeAcquisitionTracker {
void RecordRelease(const CheckedLockImpl* const lock) {
LockVector* acquired_locks = GetAcquiredLocksOnCurrentThread();
- const auto iter_at_lock =
- std::find(acquired_locks->begin(), acquired_locks->end(), lock);
+ const auto iter_at_lock = ranges::find(*acquired_locks, lock);
DCHECK(iter_at_lock != acquired_locks->end());
acquired_locks->erase(iter_at_lock);
}
diff -up chromium-86.0.4240.111/base/task/common/operations_controller_unittest.cc.a61fb57e chromium-86.0.4240.111/base/task/common/operations_controller_unittest.cc
--- chromium-86.0.4240.111/base/task/common/operations_controller_unittest.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/task/common/operations_controller_unittest.cc 2020-10-21 17:11:20.013228828 -0400
@@ -8,6 +8,7 @@
#include <cstdint>
#include <utility>
+#include "base/ranges/algorithm.h"
#include "base/threading/platform_thread.h"
#include "base/threading/simple_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -124,8 +125,7 @@ class TestThread : public SimpleThread {
}
if (!was_started)
continue;
- if (std::any_of(tokens.begin(), tokens.end(),
- [](const auto& token) { return !token; })) {
+ if (ranges::any_of(tokens, [](const auto& token) { return !token; })) {
break;
}
}
diff -up chromium-86.0.4240.111/base/task/common/task_annotator.cc.a61fb57e chromium-86.0.4240.111/base/task/common/task_annotator.cc
--- chromium-86.0.4240.111/base/task/common/task_annotator.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/task/common/task_annotator.cc 2020-10-21 17:11:20.013228828 -0400
@@ -9,6 +9,7 @@
#include "base/debug/activity_tracker.h"
#include "base/debug/alias.h"
#include "base/no_destructor.h"
+#include "base/ranges/algorithm.h"
#include "base/threading/thread_local.h"
#include "base/trace_event/base_tracing.h"
@@ -127,8 +128,7 @@ void TaskAnnotator::RunTask(const char*
task_backtrace.back() = reinterpret_cast<void*>(0x0d00d1d1d178119);
task_backtrace[1] = pending_task->posted_from.program_counter();
- std::copy(pending_task->task_backtrace.begin(),
- pending_task->task_backtrace.end(), task_backtrace.begin() + 2);
+ ranges::copy(pending_task->task_backtrace, task_backtrace.begin() + 2);
task_backtrace[kStackTaskTraceSnapshotSize - 2] =
reinterpret_cast<void*>(pending_task->ipc_hash);
debug::Alias(&task_backtrace);
diff -up chromium-86.0.4240.111/base/task/sequence_manager/sequence_manager_impl.cc.a61fb57e chromium-86.0.4240.111/base/task/sequence_manager/sequence_manager_impl.cc
--- chromium-86.0.4240.111/base/task/sequence_manager/sequence_manager_impl.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/task/sequence_manager/sequence_manager_impl.cc 2020-10-21 17:11:20.014228837 -0400
@@ -18,6 +18,7 @@
#include "base/no_destructor.h"
#include "base/optional.h"
#include "base/rand_util.h"
+#include "base/ranges/algorithm.h"
#include "base/task/sequence_manager/real_time_domain.h"
#include "base/task/sequence_manager/task_time_observer.h"
#include "base/task/sequence_manager/thread_controller_impl.h"
@@ -539,8 +540,7 @@ void SequenceManagerImpl::LogTaskDebugIn
case Settings::TaskLogging::kEnabledWithBacktrace: {
std::array<const void*, PendingTask::kTaskBacktraceLength + 1> task_trace;
task_trace[0] = task->posted_from.program_counter();
- std::copy(task->task_backtrace.begin(), task->task_backtrace.end(),
- task_trace.begin() + 1);
+ ranges::copy(task->task_backtrace, task_trace.begin() + 1);
size_t length = 0;
while (length < task_trace.size() && task_trace[length])
++length;
diff -up chromium-86.0.4240.111/base/task/sequence_manager/task_queue_impl.cc.a61fb57e chromium-86.0.4240.111/base/task/sequence_manager/task_queue_impl.cc
--- chromium-86.0.4240.111/base/task/sequence_manager/task_queue_impl.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/task/sequence_manager/task_queue_impl.cc 2020-10-21 17:11:20.014228837 -0400
@@ -10,6 +10,7 @@
#include <utility>
#include "base/logging.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/stringprintf.h"
#include "base/task/common/scoped_defer_task_posting.h"
#include "base/task/sequence_manager/sequence_manager_impl.h"
@@ -1404,7 +1405,7 @@ void TaskQueueImpl::DelayedIncomingQueue
// If we deleted something, re-enforce the heap property.
if (task_deleted)
- std::make_heap(queue_.c.begin(), queue_.c.end(), queue_.comp);
+ ranges::make_heap(queue_.c, queue_.comp);
}
Value TaskQueueImpl::DelayedIncomingQueue::AsValue(TimeTicks now) const {
diff -up chromium-86.0.4240.111/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc.a61fb57e chromium-86.0.4240.111/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc
--- chromium-86.0.4240.111/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/task/thread_pool/pooled_single_thread_task_runner_manager.cc 2020-10-21 17:11:20.015228846 -0400
@@ -4,7 +4,6 @@
#include "base/task/thread_pool/pooled_single_thread_task_runner_manager.h"
-#include <algorithm>
#include <memory>
#include <string>
#include <utility>
@@ -12,6 +11,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/ptr_util.h"
+#include "base/ranges/algorithm.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
@@ -719,7 +719,7 @@ void PooledSingleThreadTaskRunnerManager
if (workers_.empty())
return;
- auto worker_iter = std::find(workers_.begin(), workers_.end(), worker);
+ auto worker_iter = ranges::find(workers_, worker);
DCHECK(worker_iter != workers_.end());
worker_to_destroy = std::move(*worker_iter);
workers_.erase(worker_iter);
diff -up chromium-86.0.4240.111/base/task/thread_pool/thread_group_impl.cc.a61fb57e chromium-86.0.4240.111/base/task/thread_pool/thread_group_impl.cc
--- chromium-86.0.4240.111/base/task/thread_pool/thread_group_impl.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/task/thread_pool/thread_group_impl.cc 2020-10-21 17:11:20.015228846 -0400
@@ -22,6 +22,7 @@
#include "base/metrics/histogram.h"
#include "base/numerics/clamped_math.h"
#include "base/optional.h"
+#include "base/ranges/algorithm.h"
#include "base/sequence_token.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -83,10 +84,10 @@ constexpr TimeDelta kBackgroundBlockedWo
// Only used in DCHECKs.
bool ContainsWorker(const std::vector<scoped_refptr<WorkerThread>>& workers,
const WorkerThread* worker) {
- auto it = std::find_if(workers.begin(), workers.end(),
- [worker](const scoped_refptr<WorkerThread>& i) {
- return i.get() == worker;
- });
+ auto it =
+ ranges::find_if(workers, [worker](const scoped_refptr<WorkerThread>& i) {
+ return i.get() == worker;
+ });
return it != workers.end();
}
@@ -734,8 +735,7 @@ void ThreadGroupImpl::WorkerThreadDelega
outer_->idle_workers_stack_.Remove(worker);
// Remove the worker from |workers_|.
- auto worker_iter =
- std::find(outer_->workers_.begin(), outer_->workers_.end(), worker);
+ auto worker_iter = ranges::find(outer_->workers_, worker);
DCHECK(worker_iter != outer_->workers_.end());
outer_->workers_.erase(worker_iter);
}
diff -up chromium-86.0.4240.111/base/task/thread_pool/worker_thread_stack.cc.a61fb57e chromium-86.0.4240.111/base/task/thread_pool/worker_thread_stack.cc
--- chromium-86.0.4240.111/base/task/thread_pool/worker_thread_stack.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/task/thread_pool/worker_thread_stack.cc 2020-10-21 17:11:20.016228854 -0400
@@ -4,9 +4,8 @@
#include "base/task/thread_pool/worker_thread_stack.h"
-#include <algorithm>
-
#include "base/check_op.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "base/task/thread_pool/worker_thread.h"
@@ -47,7 +46,7 @@ bool WorkerThreadStack::Contains(const W
void WorkerThreadStack::Remove(const WorkerThread* worker) {
DCHECK(!IsEmpty());
DCHECK_NE(worker, stack_.back());
- auto it = std::find(stack_.begin(), stack_.end(), worker);
+ auto it = ranges::find(stack_, worker);
DCHECK(it != stack_.end());
DCHECK_NE(TimeTicks(), (*it)->GetLastUsedTime());
stack_.erase(it);
diff -up chromium-86.0.4240.111/base/test/launcher/test_launcher.cc.a61fb57e chromium-86.0.4240.111/base/test/launcher/test_launcher.cc
--- chromium-86.0.4240.111/base/test/launcher/test_launcher.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/test/launcher/test_launcher.cc 2020-10-21 17:11:20.016228854 -0400
@@ -30,6 +30,7 @@
#include "base/numerics/safe_conversions.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
+#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/pattern.h"
@@ -670,7 +671,7 @@ void TestRunner::Run(const std::vector<s
CHECK_GT(runner_count_, 0u);
tests_to_run_ = test_names;
// Reverse test order to avoid coping the whole vector when removing tests.
- std::reverse(tests_to_run_.begin(), tests_to_run_.end());
+ ranges::reverse(tests_to_run_);
runners_done_ = 0;
task_runners_.clear();
for (size_t i = 0; i < runner_count_; i++) {
@@ -1554,7 +1555,7 @@ bool TestLauncher::ShuffleTests(CommandL
std::mt19937 randomizer;
randomizer.seed(shuffle_seed);
- std::shuffle(tests_.begin(), tests_.end(), randomizer);
+ ranges::shuffle(tests_, randomizer);
fprintf(stdout, "Randomizing with seed %u\n", shuffle_seed);
fflush(stdout);
diff -up chromium-86.0.4240.111/base/test/scoped_feature_list.cc.a61fb57e chromium-86.0.4240.111/base/test/scoped_feature_list.cc
--- chromium-86.0.4240.111/base/test/scoped_feature_list.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/test/scoped_feature_list.cc 2020-10-21 17:11:20.017228863 -0400
@@ -4,12 +4,12 @@
#include "base/test/scoped_feature_list.h"
-#include <algorithm>
#include <utility>
#include <vector>
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial_param_associator.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -71,10 +71,10 @@ struct Features {
// with GetFeatureName() and also could be without parameters.
bool ContainsFeature(const std::vector<StringPiece>& feature_vector,
StringPiece feature_name) {
- auto iter = std::find_if(feature_vector.begin(), feature_vector.end(),
- [&feature_name](const StringPiece& a) {
- return GetFeatureName(a) == feature_name;
- });
+ auto iter =
+ ranges::find_if(feature_vector, [&feature_name](const StringPiece& a) {
+ return GetFeatureName(a) == feature_name;
+ });
return iter != feature_vector.end();
}
diff -up chromium-86.0.4240.111/base/test/trace_event_analyzer.cc.a61fb57e chromium-86.0.4240.111/base/test/trace_event_analyzer.cc
--- chromium-86.0.4240.111/base/test/trace_event_analyzer.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/test/trace_event_analyzer.cc 2020-10-21 17:11:20.017228863 -0400
@@ -14,6 +14,7 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted_memory.h"
+#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/strings/pattern.h"
#include "base/trace_event/trace_buffer.h"
@@ -775,7 +776,7 @@ bool TraceAnalyzer::SetEvents(const std:
raw_events_.clear();
if (!ParseEventsFromJson(json_events, &raw_events_))
return false;
- std::stable_sort(raw_events_.begin(), raw_events_.end());
+ base::ranges::stable_sort(raw_events_);
ParseMetadata();
return true;
}
@@ -964,7 +965,7 @@ bool GetRateStats(const TraceEventVector
deltas.push_back(delta);
}
- std::sort(deltas.begin(), deltas.end());
+ base::ranges::sort(deltas);
if (options) {
if (options->trim_min + options->trim_max > events.size() - kMinEvents) {
@@ -980,8 +981,8 @@ bool GetRateStats(const TraceEventVector
for (size_t i = 0; i < num_deltas; ++i)
delta_sum += deltas[i];
- stats->min_us = *std::min_element(deltas.begin(), deltas.end());
- stats->max_us = *std::max_element(deltas.begin(), deltas.end());
+ stats->min_us = *base::ranges::min_element(deltas);
+ stats->max_us = *base::ranges::max_element(deltas);
stats->mean_us = delta_sum / static_cast<double>(num_deltas);
double sum_mean_offsets_squared = 0.0;
diff -up chromium-86.0.4240.111/base/threading/hang_watcher.cc.a61fb57e chromium-86.0.4240.111/base/threading/hang_watcher.cc
--- chromium-86.0.4240.111/base/threading/hang_watcher.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/threading/hang_watcher.cc 2020-10-21 17:11:20.018228872 -0400
@@ -4,7 +4,6 @@
#include "base/threading/hang_watcher.h"
-#include <algorithm>
#include <atomic>
#include <utility>
@@ -16,6 +15,7 @@
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/no_destructor.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
@@ -413,10 +413,10 @@ HangWatcher::WatchStateSnapShot::WatchSt
// Sort |hung_watch_state_copies_| by order of decreasing hang severity so the
// most severe hang is first in the list.
- std::sort(hung_watch_state_copies_.begin(), hung_watch_state_copies_.end(),
- [](const WatchStateCopy& lhs, const WatchStateCopy& rhs) {
- return lhs.deadline < rhs.deadline;
- });
+ ranges::sort(hung_watch_state_copies_,
+ [](const WatchStateCopy& lhs, const WatchStateCopy& rhs) {
+ return lhs.deadline < rhs.deadline;
+ });
}
HangWatcher::WatchStateSnapShot::WatchStateSnapShot(
@@ -476,8 +476,8 @@ void HangWatcher::Monitor() {
// atomically. This is fine. Detecting a hang is generally best effort and
// if a thread resumes from hang in the time it takes to move on to
// capturing then its ID will be absent from the crash keys.
- bool any_thread_hung = std::any_of(
- watch_states_.cbegin(), watch_states_.cend(),
+ bool any_thread_hung = ranges::any_of(
+ watch_states_,
[this, now](const std::unique_ptr<internal::HangWatchState>& state) {
uint64_t flags;
base::TimeTicks deadline;
@@ -595,12 +595,12 @@ void HangWatcher::UnregisterThread() {
internal::HangWatchState* current_hang_watch_state =
internal::HangWatchState::GetHangWatchStateForCurrentThread()->Get();
- auto it =
- std::find_if(watch_states_.cbegin(), watch_states_.cend(),
- [current_hang_watch_state](
- const std::unique_ptr<internal::HangWatchState>& state) {
- return state.get() == current_hang_watch_state;
- });
+ auto it = ranges::find_if(
+ watch_states_,
+ [current_hang_watch_state](
+ const std::unique_ptr<internal::HangWatchState>& state) {
+ return state.get() == current_hang_watch_state;
+ });
// Thread should be registered to get unregistered.
DCHECK(it != watch_states_.end());
diff -up chromium-86.0.4240.111/base/trace_event/trace_log.cc.a61fb57e chromium-86.0.4240.111/base/trace_event/trace_log.cc
--- chromium-86.0.4240.111/base/trace_event/trace_log.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/trace_event/trace_log.cc 2020-10-21 17:11:20.018228872 -0400
@@ -4,7 +4,6 @@
#include "base/trace_event/trace_log.h"
-#include <algorithm>
#include <cmath>
#include <limits>
#include <memory>
@@ -23,6 +22,7 @@
#include "base/no_destructor.h"
#include "base/process/process.h"
#include "base/process/process_metrics.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
@@ -777,8 +777,7 @@ void TraceLog::AddEnabledStateObserver(E
void TraceLog::RemoveEnabledStateObserver(EnabledStateObserver* listener) {
AutoLock lock(observers_lock_);
enabled_state_observers_.erase(
- std::remove(enabled_state_observers_.begin(),
- enabled_state_observers_.end(), listener),
+ ranges::remove(enabled_state_observers_, listener),
enabled_state_observers_.end());
}
diff -up chromium-86.0.4240.111/base/values.cc.a61fb57e chromium-86.0.4240.111/base/values.cc
--- chromium-86.0.4240.111/base/values.cc.a61fb57e 2020-10-20 20:14:18.000000000 -0400
+++ chromium-86.0.4240.111/base/values.cc 2020-10-21 17:11:20.019228880 -0400
@@ -6,7 +6,6 @@
#include <string.h>
-#include <algorithm>
#include <cmath>
#include <new>
#include <ostream>
@@ -18,6 +17,7 @@
#include "base/json/json_writer.h"
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -1581,7 +1581,7 @@ bool ListValue::Remove(size_t index, std
}
bool ListValue::Remove(const Value& value, size_t* index) {
- auto it = std::find(list().begin(), list().end(), value);
+ auto it = ranges::find(list(), value);
if (it == list().end())
return false;
@@ -1659,7 +1659,7 @@ bool ListValue::Insert(size_t index, std
}
ListValue::const_iterator ListValue::Find(const Value& value) const {
- return std::find(GetList().begin(), GetList().end(), value);
+ return ranges::find(GetList(), value);
}
void ListValue::Swap(ListValue* other) {
diff -up chromium-86.0.4240.111/content/public/browser/content_browser_client.cc.a61fb57e chromium-86.0.4240.111/content/public/browser/content_browser_client.cc
--- chromium-86.0.4240.111/content/public/browser/content_browser_client.cc.a61fb57e 2020-10-20 20:14:33.000000000 -0400
+++ chromium-86.0.4240.111/content/public/browser/content_browser_client.cc 2020-10-21 17:11:20.019228880 -0400
@@ -9,7 +9,7 @@
// declarations instead of including more headers. If that is infeasible, adjust
// the limit. For more info, see
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
-#pragma clang max_tokens_here 880000
+#pragma clang max_tokens_here 910000
#include <utility>
diff -up chromium-86.0.4240.111/third_party/blink/renderer/core/dom/document.cc.a61fb57e chromium-86.0.4240.111/third_party/blink/renderer/core/dom/document.cc
--- chromium-86.0.4240.111/third_party/blink/renderer/core/dom/document.cc.a61fb57e 2020-10-20 20:14:40.000000000 -0400
+++ chromium-86.0.4240.111/third_party/blink/renderer/core/dom/document.cc 2020-10-21 17:11:20.021228898 -0400
@@ -33,7 +33,7 @@
// instead of including more headers. If that is infeasible, adjust the limit.
// For more info, see
// https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
-#pragma clang max_tokens_here 900000
+#pragma clang max_tokens_here 960000
#include <memory>
#include <utility>