Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:29

0001 //===- ASTVector.h - Vector that uses ASTContext for allocation ---*- C++ -*-=//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 //  This file provides ASTVector, a vector  ADT whose contents are
0010 //  allocated using the allocator associated with an ASTContext..
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 // FIXME: Most of this is copy-and-paste from BumpVector.h and SmallVector.h.
0015 // We can refactor this core logic into something common.
0016 
0017 #ifndef LLVM_CLANG_AST_ASTVECTOR_H
0018 #define LLVM_CLANG_AST_ASTVECTOR_H
0019 
0020 #include "clang/AST/ASTContextAllocate.h"
0021 #include "llvm/ADT/PointerIntPair.h"
0022 #include <algorithm>
0023 #include <cassert>
0024 #include <cstddef>
0025 #include <cstring>
0026 #include <iterator>
0027 #include <memory>
0028 #include <type_traits>
0029 #include <utility>
0030 
0031 namespace clang {
0032 
0033 class ASTContext;
0034 
0035 template<typename T>
0036 class ASTVector {
0037 private:
0038   T *Begin = nullptr;
0039   T *End = nullptr;
0040   llvm::PointerIntPair<T *, 1, bool> Capacity;
0041 
0042   void setEnd(T *P) { this->End = P; }
0043 
0044 protected:
0045   // Make a tag bit available to users of this class.
0046   // FIXME: This is a horrible hack.
0047   bool getTag() const { return Capacity.getInt(); }
0048   void setTag(bool B) { Capacity.setInt(B); }
0049 
0050 public:
0051   // Default ctor - Initialize to empty.
0052   ASTVector() : Capacity(nullptr, false) {}
0053 
0054   ASTVector(ASTVector &&O) : Begin(O.Begin), End(O.End), Capacity(O.Capacity) {
0055     O.Begin = O.End = nullptr;
0056     O.Capacity.setPointer(nullptr);
0057     O.Capacity.setInt(false);
0058   }
0059 
0060   ASTVector(const ASTContext &C, unsigned N) : Capacity(nullptr, false) {
0061     reserve(C, N);
0062   }
0063 
0064   ASTVector &operator=(ASTVector &&RHS) {
0065     ASTVector O(std::move(RHS));
0066 
0067     using std::swap;
0068 
0069     swap(Begin, O.Begin);
0070     swap(End, O.End);
0071     swap(Capacity, O.Capacity);
0072     return *this;
0073   }
0074 
0075   ~ASTVector() {
0076     if (std::is_class<T>::value) {
0077       // Destroy the constructed elements in the vector.
0078       destroy_range(Begin, End);
0079     }
0080   }
0081 
0082   using size_type = size_t;
0083   using difference_type = ptrdiff_t;
0084   using value_type = T;
0085   using iterator = T *;
0086   using const_iterator = const T *;
0087 
0088   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
0089   using reverse_iterator = std::reverse_iterator<iterator>;
0090 
0091   using reference = T &;
0092   using const_reference = const T &;
0093   using pointer = T *;
0094   using const_pointer = const T *;
0095 
0096   // forward iterator creation methods.
0097   iterator begin() { return Begin; }
0098   const_iterator begin() const { return Begin; }
0099   iterator end() { return End; }
0100   const_iterator end() const { return End; }
0101 
0102   // reverse iterator creation methods.
0103   reverse_iterator rbegin()            { return reverse_iterator(end()); }
0104   const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
0105   reverse_iterator rend()              { return reverse_iterator(begin()); }
0106   const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
0107 
0108   bool empty() const { return Begin == End; }
0109   size_type size() const { return End-Begin; }
0110 
0111   reference operator[](unsigned idx) {
0112     assert(Begin + idx < End);
0113     return Begin[idx];
0114   }
0115   const_reference operator[](unsigned idx) const {
0116     assert(Begin + idx < End);
0117     return Begin[idx];
0118   }
0119 
0120   reference front() {
0121     return begin()[0];
0122   }
0123   const_reference front() const {
0124     return begin()[0];
0125   }
0126 
0127   reference back() {
0128     return end()[-1];
0129   }
0130   const_reference back() const {
0131     return end()[-1];
0132   }
0133 
0134   void pop_back() {
0135     --End;
0136     End->~T();
0137   }
0138 
0139   T pop_back_val() {
0140     T Result = back();
0141     pop_back();
0142     return Result;
0143   }
0144 
0145   void clear() {
0146     if (std::is_class<T>::value) {
0147       destroy_range(Begin, End);
0148     }
0149     End = Begin;
0150   }
0151 
0152   /// data - Return a pointer to the vector's buffer, even if empty().
0153   pointer data() {
0154     return pointer(Begin);
0155   }
0156 
0157   /// data - Return a pointer to the vector's buffer, even if empty().
0158   const_pointer data() const {
0159     return const_pointer(Begin);
0160   }
0161 
0162   void push_back(const_reference Elt, const ASTContext &C) {
0163     if (End < this->capacity_ptr()) {
0164     Retry:
0165       new (End) T(Elt);
0166       ++End;
0167       return;
0168     }
0169     grow(C);
0170     goto Retry;
0171   }
0172 
0173   void reserve(const ASTContext &C, unsigned N) {
0174     if (unsigned(this->capacity_ptr()-Begin) < N)
0175       grow(C, N);
0176   }
0177 
0178   /// capacity - Return the total number of elements in the currently allocated
0179   /// buffer.
0180   size_t capacity() const { return this->capacity_ptr() - Begin; }
0181 
0182   /// append - Add the specified range to the end of the SmallVector.
0183   template<typename in_iter>
0184   void append(const ASTContext &C, in_iter in_start, in_iter in_end) {
0185     size_type NumInputs = std::distance(in_start, in_end);
0186 
0187     if (NumInputs == 0)
0188       return;
0189 
0190     // Grow allocated space if needed.
0191     if (NumInputs > size_type(this->capacity_ptr()-this->end()))
0192       this->grow(C, this->size()+NumInputs);
0193 
0194     // Copy the new elements over.
0195     // TODO: NEED To compile time dispatch on whether in_iter is a random access
0196     // iterator to use the fast uninitialized_copy.
0197     std::uninitialized_copy(in_start, in_end, this->end());
0198     this->setEnd(this->end() + NumInputs);
0199   }
0200 
0201   /// append - Add the specified range to the end of the SmallVector.
0202   void append(const ASTContext &C, size_type NumInputs, const T &Elt) {
0203     // Grow allocated space if needed.
0204     if (NumInputs > size_type(this->capacity_ptr()-this->end()))
0205       this->grow(C, this->size()+NumInputs);
0206 
0207     // Copy the new elements over.
0208     std::uninitialized_fill_n(this->end(), NumInputs, Elt);
0209     this->setEnd(this->end() + NumInputs);
0210   }
0211 
0212   /// uninitialized_copy - Copy the range [I, E) onto the uninitialized memory
0213   /// starting with "Dest", constructing elements into it as needed.
0214   template<typename It1, typename It2>
0215   static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
0216     std::uninitialized_copy(I, E, Dest);
0217   }
0218 
0219   iterator insert(const ASTContext &C, iterator I, const T &Elt) {
0220     if (I == this->end()) {  // Important special case for empty vector.
0221       push_back(Elt, C);
0222       return this->end()-1;
0223     }
0224 
0225     if (this->End < this->capacity_ptr()) {
0226     Retry:
0227       new (this->end()) T(this->back());
0228       this->setEnd(this->end()+1);
0229       // Push everything else over.
0230       std::copy_backward(I, this->end()-1, this->end());
0231       *I = Elt;
0232       return I;
0233     }
0234     size_t EltNo = I-this->begin();
0235     this->grow(C);
0236     I = this->begin()+EltNo;
0237     goto Retry;
0238   }
0239 
0240   iterator insert(const ASTContext &C, iterator I, size_type NumToInsert,
0241                   const T &Elt) {
0242     // Convert iterator to elt# to avoid invalidating iterator when we reserve()
0243     size_t InsertElt = I - this->begin();
0244 
0245     if (I == this->end()) { // Important special case for empty vector.
0246       append(C, NumToInsert, Elt);
0247       return this->begin() + InsertElt;
0248     }
0249 
0250     // Ensure there is enough space.
0251     reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
0252 
0253     // Uninvalidate the iterator.
0254     I = this->begin()+InsertElt;
0255 
0256     // If there are more elements between the insertion point and the end of the
0257     // range than there are being inserted, we can use a simple approach to
0258     // insertion.  Since we already reserved space, we know that this won't
0259     // reallocate the vector.
0260     if (size_t(this->end()-I) >= NumToInsert) {
0261       T *OldEnd = this->end();
0262       append(C, this->end()-NumToInsert, this->end());
0263 
0264       // Copy the existing elements that get replaced.
0265       std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
0266 
0267       std::fill_n(I, NumToInsert, Elt);
0268       return I;
0269     }
0270 
0271     // Otherwise, we're inserting more elements than exist already, and we're
0272     // not inserting at the end.
0273 
0274     // Copy over the elements that we're about to overwrite.
0275     T *OldEnd = this->end();
0276     this->setEnd(this->end() + NumToInsert);
0277     size_t NumOverwritten = OldEnd-I;
0278     this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
0279 
0280     // Replace the overwritten part.
0281     std::fill_n(I, NumOverwritten, Elt);
0282 
0283     // Insert the non-overwritten middle part.
0284     std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt);
0285     return I;
0286   }
0287 
0288   template<typename ItTy>
0289   iterator insert(const ASTContext &C, iterator I, ItTy From, ItTy To) {
0290     // Convert iterator to elt# to avoid invalidating iterator when we reserve()
0291     size_t InsertElt = I - this->begin();
0292 
0293     if (I == this->end()) { // Important special case for empty vector.
0294       append(C, From, To);
0295       return this->begin() + InsertElt;
0296     }
0297 
0298     size_t NumToInsert = std::distance(From, To);
0299 
0300     // Ensure there is enough space.
0301     reserve(C, static_cast<unsigned>(this->size() + NumToInsert));
0302 
0303     // Uninvalidate the iterator.
0304     I = this->begin()+InsertElt;
0305 
0306     // If there are more elements between the insertion point and the end of the
0307     // range than there are being inserted, we can use a simple approach to
0308     // insertion.  Since we already reserved space, we know that this won't
0309     // reallocate the vector.
0310     if (size_t(this->end()-I) >= NumToInsert) {
0311       T *OldEnd = this->end();
0312       append(C, this->end()-NumToInsert, this->end());
0313 
0314       // Copy the existing elements that get replaced.
0315       std::copy_backward(I, OldEnd-NumToInsert, OldEnd);
0316 
0317       std::copy(From, To, I);
0318       return I;
0319     }
0320 
0321     // Otherwise, we're inserting more elements than exist already, and we're
0322     // not inserting at the end.
0323 
0324     // Copy over the elements that we're about to overwrite.
0325     T *OldEnd = this->end();
0326     this->setEnd(this->end() + NumToInsert);
0327     size_t NumOverwritten = OldEnd-I;
0328     this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten);
0329 
0330     // Replace the overwritten part.
0331     for (; NumOverwritten > 0; --NumOverwritten) {
0332       *I = *From;
0333       ++I; ++From;
0334     }
0335 
0336     // Insert the non-overwritten middle part.
0337     this->uninitialized_copy(From, To, OldEnd);
0338     return I;
0339   }
0340 
0341   void resize(const ASTContext &C, unsigned N, const T &NV) {
0342     if (N < this->size()) {
0343       this->destroy_range(this->begin()+N, this->end());
0344       this->setEnd(this->begin()+N);
0345     } else if (N > this->size()) {
0346       if (this->capacity() < N)
0347         this->grow(C, N);
0348       construct_range(this->end(), this->begin()+N, NV);
0349       this->setEnd(this->begin()+N);
0350     }
0351   }
0352 
0353 private:
0354   /// grow - double the size of the allocated memory, guaranteeing space for at
0355   /// least one more element or MinSize if specified.
0356   void grow(const ASTContext &C, size_type MinSize = 1);
0357 
0358   void construct_range(T *S, T *E, const T &Elt) {
0359     for (; S != E; ++S)
0360       new (S) T(Elt);
0361   }
0362 
0363   void destroy_range(T *S, T *E) {
0364     while (S != E) {
0365       --E;
0366       E->~T();
0367     }
0368   }
0369 
0370 protected:
0371   const_iterator capacity_ptr() const {
0372     return (iterator) Capacity.getPointer();
0373   }
0374 
0375   iterator capacity_ptr() { return (iterator)Capacity.getPointer(); }
0376 };
0377 
0378 // Define this out-of-line to dissuade the C++ compiler from inlining it.
0379 template <typename T>
0380 void ASTVector<T>::grow(const ASTContext &C, size_t MinSize) {
0381   size_t CurCapacity = this->capacity();
0382   size_t CurSize = size();
0383   size_t NewCapacity = 2*CurCapacity;
0384   if (NewCapacity < MinSize)
0385     NewCapacity = MinSize;
0386 
0387   // Allocate the memory from the ASTContext.
0388   T *NewElts = new (C, alignof(T)) T[NewCapacity];
0389 
0390   // Copy the elements over.
0391   if (Begin != End) {
0392     if (std::is_class<T>::value) {
0393       std::uninitialized_copy(Begin, End, NewElts);
0394       // Destroy the original elements.
0395       destroy_range(Begin, End);
0396     } else {
0397       // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove).
0398       memcpy(NewElts, Begin, CurSize * sizeof(T));
0399     }
0400   }
0401 
0402   // ASTContext never frees any memory.
0403   Begin = NewElts;
0404   End = NewElts+CurSize;
0405   Capacity.setPointer(Begin+NewCapacity);
0406 }
0407 
0408 } // namespace clang
0409 
0410 #endif // LLVM_CLANG_AST_ASTVECTOR_H