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