1// 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" 25 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 43// 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(), 84 std::less<typename Container::value_type>()) == 85 cont.rend(); 86} 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; 94 std::set_difference(a1.begin(), a1.end(), a2.begin(), a2.end(), 95 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; 105 std::set_union(a1.begin(), a1.end(), a2.begin(), a2.end(), 106 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; 117 std::set_intersection(a1.begin(), a1.end(), a2.begin(), a2.end(), 118 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)); 128 return std::includes(a1.begin(), a1.end(), a2.begin(), a2.end()); 129} 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 270} // namespace base 271 272#endif // BASE_STL_UTIL_H_ 273