1 //==-- llvm/ADT/ilist.h - Intrusive Linked List Template ---------*- 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 // This file defines classes to implement an intrusive doubly linked list class 11 // (i.e. each node of the list must contain a next and previous field for the 12 // list. 13 // 14 // The ilist class itself should be a plug in replacement for list. This list 15 // replacement does not provide a constant time size() method, so be careful to 16 // use empty() when you really want to know if it's empty. 17 // 18 // The ilist class is implemented as a circular list. The list itself contains 19 // a sentinel node, whose Next points at begin() and whose Prev points at 20 // rbegin(). The sentinel node itself serves as end() and rend(). 21 // 22 //===----------------------------------------------------------------------===// 23 24 #ifndef LLVM_ADT_ILIST_H 25 #define LLVM_ADT_ILIST_H 26 27 #include "llvm/ADT/simple_ilist.h" 28 #include <cassert> 29 #include <cstddef> 30 #include <iterator> 31 32 namespace llvm { 33 34 /// Use delete by default for iplist and ilist. 35 /// 36 /// Specialize this to get different behaviour for ownership-related API. (If 37 /// you really want ownership semantics, consider using std::list or building 38 /// something like \a BumpPtrList.) 39 /// 40 /// \see ilist_noalloc_traits 41 template <typename NodeTy> struct ilist_alloc_traits { deleteNodeilist_alloc_traits42 static void deleteNode(NodeTy *V) { delete V; } 43 }; 44 45 /// Custom traits to do nothing on deletion. 46 /// 47 /// Specialize ilist_alloc_traits to inherit from this to disable the 48 /// non-intrusive deletion in iplist (which implies ownership). 49 /// 50 /// If you want purely intrusive semantics with no callbacks, consider using \a 51 /// simple_ilist instead. 52 /// 53 /// \code 54 /// template <> 55 /// struct ilist_alloc_traits<MyType> : ilist_noalloc_traits<MyType> {}; 56 /// \endcode 57 template <typename NodeTy> struct ilist_noalloc_traits { deleteNodeilist_noalloc_traits58 static void deleteNode(NodeTy *V) {} 59 }; 60 61 /// Callbacks do nothing by default in iplist and ilist. 62 /// 63 /// Specialize this for to use callbacks for when nodes change their list 64 /// membership. 65 template <typename NodeTy> struct ilist_callback_traits { addNodeToListilist_callback_traits66 void addNodeToList(NodeTy *) {} removeNodeFromListilist_callback_traits67 void removeNodeFromList(NodeTy *) {} 68 69 /// Callback before transferring nodes to this list. 70 /// 71 /// \pre \c this!=&OldList 72 template <class Iterator> transferNodesFromListilist_callback_traits73 void transferNodesFromList(ilist_callback_traits &OldList, Iterator /*first*/, 74 Iterator /*last*/) { 75 (void)OldList; 76 } 77 }; 78 79 /// A fragment for template traits for intrusive list that provides default 80 /// node related operations. 81 /// 82 /// TODO: Remove this layer of indirection. It's not necessary. 83 template <typename NodeTy> 84 struct ilist_node_traits : ilist_alloc_traits<NodeTy>, 85 ilist_callback_traits<NodeTy> {}; 86 87 /// Default template traits for intrusive list. 88 /// 89 /// By inheriting from this, you can easily use default implementations for all 90 /// common operations. 91 /// 92 /// TODO: Remove this customization point. Specializing ilist_traits is 93 /// already fully general. 94 template <typename NodeTy> 95 struct ilist_default_traits : public ilist_node_traits<NodeTy> {}; 96 97 /// Template traits for intrusive list. 98 /// 99 /// Customize callbacks and allocation semantics. 100 template <typename NodeTy> 101 struct ilist_traits : public ilist_default_traits<NodeTy> {}; 102 103 /// Const traits should never be instantiated. 104 template <typename Ty> struct ilist_traits<const Ty> {}; 105 106 namespace ilist_detail { 107 108 template <class T> T &make(); 109 110 /// Type trait to check for a traits class that has a getNext member (as a 111 /// canary for any of the ilist_nextprev_traits API). 112 template <class TraitsT, class NodeT> struct HasGetNext { 113 typedef char Yes[1]; 114 typedef char No[2]; 115 template <size_t N> struct SFINAE {}; 116 117 template <class U> 118 static Yes &test(U *I, decltype(I->getNext(&make<NodeT>())) * = 0); 119 template <class> static No &test(...); 120 121 public: 122 static const bool value = sizeof(test<TraitsT>(nullptr)) == sizeof(Yes); 123 }; 124 125 /// Type trait to check for a traits class that has a createSentinel member (as 126 /// a canary for any of the ilist_sentinel_traits API). 127 template <class TraitsT> struct HasCreateSentinel { 128 typedef char Yes[1]; 129 typedef char No[2]; 130 131 template <class U> 132 static Yes &test(U *I, decltype(I->createSentinel()) * = 0); 133 template <class> static No &test(...); 134 135 public: 136 static const bool value = sizeof(test<TraitsT>(nullptr)) == sizeof(Yes); 137 }; 138 139 /// Type trait to check for a traits class that has a createNode member. 140 /// Allocation should be managed in a wrapper class, instead of in 141 /// ilist_traits. 142 template <class TraitsT, class NodeT> struct HasCreateNode { 143 typedef char Yes[1]; 144 typedef char No[2]; 145 template <size_t N> struct SFINAE {}; 146 147 template <class U> 148 static Yes &test(U *I, decltype(I->createNode(make<NodeT>())) * = 0); 149 template <class> static No &test(...); 150 151 public: 152 static const bool value = sizeof(test<TraitsT>(nullptr)) == sizeof(Yes); 153 }; 154 155 template <class TraitsT, class NodeT> struct HasObsoleteCustomization { 156 static const bool value = HasGetNext<TraitsT, NodeT>::value || 157 HasCreateSentinel<TraitsT>::value || 158 HasCreateNode<TraitsT, NodeT>::value; 159 }; 160 161 } // end namespace ilist_detail 162 163 //===----------------------------------------------------------------------===// 164 // 165 /// A wrapper around an intrusive list with callbacks and non-intrusive 166 /// ownership. 167 /// 168 /// This wraps a purely intrusive list (like simple_ilist) with a configurable 169 /// traits class. The traits can implement callbacks and customize the 170 /// ownership semantics. 171 /// 172 /// This is a subset of ilist functionality that can safely be used on nodes of 173 /// polymorphic types, i.e. a heterogeneous list with a common base class that 174 /// holds the next/prev pointers. The only state of the list itself is an 175 /// ilist_sentinel, which holds pointers to the first and last nodes in the 176 /// list. 177 template <class IntrusiveListT, class TraitsT> 178 class iplist_impl : public TraitsT, IntrusiveListT { 179 typedef IntrusiveListT base_list_type; 180 181 protected: 182 typedef iplist_impl iplist_impl_type; 183 184 public: 185 typedef typename base_list_type::pointer pointer; 186 typedef typename base_list_type::const_pointer const_pointer; 187 typedef typename base_list_type::reference reference; 188 typedef typename base_list_type::const_reference const_reference; 189 typedef typename base_list_type::value_type value_type; 190 typedef typename base_list_type::size_type size_type; 191 typedef typename base_list_type::difference_type difference_type; 192 typedef typename base_list_type::iterator iterator; 193 typedef typename base_list_type::const_iterator const_iterator; 194 typedef typename base_list_type::reverse_iterator reverse_iterator; 195 typedef 196 typename base_list_type::const_reverse_iterator const_reverse_iterator; 197 198 private: 199 // TODO: Drop this assertion and the transitive type traits anytime after 200 // v4.0 is branched (i.e,. keep them for one release to help out-of-tree code 201 // update). 202 static_assert( 203 !ilist_detail::HasObsoleteCustomization<TraitsT, value_type>::value, 204 "ilist customization points have changed!"); 205 206 static bool op_less(const_reference L, const_reference R) { return L < R; } 207 static bool op_equal(const_reference L, const_reference R) { return L == R; } 208 209 public: 210 iplist_impl() = default; 211 212 iplist_impl(const iplist_impl &) = delete; 213 iplist_impl &operator=(const iplist_impl &) = delete; 214 215 iplist_impl(iplist_impl &&X) 216 : TraitsT(std::move(X)), IntrusiveListT(std::move(X)) {} 217 iplist_impl &operator=(iplist_impl &&X) { 218 *static_cast<TraitsT *>(this) = std::move(X); 219 *static_cast<IntrusiveListT *>(this) = std::move(X); 220 return *this; 221 } 222 223 ~iplist_impl() { clear(); } 224 225 // Miscellaneous inspection routines. 226 size_type max_size() const { return size_type(-1); } 227 228 using base_list_type::begin; 229 using base_list_type::end; 230 using base_list_type::rbegin; 231 using base_list_type::rend; 232 using base_list_type::empty; 233 using base_list_type::front; 234 using base_list_type::back; 235 236 void swap(iplist_impl &RHS) { 237 assert(0 && "Swap does not use list traits callback correctly yet!"); 238 base_list_type::swap(RHS); 239 } 240 241 iterator insert(iterator where, pointer New) { 242 this->addNodeToList(New); // Notify traits that we added a node... 243 return base_list_type::insert(where, *New); 244 } 245 246 iterator insert(iterator where, const_reference New) { 247 return this->insert(where, new value_type(New)); 248 } 249 250 iterator insertAfter(iterator where, pointer New) { 251 if (empty()) 252 return insert(begin(), New); 253 else 254 return insert(++where, New); 255 } 256 257 /// Clone another list. 258 template <class Cloner> void cloneFrom(const iplist_impl &L2, Cloner clone) { 259 clear(); 260 for (const_reference V : L2) 261 push_back(clone(V)); 262 } 263 264 pointer remove(iterator &IT) { 265 pointer Node = &*IT++; 266 this->removeNodeFromList(Node); // Notify traits that we removed a node... 267 base_list_type::remove(*Node); 268 return Node; 269 } 270 271 pointer remove(const iterator &IT) { 272 iterator MutIt = IT; 273 return remove(MutIt); 274 } 275 276 pointer remove(pointer IT) { return remove(iterator(IT)); } 277 pointer remove(reference IT) { return remove(iterator(IT)); } 278 279 // erase - remove a node from the controlled sequence... and delete it. 280 iterator erase(iterator where) { 281 this->deleteNode(remove(where)); 282 return where; 283 } 284 285 iterator erase(pointer IT) { return erase(iterator(IT)); } 286 iterator erase(reference IT) { return erase(iterator(IT)); } 287 288 /// Remove all nodes from the list like clear(), but do not call 289 /// removeNodeFromList() or deleteNode(). 290 /// 291 /// This should only be used immediately before freeing nodes in bulk to 292 /// avoid traversing the list and bringing all the nodes into cache. 293 void clearAndLeakNodesUnsafely() { base_list_type::clear(); } 294 295 private: 296 // transfer - The heart of the splice function. Move linked list nodes from 297 // [first, last) into position. 298 // 299 void transfer(iterator position, iplist_impl &L2, iterator first, iterator last) { 300 if (position == last) 301 return; 302 303 if (this != &L2) // Notify traits we moved the nodes... 304 this->transferNodesFromList(L2, first, last); 305 306 base_list_type::splice(position, L2, first, last); 307 } 308 309 public: 310 //===----------------------------------------------------------------------=== 311 // Functionality derived from other functions defined above... 312 // 313 314 using base_list_type::size; 315 316 iterator erase(iterator first, iterator last) { 317 while (first != last) 318 first = erase(first); 319 return last; 320 } 321 322 void clear() { erase(begin(), end()); } 323 324 // Front and back inserters... 325 void push_front(pointer val) { insert(begin(), val); } 326 void push_back(pointer val) { insert(end(), val); } 327 void pop_front() { 328 assert(!empty() && "pop_front() on empty list!"); 329 erase(begin()); 330 } 331 void pop_back() { 332 assert(!empty() && "pop_back() on empty list!"); 333 iterator t = end(); erase(--t); 334 } 335 336 // Special forms of insert... 337 template<class InIt> void insert(iterator where, InIt first, InIt last) { 338 for (; first != last; ++first) insert(where, *first); 339 } 340 341 // Splice members - defined in terms of transfer... 342 void splice(iterator where, iplist_impl &L2) { 343 if (!L2.empty()) 344 transfer(where, L2, L2.begin(), L2.end()); 345 } 346 void splice(iterator where, iplist_impl &L2, iterator first) { 347 iterator last = first; ++last; 348 if (where == first || where == last) return; // No change 349 transfer(where, L2, first, last); 350 } 351 void splice(iterator where, iplist_impl &L2, iterator first, iterator last) { 352 if (first != last) transfer(where, L2, first, last); 353 } 354 void splice(iterator where, iplist_impl &L2, reference N) { 355 splice(where, L2, iterator(N)); 356 } 357 void splice(iterator where, iplist_impl &L2, pointer N) { 358 splice(where, L2, iterator(N)); 359 } 360 361 template <class Compare> 362 void merge(iplist_impl &Right, Compare comp) { 363 if (this == &Right) 364 return; 365 this->transferNodesFromList(Right, Right.begin(), Right.end()); 366 base_list_type::merge(Right, comp); 367 } 368 void merge(iplist_impl &Right) { return merge(Right, op_less); } 369 370 using base_list_type::sort; 371 372 /// \brief Get the previous node, or \c nullptr for the list head. 373 pointer getPrevNode(reference N) const { 374 auto I = N.getIterator(); 375 if (I == begin()) 376 return nullptr; 377 return &*std::prev(I); 378 } 379 /// \brief Get the previous node, or \c nullptr for the list head. 380 const_pointer getPrevNode(const_reference N) const { 381 return getPrevNode(const_cast<reference >(N)); 382 } 383 384 /// \brief Get the next node, or \c nullptr for the list tail. 385 pointer getNextNode(reference N) const { 386 auto Next = std::next(N.getIterator()); 387 if (Next == end()) 388 return nullptr; 389 return &*Next; 390 } 391 /// \brief Get the next node, or \c nullptr for the list tail. 392 const_pointer getNextNode(const_reference N) const { 393 return getNextNode(const_cast<reference >(N)); 394 } 395 }; 396 397 /// An intrusive list with ownership and callbacks specified/controlled by 398 /// ilist_traits, only with API safe for polymorphic types. 399 /// 400 /// The \p Options parameters are the same as those for \a simple_ilist. See 401 /// there for a description of what's available. 402 template <class T, class... Options> 403 class iplist 404 : public iplist_impl<simple_ilist<T, Options...>, ilist_traits<T>> { 405 typedef typename iplist::iplist_impl_type iplist_impl_type; 406 407 public: 408 iplist() = default; 409 410 iplist(const iplist &X) = delete; 411 iplist &operator=(const iplist &X) = delete; 412 413 iplist(iplist &&X) : iplist_impl_type(std::move(X)) {} 414 iplist &operator=(iplist &&X) { 415 *static_cast<iplist_impl_type *>(this) = std::move(X); 416 return *this; 417 } 418 }; 419 420 template <class T, class... Options> using ilist = iplist<T, Options...>; 421 422 } // end namespace llvm 423 424 namespace std { 425 426 // Ensure that swap uses the fast list swap... 427 template<class Ty> 428 void swap(llvm::iplist<Ty> &Left, llvm::iplist<Ty> &Right) { 429 Left.swap(Right); 430 } 431 432 } // end namespace std 433 434 #endif // LLVM_ADT_ILIST_H 435