xref: /aosp_15_r20/external/pigweed/pw_containers/public/pw_containers/algorithm.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 //
15 // -----------------------------------------------------------------------------
16 // File: algorithm.h
17 // -----------------------------------------------------------------------------
18 //
19 // This header file provides Container-based versions of algorithmic functions
20 // within the C++ standard library, based on a subset of
21 // absl/algorithm/container.h. The following standard library sets of functions
22 // are covered within this file:
23 //
24 //   * <algorithm> functions
25 //
26 // The standard library functions operate on iterator ranges; the functions
27 // within this API operate on containers, though many return iterator ranges.
28 //
29 // All functions within this API are CamelCase instead of their std::
30 // snake_case counterparts. Calls such as `pw::containers::Foo(container, ...)
31 // are equivalent to std:: functions such as
32 // `std::foo(std::begin(cont), std::end(cont), ...)`. Functions that act on
33 // iterators but not conceptually on iterator ranges (e.g. `std::iter_swap`)
34 // have no equivalent here.
35 //
36 // For template parameter and variable naming, `C` indicates the container type
37 // to which the function is applied, `Pred` indicates the predicate object type
38 // to be used by the function and `T` indicates the applicable element type.
39 //
40 // This was forked from
41 // https://cs.opensource.google/abseil/abseil-cpp/+/main:absl/algorithm/algorithm.h;drc=12bc53e0318d80569270a5b26ccbc62b52022b89
42 #pragma once
43 
44 #include <algorithm>
45 #include <utility>
46 
47 #include "pw_containers/internal/algorithm_internal.h"
48 
49 namespace pw::containers {
50 
51 //------------------------------------------------------------------------------
52 // <algorithm> Non-modifying sequence operations
53 //------------------------------------------------------------------------------
54 
55 // AllOf()
56 //
57 // Container-based version of the <algorithm> `std::all_of()` function to
58 // test if all elements within a container satisfy a condition.
59 template <typename C, typename Pred>
AllOf(const C & c,Pred && pred)60 bool AllOf(const C& c, Pred&& pred) {
61   return std::all_of(std::begin(c), std::end(c), std::forward<Pred>(pred));
62 }
63 
64 // AnyOf()
65 //
66 // Container-based version of the <algorithm> `std::any_of()` function to
67 // test if any element in a container fulfills a condition.
68 template <typename C, typename Pred>
AnyOf(const C & c,Pred && pred)69 bool AnyOf(const C& c, Pred&& pred) {
70   return std::any_of(std::begin(c), std::end(c), std::forward<Pred>(pred));
71 }
72 
73 // NoneOf()
74 //
75 // Container-based version of the <algorithm> `std::none_of()` function to
76 // test if no elements in a container fulfill a condition.
77 template <typename C, typename Pred>
NoneOf(const C & c,Pred && pred)78 bool NoneOf(const C& c, Pred&& pred) {
79   return std::none_of(std::begin(c), std::end(c), std::forward<Pred>(pred));
80 }
81 
82 // ForEach()
83 //
84 // Container-based version of the <algorithm> `std::for_each()` function to
85 // apply a function to a container's elements.
86 template <typename C, typename Function>
ForEach(C && c,Function && f)87 std::decay_t<Function> ForEach(C&& c, Function&& f) {
88   return std::for_each(std::begin(c), std::end(c), std::forward<Function>(f));
89 }
90 
91 // Find()
92 //
93 // Container-based version of the <algorithm> `std::find()` function to find
94 // the first element containing the passed value within a container value.
95 template <typename C, typename T>
Find(C & c,T && value)96 internal_algorithm::ContainerIter<C> Find(C& c, T&& value) {
97   return std::find(std::begin(c), std::end(c), std::forward<T>(value));
98 }
99 
100 // FindIf()
101 //
102 // Container-based version of the <algorithm> `std::find_if()` function to find
103 // the first element in a container matching the given condition.
104 template <typename C, typename Pred>
FindIf(C & c,Pred && pred)105 internal_algorithm::ContainerIter<C> FindIf(C& c, Pred&& pred) {
106   return std::find_if(std::begin(c), std::end(c), std::forward<Pred>(pred));
107 }
108 
109 // FindIfNot()
110 //
111 // Container-based version of the <algorithm> `std::find_if_not()` function to
112 // find the first element in a container not matching the given condition.
113 template <typename C, typename Pred>
FindIfNot(C & c,Pred && pred)114 internal_algorithm::ContainerIter<C> FindIfNot(C& c, Pred&& pred) {
115   return std::find_if_not(std::begin(c), std::end(c), std::forward<Pred>(pred));
116 }
117 
118 // FindEnd()
119 //
120 // Container-based version of the <algorithm> `std::find_end()` function to
121 // find the last subsequence within a container.
122 template <typename Sequence1, typename Sequence2>
FindEnd(Sequence1 & sequence,Sequence2 & subsequence)123 internal_algorithm::ContainerIter<Sequence1> FindEnd(Sequence1& sequence,
124                                                      Sequence2& subsequence) {
125   return std::find_end(std::begin(sequence),
126                        std::end(sequence),
127                        std::begin(subsequence),
128                        std::end(subsequence));
129 }
130 
131 // Overload of FindEnd() for using a predicate evaluation other than `==` as
132 // the function's test condition.
133 template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
FindEnd(Sequence1 & sequence,Sequence2 & subsequence,BinaryPredicate && pred)134 internal_algorithm::ContainerIter<Sequence1> FindEnd(Sequence1& sequence,
135                                                      Sequence2& subsequence,
136                                                      BinaryPredicate&& pred) {
137   return std::find_end(std::begin(sequence),
138                        std::end(sequence),
139                        std::begin(subsequence),
140                        std::end(subsequence),
141                        std::forward<BinaryPredicate>(pred));
142 }
143 
144 // FindFirstOf()
145 //
146 // Container-based version of the <algorithm> `std::find_first_of()` function to
147 // find the first element within the container that is also within the options
148 // container.
149 template <typename C1, typename C2>
FindFirstOf(C1 & container,C2 & options)150 internal_algorithm::ContainerIter<C1> FindFirstOf(C1& container, C2& options) {
151   return std::find_first_of(std::begin(container),
152                             std::end(container),
153                             std::begin(options),
154                             std::end(options));
155 }
156 
157 // Overload of FindFirstOf() for using a predicate evaluation other than
158 // `==` as the function's test condition.
159 template <typename C1, typename C2, typename BinaryPredicate>
FindFirstOf(C1 & container,C2 & options,BinaryPredicate && pred)160 internal_algorithm::ContainerIter<C1> FindFirstOf(C1& container,
161                                                   C2& options,
162                                                   BinaryPredicate&& pred) {
163   return std::find_first_of(std::begin(container),
164                             std::end(container),
165                             std::begin(options),
166                             std::end(options),
167                             std::forward<BinaryPredicate>(pred));
168 }
169 
170 // AdjacentFind()
171 //
172 // Container-based version of the <algorithm> `std::adjacent_find()` function to
173 // find equal adjacent elements within a container.
174 template <typename Sequence>
AdjacentFind(Sequence & sequence)175 internal_algorithm::ContainerIter<Sequence> AdjacentFind(Sequence& sequence) {
176   return std::adjacent_find(std::begin(sequence), std::end(sequence));
177 }
178 
179 // Overload of AdjacentFind() for using a predicate evaluation other than
180 // `==` as the function's test condition.
181 template <typename Sequence, typename BinaryPredicate>
AdjacentFind(Sequence & sequence,BinaryPredicate && pred)182 internal_algorithm::ContainerIter<Sequence> AdjacentFind(
183     Sequence& sequence, BinaryPredicate&& pred) {
184   return std::adjacent_find(std::begin(sequence),
185                             std::end(sequence),
186                             std::forward<BinaryPredicate>(pred));
187 }
188 
189 // Count()
190 //
191 // Container-based version of the <algorithm> `std::count()` function to count
192 // values that match within a container.
193 template <typename C, typename T>
Count(const C & c,T && value)194 internal_algorithm::ContainerDifferenceType<const C> Count(const C& c,
195                                                            T&& value) {
196   return std::count(std::begin(c), std::end(c), std::forward<T>(value));
197 }
198 
199 // CountIOf()
200 //
201 // Container-based version of the <algorithm> `std::count_if()` function to
202 // count values matching a condition within a container.
203 template <typename C, typename Pred>
CountIf(const C & c,Pred && pred)204 internal_algorithm::ContainerDifferenceType<const C> CountIf(const C& c,
205                                                              Pred&& pred) {
206   return std::count_if(std::begin(c), std::end(c), std::forward<Pred>(pred));
207 }
208 
209 // Mismatch()
210 //
211 // Container-based version of the <algorithm> `std::mismatch()` function to
212 // return the first element where two ordered containers differ. Applies `==` to
213 // the first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
214 template <typename C1, typename C2>
Mismatch(C1 & c1,C2 & c2)215 internal_algorithm::ContainerIterPairType<C1, C2> Mismatch(C1& c1, C2& c2) {
216   auto first1 = std::begin(c1);
217   auto last1 = std::end(c1);
218   auto first2 = std::begin(c2);
219   auto last2 = std::end(c2);
220 
221   for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
222     // Negates equality because Cpp17EqualityComparable doesn't require clients
223     // to overload both `operator==` and `operator!=`.
224     if (!(*first1 == *first2)) {
225       break;
226     }
227   }
228 
229   return std::make_pair(first1, first2);
230 }
231 
232 // Overload of Mismatch() for using a predicate evaluation other than `==` as
233 // the function's test condition. Applies `pred`to the first N elements of `c1`
234 // and `c2`, where N = min(size(c1), size(c2)).
235 template <typename C1, typename C2, typename BinaryPredicate>
Mismatch(C1 & c1,C2 & c2,BinaryPredicate pred)236 internal_algorithm::ContainerIterPairType<C1, C2> Mismatch(
237     C1& c1, C2& c2, BinaryPredicate pred) {
238   auto first1 = std::begin(c1);
239   auto last1 = std::end(c1);
240   auto first2 = std::begin(c2);
241   auto last2 = std::end(c2);
242 
243   for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
244     if (!pred(*first1, *first2)) {
245       break;
246     }
247   }
248 
249   return std::make_pair(first1, first2);
250 }
251 
252 // Equal()
253 //
254 // Container-based version of the <algorithm> `std::equal()` function to
255 // test whether two containers are equal.
256 //
257 // NOTE: the semantics of Equal() are slightly different than those of
258 // equal(): while the latter iterates over the second container only up to the
259 // size of the first container, Equal() also checks whether the container
260 // sizes are equal.  This better matches expectations about Equal() based on
261 // its signature.
262 //
263 // Example:
264 //   vector v1 = <1, 2, 3>;
265 //   vector v2 = <1, 2, 3, 4>;
266 //   equal(std::begin(v1), std::end(v1), std::begin(v2)) returns true
267 //   Equal(v1, v2) returns false
268 
269 template <typename C1, typename C2>
Equal(const C1 & c1,const C2 & c2)270 bool Equal(const C1& c1, const C2& c2) {
271   return ((std::size(c1) == std::size(c2)) &&
272           std::equal(std::begin(c1), std::end(c1), std::begin(c2)));
273 }
274 
275 // Overload of Equal() for using a predicate evaluation other than `==` as
276 // the function's test condition.
277 template <typename C1, typename C2, typename BinaryPredicate>
Equal(const C1 & c1,const C2 & c2,BinaryPredicate && pred)278 bool Equal(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
279   return ((std::size(c1) == std::size(c2)) &&
280           std::equal(std::begin(c1),
281                      std::end(c1),
282                      std::begin(c2),
283                      std::forward<BinaryPredicate>(pred)));
284 }
285 
286 // IsPermutation()
287 //
288 // Container-based version of the <algorithm> `std::is_permutation()` function
289 // to test whether a container is a permutation of another.
290 template <typename C1, typename C2>
IsPermutation(const C1 & c1,const C2 & c2)291 bool IsPermutation(const C1& c1, const C2& c2) {
292   using std::begin;
293   using std::end;
294   return c1.size() == c2.size() &&
295          std::is_permutation(begin(c1), end(c1), begin(c2));
296 }
297 
298 // Overload of IsPermutation() for using a predicate evaluation other than
299 // `==` as the function's test condition.
300 template <typename C1, typename C2, typename BinaryPredicate>
IsPermutation(const C1 & c1,const C2 & c2,BinaryPredicate && pred)301 bool IsPermutation(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
302   using std::begin;
303   using std::end;
304   return c1.size() == c2.size() &&
305          std::is_permutation(begin(c1),
306                              end(c1),
307                              begin(c2),
308                              std::forward<BinaryPredicate>(pred));
309 }
310 
311 // Search()
312 //
313 // Container-based version of the <algorithm> `std::search()` function to search
314 // a container for a subsequence.
315 template <typename Sequence1, typename Sequence2>
Search(Sequence1 & sequence,Sequence2 & subsequence)316 internal_algorithm::ContainerIter<Sequence1> Search(Sequence1& sequence,
317                                                     Sequence2& subsequence) {
318   return std::search(std::begin(sequence),
319                      std::end(sequence),
320                      std::begin(subsequence),
321                      std::end(subsequence));
322 }
323 
324 // Overload of Search() for using a predicate evaluation other than
325 // `==` as the function's test condition.
326 template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
Search(Sequence1 & sequence,Sequence2 & subsequence,BinaryPredicate && pred)327 internal_algorithm::ContainerIter<Sequence1> Search(Sequence1& sequence,
328                                                     Sequence2& subsequence,
329                                                     BinaryPredicate&& pred) {
330   return std::search(std::begin(sequence),
331                      std::end(sequence),
332                      std::begin(subsequence),
333                      std::end(subsequence),
334                      std::forward<BinaryPredicate>(pred));
335 }
336 
337 // SearchN()
338 //
339 // Container-based version of the <algorithm> `std::search_n()` function to
340 // search a container for the first sequence of N elements.
341 template <typename Sequence, typename Size, typename T>
SearchN(Sequence & sequence,Size count,T && value)342 internal_algorithm::ContainerIter<Sequence> SearchN(Sequence& sequence,
343                                                     Size count,
344                                                     T&& value) {
345   return std::search_n(
346       std::begin(sequence), std::end(sequence), count, std::forward<T>(value));
347 }
348 
349 // Overload of SearchN() for using a predicate evaluation other than
350 // `==` as the function's test condition.
351 template <typename Sequence,
352           typename Size,
353           typename T,
354           typename BinaryPredicate>
SearchN(Sequence & sequence,Size count,T && value,BinaryPredicate && pred)355 internal_algorithm::ContainerIter<Sequence> SearchN(Sequence& sequence,
356                                                     Size count,
357                                                     T&& value,
358                                                     BinaryPredicate&& pred) {
359   return std::search_n(std::begin(sequence),
360                        std::end(sequence),
361                        count,
362                        std::forward<T>(value),
363                        std::forward<BinaryPredicate>(pred));
364 }
365 
366 }  // namespace pw::containers
367