xref: /aosp_15_r20/external/cronet/base/ranges/README.md (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker# `base::ranges`
2*6777b538SAndroid Build Coastguard Worker
3*6777b538SAndroid Build Coastguard WorkerThis directory aims to implement a C++14 version of the new `std::ranges`
4*6777b538SAndroid Build Coastguard Workeralgorithms that were introduced in C++20. These implementations are added to the
5*6777b538SAndroid Build Coastguard Worker`::base::ranges` namespace, and callers can access them by including
6*6777b538SAndroid Build Coastguard Worker[`base/ranges/algorithm.h`](https://source.chromium.org/chromium/chromium/src/+/main:base/ranges/algorithm.h).
7*6777b538SAndroid Build Coastguard Worker
8*6777b538SAndroid Build Coastguard Worker## Similarities with C++20:
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker### Automatically deducing `begin()` and `end()`
11*6777b538SAndroid Build Coastguard WorkerAs probably one of the most important changes for readability and usability, all
12*6777b538SAndroid Build Coastguard Workeralgorithms in `base::ranges` have overloads for ranges of elements, which allow
13*6777b538SAndroid Build Coastguard Workercallers to no longer specify `begin()` and `end()` iterators themselves.
14*6777b538SAndroid Build Coastguard Worker
15*6777b538SAndroid Build Coastguard WorkerBefore:
16*6777b538SAndroid Build Coastguard Worker```c++
17*6777b538SAndroid Build Coastguard Workerbool HasEvens(const std::vector<int>& vec) {
18*6777b538SAndroid Build Coastguard Worker  return std::any_of(vec.begin(), vec.end(), [](int i) { return i % 2 == 0; });
19*6777b538SAndroid Build Coastguard Worker}
20*6777b538SAndroid Build Coastguard Worker```
21*6777b538SAndroid Build Coastguard Worker
22*6777b538SAndroid Build Coastguard WorkerAfter:
23*6777b538SAndroid Build Coastguard Worker```c++
24*6777b538SAndroid Build Coastguard Workerbool HasEvens(const std::vector<int>& vec) {
25*6777b538SAndroid Build Coastguard Worker  return base::ranges::any_of(vec, [](int i) { return i % 2 == 0; });
26*6777b538SAndroid Build Coastguard Worker}
27*6777b538SAndroid Build Coastguard Worker```
28*6777b538SAndroid Build Coastguard Worker
29*6777b538SAndroid Build Coastguard WorkerFurthermore, these overloads also support binding to temporaries, so that
30*6777b538SAndroid Build Coastguard Workerapplying algorithms to return values is easier:
31*6777b538SAndroid Build Coastguard Worker
32*6777b538SAndroid Build Coastguard Worker```c++
33*6777b538SAndroid Build Coastguard Workerstd::vector<int> GetNums();
34*6777b538SAndroid Build Coastguard Worker```
35*6777b538SAndroid Build Coastguard Worker
36*6777b538SAndroid Build Coastguard WorkerBefore:
37*6777b538SAndroid Build Coastguard Worker
38*6777b538SAndroid Build Coastguard Worker```c++
39*6777b538SAndroid Build Coastguard Workerbool HasEvens() {
40*6777b538SAndroid Build Coastguard Worker  std::vector<int> nums = GetNums();
41*6777b538SAndroid Build Coastguard Worker  return std::any_of(nums.begin(), nums.end(),
42*6777b538SAndroid Build Coastguard Worker                     [](int i) { return i % 2 == 0; });
43*6777b538SAndroid Build Coastguard Worker}
44*6777b538SAndroid Build Coastguard Worker```
45*6777b538SAndroid Build Coastguard Worker
46*6777b538SAndroid Build Coastguard WorkerAfter:
47*6777b538SAndroid Build Coastguard Worker```c++
48*6777b538SAndroid Build Coastguard Workerbool HasEvens() {
49*6777b538SAndroid Build Coastguard Worker  return base::ranges::any_of(GetNums(), [](int i) { return i % 2 == 0; });
50*6777b538SAndroid Build Coastguard Worker}
51*6777b538SAndroid Build Coastguard Worker```
52*6777b538SAndroid Build Coastguard Worker
53*6777b538SAndroid Build Coastguard Worker### Support for Projections
54*6777b538SAndroid Build Coastguard WorkerIn addition to supporting automatically deducing the `begin()` and `end()`
55*6777b538SAndroid Build Coastguard Workeriterator for ranges, the `base::ranges::` algorithms also support projections,
56*6777b538SAndroid Build Coastguard Workerthat can be applied to arguments prior to passing it to supplied transformations
57*6777b538SAndroid Build Coastguard Workeror predicates. This is especially useful when ordering a collection of classes
58*6777b538SAndroid Build Coastguard Workerby a specific data member of the class. Example:
59*6777b538SAndroid Build Coastguard Worker
60*6777b538SAndroid Build Coastguard WorkerBefore:
61*6777b538SAndroid Build Coastguard Worker```cpp
62*6777b538SAndroid Build Coastguard Workerstd::sort(suggestions->begin(), suggestions->end(),
63*6777b538SAndroid Build Coastguard Worker          [](const autofill::Suggestion& a, const autofill::Suggestion& b) {
64*6777b538SAndroid Build Coastguard Worker            return a.match < b.match;
65*6777b538SAndroid Build Coastguard Worker          });
66*6777b538SAndroid Build Coastguard Worker```
67*6777b538SAndroid Build Coastguard Worker
68*6777b538SAndroid Build Coastguard WorkerAfter:
69*6777b538SAndroid Build Coastguard Worker```cpp
70*6777b538SAndroid Build Coastguard Workerbase::ranges::sort(*suggestions, /*comp=*/{}, &autofill::Suggestion::match);
71*6777b538SAndroid Build Coastguard Worker```
72*6777b538SAndroid Build Coastguard Worker
73*6777b538SAndroid Build Coastguard WorkerAnything that is callable can be used as a projection. This includes
74*6777b538SAndroid Build Coastguard Worker`FunctionObjects` like function pointers or functors, but also pointers to
75*6777b538SAndroid Build Coastguard Workermember function and pointers to data members, as shown above. When not specified
76*6777b538SAndroid Build Coastguard Workera projection defaults to `base::ranges::identity`, which simply perfectly
77*6777b538SAndroid Build Coastguard Workerforwards its argument.
78*6777b538SAndroid Build Coastguard Worker
79*6777b538SAndroid Build Coastguard WorkerProjections are supported in both range and iterator-pair overloads of the
80*6777b538SAndroid Build Coastguard Worker`base::ranges::` algorithms, for example `base::ranges::all_of` has the
81*6777b538SAndroid Build Coastguard Workerfollowing signatures:
82*6777b538SAndroid Build Coastguard Worker
83*6777b538SAndroid Build Coastguard Worker```cpp
84*6777b538SAndroid Build Coastguard Workertemplate <typename InputIterator, typename Pred, typename Proj = identity>
85*6777b538SAndroid Build Coastguard Workerbool all_of(InputIterator first, InputIterator last, Pred pred, Proj proj = {});
86*6777b538SAndroid Build Coastguard Worker
87*6777b538SAndroid Build Coastguard Workertemplate <typename Range, typename Pred, typename Proj = identity>
88*6777b538SAndroid Build Coastguard Workerbool all_of(Range&& range, Pred pred, Proj proj = {});
89*6777b538SAndroid Build Coastguard Worker```
90*6777b538SAndroid Build Coastguard Worker
91*6777b538SAndroid Build Coastguard Worker## Differences from C++20:
92*6777b538SAndroid Build Coastguard WorkerTo simplify the implementation of the `base::ranges::` algorithms, they dispatch
93*6777b538SAndroid Build Coastguard Workerto the `std::` algorithms found in C++14. This leads to the following list of
94*6777b538SAndroid Build Coastguard Workerdifferences from C++20. Since most of these differences are differences in the
95*6777b538SAndroid Build Coastguard Workerlibrary and not in the language, they could be addressed in the future by adding
96*6777b538SAndroid Build Coastguard Workercorresponding implementations.
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Worker### Lack of Constraints
99*6777b538SAndroid Build Coastguard WorkerDue to the lack of support for concepts in the language, the algorithms in
100*6777b538SAndroid Build Coastguard Worker`base::ranges` do not have the constraints that are present on the algorithms in
101*6777b538SAndroid Build Coastguard Worker`std::ranges`. Instead, they support any type, much like C++14's `std::`
102*6777b538SAndroid Build Coastguard Workeralgorithms. In the future this might be addressed by adding corresponding
103*6777b538SAndroid Build Coastguard Workerconstraints via SFINAE, should the need arise.
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Worker### Lack of Range Primitives
106*6777b538SAndroid Build Coastguard WorkerDue to C++14's lack of `std::ranges` concepts like sentinels and other range
107*6777b538SAndroid Build Coastguard Workerprimitives, algorithms taking a `[first, last)` pair rather than a complete
108*6777b538SAndroid Build Coastguard Workerrange, do not support different types for `first` and `last`. Since they rely on
109*6777b538SAndroid Build Coastguard WorkerC++14's implementation, the type must be the same. This could be addressed in
110*6777b538SAndroid Build Coastguard Workerthe future by implementing support for sentinel types ourselves.
111*6777b538SAndroid Build Coastguard Worker
112*6777b538SAndroid Build Coastguard Worker### Lack of `constexpr`
113*6777b538SAndroid Build Coastguard WorkerThe `base::ranges` algorithms can only be used in a `constexpr` context when
114*6777b538SAndroid Build Coastguard Workerthey call underlying `std::` algorithms that are themselves `constexpr`.  Before
115*6777b538SAndroid Build Coastguard WorkerC++20, only `std::min`, `std::max` and `std::minmax` are annotated
116*6777b538SAndroid Build Coastguard Workerappropriately, so code like `constexpr bool foo = base::ranges::any_of(...);`
117*6777b538SAndroid Build Coastguard Workerwill fail because the compiler will not find a `constexpr std::any_of`.  This
118*6777b538SAndroid Build Coastguard Workercould be addressed by either upgrading Chromium's STL to C++20, or implementing
119*6777b538SAndroid Build Coastguard Worker`constexpr` versions of some of these algorithms ourselves.
120*6777b538SAndroid Build Coastguard Worker
121*6777b538SAndroid Build Coastguard Worker### Lack of post C++14 algorithms
122*6777b538SAndroid Build Coastguard WorkerSince most algorithms in `base::ranges` dispatch to their C++14 equivalent, some
123*6777b538SAndroid Build Coastguard Worker`std::` algorithms that are not present in C++14 have no implementation in
124*6777b538SAndroid Build Coastguard Worker`base::ranges`. This list of algorithms includes the following:
125*6777b538SAndroid Build Coastguard Worker
126*6777b538SAndroid Build Coastguard Worker- [`std::sample`](https://en.cppreference.com/w/cpp/algorithm/sample) (added in C++17)
127*6777b538SAndroid Build Coastguard Worker
128*6777b538SAndroid Build Coastguard Worker### Return Types
129*6777b538SAndroid Build Coastguard WorkerSome of the algorithms in `std::ranges::` have different return types than their
130*6777b538SAndroid Build Coastguard Workerequivalent in `std::`. For example, while `std::for_each` returns the passed-in
131*6777b538SAndroid Build Coastguard Worker`Function`, `std::ranges::for_each` returns a `std::ranges::for_each_result`,
132*6777b538SAndroid Build Coastguard Workerconsisting of the `last` iterator and the function.
133*6777b538SAndroid Build Coastguard Worker
134*6777b538SAndroid Build Coastguard WorkerIn the cases where the return type differs, `base::ranges::` algorithms will
135*6777b538SAndroid Build Coastguard Workercontinue to return the old return type.
136*6777b538SAndroid Build Coastguard Worker
137*6777b538SAndroid Build Coastguard Worker### No blocking of ADL
138*6777b538SAndroid Build Coastguard WorkerThe algorithms defined in `std::ranges` are not found by ADL, and inhibit ADL
139*6777b538SAndroid Build Coastguard Workerwhen found by [unqualified name lookup][1]. This is done to be able to enforce
140*6777b538SAndroid Build Coastguard Workerthe constraints specified by those algorithms and commonly implemented by using
141*6777b538SAndroid Build Coastguard Workerfunction objects instead of regular functions. Since we don't support
142*6777b538SAndroid Build Coastguard Workerconstrained algorithms yet, we don't implement the blocking of ADL either.
143*6777b538SAndroid Build Coastguard Worker
144*6777b538SAndroid Build Coastguard Worker[1]: https://wg21.link/algorithms.requirements#2
145