BumpVector.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- BumpVector.h - Vector-like ADT that uses bump allocation -*- 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. //
  14. // This file provides BumpVector, a vector-like ADT whose contents are
  15. // allocated from a BumpPtrAllocator.
  16. //
  17. //===----------------------------------------------------------------------===//
  18. // FIXME: Most of this is copy-and-paste from SmallVector.h. We can
  19. // refactor this core logic into something common that is shared between
  20. // the two. The main thing that is different is the allocation strategy.
  21. #ifndef LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H
  22. #define LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H
  23. #include "llvm/ADT/PointerIntPair.h"
  24. #include "llvm/Support/Allocator.h"
  25. #include <cassert>
  26. #include <cstddef>
  27. #include <cstring>
  28. #include <iterator>
  29. #include <memory>
  30. #include <type_traits>
  31. namespace clang {
  32. class BumpVectorContext {
  33. llvm::PointerIntPair<llvm::BumpPtrAllocator*, 1> Alloc;
  34. public:
  35. /// Construct a new BumpVectorContext that creates a new BumpPtrAllocator
  36. /// and destroys it when the BumpVectorContext object is destroyed.
  37. BumpVectorContext() : Alloc(new llvm::BumpPtrAllocator(), 1) {}
  38. BumpVectorContext(BumpVectorContext &&Other) : Alloc(Other.Alloc) {
  39. Other.Alloc.setInt(false);
  40. Other.Alloc.setPointer(nullptr);
  41. }
  42. /// Construct a new BumpVectorContext that reuses an existing
  43. /// BumpPtrAllocator. This BumpPtrAllocator is not destroyed when the
  44. /// BumpVectorContext object is destroyed.
  45. BumpVectorContext(llvm::BumpPtrAllocator &A) : Alloc(&A, 0) {}
  46. ~BumpVectorContext() {
  47. if (Alloc.getInt())
  48. delete Alloc.getPointer();
  49. }
  50. llvm::BumpPtrAllocator &getAllocator() { return *Alloc.getPointer(); }
  51. };
  52. template<typename T>
  53. class BumpVector {
  54. T *Begin = nullptr;
  55. T *End = nullptr;
  56. T *Capacity = nullptr;
  57. public:
  58. // Default ctor - Initialize to empty.
  59. explicit BumpVector(BumpVectorContext &C, unsigned N) {
  60. reserve(C, N);
  61. }
  62. ~BumpVector() {
  63. if (std::is_class<T>::value) {
  64. // Destroy the constructed elements in the vector.
  65. destroy_range(Begin, End);
  66. }
  67. }
  68. using size_type = size_t;
  69. using difference_type = ptrdiff_t;
  70. using value_type = T;
  71. using iterator = T *;
  72. using const_iterator = const T *;
  73. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  74. using reverse_iterator = std::reverse_iterator<iterator>;
  75. using reference = T &;
  76. using const_reference = const T &;
  77. using pointer = T *;
  78. using const_pointer = const T *;
  79. // forward iterator creation methods.
  80. iterator begin() { return Begin; }
  81. const_iterator begin() const { return Begin; }
  82. iterator end() { return End; }
  83. const_iterator end() const { return End; }
  84. // reverse iterator creation methods.
  85. reverse_iterator rbegin() { return reverse_iterator(end()); }
  86. const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
  87. reverse_iterator rend() { return reverse_iterator(begin()); }
  88. const_reverse_iterator rend() const {
  89. return const_reverse_iterator(begin());
  90. }
  91. bool empty() const { return Begin == End; }
  92. size_type size() const { return End-Begin; }
  93. reference operator[](unsigned idx) {
  94. assert(Begin + idx < End);
  95. return Begin[idx];
  96. }
  97. const_reference operator[](unsigned idx) const {
  98. assert(Begin + idx < End);
  99. return Begin[idx];
  100. }
  101. reference front() {
  102. return begin()[0];
  103. }
  104. const_reference front() const {
  105. return begin()[0];
  106. }
  107. reference back() {
  108. return end()[-1];
  109. }
  110. const_reference back() const {
  111. return end()[-1];
  112. }
  113. void pop_back() {
  114. --End;
  115. End->~T();
  116. }
  117. T pop_back_val() {
  118. T Result = back();
  119. pop_back();
  120. return Result;
  121. }
  122. void clear() {
  123. if (std::is_class<T>::value) {
  124. destroy_range(Begin, End);
  125. }
  126. End = Begin;
  127. }
  128. /// data - Return a pointer to the vector's buffer, even if empty().
  129. pointer data() {
  130. return pointer(Begin);
  131. }
  132. /// data - Return a pointer to the vector's buffer, even if empty().
  133. const_pointer data() const {
  134. return const_pointer(Begin);
  135. }
  136. void push_back(const_reference Elt, BumpVectorContext &C) {
  137. if (End < Capacity) {
  138. Retry:
  139. new (End) T(Elt);
  140. ++End;
  141. return;
  142. }
  143. grow(C);
  144. goto Retry;
  145. }
  146. /// insert - Insert some number of copies of element into a position. Return
  147. /// iterator to position after last inserted copy.
  148. iterator insert(iterator I, size_t Cnt, const_reference E,
  149. BumpVectorContext &C) {
  150. assert(I >= Begin && I <= End && "Iterator out of bounds.");
  151. if (End + Cnt <= Capacity) {
  152. Retry:
  153. move_range_right(I, End, Cnt);
  154. construct_range(I, I + Cnt, E);
  155. End += Cnt;
  156. return I + Cnt;
  157. }
  158. ptrdiff_t D = I - Begin;
  159. grow(C, size() + Cnt);
  160. I = Begin + D;
  161. goto Retry;
  162. }
  163. void reserve(BumpVectorContext &C, unsigned N) {
  164. if (unsigned(Capacity-Begin) < N)
  165. grow(C, N);
  166. }
  167. /// capacity - Return the total number of elements in the currently allocated
  168. /// buffer.
  169. size_t capacity() const { return Capacity - Begin; }
  170. private:
  171. /// grow - double the size of the allocated memory, guaranteeing space for at
  172. /// least one more element or MinSize if specified.
  173. void grow(BumpVectorContext &C, size_type MinSize = 1);
  174. void construct_range(T *S, T *E, const T &Elt) {
  175. for (; S != E; ++S)
  176. new (S) T(Elt);
  177. }
  178. void destroy_range(T *S, T *E) {
  179. while (S != E) {
  180. --E;
  181. E->~T();
  182. }
  183. }
  184. void move_range_right(T *S, T *E, size_t D) {
  185. for (T *I = E + D - 1, *IL = S + D - 1; I != IL; --I) {
  186. --E;
  187. new (I) T(*E);
  188. E->~T();
  189. }
  190. }
  191. };
  192. // Define this out-of-line to dissuade the C++ compiler from inlining it.
  193. template <typename T>
  194. void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) {
  195. size_t CurCapacity = Capacity-Begin;
  196. size_t CurSize = size();
  197. size_t NewCapacity = 2*CurCapacity;
  198. if (NewCapacity < MinSize)
  199. NewCapacity = MinSize;
  200. // Allocate the memory from the BumpPtrAllocator.
  201. T *NewElts = C.getAllocator().template Allocate<T>(NewCapacity);
  202. // Copy the elements over.
  203. if (Begin != End) {
  204. if (std::is_class<T>::value) {
  205. std::uninitialized_copy(Begin, End, NewElts);
  206. // Destroy the original elements.
  207. destroy_range(Begin, End);
  208. } else {
  209. // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove).
  210. memcpy(NewElts, Begin, CurSize * sizeof(T));
  211. }
  212. }
  213. // For now, leak 'Begin'. We can add it back to a freelist in
  214. // BumpVectorContext.
  215. Begin = NewElts;
  216. End = NewElts+CurSize;
  217. Capacity = Begin+NewCapacity;
  218. }
  219. } // namespace clang
  220. #endif // LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H
  221. #ifdef __GNUC__
  222. #pragma GCC diagnostic pop
  223. #endif