| //===- llvm/ADT/MapVector.h - Map w/ deterministic value order --*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// This file implements a map that provides insertion order iteration. The |
| /// interface is purposefully minimal. The key is assumed to be cheap to copy |
| /// and 2 copies are kept, one for indexing in a DenseMap, one for iteration in |
| /// a std::vector. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_ADT_MAPVECTOR_H |
| #define LLVM_ADT_MAPVECTOR_H |
| |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include <cassert> |
| #include <cstddef> |
| #include <iterator> |
| #include <type_traits> |
| #include <utility> |
| #include <vector> |
| |
| namespace llvm { |
| |
| /// This class implements a map that also provides access to all stored values |
| /// in a deterministic order. The values are kept in a std::vector and the |
| /// mapping is done with DenseMap from Keys to indexes in that vector. |
| template<typename KeyT, typename ValueT, |
| typename MapType = DenseMap<KeyT, unsigned>, |
| typename VectorType = std::vector<std::pair<KeyT, ValueT>>> |
| class MapVector { |
| MapType Map; |
| VectorType Vector; |
| |
| static_assert( |
| std::is_integral_v<typename MapType::mapped_type>, |
| "The mapped_type of the specified Map must be an integral type"); |
| |
| public: |
| using key_type = KeyT; |
| using value_type = typename VectorType::value_type; |
| using size_type = typename VectorType::size_type; |
| |
| using iterator = typename VectorType::iterator; |
| using const_iterator = typename VectorType::const_iterator; |
| using reverse_iterator = typename VectorType::reverse_iterator; |
| using const_reverse_iterator = typename VectorType::const_reverse_iterator; |
| |
| /// Clear the MapVector and return the underlying vector. |
| VectorType takeVector() { |
| Map.clear(); |
| return std::move(Vector); |
| } |
| |
| size_type size() const { return Vector.size(); } |
| |
| /// Grow the MapVector so that it can contain at least \p NumEntries items |
| /// before resizing again. |
| void reserve(size_type NumEntries) { |
| Map.reserve(NumEntries); |
| Vector.reserve(NumEntries); |
| } |
| |
| iterator begin() { return Vector.begin(); } |
| const_iterator begin() const { return Vector.begin(); } |
| iterator end() { return Vector.end(); } |
| const_iterator end() const { return Vector.end(); } |
| |
| reverse_iterator rbegin() { return Vector.rbegin(); } |
| const_reverse_iterator rbegin() const { return Vector.rbegin(); } |
| reverse_iterator rend() { return Vector.rend(); } |
| const_reverse_iterator rend() const { return Vector.rend(); } |
| |
| bool empty() const { |
| return Vector.empty(); |
| } |
| |
| std::pair<KeyT, ValueT> &front() { return Vector.front(); } |
| const std::pair<KeyT, ValueT> &front() const { return Vector.front(); } |
| std::pair<KeyT, ValueT> &back() { return Vector.back(); } |
| const std::pair<KeyT, ValueT> &back() const { return Vector.back(); } |
| |
| void clear() { |
| Map.clear(); |
| Vector.clear(); |
| } |
| |
| void swap(MapVector &RHS) { |
| std::swap(Map, RHS.Map); |
| std::swap(Vector, RHS.Vector); |
| } |
| |
| ValueT &operator[](const KeyT &Key) { |
| std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(Key, 0); |
| std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair); |
| auto &I = Result.first->second; |
| if (Result.second) { |
| Vector.push_back(std::make_pair(Key, ValueT())); |
| I = Vector.size() - 1; |
| } |
| return Vector[I].second; |
| } |
| |
| // Returns a copy of the value. Only allowed if ValueT is copyable. |
| ValueT lookup(const KeyT &Key) const { |
| static_assert(std::is_copy_constructible_v<ValueT>, |
| "Cannot call lookup() if ValueT is not copyable."); |
| typename MapType::const_iterator Pos = Map.find(Key); |
| return Pos == Map.end()? ValueT() : Vector[Pos->second].second; |
| } |
| |
| std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) { |
| std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(KV.first, 0); |
| std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair); |
| auto &I = Result.first->second; |
| if (Result.second) { |
| Vector.push_back(std::make_pair(KV.first, KV.second)); |
| I = Vector.size() - 1; |
| return std::make_pair(std::prev(end()), true); |
| } |
| return std::make_pair(begin() + I, false); |
| } |
| |
| std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) { |
| // Copy KV.first into the map, then move it into the vector. |
| std::pair<KeyT, typename MapType::mapped_type> Pair = std::make_pair(KV.first, 0); |
| std::pair<typename MapType::iterator, bool> Result = Map.insert(Pair); |
| auto &I = Result.first->second; |
| if (Result.second) { |
| Vector.push_back(std::move(KV)); |
| I = Vector.size() - 1; |
| return std::make_pair(std::prev(end()), true); |
| } |
| return std::make_pair(begin() + I, false); |
| } |
| |
| bool contains(const KeyT &Key) const { return Map.find(Key) != Map.end(); } |
| |
| size_type count(const KeyT &Key) const { return contains(Key) ? 1 : 0; } |
| |
| iterator find(const KeyT &Key) { |
| typename MapType::const_iterator Pos = Map.find(Key); |
| return Pos == Map.end()? Vector.end() : |
| (Vector.begin() + Pos->second); |
| } |
| |
| const_iterator find(const KeyT &Key) const { |
| typename MapType::const_iterator Pos = Map.find(Key); |
| return Pos == Map.end()? Vector.end() : |
| (Vector.begin() + Pos->second); |
| } |
| |
| /// Remove the last element from the vector. |
| void pop_back() { |
| typename MapType::iterator Pos = Map.find(Vector.back().first); |
| Map.erase(Pos); |
| Vector.pop_back(); |
| } |
| |
| /// Remove the element given by Iterator. |
| /// |
| /// Returns an iterator to the element following the one which was removed, |
| /// which may be end(). |
| /// |
| /// \note This is a deceivingly expensive operation (linear time). It's |
| /// usually better to use \a remove_if() if possible. |
| typename VectorType::iterator erase(typename VectorType::iterator Iterator) { |
| Map.erase(Iterator->first); |
| auto Next = Vector.erase(Iterator); |
| if (Next == Vector.end()) |
| return Next; |
| |
| // Update indices in the map. |
| size_t Index = Next - Vector.begin(); |
| for (auto &I : Map) { |
| assert(I.second != Index && "Index was already erased!"); |
| if (I.second > Index) |
| --I.second; |
| } |
| return Next; |
| } |
| |
| /// Remove all elements with the key value Key. |
| /// |
| /// Returns the number of elements removed. |
| size_type erase(const KeyT &Key) { |
| auto Iterator = find(Key); |
| if (Iterator == end()) |
| return 0; |
| erase(Iterator); |
| return 1; |
| } |
| |
| /// Remove the elements that match the predicate. |
| /// |
| /// Erase all elements that match \c Pred in a single pass. Takes linear |
| /// time. |
| template <class Predicate> void remove_if(Predicate Pred); |
| }; |
| |
| template <typename KeyT, typename ValueT, typename MapType, typename VectorType> |
| template <class Function> |
| void MapVector<KeyT, ValueT, MapType, VectorType>::remove_if(Function Pred) { |
| auto O = Vector.begin(); |
| for (auto I = O, E = Vector.end(); I != E; ++I) { |
| if (Pred(*I)) { |
| // Erase from the map. |
| Map.erase(I->first); |
| continue; |
| } |
| |
| if (I != O) { |
| // Move the value and update the index in the map. |
| *O = std::move(*I); |
| Map[O->first] = O - Vector.begin(); |
| } |
| ++O; |
| } |
| // Erase trailing entries in the vector. |
| Vector.erase(O, Vector.end()); |
| } |
| |
| /// A MapVector that performs no allocations if smaller than a certain |
| /// size. |
| template <typename KeyT, typename ValueT, unsigned N> |
| struct SmallMapVector |
| : MapVector<KeyT, ValueT, SmallDenseMap<KeyT, unsigned, N>, |
| SmallVector<std::pair<KeyT, ValueT>, N>> { |
| }; |
| |
| } // end namespace llvm |
| |
| #endif // LLVM_ADT_MAPVECTOR_H |