blob: b0670b295eb87d9a28d5621f3f86883fa038a39f [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>
[email protected]c014f2b32013-09-03 23:29:1214#include <iterator>
dyaroshev5f0ff7982017-03-08 01:24:4915#include <list>
16#include <map>
17#include <set>
[email protected]7286e3fc2011-07-19 22:13:2418#include <string>
dyaroshev5f0ff7982017-03-08 01:24:4919#include <unordered_map>
20#include <unordered_set>
[email protected]7286e3fc2011-07-19 22:13:2421#include <vector>
22
[email protected]1dea7572012-12-05 21:40:2723#include "base/logging.h"
24
skyostil68be7152016-08-09 22:18:0025namespace base {
26
dyaroshev5f0ff7982017-03-08 01:24:4927namespace internal {
28
29// Calls erase on iterators of matching elements.
30template <typename Container, typename Predicate>
31void IterateAndEraseIf(Container& container, Predicate pred) {
32 for (auto it = container.begin(); it != container.end();) {
33 if (pred(*it))
34 it = container.erase(it);
35 else
36 ++it;
37 }
38}
39
40} // namespace internal
41
[email protected]6ee951a2012-06-26 17:24:0542// Clears internal memory of an STL object.
[email protected]7286e3fc2011-07-19 22:13:2443// STL clear()/reserve(0) does not always free internal memory allocated
44// This function uses swap/destructor to ensure the internal memory is freed.
[email protected]6ee951a2012-06-26 17:24:0545template<class T>
46void STLClearObject(T* obj) {
[email protected]7286e3fc2011-07-19 22:13:2447 T tmp;
48 tmp.swap(*obj);
49 // Sometimes "T tmp" allocates objects with memory (arena implementation?).
50 // Hence using additional reserve(0) even if it doesn't always work.
51 obj->reserve(0);
52}
53
robliao43eb02c2015-03-27 18:25:1154// Counts the number of instances of val in a container.
55template <typename Container, typename T>
56typename std::iterator_traits<
57 typename Container::const_iterator>::difference_type
58STLCount(const Container& container, const T& val) {
59 return std::count(container.begin(), container.end(), val);
60}
61
[email protected]7286e3fc2011-07-19 22:13:2462// Return a mutable char* pointing to a string's internal buffer,
63// which may not be null-terminated. Writing through this pointer will
64// modify the string.
65//
66// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
67// next call to a string method that invalidates iterators.
68//
69// As of 2006-04, there is no standard-blessed way of getting a
70// mutable reference to a string's internal buffer. However, issue 530
71// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
72// proposes this as the method. According to Matt Austern, this should
73// already work on all current implementations.
74inline char* string_as_array(std::string* str) {
75 // DO NOT USE const_cast<char*>(str->data())
76 return str->empty() ? NULL : &*str->begin();
77}
78
[email protected]7286e3fc2011-07-19 22:13:2479// Test to see if a set, map, hash_set or hash_map contains a particular key.
80// Returns true if the key is in the collection.
81template <typename Collection, typename Key>
82bool ContainsKey(const Collection& collection, const Key& key) {
83 return collection.find(key) != collection.end();
84}
85
robliao43eb02c2015-03-27 18:25:1186// Test to see if a collection like a vector contains a particular value.
87// Returns true if the value is in the collection.
88template <typename Collection, typename Value>
89bool ContainsValue(const Collection& collection, const Value& value) {
90 return std::find(collection.begin(), collection.end(), value) !=
91 collection.end();
92}
93
[email protected]1dea7572012-12-05 21:40:2794// Returns true if the container is sorted.
95template <typename Container>
96bool STLIsSorted(const Container& cont) {
[email protected]9a53ade2014-01-29 17:13:2797 // Note: Use reverse iterator on container to ensure we only require
98 // value_type to implement operator<.
99 return std::adjacent_find(cont.rbegin(), cont.rend(),
100 std::less<typename Container::value_type>())
101 == cont.rend();
[email protected]1dea7572012-12-05 21:40:27102}
103
104// Returns a new ResultType containing the difference of two sorted containers.
105template <typename ResultType, typename Arg1, typename Arg2>
106ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
107 DCHECK(STLIsSorted(a1));
108 DCHECK(STLIsSorted(a2));
109 ResultType difference;
110 std::set_difference(a1.begin(), a1.end(),
111 a2.begin(), a2.end(),
112 std::inserter(difference, difference.end()));
113 return difference;
114}
115
[email protected]9a53ade2014-01-29 17:13:27116// Returns a new ResultType containing the union of two sorted containers.
117template <typename ResultType, typename Arg1, typename Arg2>
118ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
119 DCHECK(STLIsSorted(a1));
120 DCHECK(STLIsSorted(a2));
121 ResultType result;
122 std::set_union(a1.begin(), a1.end(),
123 a2.begin(), a2.end(),
124 std::inserter(result, result.end()));
125 return result;
126}
127
128// Returns a new ResultType containing the intersection of two sorted
129// containers.
130template <typename ResultType, typename Arg1, typename Arg2>
131ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
132 DCHECK(STLIsSorted(a1));
133 DCHECK(STLIsSorted(a2));
134 ResultType result;
135 std::set_intersection(a1.begin(), a1.end(),
136 a2.begin(), a2.end(),
137 std::inserter(result, result.end()));
138 return result;
139}
140
141// Returns true if the sorted container |a1| contains all elements of the sorted
142// container |a2|.
143template <typename Arg1, typename Arg2>
144bool STLIncludes(const Arg1& a1, const Arg2& a2) {
145 DCHECK(STLIsSorted(a1));
146 DCHECK(STLIsSorted(a2));
147 return std::includes(a1.begin(), a1.end(),
148 a2.begin(), a2.end());
149}
150
dyaroshev5f0ff7982017-03-08 01:24:49151// Erase/EraseIf are based on library fundamentals ts v2 erase/erase_if
152// http://en.cppreference.com/w/cpp/experimental/lib_extensions_2
153// They provide a generic way to erase elements from a container.
154// The functions here implement these for the standard containers until those
155// functions are available in the C++ standard.
156// For Chromium containers overloads should be defined in their own headers
157// (like standard containers).
158// Note: there is no std::erase for standard associative containers so we don't
159// have it either.
160
161template <typename CharT, typename Traits, typename Allocator, typename Value>
162void Erase(std::basic_string<CharT, Traits, Allocator>& container,
163 const Value& value) {
164 container.erase(std::remove(container.begin(), container.end(), value),
165 container.end());
166}
167
168template <typename CharT, typename Traits, typename Allocator, class Predicate>
169void EraseIf(std::basic_string<CharT, Traits, Allocator>& container,
170 Predicate pred) {
171 container.erase(std::remove_if(container.begin(), container.end(), pred),
172 container.end());
173}
174
175template <class T, class Allocator, class Value>
176void Erase(std::deque<T, Allocator>& container, const Value& value) {
177 container.erase(std::remove(container.begin(), container.end(), value),
178 container.end());
179}
180
181template <class T, class Allocator, class Predicate>
182void EraseIf(std::deque<T, Allocator>& container, Predicate pred) {
183 container.erase(std::remove_if(container.begin(), container.end(), pred),
184 container.end());
185}
186
187template <class T, class Allocator, class Value>
188void Erase(std::vector<T, Allocator>& container, const Value& value) {
189 container.erase(std::remove(container.begin(), container.end(), value),
190 container.end());
191}
192
193template <class T, class Allocator, class Predicate>
194void EraseIf(std::vector<T, Allocator>& container, Predicate pred) {
195 container.erase(std::remove_if(container.begin(), container.end(), pred),
196 container.end());
197}
198
199template <class T, class Allocator, class Value>
200void Erase(std::forward_list<T, Allocator>& container, const Value& value) {
201 // Unlike std::forward_list::remove, this function template accepts
202 // heterogeneous types and does not force a conversion to the container's
203 // value type before invoking the == operator.
204 container.remove_if([&](const T& cur) { return cur == value; });
205}
206
207template <class T, class Allocator, class Predicate>
208void EraseIf(std::forward_list<T, Allocator>& container, Predicate pred) {
209 container.remove_if(pred);
210}
211
212template <class T, class Allocator, class Value>
213void Erase(std::list<T, Allocator>& container, const Value& value) {
214 // Unlike std::list::remove, this function template accepts heterogeneous
215 // types and does not force a conversion to the container's value type before
216 // invoking the == operator.
217 container.remove_if([&](const T& cur) { return cur == value; });
218}
219
220template <class T, class Allocator, class Predicate>
221void EraseIf(std::list<T, Allocator>& container, Predicate pred) {
222 container.remove_if(pred);
223}
224
jdoerrie5dd3a2132017-03-13 15:31:10225template <class Key, class T, class Compare, class Allocator, class Predicate>
226void EraseIf(std::map<Key, T, Compare, Allocator>& container, Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49227 internal::IterateAndEraseIf(container, pred);
228}
229
jdoerrie5dd3a2132017-03-13 15:31:10230template <class Key, class T, class Compare, class Allocator, class Predicate>
231void EraseIf(std::multimap<Key, T, Compare, Allocator>& container,
232 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49233 internal::IterateAndEraseIf(container, pred);
234}
235
jdoerrie5dd3a2132017-03-13 15:31:10236template <class Key, class Compare, class Allocator, class Predicate>
237void EraseIf(std::set<Key, Compare, Allocator>& container, Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49238 internal::IterateAndEraseIf(container, pred);
239}
240
jdoerrie5dd3a2132017-03-13 15:31:10241template <class Key, class Compare, class Allocator, class Predicate>
242void EraseIf(std::multiset<Key, Compare, Allocator>& container,
243 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49244 internal::IterateAndEraseIf(container, pred);
245}
246
jdoerrie5dd3a2132017-03-13 15:31:10247template <class Key,
248 class T,
249 class Hash,
250 class KeyEqual,
251 class Allocator,
252 class Predicate>
253void EraseIf(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& container,
254 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49255 internal::IterateAndEraseIf(container, pred);
256}
257
jdoerrie5dd3a2132017-03-13 15:31:10258template <class Key,
259 class T,
260 class Hash,
261 class KeyEqual,
262 class Allocator,
263 class Predicate>
264void EraseIf(
265 std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& container,
266 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49267 internal::IterateAndEraseIf(container, pred);
268}
269
jdoerrie5dd3a2132017-03-13 15:31:10270template <class Key,
271 class Hash,
272 class KeyEqual,
273 class Allocator,
274 class Predicate>
275void EraseIf(std::unordered_set<Key, Hash, KeyEqual, Allocator>& container,
276 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49277 internal::IterateAndEraseIf(container, pred);
278}
279
jdoerrie5dd3a2132017-03-13 15:31:10280template <class Key,
281 class Hash,
282 class KeyEqual,
283 class Allocator,
284 class Predicate>
285void EraseIf(std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& container,
286 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49287 internal::IterateAndEraseIf(container, pred);
288}
289
[email protected]1dea7572012-12-05 21:40:27290} // namespace base
291
[email protected]7286e3fc2011-07-19 22:13:24292#endif // BASE_STL_UTIL_H_