AllocatorList.h 7.5 KB

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