Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

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