Home | History | Annotate | Download | only in ADT
      1 //===- llvm/ADT/TinyPtrVector.h - 'Normally tiny' vectors -------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #ifndef LLVM_ADT_TINYPTRVECTOR_H
     11 #define LLVM_ADT_TINYPTRVECTOR_H
     12 
     13 #include "llvm/ADT/ArrayRef.h"
     14 #include "llvm/ADT/None.h"
     15 #include "llvm/ADT/PointerUnion.h"
     16 #include "llvm/ADT/SmallVector.h"
     17 #include <cassert>
     18 #include <cstddef>
     19 #include <iterator>
     20 #include <type_traits>
     21 
     22 namespace llvm {
     23 
     24 /// TinyPtrVector - This class is specialized for cases where there are
     25 /// normally 0 or 1 element in a vector, but is general enough to go beyond that
     26 /// when required.
     27 ///
     28 /// NOTE: This container doesn't allow you to store a null pointer into it.
     29 ///
     30 template <typename EltTy>
     31 class TinyPtrVector {
     32 public:
     33   using VecTy = SmallVector<EltTy, 4>;
     34   using value_type = typename VecTy::value_type;
     35   using PtrUnion = PointerUnion<EltTy, VecTy *>;
     36 
     37 private:
     38   PtrUnion Val;
     39 
     40 public:
     41   TinyPtrVector() = default;
     42 
     43   ~TinyPtrVector() {
     44     if (VecTy *V = Val.template dyn_cast<VecTy*>())
     45       delete V;
     46   }
     47 
     48   TinyPtrVector(const TinyPtrVector &RHS) : Val(RHS.Val) {
     49     if (VecTy *V = Val.template dyn_cast<VecTy*>())
     50       Val = new VecTy(*V);
     51   }
     52 
     53   TinyPtrVector &operator=(const TinyPtrVector &RHS) {
     54     if (this == &RHS)
     55       return *this;
     56     if (RHS.empty()) {
     57       this->clear();
     58       return *this;
     59     }
     60 
     61     // Try to squeeze into the single slot. If it won't fit, allocate a copied
     62     // vector.
     63     if (Val.template is<EltTy>()) {
     64       if (RHS.size() == 1)
     65         Val = RHS.front();
     66       else
     67         Val = new VecTy(*RHS.Val.template get<VecTy*>());
     68       return *this;
     69     }
     70 
     71     // If we have a full vector allocated, try to re-use it.
     72     if (RHS.Val.template is<EltTy>()) {
     73       Val.template get<VecTy*>()->clear();
     74       Val.template get<VecTy*>()->push_back(RHS.front());
     75     } else {
     76       *Val.template get<VecTy*>() = *RHS.Val.template get<VecTy*>();
     77     }
     78     return *this;
     79   }
     80 
     81   TinyPtrVector(TinyPtrVector &&RHS) : Val(RHS.Val) {
     82     RHS.Val = (EltTy)nullptr;
     83   }
     84 
     85   TinyPtrVector &operator=(TinyPtrVector &&RHS) {
     86     if (this == &RHS)
     87       return *this;
     88     if (RHS.empty()) {
     89       this->clear();
     90       return *this;
     91     }
     92 
     93     // If this vector has been allocated on the heap, re-use it if cheap. If it
     94     // would require more copying, just delete it and we'll steal the other
     95     // side.
     96     if (VecTy *V = Val.template dyn_cast<VecTy*>()) {
     97       if (RHS.Val.template is<EltTy>()) {
     98         V->clear();
     99         V->push_back(RHS.front());
    100         return *this;
    101       }
    102       delete V;
    103     }
    104 
    105     Val = RHS.Val;
    106     RHS.Val = (EltTy)nullptr;
    107     return *this;
    108   }
    109 
    110   /// Constructor from an ArrayRef.
    111   ///
    112   /// This also is a constructor for individual array elements due to the single
    113   /// element constructor for ArrayRef.
    114   explicit TinyPtrVector(ArrayRef<EltTy> Elts)
    115       : Val(Elts.empty()
    116                 ? PtrUnion()
    117                 : Elts.size() == 1
    118                       ? PtrUnion(Elts[0])
    119                       : PtrUnion(new VecTy(Elts.begin(), Elts.end()))) {}
    120 
    121   TinyPtrVector(size_t Count, EltTy Value)
    122       : Val(Count == 0 ? PtrUnion()
    123                        : Count == 1 ? PtrUnion(Value)
    124                                     : PtrUnion(new VecTy(Count, Value))) {}
    125 
    126   // implicit conversion operator to ArrayRef.
    127   operator ArrayRef<EltTy>() const {
    128     if (Val.isNull())
    129       return None;
    130     if (Val.template is<EltTy>())
    131       return *Val.getAddrOfPtr1();
    132     return *Val.template get<VecTy*>();
    133   }
    134 
    135   // implicit conversion operator to MutableArrayRef.
    136   operator MutableArrayRef<EltTy>() {
    137     if (Val.isNull())
    138       return None;
    139     if (Val.template is<EltTy>())
    140       return *Val.getAddrOfPtr1();
    141     return *Val.template get<VecTy*>();
    142   }
    143 
    144   // Implicit conversion to ArrayRef<U> if EltTy* implicitly converts to U*.
    145   template<typename U,
    146            typename std::enable_if<
    147                std::is_convertible<ArrayRef<EltTy>, ArrayRef<U>>::value,
    148                bool>::type = false>
    149   operator ArrayRef<U>() const {
    150     return operator ArrayRef<EltTy>();
    151   }
    152 
    153   bool empty() const {
    154     // This vector can be empty if it contains no element, or if it
    155     // contains a pointer to an empty vector.
    156     if (Val.isNull()) return true;
    157     if (VecTy *Vec = Val.template dyn_cast<VecTy*>())
    158       return Vec->empty();
    159     return false;
    160   }
    161 
    162   unsigned size() const {
    163     if (empty())
    164       return 0;
    165     if (Val.template is<EltTy>())
    166       return 1;
    167     return Val.template get<VecTy*>()->size();
    168   }
    169 
    170   using iterator = EltTy *;
    171   using const_iterator = const EltTy *;
    172   using reverse_iterator = std::reverse_iterator<iterator>;
    173   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
    174 
    175   iterator begin() {
    176     if (Val.template is<EltTy>())
    177       return Val.getAddrOfPtr1();
    178 
    179     return Val.template get<VecTy *>()->begin();
    180   }
    181 
    182   iterator end() {
    183     if (Val.template is<EltTy>())
    184       return begin() + (Val.isNull() ? 0 : 1);
    185 
    186     return Val.template get<VecTy *>()->end();
    187   }
    188 
    189   const_iterator begin() const {
    190     return (const_iterator)const_cast<TinyPtrVector*>(this)->begin();
    191   }
    192 
    193   const_iterator end() const {
    194     return (const_iterator)const_cast<TinyPtrVector*>(this)->end();
    195   }
    196 
    197   reverse_iterator rbegin() { return reverse_iterator(end()); }
    198   reverse_iterator rend() { return reverse_iterator(begin()); }
    199 
    200   const_reverse_iterator rbegin() const {
    201     return const_reverse_iterator(end());
    202   }
    203 
    204   const_reverse_iterator rend() const {
    205     return const_reverse_iterator(begin());
    206   }
    207 
    208   EltTy operator[](unsigned i) const {
    209     assert(!Val.isNull() && "can't index into an empty vector");
    210     if (EltTy V = Val.template dyn_cast<EltTy>()) {
    211       assert(i == 0 && "tinyvector index out of range");
    212       return V;
    213     }
    214 
    215     assert(i < Val.template get<VecTy*>()->size() &&
    216            "tinyvector index out of range");
    217     return (*Val.template get<VecTy*>())[i];
    218   }
    219 
    220   EltTy front() const {
    221     assert(!empty() && "vector empty");
    222     if (EltTy V = Val.template dyn_cast<EltTy>())
    223       return V;
    224     return Val.template get<VecTy*>()->front();
    225   }
    226 
    227   EltTy back() const {
    228     assert(!empty() && "vector empty");
    229     if (EltTy V = Val.template dyn_cast<EltTy>())
    230       return V;
    231     return Val.template get<VecTy*>()->back();
    232   }
    233 
    234   void push_back(EltTy NewVal) {
    235     assert(NewVal && "Can't add a null value");
    236 
    237     // If we have nothing, add something.
    238     if (Val.isNull()) {
    239       Val = NewVal;
    240       return;
    241     }
    242 
    243     // If we have a single value, convert to a vector.
    244     if (EltTy V = Val.template dyn_cast<EltTy>()) {
    245       Val = new VecTy();
    246       Val.template get<VecTy*>()->push_back(V);
    247     }
    248 
    249     // Add the new value, we know we have a vector.
    250     Val.template get<VecTy*>()->push_back(NewVal);
    251   }
    252 
    253   void pop_back() {
    254     // If we have a single value, convert to empty.
    255     if (Val.template is<EltTy>())
    256       Val = (EltTy)nullptr;
    257     else if (VecTy *Vec = Val.template get<VecTy*>())
    258       Vec->pop_back();
    259   }
    260 
    261   void clear() {
    262     // If we have a single value, convert to empty.
    263     if (Val.template is<EltTy>()) {
    264       Val = (EltTy)nullptr;
    265     } else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
    266       // If we have a vector form, just clear it.
    267       Vec->clear();
    268     }
    269     // Otherwise, we're already empty.
    270   }
    271 
    272   iterator erase(iterator I) {
    273     assert(I >= begin() && "Iterator to erase is out of bounds.");
    274     assert(I < end() && "Erasing at past-the-end iterator.");
    275 
    276     // If we have a single value, convert to empty.
    277     if (Val.template is<EltTy>()) {
    278       if (I == begin())
    279         Val = (EltTy)nullptr;
    280     } else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
    281       // multiple items in a vector; just do the erase, there is no
    282       // benefit to collapsing back to a pointer
    283       return Vec->erase(I);
    284     }
    285     return end();
    286   }
    287 
    288   iterator erase(iterator S, iterator E) {
    289     assert(S >= begin() && "Range to erase is out of bounds.");
    290     assert(S <= E && "Trying to erase invalid range.");
    291     assert(E <= end() && "Trying to erase past the end.");
    292 
    293     if (Val.template is<EltTy>()) {
    294       if (S == begin() && S != E)
    295         Val = (EltTy)nullptr;
    296     } else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
    297       return Vec->erase(S, E);
    298     }
    299     return end();
    300   }
    301 
    302   iterator insert(iterator I, const EltTy &Elt) {
    303     assert(I >= this->begin() && "Insertion iterator is out of bounds.");
    304     assert(I <= this->end() && "Inserting past the end of the vector.");
    305     if (I == end()) {
    306       push_back(Elt);
    307       return std::prev(end());
    308     }
    309     assert(!Val.isNull() && "Null value with non-end insert iterator.");
    310     if (EltTy V = Val.template dyn_cast<EltTy>()) {
    311       assert(I == begin());
    312       Val = Elt;
    313       push_back(V);
    314       return begin();
    315     }
    316 
    317     return Val.template get<VecTy*>()->insert(I, Elt);
    318   }
    319 
    320   template<typename ItTy>
    321   iterator insert(iterator I, ItTy From, ItTy To) {
    322     assert(I >= this->begin() && "Insertion iterator is out of bounds.");
    323     assert(I <= this->end() && "Inserting past the end of the vector.");
    324     if (From == To)
    325       return I;
    326 
    327     // If we have a single value, convert to a vector.
    328     ptrdiff_t Offset = I - begin();
    329     if (Val.isNull()) {
    330       if (std::next(From) == To) {
    331         Val = *From;
    332         return begin();
    333       }
    334 
    335       Val = new VecTy();
    336     } else if (EltTy V = Val.template dyn_cast<EltTy>()) {
    337       Val = new VecTy();
    338       Val.template get<VecTy*>()->push_back(V);
    339     }
    340     return Val.template get<VecTy*>()->insert(begin() + Offset, From, To);
    341   }
    342 };
    343 
    344 } // end namespace llvm
    345 
    346 #endif // LLVM_ADT_TINYPTRVECTOR_H
    347