lean cpp library
A lean C++ library providing efficient utility classes for high-performance C++ applications.
|
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