Home | History | Annotate | Download | only in ADT
      1 //===- llvm/ADT/AllocatorList.h - Custom allocator list ---------*- 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 #ifndef LLVM_ADT_ALLOCATORLIST_H
     11 #define LLVM_ADT_ALLOCATORLIST_H
     12 
     13 #include "llvm/ADT/iterator.h"
     14 #include "llvm/ADT/simple_ilist.h"
     15 #include "llvm/Support/Allocator.h"
     16 #include <type_traits>
     17 
     18 namespace llvm {
     19 
     20 /// A linked-list with a custom, local allocator.
     21 ///
     22 /// Expose a std::list-like interface that owns and uses a custom LLVM-style
     23 /// allocator (e.g., BumpPtrAllocator), leveraging \a simple_ilist for the
     24 /// implementation details.
     25 ///
     26 /// Because this list owns the allocator, calling \a splice() with a different
     27 /// list isn't generally safe.  As such, \a splice has been left out of the
     28 /// interface entirely.
     29 template <class T, class AllocatorT> class AllocatorList : AllocatorT {
     30   struct Node : ilist_node<Node> {
     31     Node(Node &&) = delete;
     32     Node(const Node &) = delete;
     33     Node &operator=(Node &&) = delete;
     34     Node &operator=(const Node &) = delete;
     35 
     36     Node(T &&V) : V(std::move(V)) {}
     37     Node(const T &V) : V(V) {}
     38     template <class... Ts> Node(Ts &&... Vs) : V(std::forward<Ts>(Vs)...) {}
     39     T V;
     40   };
     41 
     42   typedef simple_ilist<Node> list_type;
     43   list_type List;
     44 
     45   AllocatorT &getAlloc() { return *this; }
     46   const AllocatorT &getAlloc() const { return *this; }
     47 
     48   template <class... ArgTs> Node *create(ArgTs &&... Args) {
     49     return new (getAlloc()) Node(std::forward<ArgTs>(Args)...);
     50   }
     51 
     52   struct Cloner {
     53     AllocatorList &AL;
     54     Cloner(AllocatorList &AL) : AL(AL) {}
     55     Node *operator()(const Node &N) const { return AL.create(N.V); }
     56   };
     57 
     58   struct Disposer {
     59     AllocatorList &AL;
     60     Disposer(AllocatorList &AL) : AL(AL) {}
     61     void operator()(Node *N) const {
     62       N->~Node();
     63       AL.getAlloc().Deallocate(N);
     64     }
     65   };
     66 
     67 public:
     68   typedef T value_type;
     69   typedef T *pointer;
     70   typedef T &reference;
     71   typedef const T *const_pointer;
     72   typedef const T &const_reference;
     73   typedef typename list_type::size_type size_type;
     74   typedef typename list_type::difference_type difference_type;
     75 
     76 private:
     77   template <class ValueT, class IteratorBase>
     78   class IteratorImpl
     79       : public iterator_adaptor_base<IteratorImpl<ValueT, IteratorBase>,
     80                                      IteratorBase,
     81                                      std::bidirectional_iterator_tag, ValueT> {
     82     template <class OtherValueT, class OtherIteratorBase>
     83     friend class IteratorImpl;
     84     friend AllocatorList;
     85 
     86     typedef iterator_adaptor_base<IteratorImpl<ValueT, IteratorBase>,
     87                                   IteratorBase, std::bidirectional_iterator_tag,
     88                                   ValueT>
     89         base_type;
     90 
     91   public:
     92     typedef ValueT value_type;
     93     typedef ValueT *pointer;
     94     typedef ValueT &reference;
     95 
     96     IteratorImpl() = default;
     97     IteratorImpl(const IteratorImpl &) = default;
     98     IteratorImpl &operator=(const IteratorImpl &) = default;
     99     ~IteratorImpl() = default;
    100 
    101     explicit IteratorImpl(const IteratorBase &I) : base_type(I) {}
    102 
    103     template <class OtherValueT, class OtherIteratorBase>
    104     IteratorImpl(const IteratorImpl<OtherValueT, OtherIteratorBase> &X,
    105                  typename std::enable_if<std::is_convertible<
    106                      OtherIteratorBase, IteratorBase>::value>::type * = nullptr)
    107         : base_type(X.wrapped()) {}
    108 
    109     reference operator*() const { return base_type::wrapped()->V; }
    110     pointer operator->() const { return &operator*(); }
    111 
    112     friend bool operator==(const IteratorImpl &L, const IteratorImpl &R) {
    113       return L.wrapped() == R.wrapped();
    114     }
    115     friend bool operator!=(const IteratorImpl &L, const IteratorImpl &R) {
    116       return !(L == R);
    117     }
    118   };
    119 
    120 public:
    121   typedef IteratorImpl<T, typename list_type::iterator> iterator;
    122   typedef IteratorImpl<T, typename list_type::reverse_iterator>
    123       reverse_iterator;
    124   typedef IteratorImpl<const T, typename list_type::const_iterator>
    125       const_iterator;
    126   typedef IteratorImpl<const T, typename list_type::const_reverse_iterator>
    127       const_reverse_iterator;
    128 
    129   AllocatorList() = default;
    130   AllocatorList(AllocatorList &&X)
    131       : AllocatorT(std::move(X.getAlloc())), List(std::move(X.List)) {}
    132   AllocatorList(const AllocatorList &X) {
    133     List.cloneFrom(X.List, Cloner(*this), Disposer(*this));
    134   }
    135   AllocatorList &operator=(AllocatorList &&X) {
    136     clear(); // Dispose of current nodes explicitly.
    137     List = std::move(X.List);
    138     getAlloc() = std::move(X.getAlloc());
    139     return *this;
    140   }
    141   AllocatorList &operator=(const AllocatorList &X) {
    142     List.cloneFrom(X.List, Cloner(*this), Disposer(*this));
    143     return *this;
    144   }
    145   ~AllocatorList() { clear(); }
    146 
    147   void swap(AllocatorList &RHS) {
    148     List.swap(RHS.List);
    149     std::swap(getAlloc(), RHS.getAlloc());
    150   }
    151 
    152   bool empty() { return List.empty(); }
    153   size_t size() { return List.size(); }
    154 
    155   iterator begin() { return iterator(List.begin()); }
    156   iterator end() { return iterator(List.end()); }
    157   const_iterator begin() const { return const_iterator(List.begin()); }
    158   const_iterator end() const { return const_iterator(List.end()); }
    159   reverse_iterator rbegin() { return reverse_iterator(List.rbegin()); }
    160   reverse_iterator rend() { return reverse_iterator(List.rend()); }
    161   const_reverse_iterator rbegin() const {
    162     return const_reverse_iterator(List.rbegin());
    163   }
    164   const_reverse_iterator rend() const {
    165     return const_reverse_iterator(List.rend());
    166   }
    167 
    168   T &back() { return List.back().V; }
    169   T &front() { return List.front().V; }
    170   const T &back() const { return List.back().V; }
    171   const T &front() const { return List.front().V; }
    172 
    173   template <class... Ts> iterator emplace(iterator I, Ts &&... Vs) {
    174     return iterator(List.insert(I.wrapped(), *create(std::forward<Ts>(Vs)...)));
    175   }
    176 
    177   iterator insert(iterator I, T &&V) {
    178     return iterator(List.insert(I.wrapped(), *create(std::move(V))));
    179   }
    180   iterator insert(iterator I, const T &V) {
    181     return iterator(List.insert(I.wrapped(), *create(V)));
    182   }
    183 
    184   template <class Iterator>
    185   void insert(iterator I, Iterator First, Iterator Last) {
    186     for (; First != Last; ++First)
    187       List.insert(I.wrapped(), *create(*First));
    188   }
    189 
    190   iterator erase(iterator I) {
    191     return iterator(List.eraseAndDispose(I.wrapped(), Disposer(*this)));
    192   }
    193 
    194   iterator erase(iterator First, iterator Last) {
    195     return iterator(
    196         List.eraseAndDispose(First.wrapped(), Last.wrapped(), Disposer(*this)));
    197   }
    198 
    199   void clear() { List.clearAndDispose(Disposer(*this)); }
    200   void pop_back() { List.eraseAndDispose(--List.end(), Disposer(*this)); }
    201   void pop_front() { List.eraseAndDispose(List.begin(), Disposer(*this)); }
    202   void push_back(T &&V) { insert(end(), std::move(V)); }
    203   void push_front(T &&V) { insert(begin(), std::move(V)); }
    204   void push_back(const T &V) { insert(end(), V); }
    205   void push_front(const T &V) { insert(begin(), V); }
    206   template <class... Ts> void emplace_back(Ts &&... Vs) {
    207     emplace(end(), std::forward<Ts>(Vs)...);
    208   }
    209   template <class... Ts> void emplace_front(Ts &&... Vs) {
    210     emplace(begin(), std::forward<Ts>(Vs)...);
    211   }
    212 
    213   /// Reset the underlying allocator.
    214   ///
    215   /// \pre \c empty()
    216   void resetAlloc() {
    217     assert(empty() && "Cannot reset allocator if not empty");
    218     getAlloc().Reset();
    219   }
    220 };
    221 
    222 template <class T> using BumpPtrList = AllocatorList<T, BumpPtrAllocator>;
    223 
    224 } // end namespace llvm
    225 
    226 #endif // LLVM_ADT_ALLOCATORLIST_H
    227