lean cpp library
A lean C++ library providing efficient utility classes for high-performance C++ applications.
dynamic_array.h
00001 /*****************************************************/
00002 /* lean Containers              (c) Tobias Zirr 2011 */
00003 /*****************************************************/
00004 
00005 #ifndef LEAN_CONTAINERS_DYNAMIC_ARRAY
00006 #define LEAN_CONTAINERS_DYNAMIC_ARRAY
00007 
00008 #include "../lean.h"
00009 #include "../memory/default_heap.h"
00010 
00011 namespace lean 
00012 {
00013 namespace containers
00014 {
00015 
00017 template < class Element, class Heap = default_heap >
00018 class dynamic_array
00019 {
00020 public:
00022     typedef Heap heap_type;
00024     typedef typename heap_type::size_type size_type;
00025 
00027     typedef Element value_type;
00029     typedef value_type* pointer;
00031     typedef const value_type* const_pointer;
00033     typedef value_type& reference;
00035     typedef const value_type& const_reference;
00036 
00038     typedef pointer iterator;
00040     typedef const_pointer const_iterator;
00041 
00042 private:
00043     value_type *m_elements;
00044     value_type *m_elementsEnd;
00045 
00046     // Make sure size_type is unsigned
00047     LEAN_STATIC_ASSERT(is_unsigned<size_type>::value);
00048 
00050     static LEAN_INLINE void default_construct(Element *dest)
00051     {
00052         new (static_cast<void*>(dest)) value_type();
00053     }
00055     static void default_construct(Element *dest, Element *destEnd)
00056     {
00057         Element *destr = dest;
00058 
00059         try
00060         {
00061             for (; dest != destEnd; ++dest)
00062                 default_construct(dest);
00063         }
00064         catch(...)
00065         {
00066             destruct(destr, dest);
00067             throw;
00068         }
00069     }
00070 
00072     static LEAN_INLINE void copy_construct(Element *dest, const Element &source)
00073     {
00074         new (static_cast<void*>(dest)) value_type(source);
00075     }
00077     template <class Iterator>
00078     static void copy_construct(Iterator source, Iterator sourceEnd, Element *dest)
00079     {
00080         Element *destr = dest;
00081 
00082         try
00083         {
00084             for (; source != sourceEnd; ++dest, ++source)
00085                 copy_construct(dest, *source);
00086         }
00087         catch(...)
00088         {
00089             destruct(destr, dest);
00090             throw;
00091         }
00092     }
00093 
00095     static LEAN_INLINE void move_construct(Element *dest, Element &source)
00096     {
00097 #ifndef LEAN0X_NO_RVALUE_REFERENCES
00098         new (static_cast<void*>(dest)) value_type( std::move(source) );
00099 #else
00100         copy_construct(dest, source);
00101 #endif
00102     }
00103 
00105     static LEAN_INLINE void move(Element *dest, Element &source)
00106     {
00107 #ifndef LEAN0X_NO_RVALUE_REFERENCES
00108         *dest = std::move(source);
00109 #else
00110         *dest = source;
00111 #endif
00112     }
00114     static void move(Element *source, Element *sourceEnd, Element *dest)
00115     {
00116         for (; source != sourceEnd; ++dest, ++source)
00117             move(dest, *source);
00118     }
00119 
00121     static void destruct(value_type *destr)
00122     {
00123         destr->~value_type();
00124     }
00126     static void destruct(value_type *destr, value_type *destrEnd)
00127     {
00128         for (; destr != destrEnd; ++destr)
00129             destruct(destr);
00130     }
00131 
00133     static LEAN_INLINE value_type* allocate(size_type capacity)
00134     {
00135         return (capacity > 0)
00136             ? static_cast<value_type*>( heap_type::allocate(capacity * sizeof(value_type)) )
00137             : nullptr;
00138     }
00139     
00141     LEAN_INLINE void free()
00142     {
00143         if (m_elements)
00144         {
00145             // Do nothing on exception, resources leaking anyways!
00146             clear();
00147 
00148             value_type *oldElements = m_elements;
00149             m_elements = nullptr;
00150             m_elementsEnd = nullptr;
00151 
00152             heap_type::free(oldElements);
00153         }
00154     }
00155 
00156 public:
00158     enum consume_t
00159     {
00160         consume     
00161     };
00162 
00164     dynamic_array()
00165         : m_elements(nullptr),
00166         m_elementsEnd(nullptr) { }
00168     explicit dynamic_array(size_type capacity)
00169         : m_elements( allocate(capacity) ),
00170         m_elementsEnd( m_elements ) { }
00172     dynamic_array(const dynamic_array &right)
00173         : m_elements( allocate(right.size()) ),
00174         m_elementsEnd( m_elements + right.size() )
00175     {
00176         copy_construct(right.m_elements, right.m_elementsEnd, m_elements);
00177     }
00178 #ifndef LEAN0X_NO_RVALUE_REFERENCES
00179 
00180     dynamic_array(dynamic_array &&right)
00181         : m_elements(std::move(right.m_elements)),
00182         m_elementsEnd(std::move(right.m_elementsEnd))
00183     {
00184         right.m_elements = nullptr;
00185         right.m_elementsEnd = nullptr;
00186     }
00187 #endif
00188 
00189     dynamic_array(dynamic_array &right, consume_t)
00190         : m_elements(right.m_elements),
00191         m_elementsEnd(right.m_elementsEnd)
00192     {
00193         right.m_elements = nullptr;
00194         right.m_elementsEnd = nullptr;
00195     }
00197     ~dynamic_array()
00198     {
00199         free();
00200     }
00201 
00203     dynamic_array& operator =(const dynamic_array &right)
00204     {
00205         if (&right != this)
00206         {
00207             reset(right.size());
00208 
00209             copy_construct(right.m_elements, right.m_elementsEnd, m_elements);
00210             m_elementsEnd += right.size();
00211         }
00212         return *this;
00213     }
00214 #ifndef LEAN0X_NO_RVALUE_REFERENCES
00215 
00216     dynamic_array& operator =(dynamic_array &&right)
00217     {
00218         if (&right != this)
00219         {
00220             free();
00221 
00222             m_elements = std::move(right.m_elements);
00223             m_elementsEnd = std::move(right.m_elementsEnd);
00224 
00225             right.m_elements = nullptr;
00226             right.m_elementsEnd = nullptr;
00227         }
00228         return *this;
00229     }
00230 #endif
00231 
00233     LEAN_INLINE void* allocate_back()
00234     {
00235         return m_elementsEnd;
00236     }
00238     LEAN_INLINE reference shift_back(value_type *newElement)
00239     {
00240         LEAN_ASSERT(newElement == m_elementsEnd);
00241 
00242         return *(m_elementsEnd++);
00243     }
00244 
00246     LEAN_INLINE reference push_back()
00247     {
00248         default_construct(m_elementsEnd);
00249         return *(m_elementsEnd++);
00250     }
00252     LEAN_INLINE pointer push_back(size_type count)
00253     {
00254         Element *firstElement = m_elementsEnd;
00255         default_construct(firstElement, firstElement + count);
00256         m_elementsEnd += count;
00257         return firstElement;
00258     }
00260     LEAN_INLINE void push_back(const value_type &value)
00261     {
00262         copy_construct(m_elementsEnd, value);
00263         ++m_elementsEnd;
00264     }
00265 #ifndef LEAN0X_NO_RVALUE_REFERENCES
00266 
00267     LEAN_INLINE void push_back(value_type &&value)
00268     {
00269         move_construct(m_elementsEnd, value);
00270         ++m_elementsEnd;
00271     }
00272 #endif
00273 
00274     LEAN_INLINE void pop_back()
00275     {
00276         LEAN_ASSERT(!empty());
00277 
00278         destruct(m_elementsEnd--);
00279     }
00280 
00282     LEAN_INLINE void clear()
00283     {
00284         Element *oldElementsEnd = m_elementsEnd;
00285         m_elementsEnd = m_elements;
00286         destruct(m_elements, oldElementsEnd);
00287     }
00288 
00290     LEAN_INLINE void reset(size_type newCapacity)
00291     {
00292         free();
00293 
00294         if (newCapacity > 0)
00295         {
00296             m_elements = allocate(newCapacity);
00297             m_elementsEnd = m_elements;
00298         }
00299     }
00300     
00302     LEAN_INLINE reference front(void) { LEAN_ASSERT(!empty()); return *m_elements; };
00304     LEAN_INLINE const_reference front(void) const { LEAN_ASSERT(!empty()); return *m_elements; };
00306     LEAN_INLINE reference back(void) { LEAN_ASSERT(!empty()); return m_elementsEnd[-1]; };
00308     LEAN_INLINE const_reference back(void) const { LEAN_ASSERT(!empty()); return m_elementsEnd[-1]; };
00309 
00311     LEAN_INLINE reference operator [](size_type pos) { return m_elements[pos]; };
00313     LEAN_INLINE const_reference operator [](size_type pos) const { return m_elements[pos]; };
00314 
00316     LEAN_INLINE iterator begin(void) { return m_elements; };
00318     LEAN_INLINE const_iterator begin(void) const { return m_elements; };
00320     LEAN_INLINE iterator end(void) { return m_elementsEnd; };
00322     LEAN_INLINE const_iterator end(void) const { return m_elementsEnd; };
00323 
00325     LEAN_INLINE bool empty(void) const { return (m_elements == m_elementsEnd); };
00327     LEAN_INLINE size_type size(void) const { return m_elementsEnd - m_elements; };
00328 
00330     LEAN_INLINE void swap(dynamic_array &right) throw()
00331     {
00332         using std::swap;
00333 
00334         swap(m_elements, right.m_elements);
00335         swap(m_elementsEnd, right.m_elementsEnd);
00336     }
00337 };
00338 
00340 template <class Element, class Heap>
00341 LEAN_INLINE void swap(dynamic_array<Element, Heap> &left, dynamic_array<Element, Heap> &right)
00342 {
00343     left.swap(right);
00344 }
00345 
00346 } // namespace
00347 
00348 using containers::dynamic_array;
00349 
00350 } // namespace
00351 
00352 #endif