blob: 47cf6f8e798530e7c9133100cdaf715e8e1ce63c [file] [log] [blame]
[email protected]7286e3fc2011-07-19 22:13:241// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Derived from google3/util/gtl/stl_util.h
6
7#ifndef BASE_STL_UTIL_H_
8#define BASE_STL_UTIL_H_
[email protected]7286e3fc2011-07-19 22:13:249
[email protected]1dea7572012-12-05 21:40:2710#include <algorithm>
dyaroshev5f0ff7982017-03-08 01:24:4911#include <deque>
12#include <forward_list>
[email protected]fa95a0f2012-12-10 22:48:4213#include <functional>
jdoerrie8f516042018-04-13 09:40:3014#include <initializer_list>
[email protected]c014f2b32013-09-03 23:29:1215#include <iterator>
dyaroshev5f0ff7982017-03-08 01:24:4916#include <list>
17#include <map>
18#include <set>
[email protected]7286e3fc2011-07-19 22:13:2419#include <string>
jdoerrieb77149f2019-06-05 10:46:4920#include <type_traits>
dyaroshev5f0ff7982017-03-08 01:24:4921#include <unordered_map>
22#include <unordered_set>
jdoerrieb77149f2019-06-05 10:46:4923#include <utility>
[email protected]7286e3fc2011-07-19 22:13:2424#include <vector>
25
[email protected]1dea7572012-12-05 21:40:2726#include "base/logging.h"
Philip Rogers3f67719f2018-03-09 02:16:4427#include "base/optional.h"
jdoerrie2de200e42019-06-04 09:11:0728#include "base/template_util.h"
[email protected]1dea7572012-12-05 21:40:2729
skyostil68be7152016-08-09 22:18:0030namespace base {
31
dyaroshev5f0ff7982017-03-08 01:24:4932namespace internal {
33
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:4334// Calls erase on iterators of matching elements and returns the number of
35// removed elements.
dyaroshev5f0ff7982017-03-08 01:24:4936template <typename Container, typename Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:4337size_t IterateAndEraseIf(Container& container, Predicate pred) {
38 size_t old_size = container.size();
39 for (auto it = container.begin(), last = container.end(); it != last;) {
dyaroshev5f0ff7982017-03-08 01:24:4940 if (pred(*it))
41 it = container.erase(it);
42 else
43 ++it;
44 }
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:4345 return old_size - container.size();
dyaroshev5f0ff7982017-03-08 01:24:4946}
47
jdoerrie2de200e42019-06-04 09:11:0748template <typename Iter>
49constexpr bool IsRandomAccessIter =
50 std::is_same<typename std::iterator_traits<Iter>::iterator_category,
51 std::random_access_iterator_tag>::value;
52
jdoerrieb77149f2019-06-05 10:46:4953// Utility type traits used for specializing base::Contains() below.
54template <typename Container, typename Element, typename = void>
55struct HasFindWithNpos : std::false_type {};
56
57template <typename Container, typename Element>
58struct HasFindWithNpos<
59 Container,
60 Element,
61 void_t<decltype(std::declval<const Container&>().find(
62 std::declval<const Element&>()) != Container::npos)>>
63 : std::true_type {};
64
65template <typename Container, typename Element, typename = void>
66struct HasFindWithEnd : std::false_type {};
67
68template <typename Container, typename Element>
69struct HasFindWithEnd<Container,
70 Element,
71 void_t<decltype(std::declval<const Container&>().find(
72 std::declval<const Element&>()) !=
73 std::declval<const Container&>().end())>>
74 : std::true_type {};
75
76template <typename Container, typename Element, typename = void>
77struct HasContains : std::false_type {};
78
79template <typename Container, typename Element>
80struct HasContains<Container,
81 Element,
82 void_t<decltype(std::declval<const Container&>().contains(
83 std::declval<const Element&>()))>> : std::true_type {};
84
dyaroshev5f0ff7982017-03-08 01:24:4985} // namespace internal
86
jdoerrie8f516042018-04-13 09:40:3087// C++14 implementation of C++17's std::size():
88// http://en.cppreference.com/w/cpp/iterator/size
89template <typename Container>
90constexpr auto size(const Container& c) -> decltype(c.size()) {
91 return c.size();
92}
93
94template <typename T, size_t N>
95constexpr size_t size(const T (&array)[N]) noexcept {
96 return N;
97}
98
99// C++14 implementation of C++17's std::empty():
100// http://en.cppreference.com/w/cpp/iterator/empty
101template <typename Container>
102constexpr auto empty(const Container& c) -> decltype(c.empty()) {
103 return c.empty();
104}
105
106template <typename T, size_t N>
107constexpr bool empty(const T (&array)[N]) noexcept {
108 return false;
109}
110
111template <typename T>
112constexpr bool empty(std::initializer_list<T> il) noexcept {
113 return il.size() == 0;
114}
115
116// C++14 implementation of C++17's std::data():
117// http://en.cppreference.com/w/cpp/iterator/data
118template <typename Container>
119constexpr auto data(Container& c) -> decltype(c.data()) {
120 return c.data();
121}
122
123// std::basic_string::data() had no mutable overload prior to C++17 [1].
124// Hence this overload is provided.
125// Note: str[0] is safe even for empty strings, as they are guaranteed to be
126// null-terminated [2].
127//
128// [1] http://en.cppreference.com/w/cpp/string/basic_string/data
129// [2] http://en.cppreference.com/w/cpp/string/basic_string/operator_at
130template <typename CharT, typename Traits, typename Allocator>
131CharT* data(std::basic_string<CharT, Traits, Allocator>& str) {
132 return std::addressof(str[0]);
133}
134
135template <typename Container>
136constexpr auto data(const Container& c) -> decltype(c.data()) {
137 return c.data();
138}
139
140template <typename T, size_t N>
141constexpr T* data(T (&array)[N]) noexcept {
142 return array;
143}
144
145template <typename T>
146constexpr const T* data(std::initializer_list<T> il) noexcept {
147 return il.begin();
148}
149
Jan Wilken Dörrie6c2032812019-11-13 03:32:19150// std::array::data() was not constexpr prior to C++17 [1].
151// Hence these overloads are provided.
152//
153// [1] https://en.cppreference.com/w/cpp/container/array/data
154template <typename T, size_t N>
155constexpr T* data(std::array<T, N>& array) noexcept {
156 return !array.empty() ? &array[0] : nullptr;
157}
158
159template <typename T, size_t N>
160constexpr const T* data(const std::array<T, N>& array) noexcept {
161 return !array.empty() ? &array[0] : nullptr;
162}
163
Jan Wilken Dörrie9b751f02019-11-26 06:52:06164// C++14 implementation of C++17's std::as_const():
165// https://en.cppreference.com/w/cpp/utility/as_const
166template <typename T>
167constexpr std::add_const_t<T>& as_const(T& t) noexcept {
168 return t;
169}
170
171template <typename T>
172void as_const(const T&& t) = delete;
173
Dan Sanders97c13742018-05-17 23:12:32174// Returns a const reference to the underlying container of a container adapter.
175// Works for std::priority_queue, std::queue, and std::stack.
176template <class A>
177const typename A::container_type& GetUnderlyingContainer(const A& adapter) {
178 struct ExposedAdapter : A {
179 using A::c;
180 };
181 return adapter.*&ExposedAdapter::c;
182}
183
[email protected]6ee951a2012-06-26 17:24:05184// Clears internal memory of an STL object.
[email protected]7286e3fc2011-07-19 22:13:24185// STL clear()/reserve(0) does not always free internal memory allocated
186// This function uses swap/destructor to ensure the internal memory is freed.
[email protected]6ee951a2012-06-26 17:24:05187template<class T>
188void STLClearObject(T* obj) {
[email protected]7286e3fc2011-07-19 22:13:24189 T tmp;
190 tmp.swap(*obj);
191 // Sometimes "T tmp" allocates objects with memory (arena implementation?).
192 // Hence using additional reserve(0) even if it doesn't always work.
193 obj->reserve(0);
194}
195
robliao43eb02c2015-03-27 18:25:11196// Counts the number of instances of val in a container.
197template <typename Container, typename T>
198typename std::iterator_traits<
199 typename Container::const_iterator>::difference_type
200STLCount(const Container& container, const T& val) {
201 return std::count(container.begin(), container.end(), val);
202}
203
jdoerrieb77149f2019-06-05 10:46:49204// General purpose implementation to check if |container| contains |value|.
205template <typename Container,
206 typename Value,
207 std::enable_if_t<
208 !internal::HasFindWithNpos<Container, Value>::value &&
209 !internal::HasFindWithEnd<Container, Value>::value &&
210 !internal::HasContains<Container, Value>::value>* = nullptr>
211bool Contains(const Container& container, const Value& value) {
212 using std::begin;
213 using std::end;
214 return std::find(begin(container), end(container), value) != end(container);
215}
216
217// Specialized Contains() implementation for when |container| has a find()
218// member function and a static npos member, but no contains() member function.
219template <typename Container,
220 typename Value,
221 std::enable_if_t<internal::HasFindWithNpos<Container, Value>::value &&
222 !internal::HasContains<Container, Value>::value>* =
223 nullptr>
224bool Contains(const Container& container, const Value& value) {
225 return container.find(value) != Container::npos;
226}
227
228// Specialized Contains() implementation for when |container| has a find()
229// and end() member function, but no contains() member function.
230template <typename Container,
231 typename Value,
232 std::enable_if_t<internal::HasFindWithEnd<Container, Value>::value &&
233 !internal::HasContains<Container, Value>::value>* =
234 nullptr>
235bool Contains(const Container& container, const Value& value) {
236 return container.find(value) != container.end();
237}
238
239// Specialized Contains() implementation for when |container| has a contains()
240// member function.
241template <
242 typename Container,
243 typename Value,
244 std::enable_if_t<internal::HasContains<Container, Value>::value>* = nullptr>
245bool Contains(const Container& container, const Value& value) {
246 return container.contains(value);
247}
248
jdoerrie2de200e42019-06-04 09:11:07249// O(1) implementation of const casting an iterator for any sequence,
250// associative or unordered associative container in the STL.
251//
252// Reference: https://stackoverflow.com/a/10669041
253template <typename Container,
254 typename ConstIter,
255 std::enable_if_t<!internal::IsRandomAccessIter<ConstIter>>* = nullptr>
256constexpr auto ConstCastIterator(Container& c, ConstIter it) {
257 return c.erase(it, it);
258}
259
Jan Wilken Dörrie894226d2019-06-13 07:53:15260// Explicit overload for std::forward_list where erase() is named erase_after().
jdoerrie2de200e42019-06-04 09:11:07261template <typename T, typename Allocator>
262constexpr auto ConstCastIterator(
263 std::forward_list<T, Allocator>& c,
264 typename std::forward_list<T, Allocator>::const_iterator it) {
Jan Wilken Dörrie894226d2019-06-13 07:53:15265// The erase_after(it, it) trick used below does not work for libstdc++ [1],
266// thus we need a different way.
267// TODO(crbug.com/972541): Remove this workaround once libstdc++ is fixed on all
268// platforms.
269//
270// [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90857
271#if defined(__GLIBCXX__)
272 return c.insert_after(it, {});
273#else
jdoerrie2de200e42019-06-04 09:11:07274 return c.erase_after(it, it);
Jan Wilken Dörrie894226d2019-06-13 07:53:15275#endif
jdoerrie2de200e42019-06-04 09:11:07276}
277
278// Specialized O(1) const casting for random access iterators. This is
279// necessary, because erase() is either not available (e.g. array-like
280// containers), or has O(n) complexity (e.g. std::deque or std::vector).
281template <typename Container,
282 typename ConstIter,
283 std::enable_if_t<internal::IsRandomAccessIter<ConstIter>>* = nullptr>
284constexpr auto ConstCastIterator(Container& c, ConstIter it) {
285 using std::begin;
286 using std::cbegin;
287 return begin(c) + (it - cbegin(c));
288}
289
Marijn Kruisselbrinkbb019e32017-06-27 20:50:32290namespace internal {
291
jdoerrie2de200e42019-06-04 09:11:07292template <typename Map, typename Key, typename Value>
293std::pair<typename Map::iterator, bool> InsertOrAssignImpl(Map& map,
294 Key&& key,
295 Value&& value) {
296 auto lower = map.lower_bound(key);
297 if (lower != map.end() && !map.key_comp()(key, lower->first)) {
298 // key already exists, perform assignment.
299 lower->second = std::forward<Value>(value);
300 return {lower, false};
301 }
302
303 // key did not yet exist, insert it.
304 return {map.emplace_hint(lower, std::forward<Key>(key),
305 std::forward<Value>(value)),
306 true};
307}
308
309template <typename Map, typename Key, typename Value>
310typename Map::iterator InsertOrAssignImpl(Map& map,
311 typename Map::const_iterator hint,
312 Key&& key,
313 Value&& value) {
314 auto&& key_comp = map.key_comp();
315 if ((hint == map.begin() || key_comp(std::prev(hint)->first, key))) {
316 if (hint == map.end() || key_comp(key, hint->first)) {
317 // *(hint - 1) < key < *hint => key did not exist and hint is correct.
318 return map.emplace_hint(hint, std::forward<Key>(key),
319 std::forward<Value>(value));
320 }
321
322 if (!key_comp(hint->first, key)) {
323 // key == *hint => key already exists and hint is correct.
324 auto mutable_hint = ConstCastIterator(map, hint);
325 mutable_hint->second = std::forward<Value>(value);
326 return mutable_hint;
327 }
328 }
329
330 // hint was not helpful, dispatch to hintless version.
331 return InsertOrAssignImpl(map, std::forward<Key>(key),
332 std::forward<Value>(value))
333 .first;
334}
335
336template <typename Map, typename Key, typename... Args>
337std::pair<typename Map::iterator, bool> TryEmplaceImpl(Map& map,
338 Key&& key,
339 Args&&... args) {
340 auto lower = map.lower_bound(key);
341 if (lower != map.end() && !map.key_comp()(key, lower->first)) {
342 // key already exists, do nothing.
343 return {lower, false};
344 }
345
346 // key did not yet exist, insert it.
347 return {map.emplace_hint(lower, std::piecewise_construct,
348 std::forward_as_tuple(std::forward<Key>(key)),
349 std::forward_as_tuple(std::forward<Args>(args)...)),
350 true};
351}
352
353template <typename Map, typename Key, typename... Args>
354typename Map::iterator TryEmplaceImpl(Map& map,
355 typename Map::const_iterator hint,
356 Key&& key,
357 Args&&... args) {
358 auto&& key_comp = map.key_comp();
359 if ((hint == map.begin() || key_comp(std::prev(hint)->first, key))) {
360 if (hint == map.end() || key_comp(key, hint->first)) {
361 // *(hint - 1) < key < *hint => key did not exist and hint is correct.
362 return map.emplace_hint(
363 hint, std::piecewise_construct,
364 std::forward_as_tuple(std::forward<Key>(key)),
365 std::forward_as_tuple(std::forward<Args>(args)...));
366 }
367
368 if (!key_comp(hint->first, key)) {
369 // key == *hint => no-op, return correct hint.
370 return ConstCastIterator(map, hint);
371 }
372 }
373
374 // hint was not helpful, dispatch to hintless version.
375 return TryEmplaceImpl(map, std::forward<Key>(key),
376 std::forward<Args>(args)...)
377 .first;
378}
379
Marijn Kruisselbrinkbb019e32017-06-27 20:50:32380} // namespace internal
381
jdoerrie2de200e42019-06-04 09:11:07382// Implementation of C++17's std::map::insert_or_assign as a free function.
383template <typename Map, typename Value>
384std::pair<typename Map::iterator, bool>
385InsertOrAssign(Map& map, const typename Map::key_type& key, Value&& value) {
386 return internal::InsertOrAssignImpl(map, key, std::forward<Value>(value));
387}
388
389template <typename Map, typename Value>
390std::pair<typename Map::iterator, bool>
391InsertOrAssign(Map& map, typename Map::key_type&& key, Value&& value) {
392 return internal::InsertOrAssignImpl(map, std::move(key),
393 std::forward<Value>(value));
394}
395
396// Implementation of C++17's std::map::insert_or_assign with hint as a free
397// function.
398template <typename Map, typename Value>
399typename Map::iterator InsertOrAssign(Map& map,
400 typename Map::const_iterator hint,
401 const typename Map::key_type& key,
402 Value&& value) {
403 return internal::InsertOrAssignImpl(map, hint, key,
404 std::forward<Value>(value));
405}
406
407template <typename Map, typename Value>
408typename Map::iterator InsertOrAssign(Map& map,
409 typename Map::const_iterator hint,
410 typename Map::key_type&& key,
411 Value&& value) {
412 return internal::InsertOrAssignImpl(map, hint, std::move(key),
413 std::forward<Value>(value));
414}
415
416// Implementation of C++17's std::map::try_emplace as a free function.
417template <typename Map, typename... Args>
418std::pair<typename Map::iterator, bool>
419TryEmplace(Map& map, const typename Map::key_type& key, Args&&... args) {
420 return internal::TryEmplaceImpl(map, key, std::forward<Args>(args)...);
421}
422
423template <typename Map, typename... Args>
424std::pair<typename Map::iterator, bool> TryEmplace(Map& map,
425 typename Map::key_type&& key,
426 Args&&... args) {
427 return internal::TryEmplaceImpl(map, std::move(key),
428 std::forward<Args>(args)...);
429}
430
431// Implementation of C++17's std::map::try_emplace with hint as a free
432// function.
433template <typename Map, typename... Args>
434typename Map::iterator TryEmplace(Map& map,
435 typename Map::const_iterator hint,
436 const typename Map::key_type& key,
437 Args&&... args) {
438 return internal::TryEmplaceImpl(map, hint, key, std::forward<Args>(args)...);
439}
440
441template <typename Map, typename... Args>
442typename Map::iterator TryEmplace(Map& map,
443 typename Map::const_iterator hint,
444 typename Map::key_type&& key,
445 Args&&... args) {
446 return internal::TryEmplaceImpl(map, hint, std::move(key),
447 std::forward<Args>(args)...);
448}
449
[email protected]1dea7572012-12-05 21:40:27450// Returns true if the container is sorted.
451template <typename Container>
452bool STLIsSorted(const Container& cont) {
jdoerrie2fc218a2018-08-07 09:23:25453 return std::is_sorted(std::begin(cont), std::end(cont));
[email protected]1dea7572012-12-05 21:40:27454}
455
456// Returns a new ResultType containing the difference of two sorted containers.
457template <typename ResultType, typename Arg1, typename Arg2>
458ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
459 DCHECK(STLIsSorted(a1));
460 DCHECK(STLIsSorted(a2));
461 ResultType difference;
462 std::set_difference(a1.begin(), a1.end(),
463 a2.begin(), a2.end(),
464 std::inserter(difference, difference.end()));
465 return difference;
466}
467
[email protected]9a53ade2014-01-29 17:13:27468// Returns a new ResultType containing the union of two sorted containers.
469template <typename ResultType, typename Arg1, typename Arg2>
470ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
471 DCHECK(STLIsSorted(a1));
472 DCHECK(STLIsSorted(a2));
473 ResultType result;
474 std::set_union(a1.begin(), a1.end(),
475 a2.begin(), a2.end(),
476 std::inserter(result, result.end()));
477 return result;
478}
479
480// Returns a new ResultType containing the intersection of two sorted
481// containers.
482template <typename ResultType, typename Arg1, typename Arg2>
483ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
484 DCHECK(STLIsSorted(a1));
485 DCHECK(STLIsSorted(a2));
486 ResultType result;
487 std::set_intersection(a1.begin(), a1.end(),
488 a2.begin(), a2.end(),
489 std::inserter(result, result.end()));
490 return result;
491}
492
493// Returns true if the sorted container |a1| contains all elements of the sorted
494// container |a2|.
495template <typename Arg1, typename Arg2>
496bool STLIncludes(const Arg1& a1, const Arg2& a2) {
497 DCHECK(STLIsSorted(a1));
498 DCHECK(STLIsSorted(a2));
499 return std::includes(a1.begin(), a1.end(),
500 a2.begin(), a2.end());
501}
502
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43503// Erase/EraseIf are based on C++20's uniform container erasure API:
504// - https://eel.is/c++draft/libraryindex#:erase
505// - https://eel.is/c++draft/libraryindex#:erase_if
dyaroshev5f0ff7982017-03-08 01:24:49506// They provide a generic way to erase elements from a container.
507// The functions here implement these for the standard containers until those
508// functions are available in the C++ standard.
509// For Chromium containers overloads should be defined in their own headers
510// (like standard containers).
511// Note: there is no std::erase for standard associative containers so we don't
512// have it either.
513
514template <typename CharT, typename Traits, typename Allocator, typename Value>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43515size_t Erase(std::basic_string<CharT, Traits, Allocator>& container,
516 const Value& value) {
517 auto it = std::remove(container.begin(), container.end(), value);
518 size_t removed = std::distance(it, container.end());
519 container.erase(it, container.end());
520 return removed;
dyaroshev5f0ff7982017-03-08 01:24:49521}
522
523template <typename CharT, typename Traits, typename Allocator, class Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43524size_t EraseIf(std::basic_string<CharT, Traits, Allocator>& container,
525 Predicate pred) {
526 auto it = std::remove_if(container.begin(), container.end(), pred);
527 size_t removed = std::distance(it, container.end());
528 container.erase(it, container.end());
529 return removed;
dyaroshev5f0ff7982017-03-08 01:24:49530}
531
532template <class T, class Allocator, class Value>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43533size_t Erase(std::deque<T, Allocator>& container, const Value& value) {
534 auto it = std::remove(container.begin(), container.end(), value);
535 size_t removed = std::distance(it, container.end());
536 container.erase(it, container.end());
537 return removed;
dyaroshev5f0ff7982017-03-08 01:24:49538}
539
540template <class T, class Allocator, class Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43541size_t EraseIf(std::deque<T, Allocator>& container, Predicate pred) {
542 auto it = std::remove_if(container.begin(), container.end(), pred);
543 size_t removed = std::distance(it, container.end());
544 container.erase(it, container.end());
545 return removed;
dyaroshev5f0ff7982017-03-08 01:24:49546}
547
548template <class T, class Allocator, class Value>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43549size_t Erase(std::vector<T, Allocator>& container, const Value& value) {
550 auto it = std::remove(container.begin(), container.end(), value);
551 size_t removed = std::distance(it, container.end());
552 container.erase(it, container.end());
553 return removed;
dyaroshev5f0ff7982017-03-08 01:24:49554}
555
556template <class T, class Allocator, class Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43557size_t EraseIf(std::vector<T, Allocator>& container, Predicate pred) {
558 auto it = std::remove_if(container.begin(), container.end(), pred);
559 size_t removed = std::distance(it, container.end());
560 container.erase(it, container.end());
561 return removed;
dyaroshev5f0ff7982017-03-08 01:24:49562}
563
dyaroshev5f0ff7982017-03-08 01:24:49564template <class T, class Allocator, class Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43565size_t EraseIf(std::forward_list<T, Allocator>& container, Predicate pred) {
566 // Note: std::forward_list does not have a size() API, thus we need to use the
567 // O(n) std::distance work-around. However, given that EraseIf is O(n)
568 // already, this should not make a big difference.
569 size_t old_size = std::distance(container.begin(), container.end());
dyaroshev5f0ff7982017-03-08 01:24:49570 container.remove_if(pred);
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43571 return old_size - std::distance(container.begin(), container.end());
dyaroshev5f0ff7982017-03-08 01:24:49572}
573
dyaroshev5f0ff7982017-03-08 01:24:49574template <class T, class Allocator, class Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43575size_t EraseIf(std::list<T, Allocator>& container, Predicate pred) {
576 size_t old_size = container.size();
dyaroshev5f0ff7982017-03-08 01:24:49577 container.remove_if(pred);
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43578 return old_size - container.size();
dyaroshev5f0ff7982017-03-08 01:24:49579}
580
jdoerrie5dd3a2132017-03-13 15:31:10581template <class Key, class T, class Compare, class Allocator, class Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43582size_t EraseIf(std::map<Key, T, Compare, Allocator>& container,
583 Predicate pred) {
584 return internal::IterateAndEraseIf(container, pred);
dyaroshev5f0ff7982017-03-08 01:24:49585}
586
jdoerrie5dd3a2132017-03-13 15:31:10587template <class Key, class T, class Compare, class Allocator, class Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43588size_t EraseIf(std::multimap<Key, T, Compare, Allocator>& container,
589 Predicate pred) {
590 return internal::IterateAndEraseIf(container, pred);
dyaroshev5f0ff7982017-03-08 01:24:49591}
592
jdoerrie5dd3a2132017-03-13 15:31:10593template <class Key, class Compare, class Allocator, class Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43594size_t EraseIf(std::set<Key, Compare, Allocator>& container, Predicate pred) {
595 return internal::IterateAndEraseIf(container, pred);
dyaroshev5f0ff7982017-03-08 01:24:49596}
597
jdoerrie5dd3a2132017-03-13 15:31:10598template <class Key, class Compare, class Allocator, class Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43599size_t EraseIf(std::multiset<Key, Compare, Allocator>& container,
600 Predicate pred) {
601 return internal::IterateAndEraseIf(container, pred);
dyaroshev5f0ff7982017-03-08 01:24:49602}
603
jdoerrie5dd3a2132017-03-13 15:31:10604template <class Key,
605 class T,
606 class Hash,
607 class KeyEqual,
608 class Allocator,
609 class Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43610size_t EraseIf(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& container,
611 Predicate pred) {
612 return internal::IterateAndEraseIf(container, pred);
dyaroshev5f0ff7982017-03-08 01:24:49613}
614
jdoerrie5dd3a2132017-03-13 15:31:10615template <class Key,
616 class T,
617 class Hash,
618 class KeyEqual,
619 class Allocator,
620 class Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43621size_t EraseIf(
jdoerrie5dd3a2132017-03-13 15:31:10622 std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& container,
623 Predicate pred) {
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43624 return internal::IterateAndEraseIf(container, pred);
dyaroshev5f0ff7982017-03-08 01:24:49625}
626
jdoerrie5dd3a2132017-03-13 15:31:10627template <class Key,
628 class Hash,
629 class KeyEqual,
630 class Allocator,
631 class Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43632size_t EraseIf(std::unordered_set<Key, Hash, KeyEqual, Allocator>& container,
633 Predicate pred) {
634 return internal::IterateAndEraseIf(container, pred);
dyaroshev5f0ff7982017-03-08 01:24:49635}
636
jdoerrie5dd3a2132017-03-13 15:31:10637template <class Key,
638 class Hash,
639 class KeyEqual,
640 class Allocator,
641 class Predicate>
Jan Wilken Doerrieaf2a0d592020-02-27 10:36:43642size_t EraseIf(
643 std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& container,
644 Predicate pred) {
645 return internal::IterateAndEraseIf(container, pred);
dyaroshev5f0ff7982017-03-08 01:24:49646}
647
Maksim Sisov94461cb2020-06-12 12:48:07648template <class T, class Allocator, class Value>
649size_t Erase(std::forward_list<T, Allocator>& container, const Value& value) {
650 // Unlike std::forward_list::remove, this function template accepts
651 // heterogeneous types and does not force a conversion to the container's
652 // value type before invoking the == operator.
653 return EraseIf(container, [&](const T& cur) { return cur == value; });
654}
655
656template <class T, class Allocator, class Value>
657size_t Erase(std::list<T, Allocator>& container, const Value& value) {
658 // Unlike std::list::remove, this function template accepts heterogeneous
659 // types and does not force a conversion to the container's value type before
660 // invoking the == operator.
661 return EraseIf(container, [&](const T& cur) { return cur == value; });
662}
663
Kevin Bailey156ff6d2017-10-26 17:36:00664// A helper class to be used as the predicate with |EraseIf| to implement
665// in-place set intersection. Helps implement the algorithm of going through
666// each container an element at a time, erasing elements from the first
667// container if they aren't in the second container. Requires each container be
668// sorted. Note that the logic below appears inverted since it is returning
669// whether an element should be erased.
670template <class Collection>
671class IsNotIn {
672 public:
673 explicit IsNotIn(const Collection& collection)
674 : i_(collection.begin()), end_(collection.end()) {}
675
676 bool operator()(const typename Collection::value_type& x) {
677 while (i_ != end_ && *i_ < x)
678 ++i_;
679 if (i_ == end_)
680 return true;
681 if (*i_ == x) {
682 ++i_;
683 return false;
684 }
685 return true;
686 }
687
688 private:
689 typename Collection::const_iterator i_;
690 const typename Collection::const_iterator end_;
691};
692
Philip Rogers3f67719f2018-03-09 02:16:44693// Helper for returning the optional value's address, or nullptr.
694template <class T>
695T* OptionalOrNullptr(base::Optional<T>& optional) {
696 return optional.has_value() ? &optional.value() : nullptr;
697}
698
699template <class T>
700const T* OptionalOrNullptr(const base::Optional<T>& optional) {
701 return optional.has_value() ? &optional.value() : nullptr;
702}
703
[email protected]1dea7572012-12-05 21:40:27704} // namespace base
705
[email protected]7286e3fc2011-07-19 22:13:24706#endif // BASE_STL_UTIL_H_