blob: d08c018a0c2af6335925991422c1dc16c3ae3cb5 [file] [log] [blame]
Scott Graham66962112018-06-08 12:42:08 -07001// 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_
9
10#include <algorithm>
11#include <deque>
12#include <forward_list>
13#include <functional>
14#include <initializer_list>
15#include <iterator>
16#include <list>
17#include <map>
18#include <set>
19#include <string>
20#include <unordered_map>
21#include <unordered_set>
22#include <vector>
23
24#include "base/logging.h"
Scott Graham66962112018-06-08 12:42:08 -070025
26namespace base {
27
28namespace internal {
29
30// Calls erase on iterators of matching elements.
31template <typename Container, typename Predicate>
32void IterateAndEraseIf(Container& container, Predicate pred) {
33 for (auto it = container.begin(); it != container.end();) {
34 if (pred(*it))
35 it = container.erase(it);
36 else
37 ++it;
38 }
39}
40
41} // namespace internal
42
Scott Graham66962112018-06-08 12:42:08 -070043// Test to see if a set or map contains a particular key.
44// Returns true if the key is in the collection.
45template <typename Collection, typename Key>
46bool ContainsKey(const Collection& collection, const Key& key) {
47 return collection.find(key) != collection.end();
48}
49
50namespace internal {
51
52template <typename Collection>
53class HasKeyType {
54 template <typename C>
55 static std::true_type test(typename C::key_type*);
56 template <typename C>
57 static std::false_type test(...);
58
59 public:
60 static constexpr bool value = decltype(test<Collection>(nullptr))::value;
61};
62
63} // namespace internal
64
65// Test to see if a collection like a vector contains a particular value.
66// Returns true if the value is in the collection.
67// Don't use this on collections such as sets or maps. This is enforced by
68// disabling this method if the collection defines a key_type.
69template <typename Collection,
70 typename Value,
71 typename std::enable_if<!internal::HasKeyType<Collection>::value,
72 int>::type = 0>
73bool ContainsValue(const Collection& collection, const Value& value) {
74 return std::find(std::begin(collection), std::end(collection), value) !=
75 std::end(collection);
76}
77
78// Returns true if the container is sorted.
79template <typename Container>
80bool STLIsSorted(const Container& cont) {
81 // Note: Use reverse iterator on container to ensure we only require
82 // value_type to implement operator<.
83 return std::adjacent_find(cont.rbegin(), cont.rend(),
Scott Graham98cd3ca2018-06-14 22:26:55 -070084 std::less<typename Container::value_type>()) ==
85 cont.rend();
Scott Graham66962112018-06-08 12:42:08 -070086}
87
88// Returns a new ResultType containing the difference of two sorted containers.
89template <typename ResultType, typename Arg1, typename Arg2>
90ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
91 DCHECK(STLIsSorted(a1));
92 DCHECK(STLIsSorted(a2));
93 ResultType difference;
Scott Graham98cd3ca2018-06-14 22:26:55 -070094 std::set_difference(a1.begin(), a1.end(), a2.begin(), a2.end(),
Scott Graham66962112018-06-08 12:42:08 -070095 std::inserter(difference, difference.end()));
96 return difference;
97}
98
99// Returns a new ResultType containing the union of two sorted containers.
100template <typename ResultType, typename Arg1, typename Arg2>
101ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
102 DCHECK(STLIsSorted(a1));
103 DCHECK(STLIsSorted(a2));
104 ResultType result;
Scott Graham98cd3ca2018-06-14 22:26:55 -0700105 std::set_union(a1.begin(), a1.end(), a2.begin(), a2.end(),
Scott Graham66962112018-06-08 12:42:08 -0700106 std::inserter(result, result.end()));
107 return result;
108}
109
110// Returns a new ResultType containing the intersection of two sorted
111// containers.
112template <typename ResultType, typename Arg1, typename Arg2>
113ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
114 DCHECK(STLIsSorted(a1));
115 DCHECK(STLIsSorted(a2));
116 ResultType result;
Scott Graham98cd3ca2018-06-14 22:26:55 -0700117 std::set_intersection(a1.begin(), a1.end(), a2.begin(), a2.end(),
Scott Graham66962112018-06-08 12:42:08 -0700118 std::inserter(result, result.end()));
119 return result;
120}
121
122// Returns true if the sorted container |a1| contains all elements of the sorted
123// container |a2|.
124template <typename Arg1, typename Arg2>
125bool STLIncludes(const Arg1& a1, const Arg2& a2) {
126 DCHECK(STLIsSorted(a1));
127 DCHECK(STLIsSorted(a2));
Scott Graham98cd3ca2018-06-14 22:26:55 -0700128 return std::includes(a1.begin(), a1.end(), a2.begin(), a2.end());
Scott Graham66962112018-06-08 12:42:08 -0700129}
130
131// Erase/EraseIf are based on library fundamentals ts v2 erase/erase_if
132// http://en.cppreference.com/w/cpp/experimental/lib_extensions_2
133// They provide a generic way to erase elements from a container.
134// The functions here implement these for the standard containers until those
135// functions are available in the C++ standard.
136// For Chromium containers overloads should be defined in their own headers
137// (like standard containers).
138// Note: there is no std::erase for standard associative containers so we don't
139// have it either.
140
141template <typename CharT, typename Traits, typename Allocator, typename Value>
142void Erase(std::basic_string<CharT, Traits, Allocator>& container,
143 const Value& value) {
144 container.erase(std::remove(container.begin(), container.end(), value),
145 container.end());
146}
147
148template <typename CharT, typename Traits, typename Allocator, class Predicate>
149void EraseIf(std::basic_string<CharT, Traits, Allocator>& container,
150 Predicate pred) {
151 container.erase(std::remove_if(container.begin(), container.end(), pred),
152 container.end());
153}
154
155template <class T, class Allocator, class Value>
156void Erase(std::deque<T, Allocator>& container, const Value& value) {
157 container.erase(std::remove(container.begin(), container.end(), value),
158 container.end());
159}
160
161template <class T, class Allocator, class Predicate>
162void EraseIf(std::deque<T, Allocator>& container, Predicate pred) {
163 container.erase(std::remove_if(container.begin(), container.end(), pred),
164 container.end());
165}
166
167template <class T, class Allocator, class Value>
168void Erase(std::vector<T, Allocator>& container, const Value& value) {
169 container.erase(std::remove(container.begin(), container.end(), value),
170 container.end());
171}
172
173template <class T, class Allocator, class Predicate>
174void EraseIf(std::vector<T, Allocator>& container, Predicate pred) {
175 container.erase(std::remove_if(container.begin(), container.end(), pred),
176 container.end());
177}
178
179template <class T, class Allocator, class Value>
180void Erase(std::forward_list<T, Allocator>& container, const Value& value) {
181 // Unlike std::forward_list::remove, this function template accepts
182 // heterogeneous types and does not force a conversion to the container's
183 // value type before invoking the == operator.
184 container.remove_if([&](const T& cur) { return cur == value; });
185}
186
187template <class T, class Allocator, class Predicate>
188void EraseIf(std::forward_list<T, Allocator>& container, Predicate pred) {
189 container.remove_if(pred);
190}
191
192template <class T, class Allocator, class Value>
193void Erase(std::list<T, Allocator>& container, const Value& value) {
194 // Unlike std::list::remove, this function template accepts heterogeneous
195 // types and does not force a conversion to the container's value type before
196 // invoking the == operator.
197 container.remove_if([&](const T& cur) { return cur == value; });
198}
199
200template <class T, class Allocator, class Predicate>
201void EraseIf(std::list<T, Allocator>& container, Predicate pred) {
202 container.remove_if(pred);
203}
204
205template <class Key, class T, class Compare, class Allocator, class Predicate>
206void EraseIf(std::map<Key, T, Compare, Allocator>& container, Predicate pred) {
207 internal::IterateAndEraseIf(container, pred);
208}
209
210template <class Key, class T, class Compare, class Allocator, class Predicate>
211void EraseIf(std::multimap<Key, T, Compare, Allocator>& container,
212 Predicate pred) {
213 internal::IterateAndEraseIf(container, pred);
214}
215
216template <class Key, class Compare, class Allocator, class Predicate>
217void EraseIf(std::set<Key, Compare, Allocator>& container, Predicate pred) {
218 internal::IterateAndEraseIf(container, pred);
219}
220
221template <class Key, class Compare, class Allocator, class Predicate>
222void EraseIf(std::multiset<Key, Compare, Allocator>& container,
223 Predicate pred) {
224 internal::IterateAndEraseIf(container, pred);
225}
226
227template <class Key,
228 class T,
229 class Hash,
230 class KeyEqual,
231 class Allocator,
232 class Predicate>
233void EraseIf(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& container,
234 Predicate pred) {
235 internal::IterateAndEraseIf(container, pred);
236}
237
238template <class Key,
239 class T,
240 class Hash,
241 class KeyEqual,
242 class Allocator,
243 class Predicate>
244void EraseIf(
245 std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& container,
246 Predicate pred) {
247 internal::IterateAndEraseIf(container, pred);
248}
249
250template <class Key,
251 class Hash,
252 class KeyEqual,
253 class Allocator,
254 class Predicate>
255void EraseIf(std::unordered_set<Key, Hash, KeyEqual, Allocator>& container,
256 Predicate pred) {
257 internal::IterateAndEraseIf(container, pred);
258}
259
260template <class Key,
261 class Hash,
262 class KeyEqual,
263 class Allocator,
264 class Predicate>
265void EraseIf(std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& container,
266 Predicate pred) {
267 internal::IterateAndEraseIf(container, pred);
268}
269
Scott Graham66962112018-06-08 12:42:08 -0700270} // namespace base
271
272#endif // BASE_STL_UTIL_H_