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