1 // Helper classes and functions for the circular buffer.
3 // Copyright (c) 2003-2008 Jan Gaspar
4 // Copyright (c) 2014 Glen Joseph Fernandes // C++11 allocator model support.
6 // Use, modification, and distribution is subject to the Boost Software
7 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
10 #if !defined(BOOST_CIRCULAR_BUFFER_DETAILS_HPP)
11 #define BOOST_CIRCULAR_BUFFER_DETAILS_HPP
17 #include <boost/throw_exception.hpp>
18 #include <boost/container/allocator_traits.hpp>
19 #include <boost/core/pointer_traits.hpp>
20 #include <boost/move/move.hpp>
21 #include <boost/type_traits/is_nothrow_move_constructible.hpp>
22 #include <boost/utility/addressof.hpp>
23 #include <boost/detail/no_exceptions_support.hpp>
26 // Silence MS /W4 warnings like C4913:
27 // "user defined binary operator ',' exists but no overload could convert all operands, default built-in binary operator ',' used"
28 // This might happen when previously including some boost headers that overload the coma operator.
30 # pragma warning(push)
31 # pragma warning(disable:4913)
36 namespace cb_details {
38 template<class Pointer>
39 inline typename boost::pointer_traits<Pointer>::element_type*
40 to_address(Pointer p) BOOST_NOEXCEPT
42 return boost::pointer_traits<Pointer>::to_address(p);
45 template <class Traits> struct nonconst_traits;
47 template<class ForwardIterator, class Diff, class T, class Alloc>
48 void uninitialized_fill_n_with_alloc(
49 ForwardIterator first, Diff n, const T& item, Alloc& alloc);
51 template<class InputIterator, class ForwardIterator, class Alloc>
52 ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a);
54 template<class InputIterator, class ForwardIterator, class Alloc>
55 ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a);
59 \brief Defines the data types for a const iterator.
61 template <class Traits>
64 typedef typename Traits::value_type value_type;
65 typedef typename Traits::const_pointer pointer;
66 typedef typename Traits::const_reference reference;
67 typedef typename Traits::size_type size_type;
68 typedef typename Traits::difference_type difference_type;
71 typedef nonconst_traits<Traits> nonconst_self;
75 \struct nonconst_traits
76 \brief Defines the data types for a non-const iterator.
78 template <class Traits>
79 struct nonconst_traits {
81 typedef typename Traits::value_type value_type;
82 typedef typename Traits::pointer pointer;
83 typedef typename Traits::reference reference;
84 typedef typename Traits::size_type size_type;
85 typedef typename Traits::difference_type difference_type;
88 typedef nonconst_traits<Traits> nonconst_self;
92 \struct iterator_wrapper
93 \brief Helper iterator dereference wrapper.
95 template <class Iterator>
96 struct iterator_wrapper {
97 mutable Iterator m_it;
98 explicit iterator_wrapper(Iterator it) : m_it(it) {}
99 Iterator operator () () const { return m_it++; }
101 iterator_wrapper<Iterator>& operator = (const iterator_wrapper<Iterator>&); // do not generate
106 \brief Helper item dereference wrapper.
108 template <class Pointer, class Value>
109 struct item_wrapper {
111 explicit item_wrapper(Value item) : m_item(item) {}
112 Pointer operator () () const { return &m_item; }
114 item_wrapper<Pointer, Value>& operator = (const item_wrapper<Pointer, Value>&); // do not generate
119 \brief Helper functor for assigning n items.
121 template <class Value, class Alloc>
123 typedef typename boost::container::allocator_traits<Alloc>::size_type size_type;
127 assign_n(size_type n, Value item, Alloc& alloc) : m_n(n), m_item(item), m_alloc(alloc) {}
128 template <class Pointer>
129 void operator () (Pointer p) const {
130 uninitialized_fill_n_with_alloc(p, m_n, m_item, m_alloc);
133 assign_n<Value, Alloc>& operator = (const assign_n<Value, Alloc>&); // do not generate
138 \brief Helper functor for assigning range of items.
140 template <class Iterator, class Alloc>
141 struct assign_range {
146 assign_range(const Iterator& first, const Iterator& last, Alloc& alloc)
147 : m_first(first), m_last(last), m_alloc(alloc) {}
149 template <class Pointer>
150 void operator () (Pointer p) const {
151 boost::cb_details::uninitialized_copy(m_first, m_last, p, m_alloc);
155 template <class Iterator, class Alloc>
156 inline assign_range<Iterator, Alloc> make_assign_range(const Iterator& first, const Iterator& last, Alloc& a) {
157 return assign_range<Iterator, Alloc>(first, last, a);
161 \class capacity_control
162 \brief Capacity controller of the space optimized circular buffer.
164 template <class Size>
165 class capacity_control {
167 //! The capacity of the space-optimized circular buffer.
170 //! The lowest guaranteed or minimum capacity of the adapted space-optimized circular buffer.
176 capacity_control(Size buffer_capacity, Size min_buffer_capacity = 0)
177 : m_capacity(buffer_capacity), m_min_capacity(min_buffer_capacity)
178 { // Check for capacity lower than min_capacity.
179 BOOST_CB_ASSERT(buffer_capacity >= min_buffer_capacity);
182 // Default copy constructor.
184 // Default assign operator.
186 //! Get the capacity of the space optimized circular buffer.
187 Size capacity() const { return m_capacity; }
189 //! Get the minimal capacity of the space optimized circular buffer.
190 Size min_capacity() const { return m_min_capacity; }
192 //! Size operator - returns the capacity of the space optimized circular buffer.
193 operator Size() const { return m_capacity; }
198 \brief Random access iterator for the circular buffer.
199 \param Buff The type of the underlying circular buffer.
200 \param Traits Basic iterator types.
201 \note This iterator is not circular. It was designed
202 for iterating from begin() to end() of the circular buffer.
204 template <class Buff, class Traits>
206 public std::iterator<
207 std::random_access_iterator_tag,
208 typename Traits::value_type,
209 typename Traits::difference_type,
210 typename Traits::pointer,
211 typename Traits::reference>
212 #if BOOST_CB_ENABLE_DEBUG
213 , public debug_iterator_base
214 #endif // #if BOOST_CB_ENABLE_DEBUG
219 typedef std::iterator<
220 std::random_access_iterator_tag,
221 typename Traits::value_type,
222 typename Traits::difference_type,
223 typename Traits::pointer,
224 typename Traits::reference> base_iterator;
226 //! Non-const iterator.
227 typedef iterator<Buff, typename Traits::nonconst_self> nonconst_self;
231 //! The type of the elements stored in the circular buffer.
232 typedef typename base_iterator::value_type value_type;
234 //! Pointer to the element.
235 typedef typename base_iterator::pointer pointer;
237 //! Reference to the element.
238 typedef typename base_iterator::reference reference;
241 typedef typename Traits::size_type size_type;
244 typedef typename base_iterator::difference_type difference_type;
248 //! The circular buffer where the iterator points to.
251 //! An internal iterator.
254 // Construction & assignment
256 // Default copy constructor.
258 //! Default constructor.
259 iterator() : m_buff(0), m_it(0) {}
261 #if BOOST_CB_ENABLE_DEBUG
263 //! Copy constructor (used for converting from a non-const to a const iterator).
264 iterator(const nonconst_self& it) : debug_iterator_base(it), m_buff(it.m_buff), m_it(it.m_it) {}
266 //! Internal constructor.
268 \note This constructor is not intended to be used directly by the user.
270 iterator(const Buff* cb, const pointer p) : debug_iterator_base(cb), m_buff(cb), m_it(p) {}
274 iterator(const nonconst_self& it) : m_buff(it.m_buff), m_it(it.m_it) {}
276 iterator(const Buff* cb, const pointer p) : m_buff(cb), m_it(p) {}
278 #endif // #if BOOST_CB_ENABLE_DEBUG
281 iterator& operator = (const iterator& it) {
284 #if BOOST_CB_ENABLE_DEBUG
285 debug_iterator_base::operator =(it);
286 #endif // #if BOOST_CB_ENABLE_DEBUG
292 // Random access iterator methods
294 //! Dereferencing operator.
295 reference operator * () const {
296 BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator
297 BOOST_CB_ASSERT(m_it != 0); // check for iterator pointing to end()
301 //! Dereferencing operator.
302 pointer operator -> () const { return &(operator*()); }
304 //! Difference operator.
305 template <class Traits0>
306 difference_type operator - (const iterator<Buff, Traits0>& it) const {
307 BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator
308 BOOST_CB_ASSERT(it.is_valid(m_buff)); // check for uninitialized or invalidated iterator
309 return linearize_pointer(*this) - linearize_pointer(it);
312 //! Increment operator (prefix).
313 iterator& operator ++ () {
314 BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator
315 BOOST_CB_ASSERT(m_it != 0); // check for iterator pointing to end()
316 m_buff->increment(m_it);
317 if (m_it == m_buff->m_last)
322 //! Increment operator (postfix).
323 iterator operator ++ (int) {
324 iterator<Buff, Traits> tmp = *this;
329 //! Decrement operator (prefix).
330 iterator& operator -- () {
331 BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator
332 BOOST_CB_ASSERT(m_it != m_buff->m_first); // check for iterator pointing to begin()
334 m_it = m_buff->m_last;
335 m_buff->decrement(m_it);
339 //! Decrement operator (postfix).
340 iterator operator -- (int) {
341 iterator<Buff, Traits> tmp = *this;
346 //! Iterator addition.
347 iterator& operator += (difference_type n) {
348 BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator
350 BOOST_CB_ASSERT(m_buff->end() - *this >= n); // check for too large n
351 m_it = m_buff->add(m_it, n);
352 if (m_it == m_buff->m_last)
360 //! Iterator addition.
361 iterator operator + (difference_type n) const { return iterator<Buff, Traits>(*this) += n; }
363 //! Iterator subtraction.
364 iterator& operator -= (difference_type n) {
365 BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator
367 BOOST_CB_ASSERT(*this - m_buff->begin() >= n); // check for too large n
368 m_it = m_buff->sub(m_it == 0 ? m_buff->m_last : m_it, n);
375 //! Iterator subtraction.
376 iterator operator - (difference_type n) const { return iterator<Buff, Traits>(*this) -= n; }
378 //! Element access operator.
379 reference operator [] (difference_type n) const { return *(*this + n); }
381 // Equality & comparison
384 template <class Traits0>
385 bool operator == (const iterator<Buff, Traits0>& it) const {
386 BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator
387 BOOST_CB_ASSERT(it.is_valid(m_buff)); // check for uninitialized or invalidated iterator
388 return m_it == it.m_it;
392 template <class Traits0>
393 bool operator != (const iterator<Buff, Traits0>& it) const {
394 BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator
395 BOOST_CB_ASSERT(it.is_valid(m_buff)); // check for uninitialized or invalidated iterator
396 return m_it != it.m_it;
400 template <class Traits0>
401 bool operator < (const iterator<Buff, Traits0>& it) const {
402 BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator
403 BOOST_CB_ASSERT(it.is_valid(m_buff)); // check for uninitialized or invalidated iterator
404 return linearize_pointer(*this) < linearize_pointer(it);
408 template <class Traits0>
409 bool operator > (const iterator<Buff, Traits0>& it) const { return it < *this; }
412 template <class Traits0>
413 bool operator <= (const iterator<Buff, Traits0>& it) const { return !(it < *this); }
415 //! Greater or equal.
416 template <class Traits0>
417 bool operator >= (const iterator<Buff, Traits0>& it) const { return !(*this < it); }
421 //! Get a pointer which would point to the same element as the iterator in case the circular buffer is linearized.
422 template <class Traits0>
423 typename Traits0::pointer linearize_pointer(const iterator<Buff, Traits0>& it) const {
424 return it.m_it == 0 ? m_buff->m_buff + m_buff->size() :
425 (it.m_it < m_buff->m_first ? it.m_it + (m_buff->m_end - m_buff->m_first)
426 : m_buff->m_buff + (it.m_it - m_buff->m_first));
430 //! Iterator addition.
431 template <class Buff, class Traits>
432 inline iterator<Buff, Traits>
433 operator + (typename Traits::difference_type n, const iterator<Buff, Traits>& it) {
438 \fn ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest)
439 \brief Equivalent of <code>std::uninitialized_copy</code> but with explicit specification of value type.
441 template<class InputIterator, class ForwardIterator, class Alloc>
442 inline ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a) {
443 ForwardIterator next = dest;
445 for (; first != last; ++first, ++dest)
446 boost::container::allocator_traits<Alloc>::construct(a, cb_details::to_address(dest), *first);
448 for (; next != dest; ++next)
449 boost::container::allocator_traits<Alloc>::destroy(a, cb_details::to_address(next));
456 template<class InputIterator, class ForwardIterator, class Alloc>
457 ForwardIterator uninitialized_move_if_noexcept_impl(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a,
459 for (; first != last; ++first, ++dest)
460 boost::container::allocator_traits<Alloc>::construct(a, cb_details::to_address(dest), boost::move(*first));
464 template<class InputIterator, class ForwardIterator, class Alloc>
465 ForwardIterator uninitialized_move_if_noexcept_impl(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a,
467 return uninitialized_copy(first, last, dest, a);
471 \fn ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest)
472 \brief Equivalent of <code>std::uninitialized_copy</code> but with explicit specification of value type and moves elements if they have noexcept move constructors.
474 template<class InputIterator, class ForwardIterator, class Alloc>
475 ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a) {
476 typedef typename boost::is_nothrow_move_constructible<typename boost::container::allocator_traits<Alloc>::value_type>::type tag_t;
477 return uninitialized_move_if_noexcept_impl(first, last, dest, a, tag_t());
481 \fn void uninitialized_fill_n_with_alloc(ForwardIterator first, Diff n, const T& item, Alloc& alloc)
482 \brief Equivalent of <code>std::uninitialized_fill_n</code> with allocator.
484 template<class ForwardIterator, class Diff, class T, class Alloc>
485 inline void uninitialized_fill_n_with_alloc(ForwardIterator first, Diff n, const T& item, Alloc& alloc) {
486 ForwardIterator next = first;
488 for (; n > 0; ++first, --n)
489 boost::container::allocator_traits<Alloc>::construct(alloc, cb_details::to_address(first), item);
491 for (; next != first; ++next)
492 boost::container::allocator_traits<Alloc>::destroy(alloc, cb_details::to_address(next));
498 } // namespace cb_details
502 #if defined(_MSC_VER)
503 # pragma warning(pop)
506 #endif // #if !defined(BOOST_CIRCULAR_BUFFER_DETAILS_HPP)