Home Libraries People FAQ More

Main Page | Class Hierarchy | Class List | File List | Class Members

base.hpp

00001 // Implementation of the base circular buffer.
00002 
00003 // Copyright (c) 2003-2004 Jan Gaspar
00004 
00005 // Use, modification, and distribution is subject to the Boost Software
00006 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
00007 // http://www.boost.org/LICENSE_1_0.txt)
00008 
00009 #if !defined(BOOST_CIRCULAR_BUFFER_BASE_HPP)
00010 #define BOOST_CIRCULAR_BUFFER_BASE_HPP
00011 
00012 #if defined(_MSC_VER) && _MSC_VER >= 1200
00013     #pragma once
00014 #endif
00015 
00016 #include <boost/call_traits.hpp>
00017 #include <boost/concept_check.hpp>
00018 #include <boost/throw_exception.hpp>
00019 #include <boost/iterator/reverse_iterator.hpp>
00020 #include <algorithm>
00021 #if !defined(BOOST_NO_EXCEPTIONS)
00022     #include <stdexcept>
00023 #endif
00024 #if BOOST_CB_ENABLE_DEBUG
00025     #include <string.h>
00026 #endif
00027 
00028 namespace boost {
00029 
00042 template <class T, class Alloc>
00043 class circular_buffer : cb_details::cb_iterator_registry {
00044 
00045 // Requirements
00046     BOOST_CLASS_REQUIRE(T, boost, CopyConstructibleConcept);
00047 
00048 public:
00049 // Basic types
00050 
00052     typedef typename Alloc::value_type value_type;
00053 
00055     typedef typename Alloc::pointer pointer;
00056 
00058     typedef typename Alloc::const_pointer const_pointer;
00059 
00061     typedef typename Alloc::reference reference;
00062 
00064     typedef typename Alloc::const_reference const_reference;
00065 
00067 
00070     typedef typename Alloc::difference_type difference_type;
00071 
00073 
00076     typedef typename Alloc::size_type size_type;
00077 
00079     typedef Alloc allocator_type;
00080 
00082     allocator_type get_allocator() const { return m_alloc; }
00083 
00085 
00089     allocator_type& get_allocator() { return m_alloc; }
00090 
00091 // Helper types
00092 
00093     // Define a type that represents the "best" way to pass the value_type to a method.
00094     typedef typename call_traits<value_type>::param_type param_value_type;
00095 
00096     // Define a type that represents the "best" way to return the value_type from a const method.
00097     typedef typename call_traits<value_type>::param_type return_value_type;
00098 
00099 // Iterators
00100 
00102     typedef cb_details::cb_iterator< circular_buffer<T, Alloc>, cb_details::cb_const_traits<Alloc> > const_iterator;
00103 
00105     typedef cb_details::cb_iterator< circular_buffer<T, Alloc>, cb_details::cb_nonconst_traits<Alloc> > iterator;
00106 
00108     typedef reverse_iterator<const_iterator> const_reverse_iterator;
00109 
00111     typedef reverse_iterator<iterator> reverse_iterator;
00112 
00113 private:
00114 // Member variables
00115 
00117     pointer m_buff;
00118 
00120     pointer m_end;
00121 
00123     pointer m_first;
00124 
00126     pointer m_last;
00127 
00129     size_type m_size;
00130 
00132     allocator_type m_alloc;
00133 
00134 // Friends
00135 #if defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
00136     friend iterator;
00137     friend const_iterator;
00138 #else
00139     friend struct iterator;
00140     friend struct const_iterator;
00141 #endif
00142 
00143 public:
00144 // Element access
00145 
00147     iterator begin() { return iterator(this, empty() ? 0 : m_first); }
00148 
00150     iterator end() { return iterator(this, 0); }
00151 
00153     const_iterator begin() const { return const_iterator(this, empty() ? 0 : m_first); }
00154 
00156     const_iterator end() const { return const_iterator(this, 0); }
00157 
00159     reverse_iterator rbegin() { return reverse_iterator(end()); }
00160 
00162     reverse_iterator rend() { return reverse_iterator(begin()); }
00163     
00165     const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
00166 
00168     const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
00169 
00171 
00174     reference operator [] (size_type index) {
00175         BOOST_CB_ASSERT(index < size()); // check for invalid index
00176         return *add(m_first, index);
00177     }
00178 
00180 
00183     return_value_type operator [] (size_type index) const {
00184         BOOST_CB_ASSERT(index < size()); // check for invalid index
00185         return *add(m_first, index);
00186     }
00187 
00189 
00192     reference at(size_type index) {
00193         check_position(index);
00194         return (*this)[index];
00195     }
00196 
00198 
00201     return_value_type at(size_type index) const {
00202         check_position(index);
00203         return (*this)[index];
00204     }
00205 
00207 
00210     reference front() {
00211         BOOST_CB_ASSERT(!empty()); // check for empty buffer (front element not available)
00212         return *m_first;
00213     }
00214 
00216 
00219     reference back() {
00220         BOOST_CB_ASSERT(!empty()); // check for empty buffer (back element not available)
00221         return *((m_last == m_buff ? m_end : m_last) - 1);
00222     }
00223 
00225 
00228     return_value_type front() const {
00229         BOOST_CB_ASSERT(!empty()); // check for empty buffer (front element not available)
00230         return *m_first;
00231     }
00232 
00234 
00237     return_value_type back() const {
00238         BOOST_CB_ASSERT(!empty()); // check for empty buffer (back element not available)
00239         return *((m_last == m_buff ? m_end : m_last) - 1);
00240     }
00241 
00243 
00251     pointer data() {
00252         if (empty())
00253             return 0;
00254         if (m_first < m_last || m_last == m_buff)
00255             return m_first;
00256         size_type constructed = 0;
00257         pointer src = m_first;
00258         pointer dest = m_buff;
00259         pointer tmp = 0;
00260         BOOST_CB_TRY
00261         tmp = allocate(1);
00262         for (pointer first = m_first; dest < src; src = first) {
00263             for (size_type ii = 0; src < m_end; ++src, ++dest, ++ii) {
00264                 if (dest == first) {
00265                     first += ii;
00266                     break;
00267                 }
00268                 if (is_uninitialized(dest)) {
00269                     m_alloc.construct(dest, *src);
00270                     ++constructed;
00271                 } else {
00272                     m_alloc.construct(tmp, *src);
00273                     BOOST_CB_TRY
00274                     replace(src, *dest);
00275                     BOOST_CB_UNWIND(
00276                         destroy_item(tmp);
00277                         tidy(src);
00278                     )
00279                     BOOST_CB_TRY
00280                     replace(dest, *tmp);
00281                     BOOST_CB_UNWIND(
00282                         destroy_item(tmp);
00283                         tidy(dest);
00284                     )
00285                     destroy_item(tmp);
00286                 }
00287             }
00288         }
00289         deallocate(tmp, 1);
00290         BOOST_CB_UNWIND(
00291             deallocate(tmp, 1);
00292             m_last += constructed;
00293             m_size += constructed;
00294         )
00295         for (dest = m_buff + size(); dest < m_end; ++dest)
00296             destroy_item(dest);
00297         m_first = m_buff;
00298         m_last = add(m_buff, size());
00299         return m_buff;
00300     }
00301 
00302 // Size and capacity
00303 
00305     size_type size() const { return m_size; }
00306 
00308     size_type max_size() const { return m_alloc.max_size(); }
00309     
00311 
00315     bool empty() const { return size() == 0; }
00316 
00318 
00323     bool full() const { return size() == capacity(); }
00324 
00326     size_type capacity() const { return m_end - m_buff; }
00327 
00329 
00347     void set_capacity(size_type new_capacity, bool remove_front = true) {
00348         if (new_capacity == capacity())
00349             return;
00350         pointer buff = allocate(new_capacity);
00351         size_type new_size = std::min(new_capacity, size());
00352         BOOST_CB_TRY
00353         if (remove_front)
00354             cb_details::uninitialized_copy(end() - new_size, end(), buff, m_alloc);
00355         else
00356             cb_details::uninitialized_copy(begin(), begin() + new_size, buff, m_alloc);
00357         BOOST_CB_UNWIND(deallocate(buff, new_capacity))
00358         destroy();
00359         m_size = new_size;
00360         m_buff = m_first = buff;
00361         m_end = m_buff + new_capacity;
00362         m_last = add(m_buff, size());
00363     }
00364 
00366 
00387     void resize(size_type new_size, param_value_type item = T(), bool remove_front = true) {
00388         if (new_size > size()) {
00389             if (new_size > capacity())
00390                 set_capacity(new_size);
00391             insert(end(), new_size - size(), item);
00392         } else {
00393             if (remove_front)
00394                 erase(begin(), end() - new_size);
00395             else
00396                 erase(begin() + new_size, end());
00397         }
00398     }
00399 
00400 // Construction/Destruction
00401 
00403 
00407     explicit circular_buffer(
00408         size_type capacity,
00409         const allocator_type& alloc = allocator_type())
00410     : m_size(0), m_alloc(alloc) {
00411         m_first = m_last = m_buff = allocate(capacity);
00412         m_end = m_buff + capacity;
00413     }
00414 
00416 
00421     circular_buffer(
00422         size_type capacity,
00423         param_value_type item,
00424         const allocator_type& alloc = allocator_type())
00425     : m_size(capacity), m_alloc(alloc) {
00426         m_first = m_last = m_buff = allocate(capacity);
00427         m_end = m_buff + capacity;
00428         BOOST_CB_TRY
00429         cb_details::uninitialized_fill_n(m_buff, size(), item, m_alloc);
00430         BOOST_CB_UNWIND(deallocate(m_buff, capacity))
00431     }
00432 
00434 
00439     circular_buffer(const circular_buffer<T, Alloc>& cb)
00440     : m_size(cb.size()), m_alloc(cb.get_allocator()) {
00441         m_first = m_last = m_buff = allocate(cb.capacity());
00442         BOOST_CB_TRY
00443         m_end = cb_details::uninitialized_copy(cb.begin(), cb.end(), m_buff, m_alloc);
00444         BOOST_CB_UNWIND(deallocate(m_buff, cb.capacity()))
00445     }
00446 
00448 
00458     template <class InputIterator>
00459     circular_buffer(
00460         size_type capacity,
00461         InputIterator first,
00462         InputIterator last,
00463         const allocator_type& alloc = allocator_type())
00464     : m_alloc(alloc) {
00465         BOOST_CB_IS_CONVERTIBLE(InputIterator, value_type);
00466         BOOST_CB_ASSERT(std::distance(first, last) >= 0); // check for wrong range
00467         m_first = m_buff = allocate(capacity);
00468         m_end = m_buff + capacity;
00469         size_type diff = std::distance(first, last);
00470         if (diff > capacity) {
00471             std::advance(first, diff - capacity);
00472             m_size = capacity;
00473             m_last = m_buff;
00474         } else {
00475             m_size = diff;
00476             if (diff == capacity)
00477                 m_last = m_buff;
00478             else
00479                 m_last = m_buff + size();
00480         }
00481         BOOST_CB_TRY
00482         cb_details::uninitialized_copy(first, last, m_buff, m_alloc);
00483         BOOST_CB_UNWIND(deallocate(m_buff, capacity))
00484     }
00485 
00487     ~circular_buffer() { destroy(); }
00488 
00489 private:
00490 // Helper functors
00491 
00492     // Functor for assigning n items.
00493     struct assign_n {
00494         size_type m_n;
00495         param_value_type m_item;
00496         allocator_type& m_alloc;
00497         explicit assign_n(size_type n, param_value_type item, allocator_type& alloc) : m_n(n), m_item(item), m_alloc(alloc) {}
00498         void operator () (pointer p) const {
00499             cb_details::uninitialized_fill_n(p, m_n, m_item, m_alloc);
00500         }
00501     private:
00502         assign_n& operator = (const assign_n&); // do not generate
00503     };
00504 
00505     // Functor for assigning range of items.
00506     template <class InputIterator>
00507     struct assign_range {
00508         InputIterator m_first;
00509         InputIterator m_last;
00510         allocator_type& m_alloc;
00511         explicit assign_range(InputIterator first, InputIterator last, allocator_type& alloc) : m_first(first), m_last(last), m_alloc(alloc) {}
00512         void operator () (pointer p) const {
00513             cb_details::uninitialized_copy(m_first, m_last, p, m_alloc);
00514         }
00515     private:
00516         assign_range& operator = (const assign_range&); // do not generate
00517     };
00518 
00519 public:
00520 // Assign methods
00521 
00523 
00529     circular_buffer<T, Alloc>& operator = (const circular_buffer<T, Alloc>& cb) {
00530         if (this == &cb)
00531             return *this;
00532         pointer buff = allocate(cb.capacity());
00533         BOOST_CB_TRY
00534         pointer last = cb_details::uninitialized_copy(cb.begin(), cb.end(), buff, m_alloc);
00535         destroy();
00536         m_size = cb.size();
00537         m_first = m_buff = buff;
00538         m_end = m_buff + cb.capacity();
00539         m_last = full() ? m_buff : last;
00540         BOOST_CB_UNWIND(deallocate(buff, cb.capacity()))
00541         return *this;
00542     }
00543 
00545 
00555     void assign(size_type n, param_value_type item) { do_assign(n, assign_n(n, item, m_alloc)); }
00556     
00558 
00568     template <class InputIterator>
00569     void assign(InputIterator first, InputIterator last) {
00570         assign(first, last, cb_details::cb_iterator_category_traits<InputIterator>::tag());
00571     }
00572 
00574 
00578     void swap(circular_buffer& cb) {
00579         std::swap(m_alloc, cb.m_alloc); // in general this is not necessary,
00580                                         // because allocators should not have state
00581         std::swap(m_buff, cb.m_buff);
00582         std::swap(m_end, cb.m_end);
00583         std::swap(m_first, cb.m_first);
00584         std::swap(m_last, cb.m_last);
00585         std::swap(m_size, cb.m_size);
00586 #if BOOST_CB_ENABLE_DEBUG
00587         invalidate_all_iterators();
00588         cb.invalidate_all_iterators();
00589 #endif
00590     }
00591 
00592 // push and pop
00593 
00595 
00601     void push_back(param_value_type item) {
00602         if (full()) {
00603             if (empty())
00604                 return;
00605             replace_last(item);
00606             increment(m_last);
00607             m_first = m_last;
00608         } else {
00609             m_alloc.construct(m_last, item);
00610             increment(m_last);
00611             ++m_size;
00612         }
00613     }
00614 
00616 
00622     void push_back() { push_back(value_type()); }
00623 
00625 
00631     void push_front(param_value_type item) {
00632         if (full()) {
00633             if (empty())
00634                 return;
00635             replace_first(item);
00636             m_last = m_first;
00637         } else {
00638             decrement(m_first);
00639             BOOST_CB_TRY
00640             m_alloc.construct(m_first, item);
00641             BOOST_CB_UNWIND(increment(m_first))
00642             ++m_size;
00643         }
00644     }
00645 
00647 
00653     void push_front() { push_front(value_type()); }
00654 
00656 
00662     void pop_back() {
00663         BOOST_CB_ASSERT(!empty()); // check for empty buffer (back element not available)
00664         decrement(m_last);
00665         destroy_item(m_last);
00666         --m_size;
00667     }
00668 
00670 
00676     void pop_front() {
00677         BOOST_CB_ASSERT(!empty()); // check for empty buffer (front element not available)
00678         destroy_item(m_first);
00679         increment(m_first);
00680         --m_size;
00681     }
00682 
00683 private:
00684 // Helper wrappers
00685 
00686     // Iterator dereference wrapper.
00687     template <class InputIterator>
00688     struct iterator_wrapper {
00689         mutable InputIterator m_it;
00690         explicit iterator_wrapper(InputIterator it) : m_it(it) {}
00691         InputIterator get_reference() const { return m_it++; }
00692     };
00693 
00694     // Item dereference wrapper.
00695     struct item_wrapper {
00696         const_pointer m_item;
00697         explicit item_wrapper(param_value_type item) : m_item(&item) {}
00698         const_pointer get_reference() const { return m_item; }
00699     };
00700 
00701 public:
00702 // Insert
00703 
00705 
00714     iterator insert(iterator pos, param_value_type item) {
00715         BOOST_CB_ASSERT(pos.is_valid()); // check for uninitialized or invalidated iterator
00716         if (full() && pos == begin())
00717             return begin();
00718         if (pos.m_it == 0) {
00719             if (full())
00720                 replace_last(item);
00721             else
00722                 m_alloc.construct(m_last, item);
00723             pos.m_it = m_last;
00724         } else {
00725             pointer src = m_last;
00726             pointer dest = m_last;
00727             BOOST_CB_TRY
00728             while (src != pos.m_it) {
00729                 decrement(src);
00730                 if (dest == m_last && !full())
00731                     m_alloc.construct(dest, *src);
00732                 else
00733                     replace(dest, *src);
00734                 decrement(dest);
00735             }
00736             replace(pos.m_it, item);
00737             BOOST_CB_UNWIND(
00738                 if (dest == m_last) {
00739                     if (full()) {
00740                         increment(m_first);
00741                         --m_size;
00742                     }
00743                 } else {
00744                     if (!full()) {
00745                         increment(m_last);
00746                         ++m_size;
00747                     }
00748                     tidy(dest);
00749                 }
00750             )
00751         }
00752         increment(m_last);
00753         if (full())
00754             m_first = m_last;
00755         else
00756             ++m_size;
00757         return iterator(this, pos.m_it);
00758     }
00759 
00761 
00769     iterator insert(iterator pos) { return insert(pos, value_type()); }
00770 
00772 
00790     void insert(iterator pos, size_type n, param_value_type item) {
00791         BOOST_CB_ASSERT(pos.is_valid()); // check for uninitialized or invalidated iterator
00792         if (n == 0)
00793             return;
00794         size_type copy = capacity() - (end() - pos);
00795         if (copy == 0)
00796             return;
00797         if (n > copy)
00798             n = copy;
00799         insert_n_item(pos, n, item_wrapper(item));
00800     }
00801 
00803 
00824     template <class InputIterator>
00825     void insert(iterator pos, InputIterator first, InputIterator last) {
00826         BOOST_CB_ASSERT(pos.is_valid()); // check for uninitialized or invalidated iterator
00827         insert(pos, first, last, cb_details::cb_iterator_category_traits<InputIterator>::tag());
00828     }
00829 
00831 
00840     iterator rinsert(iterator pos, param_value_type item) {
00841         BOOST_CB_ASSERT(pos.is_valid()); // check for uninitialized or invalidated iterator
00842         if (full() && pos == end())
00843             return end();
00844         if (pos == begin()) {
00845             if (full()) {
00846                 replace_first(item);
00847             } else {
00848                 decrement(m_first);
00849                 BOOST_CB_TRY
00850                 m_alloc.construct(m_first, item);
00851                 BOOST_CB_UNWIND(increment(m_first))
00852             }
00853         } else {
00854             pointer src = m_first;
00855             pointer dest = m_first;
00856             decrement(dest);
00857             pointer it = map_pointer(pos.m_it);
00858             pointer first = m_first;
00859             decrement(first);
00860             BOOST_CB_TRY
00861             while (src != it) {
00862                 if (dest == first && !full())
00863                     m_alloc.construct(dest, *src);
00864                 else
00865                     replace(dest, *src);
00866                 increment(src);
00867                 increment(dest);
00868             }
00869             replace((--pos).m_it, item);
00870             BOOST_CB_UNWIND(
00871                 if (dest == first) {
00872                     if (full()) {
00873                         decrement(m_last);
00874                         --m_size;
00875                     }
00876                 } else {
00877                     if (!full()) {
00878                         m_first = first;
00879                         ++m_size;
00880                     }
00881                     tidy(dest);
00882                 }
00883             )
00884             decrement(m_first);
00885         }
00886         if (full())
00887             m_last = m_first;
00888         else
00889             ++m_size;
00890         return iterator(this, pos.m_it);
00891     }
00892 
00894 
00902     iterator rinsert(iterator pos) { return rinsert(pos, value_type()); }
00903 
00905 
00923     void rinsert(iterator pos, size_type n, param_value_type item) {
00924         BOOST_CB_ASSERT(pos.is_valid()); // check for uninitialized or invalidated iterator
00925         rinsert_n_item(pos, n, item_wrapper(item));
00926     }
00927 
00929 
00950     template <class InputIterator>
00951     void rinsert(iterator pos, InputIterator first, InputIterator last) {
00952         BOOST_CB_ASSERT(pos.is_valid()); // check for uninitialized or invalidated iterator
00953         rinsert(pos, first, last, cb_details::cb_iterator_category_traits<InputIterator>::tag());
00954     }
00955 
00956 // Erase
00957 
00959 
00968     iterator erase(iterator pos) {
00969         BOOST_CB_ASSERT(pos.is_valid()); // check for uninitialized or invalidated iterator
00970         BOOST_CB_ASSERT(pos.m_it != 0);  // check for iterator pointing to end()
00971         pointer next = pos.m_it;
00972         increment(next);
00973         for (pointer p = pos.m_it; next != m_last; p = next, increment(next))
00974             replace(p, *next);
00975         decrement(m_last);
00976         destroy_item(m_last);
00977         --m_size;
00978 #if BOOST_CB_ENABLE_DEBUG
00979         return empty() ? end() : iterator(this, pos.m_it);
00980 #else
00981         return empty() ? end() : pos;
00982 #endif
00983     }
00984 
00986 
00995     iterator erase(iterator first, iterator last) {
00996         BOOST_CB_ASSERT(first.is_valid());            // check for uninitialized or invalidated iterator
00997         BOOST_CB_ASSERT(last.is_valid());             // check for uninitialized or invalidated iterator
00998         BOOST_CB_ASSERT(first.m_buff == last.m_buff); // check for iterators of different containers
00999         BOOST_CB_ASSERT(first <= last);               // check for wrong range
01000         if (first == last)
01001             return first;
01002         pointer tmp = first.m_it;
01003         difference_type diff = last - first;
01004         while (last.m_it != 0)
01005             replace((first++).m_it, *last++);
01006         while (first.m_it != 0)
01007             destroy_item((first++).m_it);
01008         m_last = sub(m_last, diff);
01009         m_size -= diff;
01010         return empty() ? end() : iterator(this, tmp);
01011     }
01012 
01014 
01018     void clear() {
01019         destroy_content();
01020         m_first = m_last = m_buff;
01021         m_size = 0;
01022     }
01023 
01024 private:
01025 // Debug support
01026 
01027 #if BOOST_CB_ENABLE_DEBUG
01028     
01029     // Predicate determining if the condition for iterator invalidation has been met.
01030     struct is_invalid_condition {
01031         pointer m_p;
01032         explicit is_invalid_condition(pointer p) : m_p(p) {}
01033         bool operator () (const cb_details::cb_iterator_base* p) const {
01034             return ((iterator*)p)->m_it == m_p;
01035         }
01036     };
01037 
01038 #endif // #if BOOST_CB_ENABLE_DEBUG
01039 
01040 // Helper methods
01041 
01043     void check_position(size_type index) const {
01044         if (index >= size())
01045             throw_exception(std::out_of_range("circular_buffer"));
01046     }
01047 
01049     template <class Pointer0>
01050     void increment(Pointer0& p) const {
01051         if (++p == m_end)
01052             p = m_buff;
01053     }
01054 
01056     template <class Pointer0>
01057     void decrement(Pointer0& p) const {
01058         if (p == m_buff)
01059             p = m_end;
01060         --p;
01061     }
01062 
01064     template <class Pointer0>
01065     Pointer0 add(Pointer0 p, difference_type n) const {
01066         return p + (n < (m_end - p) ? n : n - capacity());
01067     }
01068 
01070     template <class Pointer0>
01071     Pointer0 sub(Pointer0 p, difference_type n) const {
01072         return p - (n > (p - m_buff) ? n - capacity() : n);
01073     }
01074 
01076     pointer map_pointer(pointer p) const { return p == 0 ? m_last : p; }
01077 
01079     bool is_uninitialized(const_pointer p) const {
01080         return p >= m_last && (m_first < m_last || p < m_first);
01081     }
01082 
01084 
01087     void create_or_replace(pointer pos, param_value_type item) {
01088         if (is_uninitialized(pos))
01089             m_alloc.construct(pos, item);
01090         else
01091             replace(pos, item);
01092     }
01093 
01095 
01098     void destroy_created(pointer pos) {
01099         if (is_uninitialized(pos))
01100             destroy_item(pos);
01101     }
01102 
01104     void replace(pointer pos, param_value_type item) {
01105         replace(pos, item, cb_details::cb_replace_category_traits<value_type>::tag()); // invoke optimized operation for given type
01106 #if BOOST_CB_ENABLE_DEBUG
01107         invalidate_iterators(is_invalid_condition(pos));
01108 #endif
01109     }
01110 
01112     void replace(pointer pos, param_value_type item, cb_details::cb_destroy_tag) {
01113         m_alloc.destroy(pos);
01114         m_alloc.construct(pos, item);
01115     }
01116 
01118     void replace(pointer pos, param_value_type item, cb_details::cb_assign_tag) {
01119         *pos = item;
01120     }
01121 
01123     void replace_first(param_value_type item) {
01124         decrement(m_first);
01125         BOOST_CB_TRY
01126         replace(m_first, item);
01127         BOOST_CB_UNWIND(
01128             increment(m_first);
01129             decrement(m_last);
01130             --m_size;
01131         )
01132     }
01133 
01135     void replace_last(param_value_type item) {
01136         BOOST_CB_TRY
01137         replace(m_last, item);
01138         BOOST_CB_UNWIND(
01139             decrement(m_last);
01140             --m_size;
01141         )
01142     }
01143 
01145     void tidy(pointer p) {
01146         for (; m_first != p; increment(m_first), --m_size)
01147             destroy_item(m_first);
01148         increment(m_first);
01149         --m_size;
01150     }
01151 
01153     pointer allocate(size_type n) {
01154         if (n > max_size())
01155             throw_exception(std::length_error("circular_buffer"));
01156 #if BOOST_CB_ENABLE_DEBUG
01157         pointer p = (n == 0) ? 0 : m_alloc.allocate(n, 0);
01158         ::memset(p, cb_details::CB_Unitialized, sizeof(value_type) * n);
01159         return p;
01160 #else
01161         return (n == 0) ? 0 : m_alloc.allocate(n, 0);
01162 #endif
01163     }
01164 
01166     void deallocate(pointer p, size_type n) {
01167         if (p != 0)
01168             m_alloc.deallocate(p, n);
01169     }
01170 
01172     void destroy_item(pointer p) {
01173         m_alloc.destroy(p);
01174 #if BOOST_CB_ENABLE_DEBUG
01175         invalidate_iterators(is_invalid_condition(p));
01176         ::memset(p, cb_details::CB_Unitialized, sizeof(value_type));
01177 #endif
01178     }
01179 
01181     void destroy_content() {
01182         for (size_type ii = 0; ii < size(); ++ii, increment(m_first))
01183             destroy_item(m_first);
01184     }
01185 
01187     void destroy() {
01188         destroy_content();
01189         deallocate(m_buff, capacity());
01190 #if BOOST_CB_ENABLE_DEBUG
01191         invalidate_all_iterators(); // invalidate iterators pointing to end()
01192         m_buff = 0;
01193         m_first = 0;
01194         m_last = 0;
01195         m_end = 0;
01196 #endif
01197     }
01198 
01200     template <class InputIterator>
01201     void assign(InputIterator n, InputIterator item, cb_details::cb_int_iterator_tag) {
01202         assign((size_type)n, item);
01203     }
01204 
01206     template <class InputIterator>
01207     void assign(InputIterator first, InputIterator last, std::input_iterator_tag) {
01208         BOOST_CB_IS_CONVERTIBLE(InputIterator, value_type);
01209         BOOST_CB_ASSERT(std::distance(first, last) >= 0); // check for wrong range
01210         do_assign(std::distance(first, last), assign_range<InputIterator>(first, last, m_alloc));
01211     }
01212 
01214     template <class Functor>
01215     void do_assign(size_type n, const Functor& fnc) {
01216         if (n > capacity()) {
01217             pointer buff = allocate(n);
01218             BOOST_CB_TRY
01219             fnc(buff);
01220             BOOST_CB_UNWIND(deallocate(buff, n))
01221             destroy();
01222             m_buff = buff;
01223             m_end = m_buff + n;
01224         } else {
01225             destroy_content();
01226             BOOST_CB_TRY
01227             fnc(m_buff);
01228             BOOST_CB_UNWIND(m_size = 0)
01229         }
01230         m_size = n;
01231         m_first = m_buff;
01232         m_last = add(m_buff, size());
01233     }
01234 
01236     template <class InputIterator>
01237     void insert(iterator pos, InputIterator n, InputIterator item, cb_details::cb_int_iterator_tag) {
01238         insert(pos, (size_type)n, item);
01239     }
01240 
01242     template <class InputIterator>
01243     void insert(iterator pos, InputIterator first, InputIterator last, std::input_iterator_tag) {
01244         BOOST_CB_IS_CONVERTIBLE(InputIterator, value_type);
01245         BOOST_CB_ASSERT(std::distance(first, last) >= 0); // check for wrong range
01246         difference_type n = std::distance(first, last);
01247         if (n == 0)
01248             return;
01249         difference_type copy = capacity() - (end() - pos);
01250         if (copy == 0)
01251             return;
01252         if (n > copy) {
01253             std::advance(first, n - copy);
01254             n = copy;
01255         }
01256         insert_n_item(pos, n, iterator_wrapper<InputIterator>(first));
01257     }
01258 
01260     template <class Wrapper>
01261     void insert_n_item(iterator pos, size_type n, const Wrapper& wrapper) {
01262         size_type construct = capacity() - size();
01263         if (construct > n)
01264             construct = n;
01265         if (pos.m_it == 0) {
01266             size_type ii = 0;
01267             pointer p = m_last;
01268             BOOST_CB_TRY
01269             for (; ii < construct; ++ii, increment(p))
01270                 m_alloc.construct(p, *wrapper.get_reference());
01271             for (;ii < n; ++ii, increment(p))
01272                 replace(p, *wrapper.get_reference());
01273             BOOST_CB_UNWIND(
01274                 size_type constructed = std::min(ii, construct);
01275                 m_last = add(m_last, constructed);
01276                 m_size += constructed;
01277                 if (ii >= construct)
01278                     tidy(p);
01279             )
01280         } else {
01281             pointer src = m_last;
01282             pointer dest = add(m_last, n - 1);
01283             size_type ii = 0;
01284             BOOST_CB_TRY
01285             while (src != pos.m_it) {
01286                 decrement(src);
01287                 create_or_replace(dest, *src);
01288                 decrement(dest);
01289             }
01290             for (dest = pos.m_it; ii < n; ++ii, increment(dest))
01291                 create_or_replace(dest, *wrapper.get_reference());
01292             BOOST_CB_UNWIND(
01293                 for (pointer p1 = m_last, p2 = add(m_last, n - 1); p1 != src; decrement(p2)) {
01294                     decrement(p1);
01295                     destroy_created(p2);
01296                 }
01297                 for (n = 0, src = pos.m_it; n < ii; ++n, increment(src))
01298                     destroy_created(src);
01299                 if (!is_uninitialized(dest))
01300                     tidy(dest);
01301             )
01302         }
01303         m_last = add(m_last, n);
01304         m_first = add(m_first, n - construct);
01305         m_size += construct;
01306     }
01307 
01309     template <class InputIterator>
01310     void rinsert(iterator pos, InputIterator n, InputIterator item, cb_details::cb_int_iterator_tag) {
01311         rinsert(pos, (size_type)n, item);
01312     }
01313 
01315     template <class InputIterator>
01316     void rinsert(iterator pos, InputIterator first, InputIterator last, std::input_iterator_tag) {
01317         BOOST_CB_IS_CONVERTIBLE(InputIterator, value_type);
01318         BOOST_CB_ASSERT(std::distance(first, last) >= 0); // check for wrong range
01319         rinsert_n_item(pos, std::distance(first, last), iterator_wrapper<InputIterator>(first));
01320     }
01321 
01323     template <class Wrapper>
01324     void rinsert_n_item(iterator pos, size_type n, const Wrapper& wrapper) {
01325         if (n == 0)
01326             return;
01327         size_type copy = capacity() - (pos - begin());
01328         if (copy == 0)
01329             return;
01330         if (n > copy)
01331             n = copy;
01332         size_type construct = capacity() - size();
01333         if (construct > n)
01334             construct = n;
01335         if (pos == begin()) {
01336             pointer p = sub(map_pointer(pos.m_it), n);
01337             size_type ii = n;
01338             BOOST_CB_TRY
01339             for (;ii > construct; --ii, increment(p))
01340                 replace(p, *wrapper.get_reference());
01341             for (; ii > 0; --ii, increment(p))
01342                 m_alloc.construct(p, *wrapper.get_reference());
01343             BOOST_CB_UNWIND(
01344                 size_type unwind = ii < construct ? construct - ii : 0;
01345                 pointer tmp = sub(map_pointer(pos.m_it), construct);
01346                 for (n = 0; n < unwind; ++n, increment(tmp))
01347                     destroy_item(tmp);
01348                 if (ii > construct)
01349                     tidy(p);
01350             )
01351         } else {
01352             pointer src = m_first;
01353             pointer dest = sub(m_first, n);
01354             pointer p = map_pointer(pos.m_it);
01355             size_type ii = 0;
01356             BOOST_CB_TRY
01357             while (src != p) {
01358                 create_or_replace(dest, *src);
01359                 increment(src);
01360                 increment(dest);
01361             }
01362             dest = sub(p, n);
01363             for (; ii < n; ++ii, increment(dest))
01364                 create_or_replace(dest, *wrapper.get_reference());
01365             BOOST_CB_UNWIND(
01366                 for (pointer p1 = m_first, p2 = sub(m_first, n); p1 != src; increment(p1), increment(p2))
01367                     destroy_created(p2);
01368                 p = sub(p, n);
01369                 for (n = 0; n < ii; ++n, increment(p))
01370                     destroy_created(p);
01371                 if (!is_uninitialized(dest))
01372                     tidy(dest);
01373             )
01374         }
01375         m_first = sub(m_first, n);
01376         m_last = sub(m_last, n - construct);
01377         m_size += construct;
01378     }
01379 };
01380 
01381 // Non-member functions
01382 
01384 template <class T, class Alloc>
01385 inline bool operator == (const circular_buffer<T, Alloc>& lhs,
01386                          const circular_buffer<T, Alloc>& rhs) {
01387     return lhs.size() == rhs.size() &&
01388         std::equal(lhs.begin(), lhs.end(), rhs.begin());
01389 }
01390 
01392 template <class T, class Alloc>
01393 inline bool operator < (const circular_buffer<T, Alloc>& lhs,
01394                         const circular_buffer<T, Alloc>& rhs) {
01395     return std::lexicographical_compare(
01396         lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
01397 }
01398 
01399 #if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) || defined(BOOST_MSVC)
01400 
01402 template <class T, class Alloc>
01403 inline bool operator != (const circular_buffer<T, Alloc>& lhs,
01404                          const circular_buffer<T, Alloc>& rhs) {
01405     return !(lhs == rhs);
01406 }
01407 
01409 template <class T, class Alloc>
01410 inline bool operator > (const circular_buffer<T, Alloc>& lhs,
01411                         const circular_buffer<T, Alloc>& rhs) {
01412     return rhs < lhs;
01413 }
01414 
01416 template <class T, class Alloc>
01417 inline bool operator <= (const circular_buffer<T, Alloc>& lhs,
01418                          const circular_buffer<T, Alloc>& rhs) {
01419     return !(rhs < lhs);
01420 }
01421 
01423 template <class T, class Alloc>
01424 inline bool operator >= (const circular_buffer<T, Alloc>& lhs,
01425                          const circular_buffer<T, Alloc>& rhs) {
01426     return !(lhs < rhs);
01427 }
01428 
01430 template <class T, class Alloc>
01431 inline void swap(circular_buffer<T, Alloc>& lhs, circular_buffer<T, Alloc>& rhs) {
01432     lhs.swap(rhs);
01433 }
01434 
01435 #endif // #if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) || defined(BOOST_MSVC)
01436 
01437 } // namespace boost
01438 
01439 #endif // #if !defined(BOOST_CIRCULAR_BUFFER_BASE_HPP)