blob: e22b029157d8fef40b4f71c1bd02cd457f916969 [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
Dan Sanders97c13742018-05-17 23:12:32147// Returns a const reference to the underlying container of a container adapter.
148// Works for std::priority_queue, std::queue, and std::stack.
149template <class A>
150const typename A::container_type& GetUnderlyingContainer(const A& adapter) {
151 struct ExposedAdapter : A {
152 using A::c;
153 };
154 return adapter.*&ExposedAdapter::c;
155}
156
[email protected]6ee951a2012-06-26 17:24:05157// Clears internal memory of an STL object.
[email protected]7286e3fc2011-07-19 22:13:24158// STL clear()/reserve(0) does not always free internal memory allocated
159// This function uses swap/destructor to ensure the internal memory is freed.
[email protected]6ee951a2012-06-26 17:24:05160template<class T>
161void STLClearObject(T* obj) {
[email protected]7286e3fc2011-07-19 22:13:24162 T tmp;
163 tmp.swap(*obj);
164 // Sometimes "T tmp" allocates objects with memory (arena implementation?).
165 // Hence using additional reserve(0) even if it doesn't always work.
166 obj->reserve(0);
167}
168
robliao43eb02c2015-03-27 18:25:11169// Counts the number of instances of val in a container.
170template <typename Container, typename T>
171typename std::iterator_traits<
172 typename Container::const_iterator>::difference_type
173STLCount(const Container& container, const T& val) {
174 return std::count(container.begin(), container.end(), val);
175}
176
jdoerrieb77149f2019-06-05 10:46:49177// General purpose implementation to check if |container| contains |value|.
178template <typename Container,
179 typename Value,
180 std::enable_if_t<
181 !internal::HasFindWithNpos<Container, Value>::value &&
182 !internal::HasFindWithEnd<Container, Value>::value &&
183 !internal::HasContains<Container, Value>::value>* = nullptr>
184bool Contains(const Container& container, const Value& value) {
185 using std::begin;
186 using std::end;
187 return std::find(begin(container), end(container), value) != end(container);
188}
189
190// Specialized Contains() implementation for when |container| has a find()
191// member function and a static npos member, but no contains() member function.
192template <typename Container,
193 typename Value,
194 std::enable_if_t<internal::HasFindWithNpos<Container, Value>::value &&
195 !internal::HasContains<Container, Value>::value>* =
196 nullptr>
197bool Contains(const Container& container, const Value& value) {
198 return container.find(value) != Container::npos;
199}
200
201// Specialized Contains() implementation for when |container| has a find()
202// and end() member function, but no contains() member function.
203template <typename Container,
204 typename Value,
205 std::enable_if_t<internal::HasFindWithEnd<Container, Value>::value &&
206 !internal::HasContains<Container, Value>::value>* =
207 nullptr>
208bool Contains(const Container& container, const Value& value) {
209 return container.find(value) != container.end();
210}
211
212// Specialized Contains() implementation for when |container| has a contains()
213// member function.
214template <
215 typename Container,
216 typename Value,
217 std::enable_if_t<internal::HasContains<Container, Value>::value>* = nullptr>
218bool Contains(const Container& container, const Value& value) {
219 return container.contains(value);
220}
221
jdoerrie2de200e42019-06-04 09:11:07222// O(1) implementation of const casting an iterator for any sequence,
223// associative or unordered associative container in the STL.
224//
225// Reference: https://stackoverflow.com/a/10669041
226template <typename Container,
227 typename ConstIter,
228 std::enable_if_t<!internal::IsRandomAccessIter<ConstIter>>* = nullptr>
229constexpr auto ConstCastIterator(Container& c, ConstIter it) {
230 return c.erase(it, it);
231}
232
Jan Wilken Dörrie894226d2019-06-13 07:53:15233// Explicit overload for std::forward_list where erase() is named erase_after().
jdoerrie2de200e42019-06-04 09:11:07234template <typename T, typename Allocator>
235constexpr auto ConstCastIterator(
236 std::forward_list<T, Allocator>& c,
237 typename std::forward_list<T, Allocator>::const_iterator it) {
Jan Wilken Dörrie894226d2019-06-13 07:53:15238// The erase_after(it, it) trick used below does not work for libstdc++ [1],
239// thus we need a different way.
240// TODO(crbug.com/972541): Remove this workaround once libstdc++ is fixed on all
241// platforms.
242//
243// [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90857
244#if defined(__GLIBCXX__)
245 return c.insert_after(it, {});
246#else
jdoerrie2de200e42019-06-04 09:11:07247 return c.erase_after(it, it);
Jan Wilken Dörrie894226d2019-06-13 07:53:15248#endif
jdoerrie2de200e42019-06-04 09:11:07249}
250
251// Specialized O(1) const casting for random access iterators. This is
252// necessary, because erase() is either not available (e.g. array-like
253// containers), or has O(n) complexity (e.g. std::deque or std::vector).
254template <typename Container,
255 typename ConstIter,
256 std::enable_if_t<internal::IsRandomAccessIter<ConstIter>>* = nullptr>
257constexpr auto ConstCastIterator(Container& c, ConstIter it) {
258 using std::begin;
259 using std::cbegin;
260 return begin(c) + (it - cbegin(c));
261}
262
Marijn Kruisselbrinkbb019e32017-06-27 20:50:32263namespace internal {
264
jdoerrie2de200e42019-06-04 09:11:07265template <typename Map, typename Key, typename Value>
266std::pair<typename Map::iterator, bool> InsertOrAssignImpl(Map& map,
267 Key&& key,
268 Value&& value) {
269 auto lower = map.lower_bound(key);
270 if (lower != map.end() && !map.key_comp()(key, lower->first)) {
271 // key already exists, perform assignment.
272 lower->second = std::forward<Value>(value);
273 return {lower, false};
274 }
275
276 // key did not yet exist, insert it.
277 return {map.emplace_hint(lower, std::forward<Key>(key),
278 std::forward<Value>(value)),
279 true};
280}
281
282template <typename Map, typename Key, typename Value>
283typename Map::iterator InsertOrAssignImpl(Map& map,
284 typename Map::const_iterator hint,
285 Key&& key,
286 Value&& value) {
287 auto&& key_comp = map.key_comp();
288 if ((hint == map.begin() || key_comp(std::prev(hint)->first, key))) {
289 if (hint == map.end() || key_comp(key, hint->first)) {
290 // *(hint - 1) < key < *hint => key did not exist and hint is correct.
291 return map.emplace_hint(hint, std::forward<Key>(key),
292 std::forward<Value>(value));
293 }
294
295 if (!key_comp(hint->first, key)) {
296 // key == *hint => key already exists and hint is correct.
297 auto mutable_hint = ConstCastIterator(map, hint);
298 mutable_hint->second = std::forward<Value>(value);
299 return mutable_hint;
300 }
301 }
302
303 // hint was not helpful, dispatch to hintless version.
304 return InsertOrAssignImpl(map, std::forward<Key>(key),
305 std::forward<Value>(value))
306 .first;
307}
308
309template <typename Map, typename Key, typename... Args>
310std::pair<typename Map::iterator, bool> TryEmplaceImpl(Map& map,
311 Key&& key,
312 Args&&... args) {
313 auto lower = map.lower_bound(key);
314 if (lower != map.end() && !map.key_comp()(key, lower->first)) {
315 // key already exists, do nothing.
316 return {lower, false};
317 }
318
319 // key did not yet exist, insert it.
320 return {map.emplace_hint(lower, std::piecewise_construct,
321 std::forward_as_tuple(std::forward<Key>(key)),
322 std::forward_as_tuple(std::forward<Args>(args)...)),
323 true};
324}
325
326template <typename Map, typename Key, typename... Args>
327typename Map::iterator TryEmplaceImpl(Map& map,
328 typename Map::const_iterator hint,
329 Key&& key,
330 Args&&... args) {
331 auto&& key_comp = map.key_comp();
332 if ((hint == map.begin() || key_comp(std::prev(hint)->first, key))) {
333 if (hint == map.end() || key_comp(key, hint->first)) {
334 // *(hint - 1) < key < *hint => key did not exist and hint is correct.
335 return map.emplace_hint(
336 hint, std::piecewise_construct,
337 std::forward_as_tuple(std::forward<Key>(key)),
338 std::forward_as_tuple(std::forward<Args>(args)...));
339 }
340
341 if (!key_comp(hint->first, key)) {
342 // key == *hint => no-op, return correct hint.
343 return ConstCastIterator(map, hint);
344 }
345 }
346
347 // hint was not helpful, dispatch to hintless version.
348 return TryEmplaceImpl(map, std::forward<Key>(key),
349 std::forward<Args>(args)...)
350 .first;
351}
352
Marijn Kruisselbrinkbb019e32017-06-27 20:50:32353} // namespace internal
354
jdoerrie2de200e42019-06-04 09:11:07355// Implementation of C++17's std::map::insert_or_assign as a free function.
356template <typename Map, typename Value>
357std::pair<typename Map::iterator, bool>
358InsertOrAssign(Map& map, const typename Map::key_type& key, Value&& value) {
359 return internal::InsertOrAssignImpl(map, key, std::forward<Value>(value));
360}
361
362template <typename Map, typename Value>
363std::pair<typename Map::iterator, bool>
364InsertOrAssign(Map& map, typename Map::key_type&& key, Value&& value) {
365 return internal::InsertOrAssignImpl(map, std::move(key),
366 std::forward<Value>(value));
367}
368
369// Implementation of C++17's std::map::insert_or_assign with hint as a free
370// function.
371template <typename Map, typename Value>
372typename Map::iterator InsertOrAssign(Map& map,
373 typename Map::const_iterator hint,
374 const typename Map::key_type& key,
375 Value&& value) {
376 return internal::InsertOrAssignImpl(map, hint, key,
377 std::forward<Value>(value));
378}
379
380template <typename Map, typename Value>
381typename Map::iterator InsertOrAssign(Map& map,
382 typename Map::const_iterator hint,
383 typename Map::key_type&& key,
384 Value&& value) {
385 return internal::InsertOrAssignImpl(map, hint, std::move(key),
386 std::forward<Value>(value));
387}
388
389// Implementation of C++17's std::map::try_emplace as a free function.
390template <typename Map, typename... Args>
391std::pair<typename Map::iterator, bool>
392TryEmplace(Map& map, const typename Map::key_type& key, Args&&... args) {
393 return internal::TryEmplaceImpl(map, key, std::forward<Args>(args)...);
394}
395
396template <typename Map, typename... Args>
397std::pair<typename Map::iterator, bool> TryEmplace(Map& map,
398 typename Map::key_type&& key,
399 Args&&... args) {
400 return internal::TryEmplaceImpl(map, std::move(key),
401 std::forward<Args>(args)...);
402}
403
404// Implementation of C++17's std::map::try_emplace with hint as a free
405// function.
406template <typename Map, typename... Args>
407typename Map::iterator TryEmplace(Map& map,
408 typename Map::const_iterator hint,
409 const typename Map::key_type& key,
410 Args&&... args) {
411 return internal::TryEmplaceImpl(map, hint, key, std::forward<Args>(args)...);
412}
413
414template <typename Map, typename... Args>
415typename Map::iterator TryEmplace(Map& map,
416 typename Map::const_iterator hint,
417 typename Map::key_type&& key,
418 Args&&... args) {
419 return internal::TryEmplaceImpl(map, hint, std::move(key),
420 std::forward<Args>(args)...);
421}
422
[email protected]1dea7572012-12-05 21:40:27423// Returns true if the container is sorted.
424template <typename Container>
425bool STLIsSorted(const Container& cont) {
jdoerrie2fc218a2018-08-07 09:23:25426 return std::is_sorted(std::begin(cont), std::end(cont));
[email protected]1dea7572012-12-05 21:40:27427}
428
429// Returns a new ResultType containing the difference of two sorted containers.
430template <typename ResultType, typename Arg1, typename Arg2>
431ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
432 DCHECK(STLIsSorted(a1));
433 DCHECK(STLIsSorted(a2));
434 ResultType difference;
435 std::set_difference(a1.begin(), a1.end(),
436 a2.begin(), a2.end(),
437 std::inserter(difference, difference.end()));
438 return difference;
439}
440
[email protected]9a53ade2014-01-29 17:13:27441// Returns a new ResultType containing the union of two sorted containers.
442template <typename ResultType, typename Arg1, typename Arg2>
443ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
444 DCHECK(STLIsSorted(a1));
445 DCHECK(STLIsSorted(a2));
446 ResultType result;
447 std::set_union(a1.begin(), a1.end(),
448 a2.begin(), a2.end(),
449 std::inserter(result, result.end()));
450 return result;
451}
452
453// Returns a new ResultType containing the intersection of two sorted
454// containers.
455template <typename ResultType, typename Arg1, typename Arg2>
456ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
457 DCHECK(STLIsSorted(a1));
458 DCHECK(STLIsSorted(a2));
459 ResultType result;
460 std::set_intersection(a1.begin(), a1.end(),
461 a2.begin(), a2.end(),
462 std::inserter(result, result.end()));
463 return result;
464}
465
466// Returns true if the sorted container |a1| contains all elements of the sorted
467// container |a2|.
468template <typename Arg1, typename Arg2>
469bool STLIncludes(const Arg1& a1, const Arg2& a2) {
470 DCHECK(STLIsSorted(a1));
471 DCHECK(STLIsSorted(a2));
472 return std::includes(a1.begin(), a1.end(),
473 a2.begin(), a2.end());
474}
475
dyaroshev5f0ff7982017-03-08 01:24:49476// Erase/EraseIf are based on library fundamentals ts v2 erase/erase_if
477// http://en.cppreference.com/w/cpp/experimental/lib_extensions_2
478// They provide a generic way to erase elements from a container.
479// The functions here implement these for the standard containers until those
480// functions are available in the C++ standard.
481// For Chromium containers overloads should be defined in their own headers
482// (like standard containers).
483// Note: there is no std::erase for standard associative containers so we don't
484// have it either.
485
486template <typename CharT, typename Traits, typename Allocator, typename Value>
487void Erase(std::basic_string<CharT, Traits, Allocator>& container,
488 const Value& value) {
489 container.erase(std::remove(container.begin(), container.end(), value),
490 container.end());
491}
492
493template <typename CharT, typename Traits, typename Allocator, class Predicate>
494void EraseIf(std::basic_string<CharT, Traits, Allocator>& container,
495 Predicate pred) {
496 container.erase(std::remove_if(container.begin(), container.end(), pred),
497 container.end());
498}
499
500template <class T, class Allocator, class Value>
501void Erase(std::deque<T, Allocator>& container, const Value& value) {
502 container.erase(std::remove(container.begin(), container.end(), value),
503 container.end());
504}
505
506template <class T, class Allocator, class Predicate>
507void EraseIf(std::deque<T, Allocator>& container, Predicate pred) {
508 container.erase(std::remove_if(container.begin(), container.end(), pred),
509 container.end());
510}
511
512template <class T, class Allocator, class Value>
513void Erase(std::vector<T, Allocator>& container, const Value& value) {
514 container.erase(std::remove(container.begin(), container.end(), value),
515 container.end());
516}
517
518template <class T, class Allocator, class Predicate>
519void EraseIf(std::vector<T, Allocator>& container, 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::forward_list<T, Allocator>& container, const Value& value) {
526 // Unlike std::forward_list::remove, this function template accepts
527 // heterogeneous types and does not force a conversion to the container's
528 // value type before invoking the == operator.
529 container.remove_if([&](const T& cur) { return cur == value; });
530}
531
532template <class T, class Allocator, class Predicate>
533void EraseIf(std::forward_list<T, Allocator>& container, Predicate pred) {
534 container.remove_if(pred);
535}
536
537template <class T, class Allocator, class Value>
538void Erase(std::list<T, Allocator>& container, const Value& value) {
539 // Unlike std::list::remove, this function template accepts heterogeneous
540 // types and does not force a conversion to the container's value type before
541 // invoking the == operator.
542 container.remove_if([&](const T& cur) { return cur == value; });
543}
544
545template <class T, class Allocator, class Predicate>
546void EraseIf(std::list<T, Allocator>& container, Predicate pred) {
547 container.remove_if(pred);
548}
549
jdoerrie5dd3a2132017-03-13 15:31:10550template <class Key, class T, class Compare, class Allocator, class Predicate>
551void EraseIf(std::map<Key, T, Compare, Allocator>& container, Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49552 internal::IterateAndEraseIf(container, pred);
553}
554
jdoerrie5dd3a2132017-03-13 15:31:10555template <class Key, class T, class Compare, class Allocator, class Predicate>
556void EraseIf(std::multimap<Key, T, Compare, Allocator>& container,
557 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49558 internal::IterateAndEraseIf(container, pred);
559}
560
jdoerrie5dd3a2132017-03-13 15:31:10561template <class Key, class Compare, class Allocator, class Predicate>
562void EraseIf(std::set<Key, Compare, Allocator>& container, Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49563 internal::IterateAndEraseIf(container, pred);
564}
565
jdoerrie5dd3a2132017-03-13 15:31:10566template <class Key, class Compare, class Allocator, class Predicate>
567void EraseIf(std::multiset<Key, Compare, Allocator>& container,
568 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49569 internal::IterateAndEraseIf(container, pred);
570}
571
jdoerrie5dd3a2132017-03-13 15:31:10572template <class Key,
573 class T,
574 class Hash,
575 class KeyEqual,
576 class Allocator,
577 class Predicate>
578void EraseIf(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& container,
579 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49580 internal::IterateAndEraseIf(container, pred);
581}
582
jdoerrie5dd3a2132017-03-13 15:31:10583template <class Key,
584 class T,
585 class Hash,
586 class KeyEqual,
587 class Allocator,
588 class Predicate>
589void EraseIf(
590 std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& container,
591 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49592 internal::IterateAndEraseIf(container, pred);
593}
594
jdoerrie5dd3a2132017-03-13 15:31:10595template <class Key,
596 class Hash,
597 class KeyEqual,
598 class Allocator,
599 class Predicate>
600void EraseIf(std::unordered_set<Key, Hash, KeyEqual, Allocator>& container,
601 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49602 internal::IterateAndEraseIf(container, pred);
603}
604
jdoerrie5dd3a2132017-03-13 15:31:10605template <class Key,
606 class Hash,
607 class KeyEqual,
608 class Allocator,
609 class Predicate>
610void EraseIf(std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& container,
611 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49612 internal::IterateAndEraseIf(container, pred);
613}
614
Kevin Bailey156ff6d2017-10-26 17:36:00615// A helper class to be used as the predicate with |EraseIf| to implement
616// in-place set intersection. Helps implement the algorithm of going through
617// each container an element at a time, erasing elements from the first
618// container if they aren't in the second container. Requires each container be
619// sorted. Note that the logic below appears inverted since it is returning
620// whether an element should be erased.
621template <class Collection>
622class IsNotIn {
623 public:
624 explicit IsNotIn(const Collection& collection)
625 : i_(collection.begin()), end_(collection.end()) {}
626
627 bool operator()(const typename Collection::value_type& x) {
628 while (i_ != end_ && *i_ < x)
629 ++i_;
630 if (i_ == end_)
631 return true;
632 if (*i_ == x) {
633 ++i_;
634 return false;
635 }
636 return true;
637 }
638
639 private:
640 typename Collection::const_iterator i_;
641 const typename Collection::const_iterator end_;
642};
643
Philip Rogers3f67719f2018-03-09 02:16:44644// Helper for returning the optional value's address, or nullptr.
645template <class T>
646T* OptionalOrNullptr(base::Optional<T>& optional) {
647 return optional.has_value() ? &optional.value() : nullptr;
648}
649
650template <class T>
651const T* OptionalOrNullptr(const base::Optional<T>& optional) {
652 return optional.has_value() ? &optional.value() : nullptr;
653}
654
[email protected]1dea7572012-12-05 21:40:27655} // namespace base
656
[email protected]7286e3fc2011-07-19 22:13:24657#endif // BASE_STL_UTIL_H_