From: Chris Lattner Date: Tue, 15 Dec 2009 08:29:22 +0000 (+0000) Subject: hoist the begin/end/capacity members and a few trivial methods X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=10aaf05c304e259dbb853a37d491fdc4ea54c9b1;p=oota-llvm.git hoist the begin/end/capacity members and a few trivial methods up into the non-templated SmallVectorBase class. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@91426 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/ADT/SmallVector.h b/include/llvm/ADT/SmallVector.h index 46d6b672d66..69c25d0d962 100644 --- a/include/llvm/ADT/SmallVector.h +++ b/include/llvm/ADT/SmallVector.h @@ -49,24 +49,14 @@ namespace llvm { /// SmallVectorBase - This is all the non-templated stuff common to all /// SmallVectors. class SmallVectorBase { - -}; - - -/// SmallVectorImpl - This class consists of common code factored out of the -/// SmallVector class to reduce code duplication based on the SmallVector 'N' -/// template parameter. -template -class SmallVectorImpl { protected: - T *Begin, *End, *Capacity; + 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 either use GCC extensions, or some // number of union instances for the space, which guarantee maximal alignment. -protected: #ifdef __GNUC__ typedef char U; U FirstEl __attribute__((aligned)); @@ -79,46 +69,65 @@ protected: } FirstEl; #endif // 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(&FirstEl); + } + + +public: + bool empty() const { return BeginX == EndX; } +}; + +/// SmallVectorImpl - This class consists of common code factored out of the +/// SmallVector class to reduce code duplication based on the SmallVector 'N' +/// template parameter. +template +class SmallVectorImpl : public SmallVectorBase { + void setEnd(T *P) { EndX = P; } public: // Default ctor - Initialize to empty. - explicit SmallVectorImpl(unsigned N) - : Begin(reinterpret_cast(&FirstEl)), - End(reinterpret_cast(&FirstEl)), - Capacity(reinterpret_cast(&FirstEl)+N) { + explicit SmallVectorImpl(unsigned N) : SmallVectorBase(N*sizeof(T)) { } ~SmallVectorImpl() { // Destroy the constructed elements in the vector. - destroy_range(Begin, End); + destroy_range(begin(), end()); // If this wasn't grown from the inline copy, deallocate the old space. if (!isSmall()) - operator delete(Begin); + operator delete(begin()); } typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T value_type; - typedef T* iterator; - typedef const T* const_iterator; - - typedef std::reverse_iterator const_reverse_iterator; - typedef std::reverse_iterator reverse_iterator; + typedef T *iterator; + typedef const T *const_iterator; - typedef T& reference; - typedef const T& const_reference; - typedef T* pointer; - typedef const T* const_pointer; + typedef std::reverse_iterator const_reverse_iterator; + typedef std::reverse_iterator reverse_iterator; - bool empty() const { return Begin == End; } - size_type size() const { return End-Begin; } - size_type max_size() const { return size_type(-1) / sizeof(T); } + typedef T &reference; + typedef const T &const_reference; + typedef T *pointer; + typedef const T *const_pointer; // forward iterator creation methods. - iterator begin() { return Begin; } - const_iterator begin() const { return Begin; } - iterator end() { return End; } - const_iterator end() const { return End; } + iterator begin() { return (iterator)BeginX; } + const_iterator begin() const { return (const_iterator)BeginX; } + iterator end() { return (iterator)EndX; } + const_iterator end() const { return (const_iterator)EndX; } +private: + iterator capacity_ptr() { return (iterator)CapacityX; } + const_iterator capacity_ptr() const { return (const_iterator)CapacityX; } +public: // reverse iterator creation methods. reverse_iterator rbegin() { return reverse_iterator(end()); } @@ -126,14 +135,25 @@ public: reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin());} - + size_type size() const { return end()-begin(); } + size_type max_size() const { return size_type(-1) / sizeof(T); } + + /// capacity - Return the total number of elements in the currently allocated + /// buffer. + size_t capacity() const { return capacity_ptr() - begin(); } + + /// data - Return a pointer to the vector's buffer, even if empty(). + pointer data() { return pointer(begin()); } + /// data - Return a pointer to the vector's buffer, even if empty(). + const_pointer data() const { return const_pointer(begin()); } + reference operator[](unsigned idx) { - assert(Begin + idx < End); - return Begin[idx]; + assert(begin() + idx < end()); + return begin()[idx]; } const_reference operator[](unsigned idx) const { - assert(Begin + idx < End); - return Begin[idx]; + assert(begin() + idx < end()); + return begin()[idx]; } reference front() { @@ -151,10 +171,10 @@ public: } void push_back(const_reference Elt) { - if (End < Capacity) { + if (EndX < CapacityX) { Retry: - new (End) T(Elt); - ++End; + new (end()) T(Elt); + setEnd(end()+1); return; } grow(); @@ -162,8 +182,8 @@ public: } void pop_back() { - --End; - End->~T(); + setEnd(end()-1); + end()->~T(); } T pop_back_val() { @@ -173,36 +193,36 @@ public: } void clear() { - destroy_range(Begin, End); - End = Begin; + destroy_range(begin(), end()); + EndX = BeginX; } void resize(unsigned N) { if (N < size()) { - destroy_range(Begin+N, End); - End = Begin+N; + destroy_range(begin()+N, end()); + setEnd(begin()+N); } else if (N > size()) { - if (unsigned(Capacity-Begin) < N) + if (capacity() < N) grow(N); - construct_range(End, Begin+N, T()); - End = Begin+N; + construct_range(end(), begin()+N, T()); + setEnd(begin()+N); } } void resize(unsigned N, const T &NV) { if (N < size()) { - destroy_range(Begin+N, End); - End = Begin+N; + destroy_range(begin()+N, end()); + setEnd(begin()+N); } else if (N > size()) { - if (unsigned(Capacity-Begin) < N) + if (capacity() < N) grow(N); - construct_range(End, Begin+N, NV); - End = Begin+N; + construct_range(end(), begin()+N, NV); + setEnd(begin()+N); } } void reserve(unsigned N) { - if (unsigned(Capacity-Begin) < N) + if (capacity() < N) grow(N); } @@ -214,38 +234,38 @@ public: void append(in_iter in_start, in_iter in_end) { size_type NumInputs = std::distance(in_start, in_end); // Grow allocated space if needed. - if (NumInputs > size_type(Capacity-End)) + if (NumInputs > size_type(capacity_ptr()-end())) grow(size()+NumInputs); // Copy the new elements over. - std::uninitialized_copy(in_start, in_end, End); - End += NumInputs; + std::uninitialized_copy(in_start, in_end, end()); + setEnd(end() + NumInputs); } /// append - Add the specified range to the end of the SmallVector. /// void append(size_type NumInputs, const T &Elt) { // Grow allocated space if needed. - if (NumInputs > size_type(Capacity-End)) + if (NumInputs > size_type(capacity_ptr()-end())) grow(size()+NumInputs); // Copy the new elements over. - std::uninitialized_fill_n(End, NumInputs, Elt); - End += NumInputs; + std::uninitialized_fill_n(end(), NumInputs, Elt); + setEnd(end() + NumInputs); } void assign(unsigned NumElts, const T &Elt) { clear(); - if (unsigned(Capacity-Begin) < NumElts) + if (capacity() < NumElts) grow(NumElts); - End = Begin+NumElts; - construct_range(Begin, End, Elt); + setEnd(begin()+NumElts); + construct_range(begin(), end(), Elt); } iterator erase(iterator I) { iterator N = I; // Shift all elts down one. - std::copy(I+1, End, I); + std::copy(I+1, end(), I); // Drop the last elt. pop_back(); return(N); @@ -254,36 +274,36 @@ public: iterator erase(iterator S, iterator E) { iterator N = S; // Shift all elts down. - iterator I = std::copy(E, End, S); + iterator I = std::copy(E, end(), S); // Drop the last elts. - destroy_range(I, End); - End = I; + destroy_range(I, end()); + setEnd(I); return(N); } iterator insert(iterator I, const T &Elt) { - if (I == End) { // Important special case for empty vector. + if (I == end()) { // Important special case for empty vector. push_back(Elt); return end()-1; } - if (End < Capacity) { + if (EndX < CapacityX) { Retry: - new (End) T(back()); - ++End; + new (end()) T(back()); + setEnd(end()+1); // Push everything else over. - std::copy_backward(I, End-1, End); + std::copy_backward(I, end()-1, end()); *I = Elt; return I; } - size_t EltNo = I-Begin; + size_t EltNo = I-begin(); grow(); - I = Begin+EltNo; + I = begin()+EltNo; goto Retry; } iterator insert(iterator I, size_type NumToInsert, const T &Elt) { - if (I == End) { // Important special case for empty vector. + if (I == end()) { // Important special case for empty vector. append(NumToInsert, Elt); return end()-1; } @@ -302,8 +322,8 @@ public: // insertion. Since we already reserved space, we know that this won't // reallocate the vector. if (size_t(end()-I) >= NumToInsert) { - T *OldEnd = End; - append(End-NumToInsert, End); + T *OldEnd = end(); + append(end()-NumToInsert, end()); // Copy the existing elements that get replaced. std::copy_backward(I, OldEnd-NumToInsert, OldEnd); @@ -316,10 +336,10 @@ public: // not inserting at the end. // Copy over the elements that we're about to overwrite. - T *OldEnd = End; - End += NumToInsert; + T *OldEnd = end(); + setEnd(end() + NumToInsert); size_t NumOverwritten = OldEnd-I; - std::uninitialized_copy(I, OldEnd, End-NumOverwritten); + std::uninitialized_copy(I, OldEnd, end()-NumOverwritten); // Replace the overwritten part. std::fill_n(I, NumOverwritten, Elt); @@ -331,7 +351,7 @@ public: template iterator insert(iterator I, ItTy From, ItTy To) { - if (I == End) { // Important special case for empty vector. + if (I == end()) { // Important special case for empty vector. append(From, To); return end()-1; } @@ -351,8 +371,8 @@ public: // insertion. Since we already reserved space, we know that this won't // reallocate the vector. if (size_t(end()-I) >= NumToInsert) { - T *OldEnd = End; - append(End-NumToInsert, End); + T *OldEnd = end(); + append(end()-NumToInsert, end()); // Copy the existing elements that get replaced. std::copy_backward(I, OldEnd-NumToInsert, OldEnd); @@ -365,10 +385,10 @@ public: // not inserting at the end. // Copy over the elements that we're about to overwrite. - T *OldEnd = End; - End += NumToInsert; + T *OldEnd = end(); + setEnd(end() + NumToInsert); size_t NumOverwritten = OldEnd-I; - std::uninitialized_copy(I, OldEnd, End-NumOverwritten); + std::uninitialized_copy(I, OldEnd, end()-NumOverwritten); // Replace the overwritten part. std::copy(From, From+NumOverwritten, I); @@ -378,21 +398,11 @@ public: return I; } - /// data - Return a pointer to the vector's buffer, even if empty(). - pointer data() { - return pointer(Begin); - } - - /// data - Return a pointer to the vector's buffer, even if empty(). - const_pointer data() const { - return const_pointer(Begin); - } - const SmallVectorImpl &operator=(const SmallVectorImpl &RHS); bool operator==(const SmallVectorImpl &RHS) const { if (size() != RHS.size()) return false; - for (T *This = Begin, *That = RHS.Begin, *E = Begin+size(); + for (const T *This = begin(), *That = RHS.begin(), *E = end(); This != E; ++This, ++That) if (*This != *That) return false; @@ -405,10 +415,6 @@ public: RHS.begin(), RHS.end()); } - /// capacity - Return the total number of elements in the currently allocated - /// buffer. - size_t capacity() const { return Capacity - Begin; } - /// set_size - Set the array size to \arg N, which the current array must have /// enough capacity for. /// @@ -420,17 +426,10 @@ public: /// which will only be overwritten. void set_size(unsigned N) { assert(N <= capacity()); - End = Begin + N; + setEnd(begin() + N); } private: - /// isSmall - Return true if this is a smallvector which has not had dynamic - /// memory allocated for it. - bool isSmall() const { - return static_cast(Begin) == - static_cast(&FirstEl); - } - /// grow - double the size of the allocated memory, guaranteeing space for at /// least one more element or MinSize if specified. void grow(size_type MinSize = 0); @@ -441,6 +440,7 @@ private: } void destroy_range(T *S, T *E) { + // TODO: POD while (S != E) { --E; E->~T(); @@ -451,7 +451,7 @@ private: // Define this out-of-line to dissuade the C++ compiler from inlining it. template void SmallVectorImpl::grow(size_t MinSize) { - size_t CurCapacity = Capacity-Begin; + size_t CurCapacity = capacity(); size_t CurSize = size(); size_t NewCapacity = 2*CurCapacity; if (NewCapacity < MinSize) @@ -460,21 +460,21 @@ void SmallVectorImpl::grow(size_t MinSize) { // Copy the elements over. if (is_class::value) - std::uninitialized_copy(Begin, End, NewElts); + std::uninitialized_copy(begin(), end(), NewElts); else // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove). - memcpy(NewElts, Begin, CurSize * sizeof(T)); + memcpy(NewElts, begin(), CurSize * sizeof(T)); // Destroy the original elements. - destroy_range(Begin, End); + destroy_range(begin(), end()); // If this wasn't grown from the inline copy, deallocate the old space. if (!isSmall()) - operator delete(Begin); + operator delete(begin()); - Begin = NewElts; - End = NewElts+CurSize; - Capacity = Begin+NewCapacity; + setEnd(NewElts+CurSize); + BeginX = NewElts; + CapacityX = begin()+NewCapacity; } template @@ -483,35 +483,35 @@ void SmallVectorImpl::swap(SmallVectorImpl &RHS) { // We can only avoid copying elements if neither vector is small. if (!isSmall() && !RHS.isSmall()) { - std::swap(Begin, RHS.Begin); - std::swap(End, RHS.End); - std::swap(Capacity, RHS.Capacity); + std::swap(BeginX, RHS.BeginX); + std::swap(EndX, RHS.EndX); + std::swap(CapacityX, RHS.CapacityX); return; } - if (RHS.size() > size_type(Capacity-Begin)) + if (RHS.size() > capacity()) grow(RHS.size()); - if (size() > size_type(RHS.Capacity-RHS.begin())) + if (size() > RHS.capacity()) RHS.grow(size()); // Swap the shared elements. size_t NumShared = size(); if (NumShared > RHS.size()) NumShared = RHS.size(); for (unsigned i = 0; i != static_cast(NumShared); ++i) - std::swap(Begin[i], RHS[i]); + std::swap((*this)[i], RHS[i]); // Copy over the extra elts. if (size() > RHS.size()) { size_t EltDiff = size() - RHS.size(); - std::uninitialized_copy(Begin+NumShared, End, RHS.End); - RHS.End += EltDiff; - destroy_range(Begin+NumShared, End); - End = Begin+NumShared; + std::uninitialized_copy(begin()+NumShared, end(), RHS.end()); + RHS.setEnd(RHS.end()+EltDiff); + destroy_range(begin()+NumShared, end()); + setEnd(begin()+NumShared); } else if (RHS.size() > size()) { size_t EltDiff = RHS.size() - size(); - std::uninitialized_copy(RHS.Begin+NumShared, RHS.End, End); - End += EltDiff; - destroy_range(RHS.Begin+NumShared, RHS.End); - RHS.End = RHS.Begin+NumShared; + std::uninitialized_copy(RHS.begin()+NumShared, RHS.end(), end()); + setEnd(end() + EltDiff); + destroy_range(RHS.begin()+NumShared, RHS.end()); + RHS.setEnd(RHS.begin()+NumShared); } } @@ -523,42 +523,42 @@ SmallVectorImpl::operator=(const SmallVectorImpl &RHS) { // If we already have sufficient space, assign the common elements, then // destroy any excess. - unsigned RHSSize = unsigned(RHS.size()); - unsigned CurSize = unsigned(size()); + size_t RHSSize = RHS.size(); + size_t CurSize = size(); if (CurSize >= RHSSize) { // Assign common elements. iterator NewEnd; if (RHSSize) - NewEnd = std::copy(RHS.Begin, RHS.Begin+RHSSize, Begin); + NewEnd = std::copy(RHS.begin(), RHS.begin()+RHSSize, begin()); else - NewEnd = Begin; + NewEnd = begin(); // Destroy excess elements. - destroy_range(NewEnd, End); + destroy_range(NewEnd, end()); // Trim. - End = NewEnd; + setEnd(NewEnd); return *this; } // If we have to grow to have enough elements, destroy the current elements. // This allows us to avoid copying them during the grow. - if (unsigned(Capacity-Begin) < RHSSize) { + if (capacity() < RHSSize) { // Destroy current elements. - destroy_range(Begin, End); - End = Begin; + destroy_range(begin(), end()); + setEnd(begin()); CurSize = 0; grow(RHSSize); } else if (CurSize) { // Otherwise, use assignment for the already-constructed elements. - std::copy(RHS.Begin, RHS.Begin+CurSize, Begin); + std::copy(RHS.begin(), RHS.begin()+CurSize, begin()); } // Copy construct the new elements in place. - std::uninitialized_copy(RHS.Begin+CurSize, RHS.End, Begin+CurSize); + std::uninitialized_copy(RHS.begin()+CurSize, RHS.end(), begin()+CurSize); // Set end. - End = Begin+RHSSize; + setEnd(begin()+RHSSize); return *this; }