blob: 2cec11b2e6c9069af85f3e1e7f4a600d5c4b2337 [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
225template <class T, class Allocator, class Predicate>
226void EraseIf(std::map<T, Allocator>& container, Predicate pred) {
227 internal::IterateAndEraseIf(container, pred);
228}
229
230template <class T, class Allocator, class Predicate>
231void EraseIf(std::multimap<T, Allocator>& container, Predicate pred) {
232 internal::IterateAndEraseIf(container, pred);
233}
234
235template <class T, class Allocator, class Predicate>
236void EraseIf(std::set<T, Allocator>& container, Predicate pred) {
237 internal::IterateAndEraseIf(container, pred);
238}
239
240template <class T, class Allocator, class Predicate>
241void EraseIf(std::multiset<T, Allocator>& container, Predicate pred) {
242 internal::IterateAndEraseIf(container, pred);
243}
244
245template <class T, class Allocator, class Predicate>
246void EraseIf(std::unordered_map<T, Allocator>& container, Predicate pred) {
247 internal::IterateAndEraseIf(container, pred);
248}
249
250template <class T, class Allocator, class Predicate>
251void EraseIf(std::unordered_multimap<T, Allocator>& container, Predicate pred) {
252 internal::IterateAndEraseIf(container, pred);
253}
254
255template <class T, class Allocator, class Predicate>
256void EraseIf(std::unordered_set<T, Allocator>& container, Predicate pred) {
257 internal::IterateAndEraseIf(container, pred);
258}
259
260template <class T, class Allocator, class Predicate>
261void EraseIf(std::unordered_multiset<T, Allocator>& container, Predicate pred) {
262 internal::IterateAndEraseIf(container, pred);
263}
264
[email protected]1dea7572012-12-05 21:40:27265} // namespace base
266
[email protected]7286e3fc2011-07-19 22:13:24267#endif // BASE_STL_UTIL_H_