ASTVector.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- ASTVector.h - Vector that uses ASTContext for 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 ASTVector, a vector ADT whose contents are
  15. // allocated using the allocator associated with an ASTContext..
  16. //
  17. //===----------------------------------------------------------------------===//
  18. // FIXME: Most of this is copy-and-paste from BumpVector.h and SmallVector.h.
  19. // We can refactor this core logic into something common.
  20. #ifndef LLVM_CLANG_AST_ASTVECTOR_H
  21. #define LLVM_CLANG_AST_ASTVECTOR_H
  22. #include "clang/AST/ASTContextAllocate.h"
  23. #include "llvm/ADT/PointerIntPair.h"
  24. #include <algorithm>
  25. #include <cassert>
  26. #include <cstddef>
  27. #include <cstring>
  28. #include <iterator>
  29. #include <memory>
  30. #include <type_traits>
  31. #include <utility>
  32. namespace clang {
  33. class ASTContext;
  34. template<typename T>
  35. class ASTVector {
  36. private:
  37. T *Begin = nullptr;
  38. T *End = nullptr;
  39. llvm::PointerIntPair<T *, 1, bool> Capacity;
  40. void setEnd(T *P) { this->End = P; }
  41. protected:
  42. // Make a tag bit available to users of this class.
  43. // FIXME: This is a horrible hack.
  44. bool getTag() const { return Capacity.getInt(); }
  45. void setTag(bool B) { Capacity.setInt(B); }
  46. public:
  47. // Default ctor - Initialize to empty.
  48. ASTVector() : Capacity(nullptr, false) {}
  49. ASTVector(ASTVector &&O) : Begin(O.Begin), End(O.End), Capacity(O.Capacity) {
  50. O.Begin = O.End = nullptr;
  51. O.Capacity.setPointer(nullptr);
  52. O.Capacity.setInt(false);
  53. }
  54. ASTVector(const ASTContext &C, unsigned N) : Capacity(nullptr, false) {
  55. reserve(C, N);
  56. }
  57. ASTVector &operator=(ASTVector &&RHS) {
  58. ASTVector O(std::move(RHS));
  59. using std::swap;
  60. swap(Begin, O.Begin);
  61. swap(End, O.End);
  62. swap(Capacity, O.Capacity);
  63. return *this;
  64. }
  65. ~ASTVector() {
  66. if (std::is_class<T>::value) {
  67. // Destroy the constructed elements in the vector.
  68. destroy_range(Begin, End);
  69. }
  70. }
  71. using size_type = size_t;
  72. using difference_type = ptrdiff_t;
  73. using value_type = T;
  74. using iterator = T *;
  75. using const_iterator = const T *;
  76. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  77. using reverse_iterator = std::reverse_iterator<iterator>;
  78. using reference = T &;
  79. using const_reference = const T &;
  80. using pointer = T *;
  81. using const_pointer = const T *;
  82. // forward iterator creation methods.
  83. iterator begin() { return Begin; }
  84. const_iterator begin() const { return Begin; }
  85. iterator end() { return End; }
  86. const_iterator end() const { return End; }
  87. // reverse iterator creation methods.
  88. reverse_iterator rbegin() { return reverse_iterator(end()); }
  89. const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
  90. reverse_iterator rend() { return reverse_iterator(begin()); }
  91. const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
  92. bool empty() const { return Begin == End; }
  93. size_type size() const { return End-Begin; }
  94. reference operator[](unsigned idx) {
  95. assert(Begin + idx < End);
  96. return Begin[idx];
  97. }
  98. const_reference operator[](unsigned idx) const {
  99. assert(Begin + idx < End);
  100. return Begin[idx];
  101. }
  102. reference front() {
  103. return begin()[0];
  104. }
  105. const_reference front() const {
  106. return begin()[0];
  107. }
  108. reference back() {
  109. return end()[-1];
  110. }
  111. const_reference back() const {
  112. return end()[-1];
  113. }
  114. void pop_back() {
  115. --End;
  116. End->~T();
  117. }
  118. T pop_back_val() {
  119. T Result = back();
  120. pop_back();
  121. return Result;
  122. }
  123. void clear() {
  124. if (std::is_class<T>::value) {
  125. destroy_range(Begin, End);
  126. }
  127. End = Begin;
  128. }
  129. /// data - Return a pointer to the vector's buffer, even if empty().
  130. pointer data() {
  131. return pointer(Begin);
  132. }
  133. /// data - Return a pointer to the vector's buffer, even if empty().
  134. const_pointer data() const {
  135. return const_pointer(Begin);
  136. }
  137. void push_back(const_reference Elt, const ASTContext &C) {
  138. if (End < this->capacity_ptr()) {
  139. Retry:
  140. new (End) T(Elt);
  141. ++End;
  142. return;
  143. }
  144. grow(C);
  145. goto Retry;
  146. }
  147. void reserve(const ASTContext &C, unsigned N) {
  148. if (unsigned(this->capacity_ptr()-Begin) < N)
  149. grow(C, N);
  150. }
  151. /// capacity - Return the total number of elements in the currently allocated
  152. /// buffer.
  153. size_t capacity() const { return this->capacity_ptr() - Begin; }
  154. /// append - Add the specified range to the end of the SmallVector.
  155. template<typename in_iter>
  156. void append(const ASTContext &C, in_iter in_start, in_iter in_end) {
  157. size_type NumInputs = std::distance(in_start, in_end);
  158. if (NumInputs == 0)
  159. return;
  160. // Grow allocated space if needed.
  161. if (NumInputs > size_type(this->capacity_ptr()-this->end()))
  162. this->grow(C, this->size()+NumInputs);
  163. // Copy the new elements over.
  164. // TODO: NEED To compile time dispatch on whether in_iter is a random access
  165. // iterator to use the fast uninitialized_copy.
  166. std::uninitialized_copy(in_start, in_end, this->end());
  167. this->setEnd(this->end() + NumInputs);
  168. }
  169. /// append - Add the specified range to the end of the SmallVector.
  170. void append(const ASTContext &C, size_type NumInputs, const T &Elt) {
  171. // Grow allocated space if needed.
  172. if (NumInputs > size_type(this->capacity_ptr()-this->end()))
  173. this->grow(C, this->size()+NumInputs);
  174. // Copy the new elements over.
  175. std::uninitialized_fill_n(this->end(), NumInputs, Elt);
  176. this->setEnd(this->end() + NumInputs);
  177. }
  178. /// uninitialized_copy - Copy the range [I, E) onto the uninitialized memory
  179. /// starting with "Dest", constructing elements into it as needed.
  180. template<typename It1, typename It2>
  181. static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
  182. std::uninitialized_copy(I, E, Dest);
  183. }
  184. iterator insert(const ASTContext &C, iterator I, const T &Elt) {
  185. if (I == this->end()) { // Important special case for empty vector.
  186. push_back(Elt, C);
  187. return this->end()-1;
  188. }
  189. if (this->End < this->capacity_ptr()) {
  190. Retry:
  191. new (this->end()) T(this->back());
  192. this->setEnd(this->end()+1);
  193. // Push everything else over.
  194. std::copy_backward(I, this->end()-1, this->end());
  195. *I = Elt;
  196. return I;
  197. }
  198. size_t EltNo = I-this->begin();
  199. this->grow(C);
  200. I = this->begin()+EltNo;
  201. goto Retry;
  202. }
  203. iterator insert(const ASTContext &C, iterator I, size_type NumToInsert,
  204. const T &Elt) {
  205. // Convert iterator to elt# to avoid invalidating iterator when we reserve()
  206. size_t InsertElt = I - this->begin();
  207. if (I == this->end()) { // Important special case for empty vector.
  208. append(C, NumToInsert, Elt);
  209. return this->begin() + InsertElt;
  210. }
  211. // Ensure there is enough space.
  212. reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
  213. // Uninvalidate the iterator.
  214. I = this->begin()+InsertElt;
  215. // If there are more elements between the insertion point and the end of the
  216. // range than there are being inserted, we can use a simple approach to
  217. // insertion. Since we already reserved space, we know that this won't
  218. // reallocate the vector.
  219. if (size_t(this->end()-I) >= NumToInsert) {
  220. T *OldEnd = this->end();
  221. append(C, this->end()-NumToInsert, this->end());
  222. // Copy the existing elements that get replaced.
  223. std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
  224. std::fill_n(I, NumToInsert, Elt);
  225. return I;
  226. }
  227. // Otherwise, we're inserting more elements than exist already, and we're
  228. // not inserting at the end.
  229. // Copy over the elements that we're about to overwrite.
  230. T *OldEnd = this->end();
  231. this->setEnd(this->end() + NumToInsert);
  232. size_t NumOverwritten = OldEnd-I;
  233. this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
  234. // Replace the overwritten part.
  235. std::fill_n(I, NumOverwritten, Elt);
  236. // Insert the non-overwritten middle part.
  237. std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt);
  238. return I;
  239. }
  240. template<typename ItTy>
  241. iterator insert(const ASTContext &C, iterator I, ItTy From, ItTy To) {
  242. // Convert iterator to elt# to avoid invalidating iterator when we reserve()
  243. size_t InsertElt = I - this->begin();
  244. if (I == this->end()) { // Important special case for empty vector.
  245. append(C, From, To);
  246. return this->begin() + InsertElt;
  247. }
  248. size_t NumToInsert = std::distance(From, To);
  249. // Ensure there is enough space.
  250. reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
  251. // Uninvalidate the iterator.
  252. I = this->begin()+InsertElt;
  253. // If there are more elements between the insertion point and the end of the
  254. // range than there are being inserted, we can use a simple approach to
  255. // insertion. Since we already reserved space, we know that this won't
  256. // reallocate the vector.
  257. if (size_t(this->end()-I) >= NumToInsert) {
  258. T *OldEnd = this->end();
  259. append(C, this->end()-NumToInsert, this->end());
  260. // Copy the existing elements that get replaced.
  261. std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
  262. std::copy(From, To, I);
  263. return I;
  264. }
  265. // Otherwise, we're inserting more elements than exist already, and we're
  266. // not inserting at the end.
  267. // Copy over the elements that we're about to overwrite.
  268. T *OldEnd = this->end();
  269. this->setEnd(this->end() + NumToInsert);
  270. size_t NumOverwritten = OldEnd-I;
  271. this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
  272. // Replace the overwritten part.
  273. for (; NumOverwritten > 0; --NumOverwritten) {
  274. *I = *From;
  275. ++I; ++From;
  276. }
  277. // Insert the non-overwritten middle part.
  278. this->uninitialized_copy(From, To, OldEnd);
  279. return I;
  280. }
  281. void resize(const ASTContext &C, unsigned N, const T &NV) {
  282. if (N < this->size()) {
  283. this->destroy_range(this->begin()+N, this->end());
  284. this->setEnd(this->begin()+N);
  285. } else if (N > this->size()) {
  286. if (this->capacity() < N)
  287. this->grow(C, N);
  288. construct_range(this->end(), this->begin()+N, NV);
  289. this->setEnd(this->begin()+N);
  290. }
  291. }
  292. private:
  293. /// grow - double the size of the allocated memory, guaranteeing space for at
  294. /// least one more element or MinSize if specified.
  295. void grow(const ASTContext &C, size_type MinSize = 1);
  296. void construct_range(T *S, T *E, const T &Elt) {
  297. for (; S != E; ++S)
  298. new (S) T(Elt);
  299. }
  300. void destroy_range(T *S, T *E) {
  301. while (S != E) {
  302. --E;
  303. E->~T();
  304. }
  305. }
  306. protected:
  307. const_iterator capacity_ptr() const {
  308. return (iterator) Capacity.getPointer();
  309. }
  310. iterator capacity_ptr() { return (iterator)Capacity.getPointer(); }
  311. };
  312. // Define this out-of-line to dissuade the C++ compiler from inlining it.
  313. template <typename T>
  314. void ASTVector<T>::grow(const ASTContext &C, size_t MinSize) {
  315. size_t CurCapacity = this->capacity();
  316. size_t CurSize = size();
  317. size_t NewCapacity = 2*CurCapacity;
  318. if (NewCapacity < MinSize)
  319. NewCapacity = MinSize;
  320. // Allocate the memory from the ASTContext.
  321. T *NewElts = new (C, alignof(T)) T[NewCapacity];
  322. // Copy the elements over.
  323. if (Begin != End) {
  324. if (std::is_class<T>::value) {
  325. std::uninitialized_copy(Begin, End, NewElts);
  326. // Destroy the original elements.
  327. destroy_range(Begin, End);
  328. } else {
  329. // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove).
  330. memcpy(NewElts, Begin, CurSize * sizeof(T));
  331. }
  332. }
  333. // ASTContext never frees any memory.
  334. Begin = NewElts;
  335. End = NewElts+CurSize;
  336. Capacity.setPointer(Begin+NewCapacity);
  337. }
  338. } // namespace clang
  339. #endif // LLVM_CLANG_AST_ASTVECTOR_H
  340. #ifdef __GNUC__
  341. #pragma GCC diagnostic pop
  342. #endif