blob: 83d86ad90d24d136bebd46dc02617eea5ec7e438 [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
34// Calls erase on iterators of matching elements.
35template <typename Container, typename Predicate>
36void IterateAndEraseIf(Container& container, Predicate pred) {
37 for (auto it = container.begin(); it != container.end();) {
38 if (pred(*it))
39 it = container.erase(it);
40 else
41 ++it;
42 }
43}
44
jdoerrie2de200e42019-06-04 09:11:0745template <typename Iter>
46constexpr bool IsRandomAccessIter =
47 std::is_same<typename std::iterator_traits<Iter>::iterator_category,
48 std::random_access_iterator_tag>::value;
49
jdoerrieb77149f2019-06-05 10:46:4950// Utility type traits used for specializing base::Contains() below.
51template <typename Container, typename Element, typename = void>
52struct HasFindWithNpos : std::false_type {};
53
54template <typename Container, typename Element>
55struct HasFindWithNpos<
56 Container,
57 Element,
58 void_t<decltype(std::declval<const Container&>().find(
59 std::declval<const Element&>()) != Container::npos)>>
60 : std::true_type {};
61
62template <typename Container, typename Element, typename = void>
63struct HasFindWithEnd : std::false_type {};
64
65template <typename Container, typename Element>
66struct HasFindWithEnd<Container,
67 Element,
68 void_t<decltype(std::declval<const Container&>().find(
69 std::declval<const Element&>()) !=
70 std::declval<const Container&>().end())>>
71 : std::true_type {};
72
73template <typename Container, typename Element, typename = void>
74struct HasContains : std::false_type {};
75
76template <typename Container, typename Element>
77struct HasContains<Container,
78 Element,
79 void_t<decltype(std::declval<const Container&>().contains(
80 std::declval<const Element&>()))>> : std::true_type {};
81
dyaroshev5f0ff7982017-03-08 01:24:4982} // namespace internal
83
jdoerrie8f516042018-04-13 09:40:3084// C++14 implementation of C++17's std::size():
85// http://en.cppreference.com/w/cpp/iterator/size
86template <typename Container>
87constexpr auto size(const Container& c) -> decltype(c.size()) {
88 return c.size();
89}
90
91template <typename T, size_t N>
92constexpr size_t size(const T (&array)[N]) noexcept {
93 return N;
94}
95
96// C++14 implementation of C++17's std::empty():
97// http://en.cppreference.com/w/cpp/iterator/empty
98template <typename Container>
99constexpr auto empty(const Container& c) -> decltype(c.empty()) {
100 return c.empty();
101}
102
103template <typename T, size_t N>
104constexpr bool empty(const T (&array)[N]) noexcept {
105 return false;
106}
107
108template <typename T>
109constexpr bool empty(std::initializer_list<T> il) noexcept {
110 return il.size() == 0;
111}
112
113// C++14 implementation of C++17's std::data():
114// http://en.cppreference.com/w/cpp/iterator/data
115template <typename Container>
116constexpr auto data(Container& c) -> decltype(c.data()) {
117 return c.data();
118}
119
120// std::basic_string::data() had no mutable overload prior to C++17 [1].
121// Hence this overload is provided.
122// Note: str[0] is safe even for empty strings, as they are guaranteed to be
123// null-terminated [2].
124//
125// [1] http://en.cppreference.com/w/cpp/string/basic_string/data
126// [2] http://en.cppreference.com/w/cpp/string/basic_string/operator_at
127template <typename CharT, typename Traits, typename Allocator>
128CharT* data(std::basic_string<CharT, Traits, Allocator>& str) {
129 return std::addressof(str[0]);
130}
131
132template <typename Container>
133constexpr auto data(const Container& c) -> decltype(c.data()) {
134 return c.data();
135}
136
137template <typename T, size_t N>
138constexpr T* data(T (&array)[N]) noexcept {
139 return array;
140}
141
142template <typename T>
143constexpr const T* data(std::initializer_list<T> il) noexcept {
144 return il.begin();
145}
146
Jan Wilken Dörrie6c2032812019-11-13 03:32:19147// std::array::data() was not constexpr prior to C++17 [1].
148// Hence these overloads are provided.
149//
150// [1] https://en.cppreference.com/w/cpp/container/array/data
151template <typename T, size_t N>
152constexpr T* data(std::array<T, N>& array) noexcept {
153 return !array.empty() ? &array[0] : nullptr;
154}
155
156template <typename T, size_t N>
157constexpr const T* data(const std::array<T, N>& array) noexcept {
158 return !array.empty() ? &array[0] : nullptr;
159}
160
Jan Wilken Dörrie9b751f02019-11-26 06:52:06161// C++14 implementation of C++17's std::as_const():
162// https://en.cppreference.com/w/cpp/utility/as_const
163template <typename T>
164constexpr std::add_const_t<T>& as_const(T& t) noexcept {
165 return t;
166}
167
168template <typename T>
169void as_const(const T&& t) = delete;
170
Dan Sanders97c13742018-05-17 23:12:32171// Returns a const reference to the underlying container of a container adapter.
172// Works for std::priority_queue, std::queue, and std::stack.
173template <class A>
174const typename A::container_type& GetUnderlyingContainer(const A& adapter) {
175 struct ExposedAdapter : A {
176 using A::c;
177 };
178 return adapter.*&ExposedAdapter::c;
179}
180
[email protected]6ee951a2012-06-26 17:24:05181// Clears internal memory of an STL object.
[email protected]7286e3fc2011-07-19 22:13:24182// STL clear()/reserve(0) does not always free internal memory allocated
183// This function uses swap/destructor to ensure the internal memory is freed.
[email protected]6ee951a2012-06-26 17:24:05184template<class T>
185void STLClearObject(T* obj) {
[email protected]7286e3fc2011-07-19 22:13:24186 T tmp;
187 tmp.swap(*obj);
188 // Sometimes "T tmp" allocates objects with memory (arena implementation?).
189 // Hence using additional reserve(0) even if it doesn't always work.
190 obj->reserve(0);
191}
192
robliao43eb02c2015-03-27 18:25:11193// Counts the number of instances of val in a container.
194template <typename Container, typename T>
195typename std::iterator_traits<
196 typename Container::const_iterator>::difference_type
197STLCount(const Container& container, const T& val) {
198 return std::count(container.begin(), container.end(), val);
199}
200
jdoerrieb77149f2019-06-05 10:46:49201// General purpose implementation to check if |container| contains |value|.
202template <typename Container,
203 typename Value,
204 std::enable_if_t<
205 !internal::HasFindWithNpos<Container, Value>::value &&
206 !internal::HasFindWithEnd<Container, Value>::value &&
207 !internal::HasContains<Container, Value>::value>* = nullptr>
208bool Contains(const Container& container, const Value& value) {
209 using std::begin;
210 using std::end;
211 return std::find(begin(container), end(container), value) != end(container);
212}
213
214// Specialized Contains() implementation for when |container| has a find()
215// member function and a static npos member, but no contains() member function.
216template <typename Container,
217 typename Value,
218 std::enable_if_t<internal::HasFindWithNpos<Container, Value>::value &&
219 !internal::HasContains<Container, Value>::value>* =
220 nullptr>
221bool Contains(const Container& container, const Value& value) {
222 return container.find(value) != Container::npos;
223}
224
225// Specialized Contains() implementation for when |container| has a find()
226// and end() member function, but no contains() member function.
227template <typename Container,
228 typename Value,
229 std::enable_if_t<internal::HasFindWithEnd<Container, Value>::value &&
230 !internal::HasContains<Container, Value>::value>* =
231 nullptr>
232bool Contains(const Container& container, const Value& value) {
233 return container.find(value) != container.end();
234}
235
236// Specialized Contains() implementation for when |container| has a contains()
237// member function.
238template <
239 typename Container,
240 typename Value,
241 std::enable_if_t<internal::HasContains<Container, Value>::value>* = nullptr>
242bool Contains(const Container& container, const Value& value) {
243 return container.contains(value);
244}
245
jdoerrie2de200e42019-06-04 09:11:07246// O(1) implementation of const casting an iterator for any sequence,
247// associative or unordered associative container in the STL.
248//
249// Reference: https://stackoverflow.com/a/10669041
250template <typename Container,
251 typename ConstIter,
252 std::enable_if_t<!internal::IsRandomAccessIter<ConstIter>>* = nullptr>
253constexpr auto ConstCastIterator(Container& c, ConstIter it) {
254 return c.erase(it, it);
255}
256
Jan Wilken Dörrie894226d2019-06-13 07:53:15257// Explicit overload for std::forward_list where erase() is named erase_after().
jdoerrie2de200e42019-06-04 09:11:07258template <typename T, typename Allocator>
259constexpr auto ConstCastIterator(
260 std::forward_list<T, Allocator>& c,
261 typename std::forward_list<T, Allocator>::const_iterator it) {
Jan Wilken Dörrie894226d2019-06-13 07:53:15262// The erase_after(it, it) trick used below does not work for libstdc++ [1],
263// thus we need a different way.
264// TODO(crbug.com/972541): Remove this workaround once libstdc++ is fixed on all
265// platforms.
266//
267// [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90857
268#if defined(__GLIBCXX__)
269 return c.insert_after(it, {});
270#else
jdoerrie2de200e42019-06-04 09:11:07271 return c.erase_after(it, it);
Jan Wilken Dörrie894226d2019-06-13 07:53:15272#endif
jdoerrie2de200e42019-06-04 09:11:07273}
274
275// Specialized O(1) const casting for random access iterators. This is
276// necessary, because erase() is either not available (e.g. array-like
277// containers), or has O(n) complexity (e.g. std::deque or std::vector).
278template <typename Container,
279 typename ConstIter,
280 std::enable_if_t<internal::IsRandomAccessIter<ConstIter>>* = nullptr>
281constexpr auto ConstCastIterator(Container& c, ConstIter it) {
282 using std::begin;
283 using std::cbegin;
284 return begin(c) + (it - cbegin(c));
285}
286
Marijn Kruisselbrinkbb019e32017-06-27 20:50:32287namespace internal {
288
jdoerrie2de200e42019-06-04 09:11:07289template <typename Map, typename Key, typename Value>
290std::pair<typename Map::iterator, bool> InsertOrAssignImpl(Map& map,
291 Key&& key,
292 Value&& value) {
293 auto lower = map.lower_bound(key);
294 if (lower != map.end() && !map.key_comp()(key, lower->first)) {
295 // key already exists, perform assignment.
296 lower->second = std::forward<Value>(value);
297 return {lower, false};
298 }
299
300 // key did not yet exist, insert it.
301 return {map.emplace_hint(lower, std::forward<Key>(key),
302 std::forward<Value>(value)),
303 true};
304}
305
306template <typename Map, typename Key, typename Value>
307typename Map::iterator InsertOrAssignImpl(Map& map,
308 typename Map::const_iterator hint,
309 Key&& key,
310 Value&& value) {
311 auto&& key_comp = map.key_comp();
312 if ((hint == map.begin() || key_comp(std::prev(hint)->first, key))) {
313 if (hint == map.end() || key_comp(key, hint->first)) {
314 // *(hint - 1) < key < *hint => key did not exist and hint is correct.
315 return map.emplace_hint(hint, std::forward<Key>(key),
316 std::forward<Value>(value));
317 }
318
319 if (!key_comp(hint->first, key)) {
320 // key == *hint => key already exists and hint is correct.
321 auto mutable_hint = ConstCastIterator(map, hint);
322 mutable_hint->second = std::forward<Value>(value);
323 return mutable_hint;
324 }
325 }
326
327 // hint was not helpful, dispatch to hintless version.
328 return InsertOrAssignImpl(map, std::forward<Key>(key),
329 std::forward<Value>(value))
330 .first;
331}
332
333template <typename Map, typename Key, typename... Args>
334std::pair<typename Map::iterator, bool> TryEmplaceImpl(Map& map,
335 Key&& key,
336 Args&&... args) {
337 auto lower = map.lower_bound(key);
338 if (lower != map.end() && !map.key_comp()(key, lower->first)) {
339 // key already exists, do nothing.
340 return {lower, false};
341 }
342
343 // key did not yet exist, insert it.
344 return {map.emplace_hint(lower, std::piecewise_construct,
345 std::forward_as_tuple(std::forward<Key>(key)),
346 std::forward_as_tuple(std::forward<Args>(args)...)),
347 true};
348}
349
350template <typename Map, typename Key, typename... Args>
351typename Map::iterator TryEmplaceImpl(Map& map,
352 typename Map::const_iterator hint,
353 Key&& key,
354 Args&&... args) {
355 auto&& key_comp = map.key_comp();
356 if ((hint == map.begin() || key_comp(std::prev(hint)->first, key))) {
357 if (hint == map.end() || key_comp(key, hint->first)) {
358 // *(hint - 1) < key < *hint => key did not exist and hint is correct.
359 return map.emplace_hint(
360 hint, std::piecewise_construct,
361 std::forward_as_tuple(std::forward<Key>(key)),
362 std::forward_as_tuple(std::forward<Args>(args)...));
363 }
364
365 if (!key_comp(hint->first, key)) {
366 // key == *hint => no-op, return correct hint.
367 return ConstCastIterator(map, hint);
368 }
369 }
370
371 // hint was not helpful, dispatch to hintless version.
372 return TryEmplaceImpl(map, std::forward<Key>(key),
373 std::forward<Args>(args)...)
374 .first;
375}
376
Marijn Kruisselbrinkbb019e32017-06-27 20:50:32377} // namespace internal
378
jdoerrie2de200e42019-06-04 09:11:07379// Implementation of C++17's std::map::insert_or_assign as a free function.
380template <typename Map, typename Value>
381std::pair<typename Map::iterator, bool>
382InsertOrAssign(Map& map, const typename Map::key_type& key, Value&& value) {
383 return internal::InsertOrAssignImpl(map, key, std::forward<Value>(value));
384}
385
386template <typename Map, typename Value>
387std::pair<typename Map::iterator, bool>
388InsertOrAssign(Map& map, typename Map::key_type&& key, Value&& value) {
389 return internal::InsertOrAssignImpl(map, std::move(key),
390 std::forward<Value>(value));
391}
392
393// Implementation of C++17's std::map::insert_or_assign with hint as a free
394// function.
395template <typename Map, typename Value>
396typename Map::iterator InsertOrAssign(Map& map,
397 typename Map::const_iterator hint,
398 const typename Map::key_type& key,
399 Value&& value) {
400 return internal::InsertOrAssignImpl(map, hint, key,
401 std::forward<Value>(value));
402}
403
404template <typename Map, typename Value>
405typename Map::iterator InsertOrAssign(Map& map,
406 typename Map::const_iterator hint,
407 typename Map::key_type&& key,
408 Value&& value) {
409 return internal::InsertOrAssignImpl(map, hint, std::move(key),
410 std::forward<Value>(value));
411}
412
413// Implementation of C++17's std::map::try_emplace as a free function.
414template <typename Map, typename... Args>
415std::pair<typename Map::iterator, bool>
416TryEmplace(Map& map, const typename Map::key_type& key, Args&&... args) {
417 return internal::TryEmplaceImpl(map, key, std::forward<Args>(args)...);
418}
419
420template <typename Map, typename... Args>
421std::pair<typename Map::iterator, bool> TryEmplace(Map& map,
422 typename Map::key_type&& key,
423 Args&&... args) {
424 return internal::TryEmplaceImpl(map, std::move(key),
425 std::forward<Args>(args)...);
426}
427
428// Implementation of C++17's std::map::try_emplace with hint as a free
429// function.
430template <typename Map, typename... Args>
431typename Map::iterator TryEmplace(Map& map,
432 typename Map::const_iterator hint,
433 const typename Map::key_type& key,
434 Args&&... args) {
435 return internal::TryEmplaceImpl(map, hint, key, std::forward<Args>(args)...);
436}
437
438template <typename Map, typename... Args>
439typename Map::iterator TryEmplace(Map& map,
440 typename Map::const_iterator hint,
441 typename Map::key_type&& key,
442 Args&&... args) {
443 return internal::TryEmplaceImpl(map, hint, std::move(key),
444 std::forward<Args>(args)...);
445}
446
[email protected]1dea7572012-12-05 21:40:27447// Returns true if the container is sorted.
448template <typename Container>
449bool STLIsSorted(const Container& cont) {
jdoerrie2fc218a2018-08-07 09:23:25450 return std::is_sorted(std::begin(cont), std::end(cont));
[email protected]1dea7572012-12-05 21:40:27451}
452
453// Returns a new ResultType containing the difference of two sorted containers.
454template <typename ResultType, typename Arg1, typename Arg2>
455ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
456 DCHECK(STLIsSorted(a1));
457 DCHECK(STLIsSorted(a2));
458 ResultType difference;
459 std::set_difference(a1.begin(), a1.end(),
460 a2.begin(), a2.end(),
461 std::inserter(difference, difference.end()));
462 return difference;
463}
464
[email protected]9a53ade2014-01-29 17:13:27465// Returns a new ResultType containing the union of two sorted containers.
466template <typename ResultType, typename Arg1, typename Arg2>
467ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
468 DCHECK(STLIsSorted(a1));
469 DCHECK(STLIsSorted(a2));
470 ResultType result;
471 std::set_union(a1.begin(), a1.end(),
472 a2.begin(), a2.end(),
473 std::inserter(result, result.end()));
474 return result;
475}
476
477// Returns a new ResultType containing the intersection of two sorted
478// containers.
479template <typename ResultType, typename Arg1, typename Arg2>
480ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
481 DCHECK(STLIsSorted(a1));
482 DCHECK(STLIsSorted(a2));
483 ResultType result;
484 std::set_intersection(a1.begin(), a1.end(),
485 a2.begin(), a2.end(),
486 std::inserter(result, result.end()));
487 return result;
488}
489
490// Returns true if the sorted container |a1| contains all elements of the sorted
491// container |a2|.
492template <typename Arg1, typename Arg2>
493bool STLIncludes(const Arg1& a1, const Arg2& a2) {
494 DCHECK(STLIsSorted(a1));
495 DCHECK(STLIsSorted(a2));
496 return std::includes(a1.begin(), a1.end(),
497 a2.begin(), a2.end());
498}
499
dyaroshev5f0ff7982017-03-08 01:24:49500// Erase/EraseIf are based on library fundamentals ts v2 erase/erase_if
501// http://en.cppreference.com/w/cpp/experimental/lib_extensions_2
502// They provide a generic way to erase elements from a container.
503// The functions here implement these for the standard containers until those
504// functions are available in the C++ standard.
505// For Chromium containers overloads should be defined in their own headers
506// (like standard containers).
507// Note: there is no std::erase for standard associative containers so we don't
508// have it either.
509
510template <typename CharT, typename Traits, typename Allocator, typename Value>
511void Erase(std::basic_string<CharT, Traits, Allocator>& container,
512 const Value& value) {
513 container.erase(std::remove(container.begin(), container.end(), value),
514 container.end());
515}
516
517template <typename CharT, typename Traits, typename Allocator, class Predicate>
518void EraseIf(std::basic_string<CharT, Traits, Allocator>& container,
519 Predicate pred) {
520 container.erase(std::remove_if(container.begin(), container.end(), pred),
521 container.end());
522}
523
524template <class T, class Allocator, class Value>
525void Erase(std::deque<T, Allocator>& container, const Value& value) {
526 container.erase(std::remove(container.begin(), container.end(), value),
527 container.end());
528}
529
530template <class T, class Allocator, class Predicate>
531void EraseIf(std::deque<T, Allocator>& container, Predicate pred) {
532 container.erase(std::remove_if(container.begin(), container.end(), pred),
533 container.end());
534}
535
536template <class T, class Allocator, class Value>
537void Erase(std::vector<T, Allocator>& container, const Value& value) {
538 container.erase(std::remove(container.begin(), container.end(), value),
539 container.end());
540}
541
542template <class T, class Allocator, class Predicate>
543void EraseIf(std::vector<T, Allocator>& container, Predicate pred) {
544 container.erase(std::remove_if(container.begin(), container.end(), pred),
545 container.end());
546}
547
548template <class T, class Allocator, class Value>
549void Erase(std::forward_list<T, Allocator>& container, const Value& value) {
550 // Unlike std::forward_list::remove, this function template accepts
551 // heterogeneous types and does not force a conversion to the container's
552 // value type before invoking the == operator.
553 container.remove_if([&](const T& cur) { return cur == value; });
554}
555
556template <class T, class Allocator, class Predicate>
557void EraseIf(std::forward_list<T, Allocator>& container, Predicate pred) {
558 container.remove_if(pred);
559}
560
561template <class T, class Allocator, class Value>
562void Erase(std::list<T, Allocator>& container, const Value& value) {
563 // Unlike std::list::remove, this function template accepts heterogeneous
564 // types and does not force a conversion to the container's value type before
565 // invoking the == operator.
566 container.remove_if([&](const T& cur) { return cur == value; });
567}
568
569template <class T, class Allocator, class Predicate>
570void EraseIf(std::list<T, Allocator>& container, Predicate pred) {
571 container.remove_if(pred);
572}
573
jdoerrie5dd3a2132017-03-13 15:31:10574template <class Key, class T, class Compare, class Allocator, class Predicate>
575void EraseIf(std::map<Key, T, Compare, Allocator>& container, Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49576 internal::IterateAndEraseIf(container, pred);
577}
578
jdoerrie5dd3a2132017-03-13 15:31:10579template <class Key, class T, class Compare, class Allocator, class Predicate>
580void EraseIf(std::multimap<Key, T, Compare, Allocator>& container,
581 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49582 internal::IterateAndEraseIf(container, pred);
583}
584
jdoerrie5dd3a2132017-03-13 15:31:10585template <class Key, class Compare, class Allocator, class Predicate>
586void EraseIf(std::set<Key, Compare, Allocator>& container, Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49587 internal::IterateAndEraseIf(container, pred);
588}
589
jdoerrie5dd3a2132017-03-13 15:31:10590template <class Key, class Compare, class Allocator, class Predicate>
591void EraseIf(std::multiset<Key, Compare, Allocator>& container,
592 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49593 internal::IterateAndEraseIf(container, pred);
594}
595
jdoerrie5dd3a2132017-03-13 15:31:10596template <class Key,
597 class T,
598 class Hash,
599 class KeyEqual,
600 class Allocator,
601 class Predicate>
602void EraseIf(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& container,
603 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49604 internal::IterateAndEraseIf(container, pred);
605}
606
jdoerrie5dd3a2132017-03-13 15:31:10607template <class Key,
608 class T,
609 class Hash,
610 class KeyEqual,
611 class Allocator,
612 class Predicate>
613void EraseIf(
614 std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& container,
615 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49616 internal::IterateAndEraseIf(container, pred);
617}
618
jdoerrie5dd3a2132017-03-13 15:31:10619template <class Key,
620 class Hash,
621 class KeyEqual,
622 class Allocator,
623 class Predicate>
624void EraseIf(std::unordered_set<Key, Hash, KeyEqual, Allocator>& container,
625 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49626 internal::IterateAndEraseIf(container, pred);
627}
628
jdoerrie5dd3a2132017-03-13 15:31:10629template <class Key,
630 class Hash,
631 class KeyEqual,
632 class Allocator,
633 class Predicate>
634void EraseIf(std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& container,
635 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49636 internal::IterateAndEraseIf(container, pred);
637}
638
Kevin Bailey156ff6d2017-10-26 17:36:00639// A helper class to be used as the predicate with |EraseIf| to implement
640// in-place set intersection. Helps implement the algorithm of going through
641// each container an element at a time, erasing elements from the first
642// container if they aren't in the second container. Requires each container be
643// sorted. Note that the logic below appears inverted since it is returning
644// whether an element should be erased.
645template <class Collection>
646class IsNotIn {
647 public:
648 explicit IsNotIn(const Collection& collection)
649 : i_(collection.begin()), end_(collection.end()) {}
650
651 bool operator()(const typename Collection::value_type& x) {
652 while (i_ != end_ && *i_ < x)
653 ++i_;
654 if (i_ == end_)
655 return true;
656 if (*i_ == x) {
657 ++i_;
658 return false;
659 }
660 return true;
661 }
662
663 private:
664 typename Collection::const_iterator i_;
665 const typename Collection::const_iterator end_;
666};
667
Philip Rogers3f67719f2018-03-09 02:16:44668// Helper for returning the optional value's address, or nullptr.
669template <class T>
670T* OptionalOrNullptr(base::Optional<T>& optional) {
671 return optional.has_value() ? &optional.value() : nullptr;
672}
673
674template <class T>
675const T* OptionalOrNullptr(const base::Optional<T>& optional) {
676 return optional.has_value() ? &optional.value() : nullptr;
677}
678
[email protected]1dea7572012-12-05 21:40:27679} // namespace base
680
[email protected]7286e3fc2011-07-19 22:13:24681#endif // BASE_STL_UTIL_H_