Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
apolukhin committed Jan 19, 2014
2 parents b896ace + 62233c5 commit f5303c7
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 63 deletions.
51 changes: 20 additions & 31 deletions include/boost/circular_buffer/base.hpp
Expand Up @@ -34,21 +34,10 @@
#include <utility>
#include <deque>
#include <stdexcept>
#if BOOST_CB_ENABLE_DEBUG
#include <cstring>
#endif
#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3205))
#include <stddef.h>
#endif

#if defined(BOOST_NO_STDC_NAMESPACE)
namespace std {
using ::memset;
}
#endif



namespace boost {

/*!
Expand Down Expand Up @@ -690,7 +679,7 @@ class circular_buffer
break;
}
if (is_uninitialized(dest)) {
::new (dest) value_type(this_type::move_if_noexcept(*src));
cb_details::do_construct<value_type>(dest, this_type::move_if_noexcept(*src), m_alloc);
++constructed;
} else {
value_type tmp = this_type::move_if_noexcept(*src);
Expand Down Expand Up @@ -902,7 +891,7 @@ class circular_buffer
iterator b = begin();
BOOST_TRY {
reset(buff,
cb_details::uninitialized_move_if_noexcept<value_type>(b, b + (std::min)(new_capacity, size()), buff),
cb_details::uninitialized_move_if_noexcept(b, b + (std::min)(new_capacity, size()), buff, m_alloc),
new_capacity);
} BOOST_CATCH(...) {
deallocate(buff, new_capacity);
Expand Down Expand Up @@ -977,8 +966,8 @@ class circular_buffer
pointer buff = allocate(new_capacity);
iterator e = end();
BOOST_TRY {
reset(buff, cb_details::uninitialized_move_if_noexcept<value_type>(e - (std::min)(new_capacity, size()),
e, buff), new_capacity);
reset(buff, cb_details::uninitialized_move_if_noexcept(e - (std::min)(new_capacity, size()),
e, buff, m_alloc), new_capacity);
} BOOST_CATCH(...) {
deallocate(buff, new_capacity);
BOOST_RETHROW
Expand Down Expand Up @@ -1125,7 +1114,7 @@ class circular_buffer
initialize_buffer(cb.capacity());
m_first = m_buff;
BOOST_TRY {
m_last = cb_details::uninitialized_copy<value_type>(cb.begin(), cb.end(), m_buff);
m_last = cb_details::uninitialized_copy(cb.begin(), cb.end(), m_buff, m_alloc);
} BOOST_CATCH(...) {
deallocate(m_buff, cb.capacity());
BOOST_RETHROW
Expand Down Expand Up @@ -1249,7 +1238,7 @@ class circular_buffer
return *this;
pointer buff = allocate(cb.capacity());
BOOST_TRY {
reset(buff, cb_details::uninitialized_copy<value_type>(cb.begin(), cb.end(), buff), cb.capacity());
reset(buff, cb_details::uninitialized_copy(cb.begin(), cb.end(), buff, m_alloc), cb.capacity());
} BOOST_CATCH(...) {
deallocate(buff, cb.capacity());
BOOST_RETHROW
Expand Down Expand Up @@ -1446,7 +1435,7 @@ class circular_buffer
increment(m_last);
m_first = m_last;
} else {
::new (m_last) value_type(static_cast<ValT>(item));
cb_details::do_construct<value_type>(m_last, static_cast<ValT>(item), m_alloc);
increment(m_last);
++m_size;
}
Expand All @@ -1463,7 +1452,7 @@ class circular_buffer
m_last = m_first;
} else {
decrement(m_first);
::new (m_first) value_type(static_cast<ValT>(item));
cb_details::do_construct<value_type>(m_first, static_cast<ValT>(item), m_alloc);
++m_size;
}
} BOOST_CATCH(...) {
Expand Down Expand Up @@ -2397,7 +2386,7 @@ class circular_buffer
throw_exception(std::length_error("circular_buffer"));
#if BOOST_CB_ENABLE_DEBUG
pointer p = (n == 0) ? 0 : m_alloc.allocate(n, 0);
std::memset(p, cb_details::UNINITIALIZED, sizeof(value_type) * n);
cb_details::do_fill_uninitialized_memory(p, sizeof(value_type) * n);
return p;
#else
return (n == 0) ? 0 : m_alloc.allocate(n, 0);
Expand Down Expand Up @@ -2438,7 +2427,7 @@ class circular_buffer
*/
void construct_or_replace(bool construct, pointer pos, param_value_type item) {
if (construct)
::new (pos) value_type(item);
cb_details::do_construct<value_type>(pos, item, m_alloc);
else
replace(pos, item);
}
Expand All @@ -2450,7 +2439,7 @@ class circular_buffer
*/
void construct_or_replace(bool construct, pointer pos, rvalue_type item) {
if (construct)
::new (pos) value_type(boost::move(item));
cb_details::do_construct<value_type>(pos, boost::move(item), m_alloc);
else
replace(pos, boost::move(item));
}
Expand All @@ -2460,7 +2449,7 @@ class circular_buffer
m_alloc.destroy(p);
#if BOOST_CB_ENABLE_DEBUG
invalidate_iterators(iterator(this, p));
std::memset(p, cb_details::UNINITIALIZED, sizeof(value_type));
cb_details::do_fill_uninitialized_memory(p, sizeof(value_type));
#endif
}

Expand Down Expand Up @@ -2590,7 +2579,7 @@ class circular_buffer
if (buffer_capacity == 0)
return;
while (first != last && !full()) {
::new (m_last) value_type(*first++);
cb_details::do_construct<value_type>(m_last, *first++, m_alloc);
increment(m_last);
++m_size;
}
Expand Down Expand Up @@ -2626,7 +2615,7 @@ class circular_buffer
m_size = distance;
}
BOOST_TRY {
m_last = cb_details::uninitialized_copy<value_type>(first, last, m_buff);
m_last = cb_details::uninitialized_copy(first, last, m_buff, m_alloc);
} BOOST_CATCH(...) {
deallocate(m_buff, buffer_capacity);
BOOST_RETHROW
Expand Down Expand Up @@ -2680,16 +2669,16 @@ class circular_buffer
std::deque<value_type, allocator_type> tmp(first, last, m_alloc);
size_type distance = tmp.size();
assign_n(distance, distance,
cb_details::make_assign_range<value_type>
(boost::make_move_iterator(tmp.begin()), boost::make_move_iterator(tmp.end())));
cb_details::make_assign_range
(boost::make_move_iterator(tmp.begin()), boost::make_move_iterator(tmp.end()), m_alloc));
}

//! Specialized assign method.
template <class ForwardIterator>
void assign(ForwardIterator first, ForwardIterator last, const std::forward_iterator_tag&) {
BOOST_CB_ASSERT(std::distance(first, last) >= 0); // check for wrong range
size_type distance = std::distance(first, last);
assign_n(distance, distance, cb_details::make_assign_range<value_type>(first, last));
assign_n(distance, distance, cb_details::make_assign_range(first, last, m_alloc));
}

//! Specialized assign method.
Expand Down Expand Up @@ -2732,7 +2721,7 @@ class circular_buffer
distance = new_capacity;
}
assign_n(new_capacity, distance,
cb_details::make_assign_range<value_type>(first, last));
cb_details::make_assign_range(first, last, m_alloc));
}

//! Helper assign method.
Expand Down Expand Up @@ -2855,7 +2844,7 @@ class circular_buffer
pointer p = m_last;
BOOST_TRY {
for (; ii < construct; ++ii, increment(p))
::new (p) value_type(*wrapper());
cb_details::do_construct<value_type>(p, *wrapper(), m_alloc);
for (;ii < n; ++ii, increment(p))
replace(p, *wrapper());
} BOOST_CATCH(...) {
Expand Down Expand Up @@ -2949,7 +2938,7 @@ class circular_buffer
for (;ii > construct; --ii, increment(p))
replace(p, *wrapper());
for (; ii > 0; --ii, increment(p))
::new (p) value_type(*wrapper());
cb_details::do_construct<value_type>(p, *wrapper(), m_alloc);
} BOOST_CATCH(...) {
size_type constructed = ii < construct ? construct - ii : 0;
m_last = add(m_last, constructed);
Expand Down
21 changes: 21 additions & 0 deletions include/boost/circular_buffer/debug.hpp
Expand Up @@ -13,6 +13,16 @@
#pragma once
#endif

#if BOOST_CB_ENABLE_DEBUG
#include <cstring>

#if defined(BOOST_NO_STDC_NAMESPACE)
namespace std {
using ::memset;
}
#endif

#endif // BOOST_CB_ENABLE_DEBUG
namespace boost {

namespace cb_details {
Expand All @@ -22,6 +32,17 @@ namespace cb_details {
// The value the uninitialized memory is filled with.
const int UNINITIALIZED = 0xcc;

template <class T>
inline void do_fill_uninitialized_memory(T* data, std::size_t size_in_bytes) BOOST_NOEXCEPT {
std::memset(static_cast<void*>(data), UNINITIALIZED, size_in_bytes);
}

template <class T>
inline void do_fill_uninitialized_memory(T& /*data*/, std::size_t /*size_in_bytes*/) BOOST_NOEXCEPT {
// Do nothing
}


class debug_iterator_registry;

/*!
Expand Down
89 changes: 58 additions & 31 deletions include/boost/circular_buffer/details.hpp
Expand Up @@ -38,11 +38,42 @@ template<class ForwardIterator, class Diff, class T, class Alloc>
void uninitialized_fill_n_with_alloc(
ForwardIterator first, Diff n, const T& item, Alloc& alloc);

template<class ValueType, class InputIterator, class ForwardIterator>
ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest);
template<class InputIterator, class ForwardIterator, class Alloc>
ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a);

template<class InputIterator, class ForwardIterator, class Alloc>
ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a);


//! Those `do_construct` methods are required because in C++03 default allocators
//! have `construct` method that accepts second parameter in as a const reference;
//! while move-only types emulated by Boost.Move require constructor that accepts
//! a non-const reference.
//!
//! So when we need to call `construct` and pointer to value_type is provided, we
//! assume that it is safe to call placement new instead of Alloc::construct.
//! Otherwise we are asume that user has made his own allocator or uses allocator
//! from other libraries. In that case it's users ability to provide Alloc::construct
//! with non-const reference parameter or just do not use move-only types.
template <class ValueType, class Alloc>
inline void do_construct(ValueType* p, BOOST_RV_REF(ValueType) item, Alloc&) {
::new (p) ValueType(boost::move(item));
}

template <class ValueType, class Alloc>
inline void do_construct(ValueType* p, const ValueType& item, Alloc&) {
::new (p) ValueType(item);
}

template<class ValueType, class InputIterator, class ForwardIterator>
ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest);
template <class ValueType, class Alloc, class PointerT>
inline void do_construct(PointerT& p, BOOST_RV_REF(ValueType) item, Alloc& a) {
a.construct(p, boost::move(item));
}

template <class ValueType, class Alloc, class PointerT>
inline void do_construct(PointerT& p, const ValueType& item, Alloc& a) {
a.construct(p, item);
}

/*!
\struct const_traits
Expand Down Expand Up @@ -127,23 +158,24 @@ struct assign_n {
\struct assign_range
\brief Helper functor for assigning range of items.
*/
template <class ValueType, class Iterator>
template <class Iterator, class Alloc>
struct assign_range {
Iterator m_first;
Iterator m_last;
Alloc& m_alloc;

assign_range(const Iterator& first, const Iterator& last) BOOST_NOEXCEPT
: m_first(first), m_last(last) {}
assign_range(const Iterator& first, const Iterator& last, Alloc& alloc)
: m_first(first), m_last(last), m_alloc(alloc) {}

template <class Pointer>
void operator () (Pointer p) const {
boost::cb_details::uninitialized_copy<ValueType>(m_first, m_last, p);
boost::cb_details::uninitialized_copy(m_first, m_last, p, m_alloc);
}
};

template <class ValueType, class Iterator>
inline assign_range<ValueType, Iterator> make_assign_range(const Iterator& first, const Iterator& last) {
return assign_range<ValueType, Iterator>(first, last);
template <class Iterator, class Alloc>
inline assign_range<Iterator, Alloc> make_assign_range(const Iterator& first, const Iterator& last, Alloc& a) {
return assign_range<Iterator, Alloc>(first, last, a);
}

/*!
Expand Down Expand Up @@ -427,48 +459,43 @@ operator + (typename Traits::difference_type n, const iterator<Buff, Traits>& it
\fn ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest)
\brief Equivalent of <code>std::uninitialized_copy</code> but with explicit specification of value type.
*/
template<class ValueType, class InputIterator, class ForwardIterator>
inline ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest) {
typedef ValueType value_type;

// We do not use allocator.construct and allocator.destroy
// because C++03 requires to take parameter by const reference but
// Boost.move requires nonconst reference
template<class InputIterator, class ForwardIterator, class Alloc>
inline ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a) {
ForwardIterator next = dest;
BOOST_TRY {
for (; first != last; ++first, ++dest)
::new (dest) value_type(*first);
do_construct<typename Alloc::value_type>(dest, *first, a);
} BOOST_CATCH(...) {
for (; next != dest; ++next)
next->~value_type();
a.destroy(next);
BOOST_RETHROW
}
BOOST_CATCH_END
return dest;
}

template<class ValueType, class InputIterator, class ForwardIterator>
ForwardIterator uninitialized_move_if_noexcept_impl(InputIterator first, InputIterator last, ForwardIterator dest,
template<class InputIterator, class ForwardIterator, class Alloc>
ForwardIterator uninitialized_move_if_noexcept_impl(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a,
true_type) {
for (; first != last; ++first, ++dest)
::new (dest) ValueType(boost::move(*first));
do_construct<typename Alloc::value_type>(dest, boost::move(*first), a);
return dest;
}

template<class ValueType, class InputIterator, class ForwardIterator>
ForwardIterator uninitialized_move_if_noexcept_impl(InputIterator first, InputIterator last, ForwardIterator dest,
template<class InputIterator, class ForwardIterator, class Alloc>
ForwardIterator uninitialized_move_if_noexcept_impl(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a,
false_type) {
return uninitialized_copy<ValueType>(first, last, dest);
return uninitialized_copy(first, last, dest, a);
}

/*!
\fn ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest)
\brief Equivalent of <code>std::uninitialized_copy</code> but with explicit specification of value type and moves elements if they have noexcept move constructors.
*/
template<class ValueType, class InputIterator, class ForwardIterator>
ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest) {
typedef typename boost::is_nothrow_move_constructible<ValueType>::type tag_t;
return uninitialized_move_if_noexcept_impl<ValueType>(first, last, dest, tag_t());
template<class InputIterator, class ForwardIterator, class Alloc>
ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a) {
typedef typename boost::is_nothrow_move_constructible<typename Alloc::value_type>::type tag_t;
return uninitialized_move_if_noexcept_impl(first, last, dest, a, tag_t());
}

/*!
Expand All @@ -480,7 +507,7 @@ inline void uninitialized_fill_n_with_alloc(ForwardIterator first, Diff n, const
ForwardIterator next = first;
BOOST_TRY {
for (; n > 0; ++first, --n)
alloc.construct(first, item);
do_construct<typename Alloc::value_type>(first, item, alloc);
} BOOST_CATCH(...) {
for (; next != first; ++next)
alloc.destroy(next);
Expand Down

0 comments on commit f5303c7

Please sign in to comment.