123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877 |
- // Copyright (c) 2011 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- // Derived from google3/util/gtl/stl_util.h
- #ifndef BASE_STL_UTIL_H_
- #define BASE_STL_UTIL_H_
- #include <algorithm>
- #include <deque>
- #include <forward_list>
- #include <functional>
- #include <initializer_list>
- #include <iterator>
- #include <list>
- #include <map>
- #include <set>
- #include <string>
- #include <type_traits>
- #include <unordered_map>
- #include <unordered_set>
- #include <utility>
- #include <vector>
- #include "base/check.h"
- #include "base/optional.h"
- #include "base/template_util.h"
- namespace base {
- namespace internal {
- // Calls erase on iterators of matching elements and returns the number of
- // removed elements.
- template <typename Container, typename Predicate>
- size_t IterateAndEraseIf(Container& container, Predicate pred) {
- size_t old_size = container.size();
- for (auto it = container.begin(), last = container.end(); it != last;) {
- if (pred(*it))
- it = container.erase(it);
- else
- ++it;
- }
- return old_size - container.size();
- }
- template <typename Iter>
- constexpr bool IsRandomAccessIter =
- std::is_same<typename std::iterator_traits<Iter>::iterator_category,
- std::random_access_iterator_tag>::value;
- // Utility type traits used for specializing base::Contains() below.
- template <typename Container, typename Element, typename = void>
- struct HasFindWithNpos : std::false_type {};
- template <typename Container, typename Element>
- struct HasFindWithNpos<
- Container,
- Element,
- void_t<decltype(std::declval<const Container&>().find(
- std::declval<const Element&>()) != Container::npos)>>
- : std::true_type {};
- template <typename Container, typename Element, typename = void>
- struct HasFindWithEnd : std::false_type {};
- template <typename Container, typename Element>
- struct HasFindWithEnd<Container,
- Element,
- void_t<decltype(std::declval<const Container&>().find(
- std::declval<const Element&>()) !=
- std::declval<const Container&>().end())>>
- : std::true_type {};
- template <typename Container, typename Element, typename = void>
- struct HasContains : std::false_type {};
- template <typename Container, typename Element>
- struct HasContains<Container,
- Element,
- void_t<decltype(std::declval<const Container&>().contains(
- std::declval<const Element&>()))>> : std::true_type {};
- } // namespace internal
- // C++14 implementation of C++17's std::size():
- // http://en.cppreference.com/w/cpp/iterator/size
- template <typename Container>
- constexpr auto size(const Container& c) -> decltype(c.size()) {
- return c.size();
- }
- template <typename T, size_t N>
- constexpr size_t size(const T (&array)[N]) noexcept {
- return N;
- }
- // C++14 implementation of C++17's std::empty():
- // http://en.cppreference.com/w/cpp/iterator/empty
- template <typename Container>
- constexpr auto empty(const Container& c) -> decltype(c.empty()) {
- return c.empty();
- }
- template <typename T, size_t N>
- constexpr bool empty(const T (&array)[N]) noexcept {
- return false;
- }
- template <typename T>
- constexpr bool empty(std::initializer_list<T> il) noexcept {
- return il.size() == 0;
- }
- // C++14 implementation of C++17's std::data():
- // http://en.cppreference.com/w/cpp/iterator/data
- template <typename Container>
- constexpr auto data(Container& c) -> decltype(c.data()) {
- return c.data();
- }
- // std::basic_string::data() had no mutable overload prior to C++17 [1].
- // Hence this overload is provided.
- // Note: str[0] is safe even for empty strings, as they are guaranteed to be
- // null-terminated [2].
- //
- // [1] http://en.cppreference.com/w/cpp/string/basic_string/data
- // [2] http://en.cppreference.com/w/cpp/string/basic_string/operator_at
- template <typename CharT, typename Traits, typename Allocator>
- CharT* data(std::basic_string<CharT, Traits, Allocator>& str) {
- return std::addressof(str[0]);
- }
- template <typename Container>
- constexpr auto data(const Container& c) -> decltype(c.data()) {
- return c.data();
- }
- template <typename T, size_t N>
- constexpr T* data(T (&array)[N]) noexcept {
- return array;
- }
- template <typename T>
- constexpr const T* data(std::initializer_list<T> il) noexcept {
- return il.begin();
- }
- // std::array::data() was not constexpr prior to C++17 [1].
- // Hence these overloads are provided.
- //
- // [1] https://en.cppreference.com/w/cpp/container/array/data
- template <typename T, size_t N>
- constexpr T* data(std::array<T, N>& array) noexcept {
- return !array.empty() ? &array[0] : nullptr;
- }
- template <typename T, size_t N>
- constexpr const T* data(const std::array<T, N>& array) noexcept {
- return !array.empty() ? &array[0] : nullptr;
- }
- // C++14 implementation of C++17's std::as_const():
- // https://en.cppreference.com/w/cpp/utility/as_const
- template <typename T>
- constexpr std::add_const_t<T>& as_const(T& t) noexcept {
- return t;
- }
- template <typename T>
- void as_const(const T&& t) = delete;
- namespace internal {
- // Helper struct and alias to deduce the class type from a member function
- // pointer or member object pointer.
- template <typename DecayedF>
- struct member_pointer_class {};
- template <typename ReturnT, typename ClassT>
- struct member_pointer_class<ReturnT ClassT::*> {
- using type = ClassT;
- };
- template <typename DecayedF>
- using member_pointer_class_t = typename member_pointer_class<DecayedF>::type;
- // Utility struct to detect specializations of std::reference_wrapper.
- template <typename T>
- struct is_reference_wrapper : std::false_type {};
- template <typename T>
- struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
- // Small helpers used below in internal::invoke to make the SFINAE more concise.
- template <typename F>
- const bool& IsMemFunPtr =
- std::is_member_function_pointer<std::decay_t<F>>::value;
- template <typename F>
- const bool& IsMemObjPtr = std::is_member_object_pointer<std::decay_t<F>>::value;
- template <typename F,
- typename T,
- typename MemPtrClass = member_pointer_class_t<std::decay_t<F>>>
- const bool& IsMemPtrToBaseOf =
- std::is_base_of<MemPtrClass, std::decay_t<T>>::value;
- template <typename T>
- const bool& IsRefWrapper = is_reference_wrapper<std::decay_t<T>>::value;
- template <bool B>
- using EnableIf = std::enable_if_t<B, bool>;
- // Invokes a member function pointer on a reference to an object of a suitable
- // type. Covers bullet 1 of the INVOKE definition.
- //
- // Reference: https://wg21.link/func.require#1.1
- template <typename F,
- typename T1,
- typename... Args,
- EnableIf<IsMemFunPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
- constexpr decltype(auto) invoke(F&& f, T1&& t1, Args&&... args) {
- return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
- }
- // Invokes a member function pointer on a std::reference_wrapper to an object of
- // a suitable type. Covers bullet 2 of the INVOKE definition.
- //
- // Reference: https://wg21.link/func.require#1.2
- template <typename F,
- typename T1,
- typename... Args,
- EnableIf<IsMemFunPtr<F> && IsRefWrapper<T1>> = true>
- constexpr decltype(auto) invoke(F&& f, T1&& t1, Args&&... args) {
- return (t1.get().*f)(std::forward<Args>(args)...);
- }
- // Invokes a member function pointer on a pointer-like type to an object of a
- // suitable type. Covers bullet 3 of the INVOKE definition.
- //
- // Reference: https://wg21.link/func.require#1.3
- template <typename F,
- typename T1,
- typename... Args,
- EnableIf<IsMemFunPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
- !IsRefWrapper<T1>> = true>
- constexpr decltype(auto) invoke(F&& f, T1&& t1, Args&&... args) {
- return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
- }
- // Invokes a member object pointer on a reference to an object of a suitable
- // type. Covers bullet 4 of the INVOKE definition.
- //
- // Reference: https://wg21.link/func.require#1.4
- template <typename F,
- typename T1,
- EnableIf<IsMemObjPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
- constexpr decltype(auto) invoke(F&& f, T1&& t1) {
- return std::forward<T1>(t1).*f;
- }
- // Invokes a member object pointer on a std::reference_wrapper to an object of
- // a suitable type. Covers bullet 5 of the INVOKE definition.
- //
- // Reference: https://wg21.link/func.require#1.5
- template <typename F,
- typename T1,
- EnableIf<IsMemObjPtr<F> && IsRefWrapper<T1>> = true>
- constexpr decltype(auto) invoke(F&& f, T1&& t1) {
- return t1.get().*f;
- }
- // Invokes a member object pointer on a pointer-like type to an object of a
- // suitable type. Covers bullet 6 of the INVOKE definition.
- //
- // Reference: https://wg21.link/func.require#1.6
- template <typename F,
- typename T1,
- EnableIf<IsMemObjPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
- !IsRefWrapper<T1>> = true>
- constexpr decltype(auto) invoke(F&& f, T1&& t1) {
- return (*std::forward<T1>(t1)).*f;
- }
- // Invokes a regular function or function object. Covers bullet 7 of the INVOKE
- // definition.
- //
- // Reference: https://wg21.link/func.require#1.7
- template <typename F, typename... Args>
- constexpr decltype(auto) invoke(F&& f, Args&&... args) {
- return std::forward<F>(f)(std::forward<Args>(args)...);
- }
- } // namespace internal
- // Implementation of C++17's std::invoke. This is not based on implementation
- // referenced in original std::invoke proposal, but rather a manual
- // implementation, so that it can be constexpr.
- //
- // References:
- // - https://wg21.link/n4169#implementability
- // - https://en.cppreference.com/w/cpp/utility/functional/invoke
- // - https://wg21.link/func.invoke
- template <typename F, typename... Args>
- constexpr decltype(auto) invoke(F&& f, Args&&... args) {
- return internal::invoke(std::forward<F>(f), std::forward<Args>(args)...);
- }
- // Implementation of C++20's std::identity.
- //
- // Reference:
- // - https://en.cppreference.com/w/cpp/utility/functional/identity
- // - https://wg21.link/func.identity
- struct identity {
- template <typename T>
- constexpr T&& operator()(T&& t) const noexcept {
- return std::forward<T>(t);
- }
- using is_transparent = void;
- };
- // Returns a const reference to the underlying container of a container adapter.
- // Works for std::priority_queue, std::queue, and std::stack.
- template <class A>
- const typename A::container_type& GetUnderlyingContainer(const A& adapter) {
- struct ExposedAdapter : A {
- using A::c;
- };
- return adapter.*&ExposedAdapter::c;
- }
- // Clears internal memory of an STL object.
- // STL clear()/reserve(0) does not always free internal memory allocated
- // This function uses swap/destructor to ensure the internal memory is freed.
- template<class T>
- void STLClearObject(T* obj) {
- T tmp;
- tmp.swap(*obj);
- // Sometimes "T tmp" allocates objects with memory (arena implementation?).
- // Hence using additional reserve(0) even if it doesn't always work.
- obj->reserve(0);
- }
- // Counts the number of instances of val in a container.
- template <typename Container, typename T>
- typename std::iterator_traits<
- typename Container::const_iterator>::difference_type
- STLCount(const Container& container, const T& val) {
- return std::count(container.begin(), container.end(), val);
- }
- // General purpose implementation to check if |container| contains |value|.
- template <typename Container,
- typename Value,
- std::enable_if_t<
- !internal::HasFindWithNpos<Container, Value>::value &&
- !internal::HasFindWithEnd<Container, Value>::value &&
- !internal::HasContains<Container, Value>::value>* = nullptr>
- bool Contains(const Container& container, const Value& value) {
- using std::begin;
- using std::end;
- return std::find(begin(container), end(container), value) != end(container);
- }
- // Specialized Contains() implementation for when |container| has a find()
- // member function and a static npos member, but no contains() member function.
- template <typename Container,
- typename Value,
- std::enable_if_t<internal::HasFindWithNpos<Container, Value>::value &&
- !internal::HasContains<Container, Value>::value>* =
- nullptr>
- bool Contains(const Container& container, const Value& value) {
- return container.find(value) != Container::npos;
- }
- // Specialized Contains() implementation for when |container| has a find()
- // and end() member function, but no contains() member function.
- template <typename Container,
- typename Value,
- std::enable_if_t<internal::HasFindWithEnd<Container, Value>::value &&
- !internal::HasContains<Container, Value>::value>* =
- nullptr>
- bool Contains(const Container& container, const Value& value) {
- return container.find(value) != container.end();
- }
- // Specialized Contains() implementation for when |container| has a contains()
- // member function.
- template <
- typename Container,
- typename Value,
- std::enable_if_t<internal::HasContains<Container, Value>::value>* = nullptr>
- bool Contains(const Container& container, const Value& value) {
- return container.contains(value);
- }
- // O(1) implementation of const casting an iterator for any sequence,
- // associative or unordered associative container in the STL.
- //
- // Reference: https://stackoverflow.com/a/10669041
- template <typename Container,
- typename ConstIter,
- std::enable_if_t<!internal::IsRandomAccessIter<ConstIter>>* = nullptr>
- constexpr auto ConstCastIterator(Container& c, ConstIter it) {
- return c.erase(it, it);
- }
- // Explicit overload for std::forward_list where erase() is named erase_after().
- template <typename T, typename Allocator>
- constexpr auto ConstCastIterator(
- std::forward_list<T, Allocator>& c,
- typename std::forward_list<T, Allocator>::const_iterator it) {
- // The erase_after(it, it) trick used below does not work for libstdc++ [1],
- // thus we need a different way.
- // TODO(crbug.com/972541): Remove this workaround once libstdc++ is fixed on all
- // platforms.
- //
- // [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90857
- #if defined(__GLIBCXX__)
- return c.insert_after(it, {});
- #else
- return c.erase_after(it, it);
- #endif
- }
- // Specialized O(1) const casting for random access iterators. This is
- // necessary, because erase() is either not available (e.g. array-like
- // containers), or has O(n) complexity (e.g. std::deque or std::vector).
- template <typename Container,
- typename ConstIter,
- std::enable_if_t<internal::IsRandomAccessIter<ConstIter>>* = nullptr>
- constexpr auto ConstCastIterator(Container& c, ConstIter it) {
- using std::begin;
- using std::cbegin;
- return begin(c) + (it - cbegin(c));
- }
- namespace internal {
- template <typename Map, typename Key, typename Value>
- std::pair<typename Map::iterator, bool> InsertOrAssignImpl(Map& map,
- Key&& key,
- Value&& value) {
- auto lower = map.lower_bound(key);
- if (lower != map.end() && !map.key_comp()(key, lower->first)) {
- // key already exists, perform assignment.
- lower->second = std::forward<Value>(value);
- return {lower, false};
- }
- // key did not yet exist, insert it.
- return {map.emplace_hint(lower, std::forward<Key>(key),
- std::forward<Value>(value)),
- true};
- }
- template <typename Map, typename Key, typename Value>
- typename Map::iterator InsertOrAssignImpl(Map& map,
- typename Map::const_iterator hint,
- Key&& key,
- Value&& value) {
- auto&& key_comp = map.key_comp();
- if ((hint == map.begin() || key_comp(std::prev(hint)->first, key))) {
- if (hint == map.end() || key_comp(key, hint->first)) {
- // *(hint - 1) < key < *hint => key did not exist and hint is correct.
- return map.emplace_hint(hint, std::forward<Key>(key),
- std::forward<Value>(value));
- }
- if (!key_comp(hint->first, key)) {
- // key == *hint => key already exists and hint is correct.
- auto mutable_hint = ConstCastIterator(map, hint);
- mutable_hint->second = std::forward<Value>(value);
- return mutable_hint;
- }
- }
- // hint was not helpful, dispatch to hintless version.
- return InsertOrAssignImpl(map, std::forward<Key>(key),
- std::forward<Value>(value))
- .first;
- }
- template <typename Map, typename Key, typename... Args>
- std::pair<typename Map::iterator, bool> TryEmplaceImpl(Map& map,
- Key&& key,
- Args&&... args) {
- auto lower = map.lower_bound(key);
- if (lower != map.end() && !map.key_comp()(key, lower->first)) {
- // key already exists, do nothing.
- return {lower, false};
- }
- // key did not yet exist, insert it.
- return {map.emplace_hint(lower, std::piecewise_construct,
- std::forward_as_tuple(std::forward<Key>(key)),
- std::forward_as_tuple(std::forward<Args>(args)...)),
- true};
- }
- template <typename Map, typename Key, typename... Args>
- typename Map::iterator TryEmplaceImpl(Map& map,
- typename Map::const_iterator hint,
- Key&& key,
- Args&&... args) {
- auto&& key_comp = map.key_comp();
- if ((hint == map.begin() || key_comp(std::prev(hint)->first, key))) {
- if (hint == map.end() || key_comp(key, hint->first)) {
- // *(hint - 1) < key < *hint => key did not exist and hint is correct.
- return map.emplace_hint(
- hint, std::piecewise_construct,
- std::forward_as_tuple(std::forward<Key>(key)),
- std::forward_as_tuple(std::forward<Args>(args)...));
- }
- if (!key_comp(hint->first, key)) {
- // key == *hint => no-op, return correct hint.
- return ConstCastIterator(map, hint);
- }
- }
- // hint was not helpful, dispatch to hintless version.
- return TryEmplaceImpl(map, std::forward<Key>(key),
- std::forward<Args>(args)...)
- .first;
- }
- } // namespace internal
- // Implementation of C++17's std::map::insert_or_assign as a free function.
- template <typename Map, typename Value>
- std::pair<typename Map::iterator, bool>
- InsertOrAssign(Map& map, const typename Map::key_type& key, Value&& value) {
- return internal::InsertOrAssignImpl(map, key, std::forward<Value>(value));
- }
- template <typename Map, typename Value>
- std::pair<typename Map::iterator, bool>
- InsertOrAssign(Map& map, typename Map::key_type&& key, Value&& value) {
- return internal::InsertOrAssignImpl(map, std::move(key),
- std::forward<Value>(value));
- }
- // Implementation of C++17's std::map::insert_or_assign with hint as a free
- // function.
- template <typename Map, typename Value>
- typename Map::iterator InsertOrAssign(Map& map,
- typename Map::const_iterator hint,
- const typename Map::key_type& key,
- Value&& value) {
- return internal::InsertOrAssignImpl(map, hint, key,
- std::forward<Value>(value));
- }
- template <typename Map, typename Value>
- typename Map::iterator InsertOrAssign(Map& map,
- typename Map::const_iterator hint,
- typename Map::key_type&& key,
- Value&& value) {
- return internal::InsertOrAssignImpl(map, hint, std::move(key),
- std::forward<Value>(value));
- }
- // Implementation of C++17's std::map::try_emplace as a free function.
- template <typename Map, typename... Args>
- std::pair<typename Map::iterator, bool>
- TryEmplace(Map& map, const typename Map::key_type& key, Args&&... args) {
- return internal::TryEmplaceImpl(map, key, std::forward<Args>(args)...);
- }
- template <typename Map, typename... Args>
- std::pair<typename Map::iterator, bool> TryEmplace(Map& map,
- typename Map::key_type&& key,
- Args&&... args) {
- return internal::TryEmplaceImpl(map, std::move(key),
- std::forward<Args>(args)...);
- }
- // Implementation of C++17's std::map::try_emplace with hint as a free
- // function.
- template <typename Map, typename... Args>
- typename Map::iterator TryEmplace(Map& map,
- typename Map::const_iterator hint,
- const typename Map::key_type& key,
- Args&&... args) {
- return internal::TryEmplaceImpl(map, hint, key, std::forward<Args>(args)...);
- }
- template <typename Map, typename... Args>
- typename Map::iterator TryEmplace(Map& map,
- typename Map::const_iterator hint,
- typename Map::key_type&& key,
- Args&&... args) {
- return internal::TryEmplaceImpl(map, hint, std::move(key),
- std::forward<Args>(args)...);
- }
- // Returns true if the container is sorted. Requires constexpr std::begin/end,
- // which exists for arrays in C++14.
- // Note that std::is_sorted is constexpr beginning C++20 and this should be
- // switched to use it when C++20 is supported.
- template <typename Container>
- constexpr bool STLIsSorted(const Container& cont) {
- auto it = std::begin(cont);
- const auto end = std::end(cont);
- if (it == end)
- return true;
- for (auto prev = it++; it != end; prev = it++) {
- if (*it < *prev)
- return false;
- }
- return true;
- }
- // Returns a new ResultType containing the difference of two sorted containers.
- template <typename ResultType, typename Arg1, typename Arg2>
- ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
- DCHECK(STLIsSorted(a1));
- DCHECK(STLIsSorted(a2));
- ResultType difference;
- std::set_difference(a1.begin(), a1.end(),
- a2.begin(), a2.end(),
- std::inserter(difference, difference.end()));
- return difference;
- }
- // Returns a new ResultType containing the union of two sorted containers.
- template <typename ResultType, typename Arg1, typename Arg2>
- ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
- DCHECK(STLIsSorted(a1));
- DCHECK(STLIsSorted(a2));
- ResultType result;
- std::set_union(a1.begin(), a1.end(),
- a2.begin(), a2.end(),
- std::inserter(result, result.end()));
- return result;
- }
- // Returns a new ResultType containing the intersection of two sorted
- // containers.
- template <typename ResultType, typename Arg1, typename Arg2>
- ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
- DCHECK(STLIsSorted(a1));
- DCHECK(STLIsSorted(a2));
- ResultType result;
- std::set_intersection(a1.begin(), a1.end(),
- a2.begin(), a2.end(),
- std::inserter(result, result.end()));
- return result;
- }
- // Returns true if the sorted container |a1| contains all elements of the sorted
- // container |a2|.
- template <typename Arg1, typename Arg2>
- bool STLIncludes(const Arg1& a1, const Arg2& a2) {
- DCHECK(STLIsSorted(a1));
- DCHECK(STLIsSorted(a2));
- return std::includes(a1.begin(), a1.end(),
- a2.begin(), a2.end());
- }
- // Erase/EraseIf are based on C++20's uniform container erasure API:
- // - https://eel.is/c++draft/libraryindex#:erase
- // - https://eel.is/c++draft/libraryindex#:erase_if
- // They provide a generic way to erase elements from a container.
- // The functions here implement these for the standard containers until those
- // functions are available in the C++ standard.
- // For Chromium containers overloads should be defined in their own headers
- // (like standard containers).
- // Note: there is no std::erase for standard associative containers so we don't
- // have it either.
- template <typename CharT, typename Traits, typename Allocator, typename Value>
- size_t Erase(std::basic_string<CharT, Traits, Allocator>& container,
- const Value& value) {
- auto it = std::remove(container.begin(), container.end(), value);
- size_t removed = std::distance(it, container.end());
- container.erase(it, container.end());
- return removed;
- }
- template <typename CharT, typename Traits, typename Allocator, class Predicate>
- size_t EraseIf(std::basic_string<CharT, Traits, Allocator>& container,
- Predicate pred) {
- auto it = std::remove_if(container.begin(), container.end(), pred);
- size_t removed = std::distance(it, container.end());
- container.erase(it, container.end());
- return removed;
- }
- template <class T, class Allocator, class Value>
- size_t Erase(std::deque<T, Allocator>& container, const Value& value) {
- auto it = std::remove(container.begin(), container.end(), value);
- size_t removed = std::distance(it, container.end());
- container.erase(it, container.end());
- return removed;
- }
- template <class T, class Allocator, class Predicate>
- size_t EraseIf(std::deque<T, Allocator>& container, Predicate pred) {
- auto it = std::remove_if(container.begin(), container.end(), pred);
- size_t removed = std::distance(it, container.end());
- container.erase(it, container.end());
- return removed;
- }
- template <class T, class Allocator, class Value>
- size_t Erase(std::vector<T, Allocator>& container, const Value& value) {
- auto it = std::remove(container.begin(), container.end(), value);
- size_t removed = std::distance(it, container.end());
- container.erase(it, container.end());
- return removed;
- }
- template <class T, class Allocator, class Predicate>
- size_t EraseIf(std::vector<T, Allocator>& container, Predicate pred) {
- auto it = std::remove_if(container.begin(), container.end(), pred);
- size_t removed = std::distance(it, container.end());
- container.erase(it, container.end());
- return removed;
- }
- template <class T, class Allocator, class Predicate>
- size_t EraseIf(std::forward_list<T, Allocator>& container, Predicate pred) {
- // Note: std::forward_list does not have a size() API, thus we need to use the
- // O(n) std::distance work-around. However, given that EraseIf is O(n)
- // already, this should not make a big difference.
- size_t old_size = std::distance(container.begin(), container.end());
- container.remove_if(pred);
- return old_size - std::distance(container.begin(), container.end());
- }
- template <class T, class Allocator, class Predicate>
- size_t EraseIf(std::list<T, Allocator>& container, Predicate pred) {
- size_t old_size = container.size();
- container.remove_if(pred);
- return old_size - container.size();
- }
- template <class Key, class T, class Compare, class Allocator, class Predicate>
- size_t EraseIf(std::map<Key, T, Compare, Allocator>& container,
- Predicate pred) {
- return internal::IterateAndEraseIf(container, pred);
- }
- template <class Key, class T, class Compare, class Allocator, class Predicate>
- size_t EraseIf(std::multimap<Key, T, Compare, Allocator>& container,
- Predicate pred) {
- return internal::IterateAndEraseIf(container, pred);
- }
- template <class Key, class Compare, class Allocator, class Predicate>
- size_t EraseIf(std::set<Key, Compare, Allocator>& container, Predicate pred) {
- return internal::IterateAndEraseIf(container, pred);
- }
- template <class Key, class Compare, class Allocator, class Predicate>
- size_t EraseIf(std::multiset<Key, Compare, Allocator>& container,
- Predicate pred) {
- return internal::IterateAndEraseIf(container, pred);
- }
- template <class Key,
- class T,
- class Hash,
- class KeyEqual,
- class Allocator,
- class Predicate>
- size_t EraseIf(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& container,
- Predicate pred) {
- return internal::IterateAndEraseIf(container, pred);
- }
- template <class Key,
- class T,
- class Hash,
- class KeyEqual,
- class Allocator,
- class Predicate>
- size_t EraseIf(
- std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& container,
- Predicate pred) {
- return internal::IterateAndEraseIf(container, pred);
- }
- template <class Key,
- class Hash,
- class KeyEqual,
- class Allocator,
- class Predicate>
- size_t EraseIf(std::unordered_set<Key, Hash, KeyEqual, Allocator>& container,
- Predicate pred) {
- return internal::IterateAndEraseIf(container, pred);
- }
- template <class Key,
- class Hash,
- class KeyEqual,
- class Allocator,
- class Predicate>
- size_t EraseIf(
- std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& container,
- Predicate pred) {
- return internal::IterateAndEraseIf(container, pred);
- }
- template <class T, class Allocator, class Value>
- size_t Erase(std::forward_list<T, Allocator>& container, const Value& value) {
- // Unlike std::forward_list::remove, this function template accepts
- // heterogeneous types and does not force a conversion to the container's
- // value type before invoking the == operator.
- return EraseIf(container, [&](const T& cur) { return cur == value; });
- }
- template <class T, class Allocator, class Value>
- size_t Erase(std::list<T, Allocator>& container, const Value& value) {
- // Unlike std::list::remove, this function template accepts heterogeneous
- // types and does not force a conversion to the container's value type before
- // invoking the == operator.
- return EraseIf(container, [&](const T& cur) { return cur == value; });
- }
- // A helper class to be used as the predicate with |EraseIf| to implement
- // in-place set intersection. Helps implement the algorithm of going through
- // each container an element at a time, erasing elements from the first
- // container if they aren't in the second container. Requires each container be
- // sorted. Note that the logic below appears inverted since it is returning
- // whether an element should be erased.
- template <class Collection>
- class IsNotIn {
- public:
- explicit IsNotIn(const Collection& collection)
- : i_(collection.begin()), end_(collection.end()) {}
- bool operator()(const typename Collection::value_type& x) {
- while (i_ != end_ && *i_ < x)
- ++i_;
- if (i_ == end_)
- return true;
- if (*i_ == x) {
- ++i_;
- return false;
- }
- return true;
- }
- private:
- typename Collection::const_iterator i_;
- const typename Collection::const_iterator end_;
- };
- // Helper for returning the optional value's address, or nullptr.
- template <class T>
- T* OptionalOrNullptr(base::Optional<T>& optional) {
- return optional.has_value() ? &optional.value() : nullptr;
- }
- template <class T>
- const T* OptionalOrNullptr(const base::Optional<T>& optional) {
- return optional.has_value() ? &optional.value() : nullptr;
- }
- // Helper for creating an Optional<T> from a potentially nullptr T*.
- template <class T>
- base::Optional<T> OptionalFromPtr(const T* value) {
- if (value)
- return base::Optional<T>(*value);
- return base::nullopt;
- }
- } // namespace base
- #endif // BASE_STL_UTIL_H_
|