LCOV - code coverage report
Current view: top level - include/llvm/ADT - PriorityWorklist.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 179 270 66.3 %
Date: 2018-10-20 13:21:21 Functions: 19 34 55.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- PriorityWorklist.h - Worklist with insertion priority ----*- C++ -*-===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : ///
      10             : /// \file
      11             : ///
      12             : /// This file provides a priority worklist. See the class comments for details.
      13             : ///
      14             : //===----------------------------------------------------------------------===//
      15             : 
      16             : #ifndef LLVM_ADT_PRIORITYWORKLIST_H
      17             : #define LLVM_ADT_PRIORITYWORKLIST_H
      18             : 
      19             : #include "llvm/ADT/DenseMap.h"
      20             : #include "llvm/ADT/STLExtras.h"
      21             : #include "llvm/ADT/SmallVector.h"
      22             : #include "llvm/Support/Compiler.h"
      23             : #include <algorithm>
      24             : #include <cassert>
      25             : #include <cstddef>
      26             : #include <iterator>
      27             : #include <type_traits>
      28             : #include <vector>
      29             : 
      30             : namespace llvm {
      31             : 
      32             : /// A FILO worklist that prioritizes on re-insertion without duplication.
      33             : ///
      34             : /// This is very similar to a \c SetVector with the primary difference that
      35             : /// while re-insertion does not create a duplicate, it does adjust the
      36             : /// visitation order to respect the last insertion point. This can be useful
      37             : /// when the visit order needs to be prioritized based on insertion point
      38             : /// without actually having duplicate visits.
      39             : ///
      40             : /// Note that this doesn't prevent re-insertion of elements which have been
      41             : /// visited -- if you need to break cycles, a set will still be necessary.
      42             : ///
      43             : /// The type \c T must be default constructable to a null value that will be
      44             : /// ignored. It is an error to insert such a value, and popping elements will
      45             : /// never produce such a value. It is expected to be used with common nullable
      46             : /// types like pointers or optionals.
      47             : ///
      48             : /// Internally this uses a vector to store the worklist and a map to identify
      49             : /// existing elements in the worklist. Both of these may be customized, but the
      50             : /// map must support the basic DenseMap API for mapping from a T to an integer
      51             : /// index into the vector.
      52             : ///
      53             : /// A partial specialization is provided to automatically select a SmallVector
      54             : /// and a SmallDenseMap if custom data structures are not provided.
      55             : template <typename T, typename VectorT = std::vector<T>,
      56             :           typename MapT = DenseMap<T, ptrdiff_t>>
      57             : class PriorityWorklist {
      58             : public:
      59             :   using value_type = T;
      60             :   using key_type = T;
      61             :   using reference = T&;
      62             :   using const_reference = const T&;
      63             :   using size_type = typename MapT::size_type;
      64             : 
      65             :   /// Construct an empty PriorityWorklist
      66             :   PriorityWorklist() = default;
      67             : 
      68             :   /// Determine if the PriorityWorklist is empty or not.
      69             :   bool empty() const {
      70        3423 :     return V.empty();
      71             :   }
      72             : 
      73             :   /// Returns the number of elements in the worklist.
      74             :   size_type size() const {
      75             :     return M.size();
      76             :   }
      77             : 
      78             :   /// Count the number of elements of a given key in the PriorityWorklist.
      79             :   /// \returns 0 if the element is not in the PriorityWorklist, 1 if it is.
      80             :   size_type count(const key_type &key) const {
      81             :     return M.count(key);
      82             :   }
      83             : 
      84             :   /// Return the last element of the PriorityWorklist.
      85             :   const T &back() const {
      86             :     assert(!empty() && "Cannot call back() on empty PriorityWorklist!");
      87             :     return V.back();
      88             :   }
      89             : 
      90             :   /// Insert a new element into the PriorityWorklist.
      91             :   /// \returns true if the element was inserted into the PriorityWorklist.
      92        2287 :   bool insert(const T &X) {
      93             :     assert(X != T() && "Cannot insert a null (default constructed) value!");
      94        2287 :     auto InsertResult = M.insert({X, V.size()});
      95        2287 :     if (InsertResult.second) {
      96             :       // Fresh value, just append it to the vector.
      97        2265 :       V.push_back(X);
      98        2265 :       return true;
      99             :     }
     100             : 
     101          22 :     auto &Index = InsertResult.first->second;
     102             :     assert(V[Index] == X && "Value not actually at index in map!");
     103          44 :     if (Index != (ptrdiff_t)(V.size() - 1)) {
     104             :       // If the element isn't at the back, null it out and append a fresh one.
     105          14 :       V[Index] = T();
     106          14 :       Index = (ptrdiff_t)V.size();
     107          14 :       V.push_back(X);
     108             :     }
     109             :     return false;
     110             :   }
     111         133 : 
     112             :   /// Insert a sequence of new elements into the PriorityWorklist.
     113         133 :   template <typename SequenceT>
     114         133 :   typename std::enable_if<!std::is_convertible<SequenceT, T>::value>::type
     115         220 :   insert(SequenceT &&Input) {
     116         348 :     if (std::begin(Input) == std::end(Input))
     117         128 :       // Nothing to do for an empty input sequence.
     118             :       return;
     119             : 
     120           5 :     // First pull the input sequence into the vector as a bulk append
     121             :     // operation.
     122         230 :     ptrdiff_t StartIndex = V.size();
     123         440 :     V.insert(V.end(), std::begin(Input), std::end(Input));
     124           5 :     // Now walk backwards fixing up the index map and deleting any duplicates.
     125         744 :     for (ptrdiff_t i = V.size() - 1; i >= StartIndex; --i) {
     126         304 :       auto InsertResult = M.insert({V[i], i});
     127         299 :       if (InsertResult.second)
     128         299 :         continue;
     129             : 
     130        1037 :       // If the existing index is before this insert's start, nuke that one and
     131             :       // move it up.
     132        1037 :       ptrdiff_t &Index = InsertResult.first->second;
     133        1037 :       if (Index < StartIndex) {
     134           0 :         V[Index] = T();
     135        1032 :         Index = i;
     136        1032 :         continue;
     137             :       }
     138             : 
     139           5 :       // Otherwise the existing one comes first so just clear out the value in
     140             :       // this slot.
     141          10 :       V[i] = T();
     142             :     }
     143           5 :   }
     144           5 : 
     145           5 :   /// Remove the last element of the PriorityWorklist.
     146         134 :   void pop_back() {
     147             :     assert(!empty() && "Cannot remove an element when empty!");
     148             :     assert(back() != T() && "Cannot have a null element at the back!");
     149         268 :     M.erase(back());
     150             :     do {
     151             :       V.pop_back();
     152         134 :     } while (!V.empty() && V.back() == T());
     153         904 :   }
     154         768 : 
     155             :   LLVM_NODISCARD T pop_back_val() {
     156         134 :     T Ret = back();
     157         134 :     pop_back();
     158             :     return Ret;
     159             :   }
     160         768 : 
     161        1535 :   /// Erase an item from the worklist.
     162             :   ///
     163        2451 :   /// Note that this is constant time due to the nature of the worklist implementation.
     164         915 :   bool erase(const T& X) {
     165         915 :     auto I = M.find(X);
     166         913 :     if (I == M.end())
     167             :       return false;
     168             : 
     169             :     assert(V[I->second] == X && "Value not actually at index in map!");
     170           8 :     if (I->second == (ptrdiff_t)(V.size() - 1)) {
     171           8 :       do {
     172           6 :         V.pop_back();
     173           6 :       } while (!V.empty() && V.back() == T());
     174           6 :     } else {
     175           0 :       V[I->second] = T();
     176             :     }
     177             :     M.erase(I);
     178           0 :     return true;
     179           3 :   }
     180             : 
     181             :   /// Erase items from the set vector based on a predicate function.
     182           1 :   ///
     183             :   /// This is intended to be equivalent to the following code, if we could
     184        3283 :   /// write it:
     185             :   ///
     186             :   /// \code
     187        6566 :   ///   V.erase(remove_if(V, P), V.end());
     188             :   /// \endcode
     189           1 :   ///
     190        3288 :   /// However, PriorityWorklist doesn't expose non-const iterators, making any
     191        3283 :   /// algorithm like remove_if impossible to use.
     192        1257 :   ///
     193           2 :   /// \returns true if any element is removed.
     194           2 :   template <typename UnaryPredicate>
     195        2508 :   bool erase_if(UnaryPredicate P) {
     196             :     typename VectorT::iterator E =
     197             :         remove_if(V, TestAndEraseFromMap<UnaryPredicate>(P, M));
     198        1253 :     if (E == V.end())
     199        1254 :       return false;
     200        1098 :     for (auto I = V.begin(); I != E; ++I)
     201           1 :       if (*I != T())
     202           1 :         M[*I] = I - V.begin();
     203        2195 :     V.erase(E, V.end());
     204             :     return true;
     205             :   }
     206        1101 : 
     207        1097 :   /// Reverse the items in the PriorityWorklist.
     208         933 :   ///
     209             :   /// This does an in-place reversal. Other kinds of reverse aren't easy to
     210         210 :   /// support in the face of the worklist semantics.
     211        2077 : 
     212           1 :   /// Completely clear the PriorityWorklist
     213             :   void clear() {
     214         933 :     M.clear();
     215         933 :     V.clear();
     216             :   }
     217             : 
     218        3074 : private:
     219        3075 :   /// A wrapper predicate designed for use with std::remove_if.
     220             :   ///
     221           4 :   /// This predicate wraps a predicate suitable for use with std::remove_if to
     222           2 :   /// call M.erase(x) on each element which is slated for removal. This just
     223           2 :   /// allows the predicate to be move only which we can't do with lambdas
     224           2 :   /// today.
     225             :   template <typename UnaryPredicateT>
     226             :   class TestAndEraseFromMap {
     227             :     UnaryPredicateT P;
     228           1 :     MapT &M;
     229           1 : 
     230           1 :   public:
     231           1 :     TestAndEraseFromMap(UnaryPredicateT P, MapT &M)
     232           1 :         : P(std::move(P)), M(M) {}
     233             : 
     234             :     bool operator()(const T &Arg) {
     235             :       if (Arg == T())
     236             :         // Skip null values in the PriorityWorklist.
     237           0 :         return false;
     238             : 
     239             :       if (P(Arg)) {
     240           2 :         M.erase(Arg);
     241           2 :         return true;
     242             :       }
     243             :       return false;
     244             :     }
     245             :   };
     246             : 
     247           1 :   /// The map from value to index in the vector.
     248           2 :   MapT M;
     249             : 
     250           7 :   /// The vector of elements in insertion order.
     251           5 :   VectorT V;
     252           5 : };
     253           4 : 
     254             : /// A version of \c PriorityWorklist that selects small size optimized data
     255             : /// structures for the vector and map.
     256             : template <typename T, unsigned N>
     257          59 : class SmallPriorityWorklist
     258           2 :     : public PriorityWorklist<T, SmallVector<T, N>,
     259           1 :                               SmallDenseMap<T, ptrdiff_t>> {
     260           1 : public:
     261           1 :   SmallPriorityWorklist() = default;
     262             : };
     263             : 
     264             : } // end namespace llvm
     265             : 
     266           2 : #endif // LLVM_ADT_PRIORITYWORKLIST_H

Generated by: LCOV version 1.13