diff --git a/include/boost/circular_buffer/base.hpp b/include/boost/circular_buffer/base.hpp index 47441544..113fb661 100644 --- a/include/boost/circular_buffer/base.hpp +++ b/include/boost/circular_buffer/base.hpp @@ -1429,7 +1429,7 @@ private empty_value boost::allocator_construct(alloc(), boost::to_address(m_last), static_cast(item)); increment(m_last); ++m_size; - } + } } /*! INTERNAL ONLY */ @@ -1454,6 +1454,86 @@ private empty_value BOOST_CATCH_END } +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + template + void emplace_back_impl(BOOST_FWD_REF(Args) ...args) { + if (full()) { + if (empty()) + return; + destroy_item(m_last); + boost::allocator_construct(alloc(), boost::to_address(m_last), ::boost::forward(args)...); + increment(m_last); + m_first = m_last; + } else { + boost::allocator_construct(alloc(), boost::to_address(m_last), ::boost::forward(args)...); + increment(m_last); + ++m_size; + } + } +#else + template + void emplace_back_impl(BOOST_FWD_REF(V) value) { + if (full()) { + if (empty()) + return; + destroy_item(m_last); + boost::allocator_construct(alloc(), boost::to_address(m_last), ::boost::forward(args)...); + increment(m_last); + m_first = m_last; + } else { + boost::allocator_construct(alloc(), boost::to_address(m_last), ::boost::forward(value)); + increment(m_last); + ++m_size; + } + } +#endif + +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + template + void emplace_front_impl(BOOST_FWD_REF(Args) ...args) { + BOOST_TRY { + if (full()) { + if (empty()) + return; + decrement(m_first); + destroy_item(m_first); + boost::allocator_construct(alloc(), boost::to_address(m_first), ::boost::forward(args)...); + m_last = m_first; + } else { + decrement(m_first); + boost::allocator_construct(alloc(), boost::to_address(m_first), ::boost::forward(args)...); + ++m_size; + } + } BOOST_CATCH(...) { + increment(m_first); + BOOST_RETHROW + } + BOOST_CATCH_END + } +#else + template + void emplace_front_impl(BOOST_FWD_REF(V) value) { + BOOST_TRY { + if (full()) { + if (empty()) + return; + decrement(m_first); + destroy_item(m_first); + boost::allocator_construct(alloc(), boost::to_address(m_first), ::boost::forward(args)...); + m_last = m_first; + } else { + decrement(m_first); + boost::allocator_construct(alloc(), boost::to_address(m_first), ::boost::forward(value)); + ++m_size; + } + } BOOST_CATCH(...) { + increment(m_first); + BOOST_RETHROW + } + BOOST_CATCH_END + } +#endif + public: //! Insert a new element at the end of the circular_buffer. /*! @@ -1583,6 +1663,64 @@ private empty_value push_front(boost::move(temp)); } + //! Construct a new element at the end of the circular_buffer. + /*! + \post if capacity() > 0 then back() == item
+ If the circular_buffer is full, the first element will be removed. If the capacity is + 0, nothing will be inserted. + \param item The element to be inserted. + \throws Whatever T::T(Args...) throws. + Whatever T::operator = (T&&) throws. + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Does not invalidate any iterators with the exception of iterators pointing to the overwritten element. + \par Complexity + Constant (in the size of the circular_buffer). + \sa \link push_back() push_back(const_reference)\endlink, + pop_back(), emplace_front() + */ +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + template + void emplace_back(BOOST_FWD_REF(Args) ...args) { + emplace_back_impl(::boost::forward(args)...); + } +#else + template + void emplace_back(BOOST_FWD_REF(V) value) { + emplace_back_impl(::boost::forward(value)); + } +#endif + + //! Construct a new element at the beginning of the circular_buffer. + /*! + \post if capacity() > 0 then back() == item
+ If the circular_buffer is full, the last element will be removed. If the capacity is + 0, nothing will be inserted. + \param item The element to be inserted. + \throws Whatever T::T(Args...) throws. + Whatever T::operator = (T&&) throws. + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Does not invalidate any iterators with the exception of iterators pointing to the overwritten element. + \par Complexity + Constant (in the size of the circular_buffer). + \sa \link push_front() push_front(const_reference)\endlink, + pop_front(), emplace_back() + */ +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + template + void emplace_front(BOOST_FWD_REF(Args) ...args) { + emplace_front_impl(::boost::forward(args)...); + } +#else + template + void emplace_front(BOOST_FWD_REF(V) value) { + emplace_front_impl(::boost::forward(value)); + } +#endif + //! Remove the last element from the circular_buffer. /*! \pre !empty() diff --git a/include/boost/circular_buffer/space_optimized.hpp b/include/boost/circular_buffer/space_optimized.hpp index 21681fd3..81613d78 100644 --- a/include/boost/circular_buffer/space_optimized.hpp +++ b/include/boost/circular_buffer/space_optimized.hpp @@ -905,6 +905,76 @@ public:
circular_buffer::push_front(); } + //! Construct a new element at the end of the space optimized circular buffer. + /*! + \post if capacity().%capacity() > 0 then back() == item
+ If the circular_buffer_space_optimized is full, the first element will be removed. If the + capacity is 0, nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param item The element to be inserted. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(Args...) throws. + Whatever T::operator = (T&&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link push_front() push_front(const_reference)\endlink, pop_back(), + pop_front() + */ +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + template + void emplace_back(BOOST_FWD_REF(Args) ...args) { + check_low_capacity(); + circular_buffer::emplace_back(::boost::forward(args)...); + } +#else + template + void emplace_back(BOOST_FWD_REF(V) value) { + check_low_capacity(); + circular_buffer::emplace_back(::boost::forward(value)); + } +#endif + + //! Construct a new element at the beginning of the space optimized circular buffer. + /*! + \post if capacity().%capacity() > 0 then front() == item
+ If the circular_buffer_space_optimized is full, the last element will be removed. If the + capacity is 0, nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param item The element to be inserted. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(Args...) throws or nothing if T::T(T&&) is noexcept. + Whatever T::operator = (T&&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link push_back() push_back(const_reference)\endlink, pop_back(), + pop_front() + */ +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + template + void emplace_front(BOOST_FWD_REF(Args) ...args) { + check_low_capacity(); + circular_buffer::emplace_front(::boost::forward(args)...); + } +#else + template + void emplace_front(BOOST_FWD_REF(V) value) { + check_low_capacity(); + circular_buffer::emplace_front(::boost::forward(value)); + } +#endif + //! Remove the last element from the space optimized circular buffer. /*! \pre !empty() diff --git a/test/common.ipp b/test/common.ipp index 4d3d2790..0d99a685 100644 --- a/test/common.ipp +++ b/test/common.ipp @@ -1153,6 +1153,32 @@ void pop_back_test() { generic_test(cb); } +void emplace_test(){ + CB_CONTAINER cb(4); + cb.emplace_back(4); + cb.emplace_back(5); + cb.emplace_back(6); + cb.emplace_back(7); + + BOOST_TEST(cb.size() == 4); + BOOST_TEST(cb.front() == 4); + BOOST_TEST(cb.back() == 7); + + cb.emplace_front(3); + cb.emplace_front(2); + + BOOST_TEST(cb.front() == 2); + BOOST_TEST(cb.back() == 5); + + cb.emplace_front(1); + cb.emplace_front(0); + + BOOST_TEST(cb.size() == 4); + BOOST_TEST(*cb.begin() == 0); + BOOST_TEST(cb.front() == 0); + BOOST_TEST(cb.back() == 3); +} + void insert_test() { CB_CONTAINER cb1(4); @@ -2467,6 +2493,7 @@ void run_common_tests() swap_test(); push_back_test(); pop_back_test(); + emplace_test(); insert_test(); insert_n_test(); insert_range_test();