stl_util.h 25 KB

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