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_ACCUMULATION_VECTOR 00006 #define LEAN_CONTAINERS_ACCUMULATION_VECTOR 00007 00008 #include "../lean.h" 00009 #include <algorithm> 00010 #include "default_reallocation_policy.h" 00011 00012 namespace lean 00013 { 00014 namespace containers 00015 { 00016 00017 namespace Impl 00018 { 00019 00021 template <class Container> 00022 class has_reverse_iterator 00023 { 00024 private: 00025 typedef char yes[1]; 00026 typedef char no[2]; 00027 00028 template <class T> 00029 static yes& sfinae_check(T*, typename T::reverse_iterator* = nullptr); 00030 static no& sfinae_check(...); 00031 00032 public: 00034 static const bool value = ( 00035 sizeof( has_reverse_iterator::sfinae_check( static_cast<Container*>(nullptr) ) ) 00036 == 00037 sizeof(yes) ); 00038 }; 00039 00041 template <bool HasReverseIterators, class Container> 00042 struct reverse_iterators_impl 00043 { 00044 typedef void reverse_iterator; 00045 typedef void const_reverse_iterator; 00046 }; 00047 template <class Container> 00048 struct reverse_iterators_impl<true, Container> 00049 { 00050 typedef typename Container::reverse_iterator reverse_iterator; 00051 typedef typename Container::const_reverse_iterator const_reverse_iterator; 00052 }; 00053 00055 template <class Container> 00056 struct reverse_iterators 00057 : public reverse_iterators_impl<has_reverse_iterator<Container>::value, Container> { }; 00058 00059 } // namespace 00060 00062 00066 template < class Container, class ReallocationPolicy = default_reallocation_policy<Container> > 00067 class accumulation_vector 00068 { 00069 public: 00071 typedef Container container_type; 00073 typedef ReallocationPolicy reallocation_policy; 00074 00076 typedef typename container_type::value_type value_type; 00078 typedef typename container_type::size_type size_type; 00080 typedef typename container_type::allocator_type allocator_type; 00082 typedef typename container_type::difference_type difference_type; 00083 00085 typedef typename container_type::pointer pointer; 00087 typedef typename container_type::const_pointer const_pointer; 00089 typedef typename container_type::reference reference; 00091 typedef typename container_type::const_reference const_reference; 00093 typedef typename container_type::value_type value_type; 00094 00096 typedef typename container_type::iterator iterator; 00098 typedef typename container_type::const_iterator const_iterator; 00099 00101 typedef typename Impl::reverse_iterators<Container>::reverse_iterator reverse_iterator; 00103 typedef typename Impl::reverse_iterators<Container>::const_reverse_iterator const_reverse_iterator; 00104 00105 private: 00106 container_type m_container; 00107 size_type m_size; 00108 00110 LEAN_INLINE void reserve_internal(size_type newCount) 00111 { 00112 ReallocationPolicy::reserve(m_container, newCount); 00113 } 00115 LEAN_INLINE void growTo(size_type newCount) 00116 { 00117 ReallocationPolicy::pre_resize(m_container, newCount); 00118 } 00120 LEAN_INLINE void grow(size_type count) 00121 { 00122 growTo(m_size + count); 00123 } 00124 00126 LEAN_INLINE void assert_outside(const value_type& value) 00127 { 00128 LEAN_ASSERT(lean::addressof(value) < lean::addressof(*m_container.begin()) || lean::addressof(*m_container.end()) <= lean::addressof(value)); 00129 } 00130 00132 LEAN_NOINLINE static void out_of_range() 00133 { 00134 throw std::out_of_range("accumulation_vector<T> out of range"); 00135 } 00137 LEAN_INLINE void check_pos(size_type pos) const 00138 { 00139 if (pos >= m_size) 00140 out_of_range(); 00141 } 00142 00143 public: 00145 accumulation_vector() 00146 : m_size(0) { } 00148 explicit accumulation_vector(const allocator_type &allocator) 00149 : m_container(allocator), 00150 m_size(0) { } 00152 explicit accumulation_vector(size_type count) 00153 : m_container(count), 00154 m_size(count) { } 00156 accumulation_vector(size_type count, const value_type& value) 00157 : m_container(count, value), 00158 m_size(count) { } 00160 accumulation_vector(size_type count, const value_type& value, const allocator_type& allocator) 00161 : m_container(count, value, allocator), 00162 m_size(count) { } 00164 accumulation_vector(const accumulation_vector& right) 00165 : m_container(right.m_container), 00166 m_size(right.m_size) { } 00167 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00168 00169 accumulation_vector(accumulation_vector&& right) 00170 : m_container(std::move(right.m_container)), 00171 m_size(std::move(right.m_size)) { } 00172 #endif 00173 00174 template<class Iterator> 00175 accumulation_vector(Iterator itFirst, Iterator itEnd) 00176 : m_container(itFirst, itEnd), 00177 m_size(m_container.size()) { } 00179 template<class Iterator> 00180 accumulation_vector(Iterator itFirst, Iterator itEnd, const allocator_type& allocator) 00181 : m_container(itFirst, itEnd, allocator), 00182 m_size(m_container.size()) { } 00183 00185 accumulation_vector& operator =(const accumulation_vector& right) 00186 { 00187 if (this != &right) 00188 { 00189 if (right.empty()) 00190 // Clearing is extremely fast for this class 00191 clear(); 00192 else 00193 // Suppress destruction, assign manually 00194 assign(right.begin(), right.end()); 00195 } 00196 00197 return *this; 00198 } 00199 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00200 00201 inline accumulation_vector& operator =(accumulation_vector&& right) 00202 { 00203 if (this != &right) 00204 { 00205 if (right.empty()) 00206 // Keep own allocated storage 00207 clear(); 00208 else 00209 { 00210 // Invoke default move operators 00211 m_container = std::move(right.m_container); 00212 m_size = std::move(right.m_size); 00213 } 00214 } 00215 00216 return *this; 00217 } 00218 #endif 00219 00221 LEAN_INLINE size_type size(void) const { return m_size; }; 00223 LEAN_INLINE bool empty(void) const { return (m_size == 0); }; 00224 00226 LEAN_INLINE value_type& push_back(void) 00227 { 00228 if (m_size == m_container.size()) 00229 { 00230 grow(1); 00231 m_container.push_back(value_type()); 00232 } 00233 00234 return m_container[m_size++]; 00235 } 00237 LEAN_INLINE void push_back(const value_type& value) 00238 { 00239 assert_outside(value); 00240 00241 if (m_size == m_container.size()) 00242 { 00243 grow(1); 00244 m_container.push_back(value); 00245 } 00246 else 00247 m_container[m_size] = value; 00248 00249 ++m_size; 00250 } 00251 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00252 00253 LEAN_INLINE void push_back(value_type&& value) 00254 { 00255 assert_outside(value); 00256 00257 if (m_size == m_container.size()) 00258 { 00259 grow(1); 00260 m_container.push_back(std::move(value)); 00261 } 00262 else 00263 m_container[m_size] = std::move(value); 00264 00265 ++m_size; 00266 } 00267 #endif 00268 00270 LEAN_INLINE void pop_back(void) 00271 { 00272 LEAN_ASSERT(!empty()); 00273 00274 --m_size; 00275 } 00276 00278 iterator insert(iterator itWhere) 00279 { 00280 if (m_size == m_container.size()) 00281 { 00282 size_type index = itWhere - m_container.begin(); 00283 grow(1); 00284 itWhere = m_container.insert(m_container.begin() + index, value_type()); 00285 } 00286 else 00287 std::copy_backward(itWhere, end(), ++end()); 00288 00289 ++m_size; 00290 return itWhere; 00291 } 00293 iterator insert(iterator itWhere, const value_type& value) 00294 { 00295 assert_outside(value); 00296 00297 if (m_size == m_container.size()) 00298 { 00299 size_type index = itWhere - m_container.begin(); 00300 grow(1); 00301 itWhere = m_container.insert(m_container.begin() + index, value); 00302 ++m_size; 00303 } 00304 else 00305 { 00306 std::copy_backward(itWhere, end(), ++end()); 00307 ++m_size; 00308 *itWhere = value; 00309 } 00310 00311 return itWhere; 00312 } 00313 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00314 00315 iterator insert(iterator itWhere, value_type&& value) 00316 { 00317 assert_outside(value); 00318 00319 if (m_size == m_container.size()) 00320 { 00321 size_type index = itWhere - m_container.begin(); 00322 grow(1); 00323 itWhere = m_container.insert(m_container.begin() + index, std::move(value)); 00324 ++m_size; 00325 } 00326 else 00327 { 00328 std::copy_backward(itWhere, end(), ++end()); 00329 ++m_size; 00330 *itWhere = std::move(value); 00331 } 00332 00333 return itWhere; 00334 } 00335 #endif 00336 00338 iterator insert(iterator itWhere, size_type count) 00339 { 00340 size_type newSize = m_size + count; 00341 00342 if(newSize > m_container.size()) 00343 { 00344 size_type index = itWhere - m_container.begin(); 00345 growTo(newSize); 00346 m_container.resize(newSize); 00347 itWhere = m_container.begin() + index; 00348 } 00349 00350 std::copy_backward(itWhere, end(), end() + count); 00351 m_size = newSize; 00352 00353 return itWhere; 00354 } 00356 LEAN_INLINE void insert(iterator itWhere, size_type count, const value_type& value) 00357 { 00358 assert_outside(value); 00359 00360 std::fill_n( 00361 insert(itWhere, count), 00362 count, value); 00363 } 00365 template<class Iterator> 00366 void insert(iterator itWhere, Iterator itFirst, Iterator itEnd) 00367 { 00368 LEAN_ASSERT(itFirst <= itEnd); 00369 00370 size_type count = itEnd - itFirst; 00371 size_type index = lean::addressof(*itFirst) - lean::addressof(*m_container.begin()); 00372 00373 // Index is unsigned, make use of wrap-around 00374 if (index < m_size) 00375 { 00376 size_type endIndex = lean::addressof(*itEnd) - lean::addressof(*m_container.begin()); 00377 00378 LEAN_ASSERT(itEnd <= itWhere || itWhere <= itFirst); 00379 00380 if (itWhere <= itFirst) 00381 { 00382 index += count; 00383 endIndex += count; 00384 } 00385 itWhere = insert(itWhere, count); 00386 00387 itFirst = m_container.begin() + index; 00388 itEnd = m_container.begin() + endIndex; 00389 } 00390 else 00391 itWhere = insert(itWhere, count); 00392 00393 std::copy(itFirst, itEnd, itWhere); 00394 } 00395 00397 LEAN_INLINE iterator erase(iterator itWhere) 00398 { 00399 LEAN_ASSERT(!empty()); 00400 00401 std::copy(++iterator(itWhere), end(), itWhere); 00402 --m_size; 00403 00404 return itWhere; 00405 } 00407 LEAN_INLINE void erase(iterator itFirst, iterator itEnd) 00408 { 00409 std::copy(itEnd, end(), itFirst); 00410 m_size -= itEnd - itFirst; 00411 } 00412 00414 void assign(size_type count, const value_type& value) 00415 { 00416 assert_outside(value); 00417 00418 if(count > m_container.size()) 00419 { 00420 growTo(count); 00421 m_container.resize(count); 00422 } 00423 00424 std::fill_n(m_container.begin(), count, value); 00425 m_size = count; 00426 } 00428 template<class Iterator> 00429 void assign(Iterator itFirst, Iterator itEnd) 00430 { 00431 LEAN_ASSERT(itFirst <= itEnd); 00432 00433 size_t count = itEnd - itFirst; 00434 00435 if(count > m_container.size()) 00436 { 00437 size_type index = lean::addressof(*itFirst) - lean::addressof(*m_container.begin()); 00438 size_type endIndex = lean::addressof(*itEnd) - lean::addressof(*m_container.begin()); 00439 00440 growTo(count); 00441 m_container.resize(count); 00442 00443 // Index is unsigned, make use of wrap-around 00444 if (index < m_size) 00445 { 00446 itFirst = m_container.begin() + index; 00447 itEnd = m_container.begin() + endIndex; 00448 } 00449 } 00450 00451 std::copy(itFirst, itEnd, m_container.begin()); 00452 m_size = count; 00453 } 00454 00456 LEAN_INLINE void clear(void) { m_size = 0; } 00457 00459 LEAN_INLINE allocator_type get_allocator() const { return m_container.get_allocator(); } 00461 LEAN_INLINE size_type max_size(void) const { return m_container.max_size(); } 00462 00464 LEAN_INLINE size_type capacity(void) const { return m_container.capacity(); } 00466 LEAN_INLINE void reserve(size_type count) 00467 { 00468 reserve_internal(count); 00469 } 00471 void resize(size_type count) 00472 { 00473 if(count > m_container.size()) 00474 { 00475 growTo(count); 00476 m_container.resize(count); 00477 } 00478 00479 m_size = count; 00480 } 00482 void resize(size_type count, const value_type& value) 00483 { 00484 if(count > m_container.size()) 00485 { 00486 growTo(count); 00487 m_container.resize(count); 00488 } 00489 00490 if(count > m_size) 00491 std::fill_n(end(), count - m_size, value); 00492 00493 m_size = count; 00494 } 00495 00497 LEAN_INLINE reference at(size_type pos) { check_pos(pos); return m_container.at(pos); } 00499 LEAN_INLINE const_reference at(size_type pos) const { check_pos(pos); return m_container.at(pos); } 00501 LEAN_INLINE reference front(void) { LEAN_ASSERT(!empty()); return m_container.front(); } 00503 LEAN_INLINE const_reference front(void) const { LEAN_ASSERT(!empty()); return m_container.front(); } 00505 LEAN_INLINE reference back(void) { LEAN_ASSERT(!empty()); return m_container[m_size - 1]; } 00507 LEAN_INLINE const_reference back(void) const { LEAN_ASSERT(!empty()); return m_container[m_size - 1]; } 00508 00510 LEAN_INLINE reference operator [] (size_type pos) { return m_container[pos]; } 00512 LEAN_INLINE const_reference operator [] (size_type pos) const { return m_container[pos]; } 00513 00515 LEAN_INLINE iterator begin(void) { return m_container.begin(); } 00517 LEAN_INLINE const_iterator begin(void) const { return m_container.begin(); } 00519 LEAN_INLINE iterator end(void) { return m_container.begin() + m_size; } 00521 LEAN_INLINE const_iterator end(void) const { return m_container.begin() + m_size; } 00522 00524 LEAN_INLINE reverse_iterator rbegin(void) { return m_container.rend() - m_size; } 00526 LEAN_INLINE const_reverse_iterator rbegin(void) const { return m_container.rend() - m_size; } 00528 LEAN_INLINE reverse_iterator rend(void) { return m_container.rend(); } 00530 LEAN_INLINE const_reverse_iterator rend(void) const { return m_container.rend(); } 00531 00532 // Swaps the elements of two accumulation vectors. 00533 LEAN_INLINE void swap(accumulation_vector& right) 00534 { 00535 using std::swap; 00536 00537 swap(m_container, right.m_container); 00538 swap(m_size, right.m_size); 00539 } 00540 }; 00541 00543 template<class Container, class Policy> 00544 LEAN_INLINE bool operator ==(const accumulation_vector<Container, Policy>& left, 00545 const accumulation_vector<Container, Policy>& right) 00546 { 00547 return (left.size() == right.size()) && std::equal(left.begin(), left.end(), right.begin()); 00548 } 00549 00551 template<class Container, class Policy> 00552 LEAN_INLINE bool operator !=(const accumulation_vector<Container, Policy>& left, 00553 const accumulation_vector<Container, Policy>& right) 00554 { 00555 return !(left == right); 00556 } 00557 00559 template<class Container, class Policy> 00560 LEAN_INLINE bool operator <(const accumulation_vector<Container, Policy>& left, 00561 const accumulation_vector<Container, Policy>& right) 00562 { 00563 return std::lexicographical_compare(left.begin(), left.end(), right.begin(), right.end()); 00564 } 00565 00567 template<class Container, class Policy> 00568 LEAN_INLINE bool operator >(const accumulation_vector<Container, Policy>& left, 00569 const accumulation_vector<Container, Policy>& right) 00570 { 00571 return (right < left); 00572 } 00573 00575 template<class Container, class Policy> 00576 LEAN_INLINE bool operator <=(const accumulation_vector<Container, Policy>& left, 00577 const accumulation_vector<Container, Policy>& right) 00578 { 00579 return !(right < left); 00580 } 00581 00583 template<class Container, class Policy> 00584 LEAN_INLINE bool operator >=(const accumulation_vector<Container, Policy>& left, 00585 const accumulation_vector<Container, Policy>& right) 00586 { 00587 return !(left < right); 00588 } 00589 00590 // Swaps the elements of two accumulation vectors. 00591 template<class Container, class Policy> 00592 LEAN_INLINE void swap(accumulation_vector<Container, Policy>& left, 00593 accumulation_vector<Container, Policy>& right) 00594 { 00595 left.swap(right); 00596 } 00597 00598 } // namespace 00599 00600 using containers::accumulation_vector; 00601 00602 } // namespace 00603 00604 #endif