blob: 186bf12b4400d4e295994b09062993da6b478972 [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
brettw1ce49f62017-04-27 19:42:3279// Test to see if a set or map contains a particular key.
[email protected]7286e3fc2011-07-19 22:13:2480// 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
Marijn Kruisselbrinkbb019e32017-06-27 20:50:3286namespace internal {
87
88template <typename Collection>
89class HasKeyType {
90 template <typename C>
91 static std::true_type test(typename C::key_type*);
92 template <typename C>
93 static std::false_type test(...);
94
95 public:
96 static constexpr bool value = decltype(test<Collection>(nullptr))::value;
97};
98
99} // namespace internal
100
robliao43eb02c2015-03-27 18:25:11101// Test to see if a collection like a vector contains a particular value.
102// Returns true if the value is in the collection.
Marijn Kruisselbrinkbb019e32017-06-27 20:50:32103// Don't use this on collections such as sets or maps. This is enforced by
104// disabling this method if the collection defines a key_type.
105template <typename Collection,
106 typename Value,
107 typename std::enable_if<!internal::HasKeyType<Collection>::value,
108 int>::type = 0>
robliao43eb02c2015-03-27 18:25:11109bool ContainsValue(const Collection& collection, const Value& value) {
tsepez1bc34662017-04-20 18:11:46110 return std::find(std::begin(collection), std::end(collection), value) !=
111 std::end(collection);
robliao43eb02c2015-03-27 18:25:11112}
113
[email protected]1dea7572012-12-05 21:40:27114// Returns true if the container is sorted.
115template <typename Container>
116bool STLIsSorted(const Container& cont) {
[email protected]9a53ade2014-01-29 17:13:27117 // Note: Use reverse iterator on container to ensure we only require
118 // value_type to implement operator<.
119 return std::adjacent_find(cont.rbegin(), cont.rend(),
120 std::less<typename Container::value_type>())
121 == cont.rend();
[email protected]1dea7572012-12-05 21:40:27122}
123
124// Returns a new ResultType containing the difference of two sorted containers.
125template <typename ResultType, typename Arg1, typename Arg2>
126ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
127 DCHECK(STLIsSorted(a1));
128 DCHECK(STLIsSorted(a2));
129 ResultType difference;
130 std::set_difference(a1.begin(), a1.end(),
131 a2.begin(), a2.end(),
132 std::inserter(difference, difference.end()));
133 return difference;
134}
135
[email protected]9a53ade2014-01-29 17:13:27136// Returns a new ResultType containing the union of two sorted containers.
137template <typename ResultType, typename Arg1, typename Arg2>
138ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
139 DCHECK(STLIsSorted(a1));
140 DCHECK(STLIsSorted(a2));
141 ResultType result;
142 std::set_union(a1.begin(), a1.end(),
143 a2.begin(), a2.end(),
144 std::inserter(result, result.end()));
145 return result;
146}
147
148// Returns a new ResultType containing the intersection of two sorted
149// containers.
150template <typename ResultType, typename Arg1, typename Arg2>
151ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
152 DCHECK(STLIsSorted(a1));
153 DCHECK(STLIsSorted(a2));
154 ResultType result;
155 std::set_intersection(a1.begin(), a1.end(),
156 a2.begin(), a2.end(),
157 std::inserter(result, result.end()));
158 return result;
159}
160
161// Returns true if the sorted container |a1| contains all elements of the sorted
162// container |a2|.
163template <typename Arg1, typename Arg2>
164bool STLIncludes(const Arg1& a1, const Arg2& a2) {
165 DCHECK(STLIsSorted(a1));
166 DCHECK(STLIsSorted(a2));
167 return std::includes(a1.begin(), a1.end(),
168 a2.begin(), a2.end());
169}
170
dyaroshev5f0ff7982017-03-08 01:24:49171// Erase/EraseIf are based on library fundamentals ts v2 erase/erase_if
172// http://en.cppreference.com/w/cpp/experimental/lib_extensions_2
173// They provide a generic way to erase elements from a container.
174// The functions here implement these for the standard containers until those
175// functions are available in the C++ standard.
176// For Chromium containers overloads should be defined in their own headers
177// (like standard containers).
178// Note: there is no std::erase for standard associative containers so we don't
179// have it either.
180
181template <typename CharT, typename Traits, typename Allocator, typename Value>
182void Erase(std::basic_string<CharT, Traits, Allocator>& container,
183 const Value& value) {
184 container.erase(std::remove(container.begin(), container.end(), value),
185 container.end());
186}
187
188template <typename CharT, typename Traits, typename Allocator, class Predicate>
189void EraseIf(std::basic_string<CharT, Traits, Allocator>& container,
190 Predicate pred) {
191 container.erase(std::remove_if(container.begin(), container.end(), pred),
192 container.end());
193}
194
195template <class T, class Allocator, class Value>
196void Erase(std::deque<T, Allocator>& container, const Value& value) {
197 container.erase(std::remove(container.begin(), container.end(), value),
198 container.end());
199}
200
201template <class T, class Allocator, class Predicate>
202void EraseIf(std::deque<T, Allocator>& container, Predicate pred) {
203 container.erase(std::remove_if(container.begin(), container.end(), pred),
204 container.end());
205}
206
207template <class T, class Allocator, class Value>
208void Erase(std::vector<T, Allocator>& container, const Value& value) {
209 container.erase(std::remove(container.begin(), container.end(), value),
210 container.end());
211}
212
213template <class T, class Allocator, class Predicate>
214void EraseIf(std::vector<T, Allocator>& container, Predicate pred) {
215 container.erase(std::remove_if(container.begin(), container.end(), pred),
216 container.end());
217}
218
219template <class T, class Allocator, class Value>
220void Erase(std::forward_list<T, Allocator>& container, const Value& value) {
221 // Unlike std::forward_list::remove, this function template accepts
222 // heterogeneous types and does not force a conversion to the container's
223 // value type before invoking the == operator.
224 container.remove_if([&](const T& cur) { return cur == value; });
225}
226
227template <class T, class Allocator, class Predicate>
228void EraseIf(std::forward_list<T, Allocator>& container, Predicate pred) {
229 container.remove_if(pred);
230}
231
232template <class T, class Allocator, class Value>
233void Erase(std::list<T, Allocator>& container, const Value& value) {
234 // Unlike std::list::remove, this function template accepts heterogeneous
235 // types and does not force a conversion to the container's value type before
236 // invoking the == operator.
237 container.remove_if([&](const T& cur) { return cur == value; });
238}
239
240template <class T, class Allocator, class Predicate>
241void EraseIf(std::list<T, Allocator>& container, Predicate pred) {
242 container.remove_if(pred);
243}
244
jdoerrie5dd3a2132017-03-13 15:31:10245template <class Key, class T, class Compare, class Allocator, class Predicate>
246void EraseIf(std::map<Key, T, Compare, Allocator>& container, Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49247 internal::IterateAndEraseIf(container, pred);
248}
249
jdoerrie5dd3a2132017-03-13 15:31:10250template <class Key, class T, class Compare, class Allocator, class Predicate>
251void EraseIf(std::multimap<Key, T, Compare, Allocator>& container,
252 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49253 internal::IterateAndEraseIf(container, pred);
254}
255
jdoerrie5dd3a2132017-03-13 15:31:10256template <class Key, class Compare, class Allocator, class Predicate>
257void EraseIf(std::set<Key, Compare, Allocator>& container, Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49258 internal::IterateAndEraseIf(container, pred);
259}
260
jdoerrie5dd3a2132017-03-13 15:31:10261template <class Key, class Compare, class Allocator, class Predicate>
262void EraseIf(std::multiset<Key, Compare, Allocator>& container,
263 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49264 internal::IterateAndEraseIf(container, pred);
265}
266
jdoerrie5dd3a2132017-03-13 15:31:10267template <class Key,
268 class T,
269 class Hash,
270 class KeyEqual,
271 class Allocator,
272 class Predicate>
273void EraseIf(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& container,
274 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49275 internal::IterateAndEraseIf(container, pred);
276}
277
jdoerrie5dd3a2132017-03-13 15:31:10278template <class Key,
279 class T,
280 class Hash,
281 class KeyEqual,
282 class Allocator,
283 class Predicate>
284void EraseIf(
285 std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& container,
286 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49287 internal::IterateAndEraseIf(container, pred);
288}
289
jdoerrie5dd3a2132017-03-13 15:31:10290template <class Key,
291 class Hash,
292 class KeyEqual,
293 class Allocator,
294 class Predicate>
295void EraseIf(std::unordered_set<Key, Hash, KeyEqual, Allocator>& container,
296 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49297 internal::IterateAndEraseIf(container, pred);
298}
299
jdoerrie5dd3a2132017-03-13 15:31:10300template <class Key,
301 class Hash,
302 class KeyEqual,
303 class Allocator,
304 class Predicate>
305void EraseIf(std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& container,
306 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49307 internal::IterateAndEraseIf(container, pred);
308}
309
Kevin Bailey156ff6d2017-10-26 17:36:00310// A helper class to be used as the predicate with |EraseIf| to implement
311// in-place set intersection. Helps implement the algorithm of going through
312// each container an element at a time, erasing elements from the first
313// container if they aren't in the second container. Requires each container be
314// sorted. Note that the logic below appears inverted since it is returning
315// whether an element should be erased.
316template <class Collection>
317class IsNotIn {
318 public:
319 explicit IsNotIn(const Collection& collection)
320 : i_(collection.begin()), end_(collection.end()) {}
321
322 bool operator()(const typename Collection::value_type& x) {
323 while (i_ != end_ && *i_ < x)
324 ++i_;
325 if (i_ == end_)
326 return true;
327 if (*i_ == x) {
328 ++i_;
329 return false;
330 }
331 return true;
332 }
333
334 private:
335 typename Collection::const_iterator i_;
336 const typename Collection::const_iterator end_;
337};
338
[email protected]1dea7572012-12-05 21:40:27339} // namespace base
340
[email protected]7286e3fc2011-07-19 22:13:24341#endif // BASE_STL_UTIL_H_