aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/llvm/ADT/SmallVector.h196
1 files changed, 196 insertions, 0 deletions
diff --git a/include/llvm/ADT/SmallVector.h b/include/llvm/ADT/SmallVector.h
new file mode 100644
index 0000000..c75453f
--- /dev/null
+++ b/include/llvm/ADT/SmallVector.h
@@ -0,0 +1,196 @@
+//===- llvm/ADT/SmallVector.h - 'Normally small' vectors --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the SmallVector class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_SMALLVECTOR_H
+#define LLVM_ADT_SMALLVECTOR_H
+
+#include <cassert>
+#include <memory>
+
+namespace llvm {
+
+/// 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
+/// in-place, which allows it to avoid heap allocation when the actual number of
+/// elements is below that threshold. This allows normal "small" cases to be
+/// fast without losing generality for large inputs.
+///
+/// Note that this does not attempt to be exception safe.
+///
+template <typename T, unsigned N>
+class SmallVector {
+ // 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.
+ union U {
+ double D;
+ long double LD;
+ long long L;
+ void *P;
+ };
+
+ /// InlineElts - These are the 'N' elements that are stored inline in the body
+ /// of the vector
+ U InlineElts[(sizeof(T)*N+sizeof(U)-1)/sizeof(U)];
+ T *Begin, *End, *Capacity;
+public:
+ // Default ctor - Initialize to empty.
+ SmallVector() : Begin((T*)InlineElts), End(Begin), Capacity(Begin+N) {
+ }
+
+ SmallVector(const SmallVector &RHS) {
+ unsigned RHSSize = RHS.size();
+ Begin = (T*)InlineElts;
+
+ // Doesn't fit in the small case? Allocate space.
+ if (RHSSize > N) {
+ End = Capacity = Begin;
+ grow(RHSSize);
+ }
+ End = Begin+RHSSize;
+ Capacity = Begin+N;
+ std::uninitialized_copy(RHS.begin(), RHS.end(), Begin);
+ }
+ ~SmallVector() {
+ // If this wasn't grown from the inline copy, deallocate the old space.
+ if ((void*)Begin != (void*)InlineElts)
+ delete[] (char*)Begin;
+ }
+
+ typedef size_t size_type;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+ typedef T& reference;
+ typedef const T& const_reference;
+
+ bool empty() const { return Begin == End; }
+ size_type size() const { return End-Begin; }
+
+ iterator begin() { return Begin; }
+ const_iterator begin() const { return Begin; }
+
+ iterator end() { return End; }
+ const_iterator end() const { return End; }
+
+ reference operator[](unsigned idx) {
+ assert(idx < size() && "out of range reference!");
+ return Begin[idx];
+ }
+ const_reference operator[](unsigned idx) const {
+ assert(idx < size() && "out of range reference!");
+ return Begin[idx];
+ }
+
+ reference back() {
+ assert(!empty() && "SmallVector is empty!");
+ return end()[-1];
+ }
+ const_reference back() const {
+ assert(!empty() && "SmallVector is empty!");
+ return end()[-1];
+ }
+
+ void push_back(const_reference Elt) {
+ if (End < Capacity) {
+ Retry:
+ new (End) T(Elt);
+ ++End;
+ return;
+ }
+ grow();
+ goto Retry;
+ }
+
+ const SmallVector &operator=(const SmallVector &RHS) {
+ // Avoid self-assignment.
+ if (this == &RHS) return *this;
+
+ // If we already have sufficient space, assign the common elements, then
+ // destroy any excess.
+ unsigned RHSSize = RHS.size();
+ unsigned CurSize = size();
+ if (CurSize >= RHSSize) {
+ // Assign common elements.
+ for (unsigned i = 0; i != RHSSize; ++i)
+ Begin[i] = RHS.Begin[i];
+
+ // Destroy excess elements.
+ for (unsigned i = RHSSize; i != CurSize; ++i)
+ Begin[i].~T();
+
+ // Trim.
+ End = Begin + RHSSize;
+ 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 (Capacity-Begin < RHSSize) {
+ // Destroy current elements.
+ for (T *I = Begin, E = End; I != E; ++I)
+ I->~T();
+ End = Begin;
+ CurSize = 0;
+ grow(RHSSize);
+ } else {
+ // Otherwise, use assignment for the already-constructed elements.
+ for (unsigned i = 0; i != CurSize; ++i)
+ Begin[i] = RHS.Begin[i];
+ }
+
+ // Copy construct the new elements in place.
+ std::uninitialized_copy(RHS.Begin+CurSize, RHS.End, Begin+CurSize);
+
+ // Set end.
+ End = Begin+RHSSize;
+ }
+
+private:
+ /// isSmall - Return true if this is a smallvector which has not had dynamic
+ /// memory allocated for it.
+ bool isSmall() const {
+ return (void*)Begin == (void*)InlineElts;
+ }
+
+ /// grow - double the size of the allocated memory, guaranteeing space for at
+ /// least one more element or MinSize if specified.
+ void grow(unsigned MinSize = 0) {
+ unsigned CurCapacity = Capacity-Begin;
+ unsigned CurSize = size();
+ unsigned NewCapacity = 2*CurCapacity;
+ if (NewCapacity < MinSize)
+ NewCapacity = MinSize;
+ T *NewElts = reinterpret_cast<T*>(new char[NewCapacity*sizeof(T)]);
+
+ // Copy the elements over.
+ std::uninitialized_copy(Begin, End, NewElts);
+
+ // Destroy the original elements.
+ for (T *I = Begin, *E = End; I != E; ++I)
+ I->~T();
+
+ // If this wasn't grown from the inline copy, deallocate the old space.
+ if (!isSmall())
+ delete[] (char*)Begin;
+
+ Begin = NewElts;
+ End = NewElts+CurSize;
+ Capacity = Begin+NewCapacity*2;
+ }
+};
+
+} // End llvm namespace
+
+#endif