#ifndef LLVM_ADT_SMALLVECTOR_H
#define LLVM_ADT_SMALLVECTOR_H
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MathExtras.h"
#include "llvm/Support/type_traits.h"
#include <algorithm>
#include <cassert>
protected:
void *BeginX, *EndX, *CapacityX;
- // Allocate raw space for N elements of type T. If T has a ctor or dtor, we
- // don't want it to be automatically run, so we need to represent the space as
- // something else. An array of char would work great, but might not be
- // aligned sufficiently. Instead we use some number of union instances for
- // the space, which guarantee maximal alignment.
- union U {
- double D;
- long double LD;
- long long L;
- void *P;
- } FirstEl;
- // Space after 'FirstEl' is clobbered, do not add any instance vars after it.
-
protected:
- SmallVectorBase(size_t Size)
- : BeginX(&FirstEl), EndX(&FirstEl), CapacityX((char*)&FirstEl+Size) {}
-
- /// isSmall - Return true if this is a smallvector which has not had dynamic
- /// memory allocated for it.
- bool isSmall() const {
- return BeginX == static_cast<const void*>(&FirstEl);
- }
-
- /// resetToSmall - Put this vector in a state of being small.
- void resetToSmall() {
- BeginX = EndX = CapacityX = &FirstEl;
- }
+ SmallVectorBase(void *FirstEl, size_t Size)
+ : BeginX(FirstEl), EndX(FirstEl), CapacityX((char*)FirstEl+Size) {}
/// grow_pod - This is an implementation of the grow() method which only works
/// on POD-like data types and is out of line to reduce code duplication.
- void grow_pod(size_t MinSizeInBytes, size_t TSize);
+ void grow_pod(void *FirstEl, size_t MinSizeInBytes, size_t TSize);
public:
/// size_in_bytes - This returns size()*sizeof(T).
size_t size_in_bytes() const {
return size_t((char*)EndX - (char*)BeginX);
}
-
+
/// capacity_in_bytes - This returns capacity()*sizeof(T).
size_t capacity_in_bytes() const {
return size_t((char*)CapacityX - (char*)BeginX);
}
- bool empty() const { return BeginX == EndX; }
+ bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return BeginX == EndX; }
};
+template <typename T, unsigned N> struct SmallVectorStorage;
-template <typename T>
+/// SmallVectorTemplateCommon - This is the part of SmallVectorTemplateBase
+/// which does not depend on whether the type T is a POD. The extra dummy
+/// template argument is used by ArrayRef to avoid unnecessarily requiring T
+/// to be complete.
+template <typename T, typename = void>
class SmallVectorTemplateCommon : public SmallVectorBase {
+private:
+ template <typename, unsigned> friend struct SmallVectorStorage;
+
+ // Allocate raw space for N elements of type T. If T has a ctor or dtor, we
+ // don't want it to be automatically run, so we need to represent the space as
+ // something else. Use an array of char of sufficient alignment.
+ typedef llvm::AlignedCharArrayUnion<T> U;
+ U FirstEl;
+ // Space after 'FirstEl' is clobbered, do not add any instance vars after it.
+
protected:
- SmallVectorTemplateCommon(size_t Size) : SmallVectorBase(Size) {}
+ SmallVectorTemplateCommon(size_t Size) : SmallVectorBase(&FirstEl, Size) {}
+
+ void grow_pod(size_t MinSizeInBytes, size_t TSize) {
+ SmallVectorBase::grow_pod(&FirstEl, MinSizeInBytes, TSize);
+ }
+
+ /// isSmall - Return true if this is a smallvector which has not had dynamic
+ /// memory allocated for it.
+ bool isSmall() const {
+ return BeginX == static_cast<const void*>(&FirstEl);
+ }
+
+ /// resetToSmall - Put this vector in a state of being small.
+ void resetToSmall() {
+ BeginX = EndX = CapacityX = &FirstEl;
+ }
void setEnd(T *P) { this->EndX = P; }
public:
}
reference front() {
+ assert(!empty());
return begin()[0];
}
const_reference front() const {
+ assert(!empty());
return begin()[0];
}
reference back() {
+ assert(!empty());
return end()[-1];
}
const_reference back() const {
+ assert(!empty());
return end()[-1];
}
};
/// std::move, but not all stdlibs actually provide that.
template<typename It1, typename It2>
static It2 move(It1 I, It1 E, It2 Dest) {
-#if LLVM_USE_RVALUE_REFERENCES
for (; I != E; ++I, ++Dest)
*Dest = ::std::move(*I);
return Dest;
-#else
- return ::std::copy(I, E, Dest);
-#endif
}
/// move_backward - Use move-assignment to move the range
/// std::move_backward, but not all stdlibs actually provide that.
template<typename It1, typename It2>
static It2 move_backward(It1 I, It1 E, It2 Dest) {
-#if LLVM_USE_RVALUE_REFERENCES
while (I != E)
*--Dest = ::std::move(*--E);
return Dest;
-#else
- return ::std::copy_backward(I, E, Dest);
-#endif
}
/// uninitialized_move - Move the range [I, E) into the uninitialized
/// memory starting with "Dest", constructing elements as needed.
template<typename It1, typename It2>
static void uninitialized_move(It1 I, It1 E, It2 Dest) {
-#if LLVM_USE_RVALUE_REFERENCES
for (; I != E; ++I, ++Dest)
::new ((void*) &*Dest) T(::std::move(*I));
-#else
- ::std::uninitialized_copy(I, E, Dest);
-#endif
}
/// uninitialized_copy - Copy the range [I, E) onto the uninitialized
goto Retry;
}
-#if LLVM_USE_RVALUE_REFERENCES
void push_back(T &&Elt) {
if (this->EndX < this->CapacityX) {
Retry:
this->grow();
goto Retry;
}
-#endif
-
+
void pop_back() {
this->setEnd(this->end()-1);
this->end()->~T();
void SmallVectorTemplateBase<T, isPodLike>::grow(size_t MinSize) {
size_t CurCapacity = this->capacity();
size_t CurSize = this->size();
- size_t NewCapacity = 2*CurCapacity + 1; // Always grow, even from zero.
+ // Always grow, even from zero.
+ size_t NewCapacity = size_t(NextPowerOf2(CurCapacity+2));
if (NewCapacity < MinSize)
NewCapacity = MinSize;
T *NewElts = static_cast<T*>(malloc(NewCapacity*sizeof(T)));
class SmallVectorImpl : public SmallVectorTemplateBase<T, isPodLike<T>::value> {
typedef SmallVectorTemplateBase<T, isPodLike<T>::value > SuperClass;
- SmallVectorImpl(const SmallVectorImpl&); // DISABLED.
+ SmallVectorImpl(const SmallVectorImpl&) LLVM_DELETED_FUNCTION;
public:
typedef typename SuperClass::iterator iterator;
typedef typename SuperClass::size_type size_type;
this->grow(N);
}
- T pop_back_val() {
-#if LLVM_USE_RVALUE_REFERENCES
+ T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() {
T Result = ::std::move(this->back());
-#else
- T Result = this->back();
-#endif
this->pop_back();
return Result;
}
return(N);
}
-#if LLVM_USE_RVALUE_REFERENCES
iterator insert(iterator I, T &&Elt) {
if (I == this->end()) { // Important special case for empty vector.
this->push_back(::std::move(Elt));
I = this->begin()+EltNo;
goto Retry;
}
-#endif
iterator insert(iterator I, const T &Elt) {
if (I == this->end()) { // Important special case for empty vector.
SmallVectorImpl &operator=(const SmallVectorImpl &RHS);
-#if LLVM_USE_RVALUE_REFERENCES
SmallVectorImpl &operator=(SmallVectorImpl &&RHS);
-#endif
bool operator==(const SmallVectorImpl &RHS) const {
if (this->size() != RHS.size()) return false;
RHS.begin(), RHS.end());
}
- /// set_size - Set the array size to \arg N, which the current array must have
- /// enough capacity for.
+ /// Set the array size to \p N, which the current array must have enough
+ /// capacity for.
///
/// This does not construct or destroy any elements in the vector.
///
return *this;
}
-#if LLVM_USE_RVALUE_REFERENCES
template <typename T>
SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
// Avoid self-assignment.
RHS.clear();
return *this;
}
-#endif
+
+/// Storage for the SmallVector elements which aren't contained in
+/// SmallVectorTemplateCommon. There are 'N-1' elements here. The remaining '1'
+/// element is in the base class. This is specialized for the N=1 and N=0 cases
+/// to avoid allocating unnecessary storage.
+template <typename T, unsigned N>
+struct SmallVectorStorage {
+ typename SmallVectorTemplateCommon<T>::U InlineElts[N - 1];
+};
+template <typename T> struct SmallVectorStorage<T, 1> {};
+template <typename T> struct SmallVectorStorage<T, 0> {};
/// SmallVector - This is a 'vector' (really, a variable-sized array), optimized
/// for the case when the array is small. It contains some number of elements
///
template <typename T, unsigned N>
class SmallVector : public SmallVectorImpl<T> {
- /// InlineElts - These are 'N-1' elements that are stored inline in the body
- /// of the vector. The extra '1' element is stored in SmallVectorImpl.
- typedef typename SmallVectorImpl<T>::U U;
- enum {
- // MinUs - The number of U's require to cover N T's.
- MinUs = (static_cast<unsigned int>(sizeof(T))*N +
- static_cast<unsigned int>(sizeof(U)) - 1) /
- static_cast<unsigned int>(sizeof(U)),
-
- // NumInlineEltsElts - The number of elements actually in this array. There
- // is already one in the parent class, and we have to round up to avoid
- // having a zero-element array.
- NumInlineEltsElts = MinUs > 1 ? (MinUs - 1) : 1,
-
- // NumTsAvailable - The number of T's we actually have space for, which may
- // be more than N due to rounding.
- NumTsAvailable = (NumInlineEltsElts+1)*static_cast<unsigned int>(sizeof(U))/
- static_cast<unsigned int>(sizeof(T))
- };
- U InlineElts[NumInlineEltsElts];
+ /// Storage - Inline space for elements which aren't stored in the base class.
+ SmallVectorStorage<T, N> Storage;
public:
- SmallVector() : SmallVectorImpl<T>(NumTsAvailable) {
+ SmallVector() : SmallVectorImpl<T>(N) {
}
explicit SmallVector(unsigned Size, const T &Value = T())
- : SmallVectorImpl<T>(NumTsAvailable) {
+ : SmallVectorImpl<T>(N) {
this->assign(Size, Value);
}
template<typename ItTy>
- SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(NumTsAvailable) {
+ SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
this->append(S, E);
}
- SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(NumTsAvailable) {
- if (!RHS.empty())
- SmallVectorImpl<T>::operator=(RHS);
+ template <typename RangeTy>
+ explicit SmallVector(const llvm::iterator_range<RangeTy> R)
+ : SmallVectorImpl<T>(N) {
+ this->append(R.begin(), R.end());
}
- const SmallVector &operator=(const SmallVector &RHS) {
- SmallVectorImpl<T>::operator=(RHS);
- return *this;
- }
-
-#if LLVM_USE_RVALUE_REFERENCES
- SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(NumTsAvailable) {
- if (!RHS.empty())
- SmallVectorImpl<T>::operator=(::std::move(RHS));
- }
-
- const SmallVector &operator=(SmallVector &&RHS) {
- SmallVectorImpl<T>::operator=(::std::move(RHS));
- return *this;
- }
-#endif
-
-};
-
-/// Specialize SmallVector at N=0. This specialization guarantees
-/// that it can be instantiated at an incomplete T if none of its
-/// members are required.
-template <typename T>
-class SmallVector<T,0> : public SmallVectorImpl<T> {
-public:
- SmallVector() : SmallVectorImpl<T>(0) {
- }
-
- explicit SmallVector(unsigned Size, const T &Value = T())
- : SmallVectorImpl<T>(0) {
- this->assign(Size, Value);
- }
-
- template<typename ItTy>
- SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(0) {
- this->append(S, E);
- }
-
- SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(0) {
+ SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) {
if (!RHS.empty())
SmallVectorImpl<T>::operator=(RHS);
}
return *this;
}
-#if LLVM_USE_RVALUE_REFERENCES
- SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(0) {
+ SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(N) {
if (!RHS.empty())
SmallVectorImpl<T>::operator=(::std::move(RHS));
}
SmallVectorImpl<T>::operator=(::std::move(RHS));
return *this;
}
-#endif
};
template<typename T, unsigned N>