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