AllocatorList.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- llvm/ADT/AllocatorList.h - Custom allocator list ---------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_ADT_ALLOCATORLIST_H
  14. #define LLVM_ADT_ALLOCATORLIST_H
  15. #include "llvm/ADT/ilist_node.h"
  16. #include "llvm/ADT/iterator.h"
  17. #include "llvm/ADT/simple_ilist.h"
  18. #include "llvm/Support/Allocator.h"
  19. #include <cassert>
  20. #include <cstddef>
  21. #include <iterator>
  22. #include <type_traits>
  23. #include <utility>
  24. namespace llvm {
  25. /// A linked-list with a custom, local allocator.
  26. ///
  27. /// Expose a std::list-like interface that owns and uses a custom LLVM-style
  28. /// allocator (e.g., BumpPtrAllocator), leveraging \a simple_ilist for the
  29. /// implementation details.
  30. ///
  31. /// Because this list owns the allocator, calling \a splice() with a different
  32. /// list isn't generally safe. As such, \a splice has been left out of the
  33. /// interface entirely.
  34. template <class T, class AllocatorT> class AllocatorList : AllocatorT {
  35. struct Node : ilist_node<Node> {
  36. Node(Node &&) = delete;
  37. Node(const Node &) = delete;
  38. Node &operator=(Node &&) = delete;
  39. Node &operator=(const Node &) = delete;
  40. Node(T &&V) : V(std::move(V)) {}
  41. Node(const T &V) : V(V) {}
  42. template <class... Ts> Node(Ts &&... Vs) : V(std::forward<Ts>(Vs)...) {}
  43. T V;
  44. };
  45. using list_type = simple_ilist<Node>;
  46. list_type List;
  47. AllocatorT &getAlloc() { return *this; }
  48. const AllocatorT &getAlloc() const { return *this; }
  49. template <class... ArgTs> Node *create(ArgTs &&... Args) {
  50. return new (getAlloc()) Node(std::forward<ArgTs>(Args)...);
  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. struct Disposer {
  58. AllocatorList &AL;
  59. Disposer(AllocatorList &AL) : AL(AL) {}
  60. void operator()(Node *N) const {
  61. N->~Node();
  62. AL.getAlloc().Deallocate(N);
  63. }
  64. };
  65. public:
  66. using value_type = T;
  67. using pointer = T *;
  68. using reference = T &;
  69. using const_pointer = const T *;
  70. using const_reference = const T &;
  71. using size_type = typename list_type::size_type;
  72. using difference_type = typename list_type::difference_type;
  73. private:
  74. template <class ValueT, class IteratorBase>
  75. class IteratorImpl
  76. : public iterator_adaptor_base<IteratorImpl<ValueT, IteratorBase>,
  77. IteratorBase,
  78. std::bidirectional_iterator_tag, ValueT> {
  79. template <class OtherValueT, class OtherIteratorBase>
  80. friend class IteratorImpl;
  81. friend AllocatorList;
  82. using base_type =
  83. iterator_adaptor_base<IteratorImpl<ValueT, IteratorBase>, IteratorBase,
  84. std::bidirectional_iterator_tag, ValueT>;
  85. public:
  86. using value_type = ValueT;
  87. using pointer = ValueT *;
  88. using reference = ValueT &;
  89. IteratorImpl() = default;
  90. IteratorImpl(const IteratorImpl &) = default;
  91. IteratorImpl &operator=(const IteratorImpl &) = default;
  92. explicit IteratorImpl(const IteratorBase &I) : base_type(I) {}
  93. template <class OtherValueT, class OtherIteratorBase>
  94. IteratorImpl(const IteratorImpl<OtherValueT, OtherIteratorBase> &X,
  95. std::enable_if_t<std::is_convertible<
  96. OtherIteratorBase, IteratorBase>::value> * = nullptr)
  97. : base_type(X.wrapped()) {}
  98. ~IteratorImpl() = default;
  99. reference operator*() const { return base_type::wrapped()->V; }
  100. pointer operator->() const { return &operator*(); }
  101. };
  102. public:
  103. using iterator = IteratorImpl<T, typename list_type::iterator>;
  104. using reverse_iterator =
  105. IteratorImpl<T, typename list_type::reverse_iterator>;
  106. using const_iterator =
  107. IteratorImpl<const T, typename list_type::const_iterator>;
  108. using const_reverse_iterator =
  109. IteratorImpl<const T, typename list_type::const_reverse_iterator>;
  110. AllocatorList() = default;
  111. AllocatorList(AllocatorList &&X)
  112. : AllocatorT(std::move(X.getAlloc())), List(std::move(X.List)) {}
  113. AllocatorList(const AllocatorList &X) {
  114. List.cloneFrom(X.List, Cloner(*this), Disposer(*this));
  115. }
  116. AllocatorList &operator=(AllocatorList &&X) {
  117. clear(); // Dispose of current nodes explicitly.
  118. List = std::move(X.List);
  119. getAlloc() = std::move(X.getAlloc());
  120. return *this;
  121. }
  122. AllocatorList &operator=(const AllocatorList &X) {
  123. List.cloneFrom(X.List, Cloner(*this), Disposer(*this));
  124. return *this;
  125. }
  126. ~AllocatorList() { clear(); }
  127. void swap(AllocatorList &RHS) {
  128. List.swap(RHS.List);
  129. std::swap(getAlloc(), RHS.getAlloc());
  130. }
  131. bool empty() { return List.empty(); }
  132. size_t size() { return List.size(); }
  133. iterator begin() { return iterator(List.begin()); }
  134. iterator end() { return iterator(List.end()); }
  135. const_iterator begin() const { return const_iterator(List.begin()); }
  136. const_iterator end() const { return const_iterator(List.end()); }
  137. reverse_iterator rbegin() { return reverse_iterator(List.rbegin()); }
  138. reverse_iterator rend() { return reverse_iterator(List.rend()); }
  139. const_reverse_iterator rbegin() const {
  140. return const_reverse_iterator(List.rbegin());
  141. }
  142. const_reverse_iterator rend() const {
  143. return const_reverse_iterator(List.rend());
  144. }
  145. T &back() { return List.back().V; }
  146. T &front() { return List.front().V; }
  147. const T &back() const { return List.back().V; }
  148. const T &front() const { return List.front().V; }
  149. template <class... Ts> iterator emplace(iterator I, Ts &&... Vs) {
  150. return iterator(List.insert(I.wrapped(), *create(std::forward<Ts>(Vs)...)));
  151. }
  152. iterator insert(iterator I, T &&V) {
  153. return iterator(List.insert(I.wrapped(), *create(std::move(V))));
  154. }
  155. iterator insert(iterator I, const T &V) {
  156. return iterator(List.insert(I.wrapped(), *create(V)));
  157. }
  158. template <class Iterator>
  159. void insert(iterator I, Iterator First, Iterator Last) {
  160. for (; First != Last; ++First)
  161. List.insert(I.wrapped(), *create(*First));
  162. }
  163. iterator erase(iterator I) {
  164. return iterator(List.eraseAndDispose(I.wrapped(), Disposer(*this)));
  165. }
  166. iterator erase(iterator First, iterator Last) {
  167. return iterator(
  168. List.eraseAndDispose(First.wrapped(), Last.wrapped(), Disposer(*this)));
  169. }
  170. void clear() { List.clearAndDispose(Disposer(*this)); }
  171. void pop_back() { List.eraseAndDispose(--List.end(), Disposer(*this)); }
  172. void pop_front() { List.eraseAndDispose(List.begin(), Disposer(*this)); }
  173. void push_back(T &&V) { insert(end(), std::move(V)); }
  174. void push_front(T &&V) { insert(begin(), std::move(V)); }
  175. void push_back(const T &V) { insert(end(), V); }
  176. void push_front(const T &V) { insert(begin(), V); }
  177. template <class... Ts> void emplace_back(Ts &&... Vs) {
  178. emplace(end(), std::forward<Ts>(Vs)...);
  179. }
  180. template <class... Ts> void emplace_front(Ts &&... Vs) {
  181. emplace(begin(), std::forward<Ts>(Vs)...);
  182. }
  183. /// Reset the underlying allocator.
  184. ///
  185. /// \pre \c empty()
  186. void resetAlloc() {
  187. assert(empty() && "Cannot reset allocator if not empty");
  188. getAlloc().Reset();
  189. }
  190. };
  191. template <class T> using BumpPtrList = AllocatorList<T, BumpPtrAllocator>;
  192. } // end namespace llvm
  193. #endif // LLVM_ADT_ALLOCATORLIST_H
  194. #ifdef __GNUC__
  195. #pragma GCC diagnostic pop
  196. #endif