blob: edd14d38ffcb1087aeccd6cee7a6aa86eb94af49 [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>
jdoerrie8f516042018-04-13 09:40:3014#include <initializer_list>
[email protected]c014f2b32013-09-03 23:29:1215#include <iterator>
dyaroshev5f0ff7982017-03-08 01:24:4916#include <list>
17#include <map>
18#include <set>
[email protected]7286e3fc2011-07-19 22:13:2419#include <string>
dyaroshev5f0ff7982017-03-08 01:24:4920#include <unordered_map>
21#include <unordered_set>
[email protected]7286e3fc2011-07-19 22:13:2422#include <vector>
23
[email protected]1dea7572012-12-05 21:40:2724#include "base/logging.h"
Philip Rogers3f67719f2018-03-09 02:16:4425#include "base/optional.h"
[email protected]1dea7572012-12-05 21:40:2726
skyostil68be7152016-08-09 22:18:0027namespace base {
28
dyaroshev5f0ff7982017-03-08 01:24:4929namespace internal {
30
31// Calls erase on iterators of matching elements.
32template <typename Container, typename Predicate>
33void IterateAndEraseIf(Container& container, Predicate pred) {
34 for (auto it = container.begin(); it != container.end();) {
35 if (pred(*it))
36 it = container.erase(it);
37 else
38 ++it;
39 }
40}
41
42} // namespace internal
43
jdoerrie8f516042018-04-13 09:40:3044// C++14 implementation of C++17's std::size():
45// http://en.cppreference.com/w/cpp/iterator/size
46template <typename Container>
47constexpr auto size(const Container& c) -> decltype(c.size()) {
48 return c.size();
49}
50
51template <typename T, size_t N>
52constexpr size_t size(const T (&array)[N]) noexcept {
53 return N;
54}
55
56// C++14 implementation of C++17's std::empty():
57// http://en.cppreference.com/w/cpp/iterator/empty
58template <typename Container>
59constexpr auto empty(const Container& c) -> decltype(c.empty()) {
60 return c.empty();
61}
62
63template <typename T, size_t N>
64constexpr bool empty(const T (&array)[N]) noexcept {
65 return false;
66}
67
68template <typename T>
69constexpr bool empty(std::initializer_list<T> il) noexcept {
70 return il.size() == 0;
71}
72
73// C++14 implementation of C++17's std::data():
74// http://en.cppreference.com/w/cpp/iterator/data
75template <typename Container>
76constexpr auto data(Container& c) -> decltype(c.data()) {
77 return c.data();
78}
79
80// std::basic_string::data() had no mutable overload prior to C++17 [1].
81// Hence this overload is provided.
82// Note: str[0] is safe even for empty strings, as they are guaranteed to be
83// null-terminated [2].
84//
85// [1] http://en.cppreference.com/w/cpp/string/basic_string/data
86// [2] http://en.cppreference.com/w/cpp/string/basic_string/operator_at
87template <typename CharT, typename Traits, typename Allocator>
88CharT* data(std::basic_string<CharT, Traits, Allocator>& str) {
89 return std::addressof(str[0]);
90}
91
92template <typename Container>
93constexpr auto data(const Container& c) -> decltype(c.data()) {
94 return c.data();
95}
96
97template <typename T, size_t N>
98constexpr T* data(T (&array)[N]) noexcept {
99 return array;
100}
101
102template <typename T>
103constexpr const T* data(std::initializer_list<T> il) noexcept {
104 return il.begin();
105}
106
[email protected]6ee951a2012-06-26 17:24:05107// Clears internal memory of an STL object.
[email protected]7286e3fc2011-07-19 22:13:24108// STL clear()/reserve(0) does not always free internal memory allocated
109// This function uses swap/destructor to ensure the internal memory is freed.
[email protected]6ee951a2012-06-26 17:24:05110template<class T>
111void STLClearObject(T* obj) {
[email protected]7286e3fc2011-07-19 22:13:24112 T tmp;
113 tmp.swap(*obj);
114 // Sometimes "T tmp" allocates objects with memory (arena implementation?).
115 // Hence using additional reserve(0) even if it doesn't always work.
116 obj->reserve(0);
117}
118
robliao43eb02c2015-03-27 18:25:11119// Counts the number of instances of val in a container.
120template <typename Container, typename T>
121typename std::iterator_traits<
122 typename Container::const_iterator>::difference_type
123STLCount(const Container& container, const T& val) {
124 return std::count(container.begin(), container.end(), val);
125}
126
[email protected]7286e3fc2011-07-19 22:13:24127// Return a mutable char* pointing to a string's internal buffer,
128// which may not be null-terminated. Writing through this pointer will
129// modify the string.
130//
131// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
132// next call to a string method that invalidates iterators.
133//
134// As of 2006-04, there is no standard-blessed way of getting a
135// mutable reference to a string's internal buffer. However, issue 530
136// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
137// proposes this as the method. According to Matt Austern, this should
138// already work on all current implementations.
jdoerrie8f516042018-04-13 09:40:30139//
140// DEPRECATED(https://crbug.com/831499), use base::data(std::string&) instead.
[email protected]7286e3fc2011-07-19 22:13:24141inline char* string_as_array(std::string* str) {
142 // DO NOT USE const_cast<char*>(str->data())
143 return str->empty() ? NULL : &*str->begin();
144}
145
brettw1ce49f62017-04-27 19:42:32146// Test to see if a set or map contains a particular key.
[email protected]7286e3fc2011-07-19 22:13:24147// Returns true if the key is in the collection.
148template <typename Collection, typename Key>
149bool ContainsKey(const Collection& collection, const Key& key) {
150 return collection.find(key) != collection.end();
151}
152
Marijn Kruisselbrinkbb019e32017-06-27 20:50:32153namespace internal {
154
155template <typename Collection>
156class HasKeyType {
157 template <typename C>
158 static std::true_type test(typename C::key_type*);
159 template <typename C>
160 static std::false_type test(...);
161
162 public:
163 static constexpr bool value = decltype(test<Collection>(nullptr))::value;
164};
165
166} // namespace internal
167
robliao43eb02c2015-03-27 18:25:11168// Test to see if a collection like a vector contains a particular value.
169// Returns true if the value is in the collection.
Marijn Kruisselbrinkbb019e32017-06-27 20:50:32170// Don't use this on collections such as sets or maps. This is enforced by
171// disabling this method if the collection defines a key_type.
172template <typename Collection,
173 typename Value,
174 typename std::enable_if<!internal::HasKeyType<Collection>::value,
175 int>::type = 0>
robliao43eb02c2015-03-27 18:25:11176bool ContainsValue(const Collection& collection, const Value& value) {
tsepez1bc34662017-04-20 18:11:46177 return std::find(std::begin(collection), std::end(collection), value) !=
178 std::end(collection);
robliao43eb02c2015-03-27 18:25:11179}
180
[email protected]1dea7572012-12-05 21:40:27181// Returns true if the container is sorted.
182template <typename Container>
183bool STLIsSorted(const Container& cont) {
[email protected]9a53ade2014-01-29 17:13:27184 // Note: Use reverse iterator on container to ensure we only require
185 // value_type to implement operator<.
186 return std::adjacent_find(cont.rbegin(), cont.rend(),
187 std::less<typename Container::value_type>())
188 == cont.rend();
[email protected]1dea7572012-12-05 21:40:27189}
190
191// Returns a new ResultType containing the difference of two sorted containers.
192template <typename ResultType, typename Arg1, typename Arg2>
193ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
194 DCHECK(STLIsSorted(a1));
195 DCHECK(STLIsSorted(a2));
196 ResultType difference;
197 std::set_difference(a1.begin(), a1.end(),
198 a2.begin(), a2.end(),
199 std::inserter(difference, difference.end()));
200 return difference;
201}
202
[email protected]9a53ade2014-01-29 17:13:27203// Returns a new ResultType containing the union of two sorted containers.
204template <typename ResultType, typename Arg1, typename Arg2>
205ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
206 DCHECK(STLIsSorted(a1));
207 DCHECK(STLIsSorted(a2));
208 ResultType result;
209 std::set_union(a1.begin(), a1.end(),
210 a2.begin(), a2.end(),
211 std::inserter(result, result.end()));
212 return result;
213}
214
215// Returns a new ResultType containing the intersection of two sorted
216// containers.
217template <typename ResultType, typename Arg1, typename Arg2>
218ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
219 DCHECK(STLIsSorted(a1));
220 DCHECK(STLIsSorted(a2));
221 ResultType result;
222 std::set_intersection(a1.begin(), a1.end(),
223 a2.begin(), a2.end(),
224 std::inserter(result, result.end()));
225 return result;
226}
227
228// Returns true if the sorted container |a1| contains all elements of the sorted
229// container |a2|.
230template <typename Arg1, typename Arg2>
231bool STLIncludes(const Arg1& a1, const Arg2& a2) {
232 DCHECK(STLIsSorted(a1));
233 DCHECK(STLIsSorted(a2));
234 return std::includes(a1.begin(), a1.end(),
235 a2.begin(), a2.end());
236}
237
dyaroshev5f0ff7982017-03-08 01:24:49238// Erase/EraseIf are based on library fundamentals ts v2 erase/erase_if
239// http://en.cppreference.com/w/cpp/experimental/lib_extensions_2
240// They provide a generic way to erase elements from a container.
241// The functions here implement these for the standard containers until those
242// functions are available in the C++ standard.
243// For Chromium containers overloads should be defined in their own headers
244// (like standard containers).
245// Note: there is no std::erase for standard associative containers so we don't
246// have it either.
247
248template <typename CharT, typename Traits, typename Allocator, typename Value>
249void Erase(std::basic_string<CharT, Traits, Allocator>& container,
250 const Value& value) {
251 container.erase(std::remove(container.begin(), container.end(), value),
252 container.end());
253}
254
255template <typename CharT, typename Traits, typename Allocator, class Predicate>
256void EraseIf(std::basic_string<CharT, Traits, Allocator>& container,
257 Predicate pred) {
258 container.erase(std::remove_if(container.begin(), container.end(), pred),
259 container.end());
260}
261
262template <class T, class Allocator, class Value>
263void Erase(std::deque<T, Allocator>& container, const Value& value) {
264 container.erase(std::remove(container.begin(), container.end(), value),
265 container.end());
266}
267
268template <class T, class Allocator, class Predicate>
269void EraseIf(std::deque<T, Allocator>& container, Predicate pred) {
270 container.erase(std::remove_if(container.begin(), container.end(), pred),
271 container.end());
272}
273
274template <class T, class Allocator, class Value>
275void Erase(std::vector<T, Allocator>& container, const Value& value) {
276 container.erase(std::remove(container.begin(), container.end(), value),
277 container.end());
278}
279
280template <class T, class Allocator, class Predicate>
281void EraseIf(std::vector<T, Allocator>& container, Predicate pred) {
282 container.erase(std::remove_if(container.begin(), container.end(), pred),
283 container.end());
284}
285
286template <class T, class Allocator, class Value>
287void Erase(std::forward_list<T, Allocator>& container, const Value& value) {
288 // Unlike std::forward_list::remove, this function template accepts
289 // heterogeneous types and does not force a conversion to the container's
290 // value type before invoking the == operator.
291 container.remove_if([&](const T& cur) { return cur == value; });
292}
293
294template <class T, class Allocator, class Predicate>
295void EraseIf(std::forward_list<T, Allocator>& container, Predicate pred) {
296 container.remove_if(pred);
297}
298
299template <class T, class Allocator, class Value>
300void Erase(std::list<T, Allocator>& container, const Value& value) {
301 // Unlike std::list::remove, this function template accepts heterogeneous
302 // types and does not force a conversion to the container's value type before
303 // invoking the == operator.
304 container.remove_if([&](const T& cur) { return cur == value; });
305}
306
307template <class T, class Allocator, class Predicate>
308void EraseIf(std::list<T, Allocator>& container, Predicate pred) {
309 container.remove_if(pred);
310}
311
jdoerrie5dd3a2132017-03-13 15:31:10312template <class Key, class T, class Compare, class Allocator, class Predicate>
313void EraseIf(std::map<Key, T, Compare, Allocator>& container, Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49314 internal::IterateAndEraseIf(container, pred);
315}
316
jdoerrie5dd3a2132017-03-13 15:31:10317template <class Key, class T, class Compare, class Allocator, class Predicate>
318void EraseIf(std::multimap<Key, T, Compare, Allocator>& container,
319 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49320 internal::IterateAndEraseIf(container, pred);
321}
322
jdoerrie5dd3a2132017-03-13 15:31:10323template <class Key, class Compare, class Allocator, class Predicate>
324void EraseIf(std::set<Key, Compare, Allocator>& container, Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49325 internal::IterateAndEraseIf(container, pred);
326}
327
jdoerrie5dd3a2132017-03-13 15:31:10328template <class Key, class Compare, class Allocator, class Predicate>
329void EraseIf(std::multiset<Key, Compare, Allocator>& container,
330 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49331 internal::IterateAndEraseIf(container, pred);
332}
333
jdoerrie5dd3a2132017-03-13 15:31:10334template <class Key,
335 class T,
336 class Hash,
337 class KeyEqual,
338 class Allocator,
339 class Predicate>
340void EraseIf(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& container,
341 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49342 internal::IterateAndEraseIf(container, pred);
343}
344
jdoerrie5dd3a2132017-03-13 15:31:10345template <class Key,
346 class T,
347 class Hash,
348 class KeyEqual,
349 class Allocator,
350 class Predicate>
351void EraseIf(
352 std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& container,
353 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49354 internal::IterateAndEraseIf(container, pred);
355}
356
jdoerrie5dd3a2132017-03-13 15:31:10357template <class Key,
358 class Hash,
359 class KeyEqual,
360 class Allocator,
361 class Predicate>
362void EraseIf(std::unordered_set<Key, Hash, KeyEqual, Allocator>& container,
363 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49364 internal::IterateAndEraseIf(container, pred);
365}
366
jdoerrie5dd3a2132017-03-13 15:31:10367template <class Key,
368 class Hash,
369 class KeyEqual,
370 class Allocator,
371 class Predicate>
372void EraseIf(std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& container,
373 Predicate pred) {
dyaroshev5f0ff7982017-03-08 01:24:49374 internal::IterateAndEraseIf(container, pred);
375}
376
Kevin Bailey156ff6d2017-10-26 17:36:00377// A helper class to be used as the predicate with |EraseIf| to implement
378// in-place set intersection. Helps implement the algorithm of going through
379// each container an element at a time, erasing elements from the first
380// container if they aren't in the second container. Requires each container be
381// sorted. Note that the logic below appears inverted since it is returning
382// whether an element should be erased.
383template <class Collection>
384class IsNotIn {
385 public:
386 explicit IsNotIn(const Collection& collection)
387 : i_(collection.begin()), end_(collection.end()) {}
388
389 bool operator()(const typename Collection::value_type& x) {
390 while (i_ != end_ && *i_ < x)
391 ++i_;
392 if (i_ == end_)
393 return true;
394 if (*i_ == x) {
395 ++i_;
396 return false;
397 }
398 return true;
399 }
400
401 private:
402 typename Collection::const_iterator i_;
403 const typename Collection::const_iterator end_;
404};
405
Philip Rogers3f67719f2018-03-09 02:16:44406// Helper for returning the optional value's address, or nullptr.
407template <class T>
408T* OptionalOrNullptr(base::Optional<T>& optional) {
409 return optional.has_value() ? &optional.value() : nullptr;
410}
411
412template <class T>
413const T* OptionalOrNullptr(const base::Optional<T>& optional) {
414 return optional.has_value() ? &optional.value() : nullptr;
415}
416
[email protected]1dea7572012-12-05 21:40:27417} // namespace base
418
[email protected]7286e3fc2011-07-19 22:13:24419#endif // BASE_STL_UTIL_H_