diff --git a/include/boost/container/allocator_traits.hpp b/include/boost/container/allocator_traits.hpp index 828d664..64e4352 100644 --- a/include/boost/container/allocator_traits.hpp +++ b/include/boost/container/allocator_traits.hpp @@ -32,7 +32,10 @@ #include //numeric_limits<>::max() #include //placement new #include //std::allocator + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #include +#endif ///@cond @@ -211,7 +214,7 @@ struct allocator_traits //! //! Throws: Nothing static void deallocate(Alloc &a, pointer p, size_type n) - { return a.deallocate(p, n); } + { a.deallocate(p, n); } //! Effects: calls `a.allocate(n, p)` if that call is well-formed; //! otherwise, invokes `a.allocate(n)` @@ -250,7 +253,19 @@ struct allocator_traits //! Returns: `a.select_on_container_copy_construction()` if that expression is well-formed; //! otherwise, a. - static Alloc select_on_container_copy_construction(const Alloc &a) + static + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + typename container_detail::if_c + < boost::container::container_detail:: + has_member_function_callable_with_select_on_container_copy_construction + ::value + , Alloc + , const Alloc & + >::type + #else + Alloc + #endif + select_on_container_copy_construction(const Alloc &a) { const bool value = boost::container::container_detail:: has_member_function_callable_with_select_on_container_copy_construction @@ -295,7 +310,7 @@ struct allocator_traits static Alloc priv_select_on_container_copy_construction(boost::true_type, const Alloc &a) { return a.select_on_container_copy_construction(); } - static Alloc priv_select_on_container_copy_construction(boost::false_type, const Alloc &a) + static const Alloc &priv_select_on_container_copy_construction(boost::false_type, const Alloc &a) { return a; } #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index 32fa480..5ff423d 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -46,12 +46,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -830,11 +830,11 @@ class deque : protected deque_base if (len > size()) { FwdIt mid = first; std::advance(mid, this->size()); - boost::copy_or_move(first, mid, begin()); + boost::container::copy(first, mid, begin()); this->insert(this->cend(), mid, last); } else{ - this->erase(boost::copy_or_move(first, last, this->begin()), cend()); + this->erase(boost::container::copy(first, last, this->begin()), cend()); } } #endif @@ -1575,7 +1575,7 @@ class deque : protected deque_base } void priv_range_check(size_type n) const - { if (n >= this->size()) BOOST_RETHROW std::out_of_range("deque"); } + { if (n >= this->size()) throw_out_of_range("deque::at out of range"); } template iterator priv_insert(const_iterator position, BOOST_FWD_REF(U) x) @@ -1721,11 +1721,11 @@ class deque : protected deque_base this->members_.m_finish = new_finish; } else{ - pos = this->members_.m_finish - elemsafter; + pos = old_finish - elemsafter; if (elemsafter >= n) { - iterator finish_n = this->members_.m_finish - difference_type(n); + iterator finish_n = old_finish - difference_type(n); ::boost::container::uninitialized_move_alloc - (this->alloc(), finish_n, this->members_.m_finish, this->members_.m_finish); + (this->alloc(), finish_n, old_finish, old_finish); this->members_.m_finish = new_finish; boost::move_backward(pos, finish_n, old_finish); interf.copy_n_and_update(pos, n); @@ -1733,25 +1733,17 @@ class deque : protected deque_base else { const size_type raw_gap = n - elemsafter; ::boost::container::uninitialized_move_alloc - (this->alloc(), pos, old_finish, this->members_.m_finish + raw_gap); + (this->alloc(), pos, old_finish, old_finish + raw_gap); BOOST_TRY{ + interf.copy_n_and_update(pos, elemsafter); interf.uninitialized_copy_n_and_update(old_finish, raw_gap); } BOOST_CATCH(...){ - this->priv_destroy_range(this->members_.m_finish, this->members_.m_finish + (old_finish - pos)); + this->priv_destroy_range(old_finish, old_finish + elemsafter); BOOST_RETHROW } BOOST_CATCH_END this->members_.m_finish = new_finish; - interf.copy_n_and_update(pos, elemsafter); - /* - interf.uninitialized_copy_some_and_update(old_finish, elemsafter, false); - this->members_.m_finish += n-elemsafter; - ::boost::container::uninitialized_move_alloc - (this->alloc(), pos, old_finish, this->members_.m_finish); - this->members_.m_finish = new_finish; - interf.copy_remaining_to(pos); - */ } } } @@ -1840,12 +1832,10 @@ class deque : protected deque_base ++cur_node) { FwdIt mid = first; std::advance(mid, this->s_buffer_size()); - ::boost::container::uninitialized_copy_or_move_alloc - (this->alloc(), first, mid, *cur_node); + ::boost::container::uninitialized_copy_alloc(this->alloc(), first, mid, *cur_node); first = mid; } - ::boost::container::uninitialized_copy_or_move_alloc - (this->alloc(), first, last, this->members_.m_finish.m_first); + ::boost::container::uninitialized_copy_alloc(this->alloc(), first, last, this->members_.m_finish.m_first); } BOOST_CATCH(...){ this->priv_destroy_range(this->members_.m_start, iterator(*cur_node, cur_node)); diff --git a/include/boost/container/detail/adaptive_node_pool_impl.hpp b/include/boost/container/detail/adaptive_node_pool_impl.hpp index 42bdf43..8b673cf 100644 --- a/include/boost/container/detail/adaptive_node_pool_impl.hpp +++ b/include/boost/container/detail/adaptive_node_pool_impl.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -780,7 +781,7 @@ class private_adaptive_node_pool_impl //In case of error, free memory deallocating all nodes (the new ones allocated //in this function plus previously stored nodes in chain). this->deallocate_nodes(chain); - throw std::bad_alloc(); + throw_bad_alloc(); } block_info_t &c_info = *new(mem_address)block_info_t(); mem_address += HdrSize; @@ -812,7 +813,7 @@ class private_adaptive_node_pool_impl //In case of error, free memory deallocating all nodes (the new ones allocated //in this function plus previously stored nodes in chain). this->deallocate_nodes(chain); - throw std::bad_alloc(); + throw_bad_alloc(); } //First initialize header information on the last subblock char *hdr_addr = mem_address + m_real_block_alignment*(m_num_subblocks-1); diff --git a/include/boost/container/detail/advanced_insert_int.hpp b/include/boost/container/detail/advanced_insert_int.hpp index 4c4fef6..86e2628 100644 --- a/include/boost/container/detail/advanced_insert_int.hpp +++ b/include/boost/container/detail/advanced_insert_int.hpp @@ -27,6 +27,32 @@ namespace boost { namespace container { namespace container_detail { +template +struct move_insert_range_proxy +{ + typedef typename allocator_traits::size_type size_type; + typedef typename allocator_traits::value_type value_type; + + move_insert_range_proxy(A& a, FwdIt first) + : a_(a), first_(first) + {} + + void uninitialized_copy_n_and_update(Iterator p, size_type n) + { + this->first_ = ::boost::container::uninitialized_move_alloc_n_source + (this->a_, this->first_, n, p); + } + + void copy_n_and_update(Iterator p, size_type n) + { + this->first_ = ::boost::container::move_n_source(this->first_, n, p); + } + + A &a_; + FwdIt first_; +}; + + template struct insert_range_proxy { @@ -37,15 +63,14 @@ struct insert_range_proxy : a_(a), first_(first) {} - void uninitialized_copy_n_and_update(Iterator pos, size_type n) + void uninitialized_copy_n_and_update(Iterator p, size_type n) { - this->first_ = ::boost::container::uninitialized_copy_or_move_alloc_n_source - (this->a_, this->first_, n, pos); + this->first_ = ::boost::container::uninitialized_copy_alloc_n_source(this->a_, this->first_, n, p); } - void copy_n_and_update(Iterator pos, size_type n) + void copy_n_and_update(Iterator p, size_type n) { - this->first_ = ::boost::container::copy_or_move_n_source(this->first_, n, pos); + this->first_ = ::boost::container::copy_n_source(this->first_, n, p); } A &a_; @@ -63,10 +88,10 @@ struct insert_n_copies_proxy : a_(a), v_(v) {} - void uninitialized_copy_n_and_update(Iterator p, size_type n) - { std::uninitialized_fill_n(p, n, v_); } + void uninitialized_copy_n_and_update(Iterator p, size_type n) const + { boost::container::uninitialized_fill_alloc_n(this->a_, v_, n, p); } - void copy_n_and_update(Iterator p, size_type n) + void copy_n_and_update(Iterator p, size_type n) const { std::fill_n(p, n, v_); } A &a_; @@ -85,25 +110,10 @@ struct insert_default_constructed_n_proxy : a_(a) {} - void uninitialized_copy_n_and_update(Iterator p, size_type n) - { - Iterator orig_p = p; - size_type n_left = n; - BOOST_TRY{ - for(; n_left--; ++p){ - alloc_traits::construct(this->a_, container_detail::to_raw_pointer(&*p)); - } - } - BOOST_CATCH(...){ - for(; orig_p != p; ++orig_p){ - alloc_traits::destroy(this->a_, container_detail::to_raw_pointer(&*orig_p++)); - } - BOOST_RETHROW - } - BOOST_CATCH_END - } + void uninitialized_copy_n_and_update(Iterator p, size_type n) const + { boost::container::uninitialized_default_alloc_n(this->a_, n, p); } - void copy_n_and_update(Iterator, size_type) + void copy_n_and_update(Iterator, size_type) const { BOOST_ASSERT(false); } @@ -123,7 +133,7 @@ struct insert_copy_proxy : a_(a), v_(v) {} - void uninitialized_copy_n_and_update(Iterator p, size_type n) + void uninitialized_copy_n_and_update(Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; alloc_traits::construct( this->a_ @@ -132,7 +142,7 @@ struct insert_copy_proxy ); } - void copy_n_and_update(Iterator p, size_type n) + void copy_n_and_update(Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; *p =v_; @@ -154,7 +164,7 @@ struct insert_move_proxy : a_(a), v_(v) {} - void uninitialized_copy_n_and_update(Iterator p, size_type n) + void uninitialized_copy_n_and_update(Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; alloc_traits::construct( this->a_ @@ -163,7 +173,7 @@ struct insert_move_proxy ); } - void copy_n_and_update(Iterator p, size_type n) + void copy_n_and_update(Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; *p = ::boost::move(v_); diff --git a/include/boost/container/detail/allocator_version_traits.hpp b/include/boost/container/detail/allocator_version_traits.hpp index d69e61b..4cef676 100644 --- a/include/boost/container/detail/allocator_version_traits.hpp +++ b/include/boost/container/detail/allocator_version_traits.hpp @@ -18,13 +18,13 @@ #include #include #include //allocator_traits +#include #include //multiallocation_chain #include //version_type #include //allocation_type #include //integral_constant #include //pointer_traits #include //pair -#include //runtime_error #include //BOOST_TRY namespace boost { @@ -135,7 +135,7 @@ struct allocator_version_traits std::pair ret(pointer(), false); if(!(command & allocate_new)){ if(!(command & nothrow_allocation)){ - throw std::runtime_error("version 1 allocator without allocate_new flag"); + throw_logic_error("version 1 allocator without allocate_new flag"); } } else{ diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 2af12d4..90f0352 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -33,6 +33,9 @@ #include #include #include +#ifdef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER +#include +#endif #include namespace boost { @@ -73,10 +76,19 @@ class flat_tree_value_compare template struct get_flat_tree_iterators { + #ifdef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + typedef Pointer iterator; + typedef typename boost::intrusive:: + pointer_traits::element_type iterator_element_type; + typedef typename boost::intrusive:: + pointer_traits:: template + rebind_pointer::type const_iterator; + #else //BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER typedef typename container_detail:: vector_iterator iterator; typedef typename container_detail:: vector_const_iterator const_iterator; + #endif //BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; }; @@ -145,7 +157,7 @@ class flat_tree void swap(Data &d) { value_compare& mycomp = *this, & othercomp = d; - container_detail::do_swap(mycomp, othercomp); + boost::container::swap_dispatch(mycomp, othercomp); this->m_vect.swap(d.m_vect); } @@ -785,7 +797,7 @@ class flat_tree const value_compare &value_comp = this->m_data; commit_data.position = this->priv_lower_bound(b, e, KeyOfValue()(val)); return std::pair - ( *reinterpret_cast(&commit_data.position) + ( iterator(vector_iterator_get_ptr(commit_data.position)) , commit_data.position == e || value_comp(val, *commit_data.position)); } @@ -813,10 +825,10 @@ class flat_tree if(pos != this->cbegin() && !value_comp(val, pos[-1])){ if(value_comp(pos[-1], val)){ commit_data.position = pos; - return std::pair(*reinterpret_cast(&pos), true); + return std::pair(iterator(vector_iterator_get_ptr(pos)), true); } else{ - return std::pair(*reinterpret_cast(&pos), false); + return std::pair(iterator(vector_iterator_get_ptr(pos)), false); } } return this->priv_insert_unique_prepare(this->cbegin(), pos, val, commit_data); diff --git a/include/boost/container/detail/iterators.hpp b/include/boost/container/detail/iterators.hpp index f58c4ce..bba7205 100644 --- a/include/boost/container/detail/iterators.hpp +++ b/include/boost/container/detail/iterators.hpp @@ -114,7 +114,7 @@ class constant_iterator const T& operator*() const { return dereference(); } - const T& operator[] (Difference n) const + const T& operator[] (Difference ) const { return dereference(); } const T* operator->() const @@ -335,7 +335,7 @@ class repeat_iterator T& operator*() const { return dereference(); } - T& operator[] (Difference n) const + T& operator[] (Difference ) const { return dereference(); } T *operator->() const diff --git a/include/boost/container/detail/memory_util.hpp b/include/boost/container/detail/memory_util.hpp index c00172c..ac9a899 100644 --- a/include/boost/container/detail/memory_util.hpp +++ b/include/boost/container/detail/memory_util.hpp @@ -51,6 +51,12 @@ #define BOOST_PP_ITERATION_PARAMS_1 (3, (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS+1, )) #include BOOST_PP_ITERATE() +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME swap +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEGIN namespace boost { namespace container { namespace container_detail { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_PP_ITERATION_PARAMS_1 (3, (0, 1, )) +#include BOOST_PP_ITERATE() + namespace boost { namespace container { namespace container_detail { diff --git a/include/boost/container/detail/node_pool_impl.hpp b/include/boost/container/detail/node_pool_impl.hpp index 53e35ac..2103898 100644 --- a/include/boost/container/detail/node_pool_impl.hpp +++ b/include/boost/container/detail/node_pool_impl.hpp @@ -208,8 +208,6 @@ class private_node_pool_impl BOOST_ASSERT(m_allocated==0); size_type blocksize = get_rounded_size (m_real_node_size*m_nodes_per_block, (size_type)alignment_of::value); - typename blockslist_t::iterator - it(m_blocklist.begin()), itend(m_blocklist.end()), aux; //We iterate though the NodeBlock list to free the memory while(!m_blocklist.empty()){ diff --git a/include/boost/container/detail/utilities.hpp b/include/boost/container/detail/utilities.hpp index 5c294e1..81e0ed8 100644 --- a/include/boost/container/detail/utilities.hpp +++ b/include/boost/container/detail/utilities.hpp @@ -13,22 +13,81 @@ #include "config_begin.hpp" #include +#include //for ::memcpy #include #include #include #include #include +#include +#include #include #include #include #include #include #include +#include +#include +#include +#include #include #include +#include //std::distance namespace boost { namespace container { + +////////////////////////////////////////////////////////////////////////////// +// +// swap +// +////////////////////////////////////////////////////////////////////////////// + +namespace container_swap { + +template::value > +struct has_member_swap +{ + static const bool value = boost::container::container_detail:: + has_member_function_callable_with_swap::value; +}; + +template +struct has_member_swap +{ + static const bool value = false; +}; + +} //namespace container_swap { + +template inline +typename container_detail::enable_if_c + ::value, void>::type +swap_dispatch(T &left, T &right) //swap using member swap +{ + left.swap(right); // may throw +} + +template inline +typename container_detail::enable_if_c + ::value && boost::has_move_emulation_enabled::value, void>::type + swap_dispatch(T &left, T &right) +{ + T temp(boost::move(left)); // may throw + left = boost::move(right); // may throw + right = boost::move(temp); // may throw +} + +template inline +typename container_detail::enable_if_c + ::value && !boost::has_move_emulation_enabled::value, void>::type + swap_dispatch(T &left, T &right) +{ + using std::swap; + swap(left, right); // may throw +} + namespace container_detail { template @@ -78,13 +137,6 @@ inline typename Pointer::element_type* to_raw_pointer(const Pointer &p) { return boost::container::container_detail::to_raw_pointer(p.operator->()); } -//!To avoid ADL problems with swap -template -inline void do_swap(T& x, T& y) -{ - using std::swap; - swap(x, y); -} template inline void swap_alloc(AllocatorType &, AllocatorType &, container_detail::false_type) @@ -93,7 +145,7 @@ inline void swap_alloc(AllocatorType &, AllocatorType &, container_detail::false template inline void swap_alloc(AllocatorType &l, AllocatorType &r, container_detail::true_type) -{ container_detail::do_swap(l, r); } +{ boost::container::swap_dispatch(l, r); } template inline void assign_alloc(AllocatorType &, const AllocatorType &, container_detail::false_type) @@ -126,7 +178,175 @@ struct ct_rounded_size enum { value = ((OrigSize-1)/RoundTo+1)*RoundTo }; }; +template +struct are_elements_contiguous +{ + static const bool value = false; +}; + +///////////////////////// +// raw pointers +///////////////////////// + +template +struct are_elements_contiguous +{ + static const bool value = true; +}; + +///////////////////////// +// predeclarations +///////////////////////// + +#ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + +template +class vector_iterator; + +template +class vector_const_iterator; + +#endif //BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + } //namespace container_detail { +} //namespace container { + +namespace interprocess { + +template +class offset_ptr; + +} //namespace interprocess { + +namespace container { + +namespace container_detail { + +///////////////////////// +//vector_[const_]iterator +///////////////////////// + +#ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + +template +struct are_elements_contiguous > +{ + static const bool value = true; +}; + +template +struct are_elements_contiguous > +{ + static const bool value = true; +}; + +#endif //BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + +///////////////////////// +// offset_ptr +///////////////////////// + +template +struct are_elements_contiguous< ::boost::interprocess::offset_ptr > +{ + static const bool value = true; +}; + +template +struct are_contiguous_and_same +{ + static const bool is_same_io = + is_same< typename remove_const< typename ::std::iterator_traits::value_type >::type + , typename ::std::iterator_traits::value_type + >::value; + static const bool value = is_same_io && + are_elements_contiguous::value && + are_elements_contiguous::value; +}; + +template +struct is_memcpy_copy_assignable +{ + static const bool value = are_contiguous_and_same::value && + boost::has_trivial_assign< typename ::std::iterator_traits::value_type >::value; +}; + +template +struct is_memcpy_copy_constructible +{ + static const bool value = are_contiguous_and_same::value && + boost::has_trivial_copy< typename ::std::iterator_traits::value_type >::value; +}; + +template +struct enable_if_memcpy_copy_constructible + : public enable_if_c::value, R> +{}; + +template +struct disable_if_memcpy_copy_constructible + : public enable_if_c::value, R> +{}; + +template +struct enable_if_memcpy_copy_assignable + : public enable_if_c::value, R> +{}; + +template +struct disable_if_memcpy_copy_assignable + : public enable_if_c::value, R> +{}; + +template + // F models ForwardIterator +inline F memcpy(I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ + typedef typename std::iterator_traits::value_type value_type; + typename std::iterator_traits::difference_type n = std::distance(f, l); + ::memcpy(container_detail::addressof(*r), container_detail::addressof(*f), sizeof(value_type)*n); + std::advance(r, n); + return r; +} + +template + // F models ForwardIterator +F memcpy_n(I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ + typedef typename std::iterator_traits::value_type value_type; + ::memcpy(container_detail::addressof(*r), container_detail::addressof(*f), sizeof(value_type)*n); + std::advance(r, n); + return r; +} + +template + // F models ForwardIterator +I memcpy_n_source(I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ + typedef typename std::iterator_traits::value_type value_type; + ::memcpy(container_detail::addressof(*r), container_detail::addressof(*f), sizeof(value_type)*n); + std::advance(f, n); + return f; +} + +template + // F models ForwardIterator +I memcpy_n_source_dest(I f, typename std::iterator_traits::difference_type n, F &r) BOOST_CONTAINER_NOEXCEPT +{ + typedef typename std::iterator_traits::value_type value_type; + ::memcpy(container_detail::addressof(*r), container_detail::addressof(*f), sizeof(value_type)*n); + std::advance(f, n); + std::advance(r, n); + return f; +} + + +} //namespace container_detail { + ////////////////////////////////////////////////////////////////////////////// // @@ -134,18 +354,20 @@ struct ct_rounded_size // ////////////////////////////////////////////////////////////////////////////// + //! Effects: //! \code -//! for (; first != last; ++result, ++first) -//! allocator_traits::construct(a, &*result, boost::move(*first)); +//! for (; f != l; ++r, ++f) +//! allocator_traits::construct(a, &*r, boost::move(*f)); //! \endcode //! -//! Returns: result +//! Returns: r template // F models ForwardIterator -F uninitialized_move_alloc(A &a, I f, I l, F r) +inline typename container_detail::disable_if_memcpy_copy_constructible::type + uninitialized_move_alloc(A &a, I f, I l, F r) { F back = r; BOOST_TRY{ @@ -164,6 +386,14 @@ F uninitialized_move_alloc(A &a, I f, I l, F r) return r; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_constructible::type + uninitialized_move_alloc(A &, I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy(f, l, r); } + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_move_alloc_n @@ -172,16 +402,17 @@ F uninitialized_move_alloc(A &a, I f, I l, F r) //! Effects: //! \code -//! for (; n--; ++result, ++first) -//! allocator_traits::construct(a, &*result, boost::move(*first)); +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r, boost::move(*f)); //! \endcode //! -//! Returns: result +//! Returns: r template // F models ForwardIterator -F uninitialized_move_alloc_n(A &a, I f, typename std::iterator_traits::difference_type n, F r) +inline typename container_detail::disable_if_memcpy_copy_constructible::type + uninitialized_move_alloc_n(A &a, I f, typename std::iterator_traits::difference_type n, F r) { F back = r; BOOST_TRY{ @@ -200,6 +431,14 @@ F uninitialized_move_alloc_n(A &a, I f, typename std::iterator_traits::differ return r; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_constructible::type + uninitialized_move_alloc_n(A &, I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n(f, n, r); } + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_move_alloc_n_source @@ -208,16 +447,17 @@ F uninitialized_move_alloc_n(A &a, I f, typename std::iterator_traits::differ //! Effects: //! \code -//! for (; n--; ++result, ++first) -//! allocator_traits::construct(a, &*result, boost::move(*first)); +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r, boost::move(*f)); //! \endcode //! -//! Returns: first (after incremented) +//! Returns: f (after incremented) template // F models ForwardIterator -I uninitialized_move_alloc_n_source(A &a, I f, typename std::iterator_traits::difference_type n, F r) +inline typename container_detail::disable_if_memcpy_copy_constructible::type + uninitialized_move_alloc_n_source(A &a, I f, typename std::iterator_traits::difference_type n, F r) { F back = r; BOOST_TRY{ @@ -236,6 +476,14 @@ I uninitialized_move_alloc_n_source(A &a, I f, typename std::iterator_traits: return f; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_constructible::type + uninitialized_move_alloc_n_source(A &, I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n_source(f, n, r); } + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_copy_alloc @@ -244,16 +492,17 @@ I uninitialized_move_alloc_n_source(A &a, I f, typename std::iterator_traits: //! Effects: //! \code -//! for (; first != last; ++result, ++first) -//! allocator_traits::construct(a, &*result, *first); +//! for (; f != l; ++r, ++f) +//! allocator_traits::construct(a, &*r, *f); //! \endcode //! -//! Returns: result +//! Returns: r template // F models ForwardIterator -F uninitialized_copy_alloc(A &a, I f, I l, F r) +inline typename container_detail::disable_if_memcpy_copy_constructible::type + uninitialized_copy_alloc(A &a, I f, I l, F r) { F back = r; BOOST_TRY{ @@ -272,6 +521,14 @@ F uninitialized_copy_alloc(A &a, I f, I l, F r) return r; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_constructible::type + uninitialized_copy_alloc(A &, I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy(f, l, r); } + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_copy_alloc_n @@ -280,16 +537,17 @@ F uninitialized_copy_alloc(A &a, I f, I l, F r) //! Effects: //! \code -//! for (; n--; ++result, ++first) -//! allocator_traits::construct(a, &*result, *first); +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r, *f); //! \endcode //! -//! Returns: result +//! Returns: r template // F models ForwardIterator -F uninitialized_copy_alloc_n(A &a, I f, typename std::iterator_traits::difference_type n, F r) +inline typename container_detail::disable_if_memcpy_copy_constructible::type + uninitialized_copy_alloc_n(A &a, I f, typename std::iterator_traits::difference_type n, F r) { F back = r; BOOST_TRY{ @@ -308,6 +566,14 @@ F uninitialized_copy_alloc_n(A &a, I f, typename std::iterator_traits::differ return r; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_constructible::type + uninitialized_copy_alloc_n(A &, I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n(f, n, r); } + ////////////////////////////////////////////////////////////////////////////// // // uninitialized_copy_alloc_n_source @@ -316,16 +582,17 @@ F uninitialized_copy_alloc_n(A &a, I f, typename std::iterator_traits::differ //! Effects: //! \code -//! for (; n--; ++result, ++first) -//! allocator_traits::construct(a, &*result, *first); +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r, *f); //! \endcode //! -//! Returns: first (after incremented) +//! Returns: f (after incremented) template // F models ForwardIterator -I uninitialized_copy_alloc_n_source(A &a, I f, typename std::iterator_traits::difference_type n, F r) +inline typename container_detail::disable_if_memcpy_copy_constructible::type + uninitialized_copy_alloc_n_source(A &a, I f, typename std::iterator_traits::difference_type n, F r) { F back = r; BOOST_TRY{ @@ -344,24 +611,67 @@ I uninitialized_copy_alloc_n_source(A &a, I f, typename std::iterator_traits: return f; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_constructible::type + uninitialized_copy_alloc_n_source(A &, I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n_source(f, n, r); } + ////////////////////////////////////////////////////////////////////////////// // -// uninitialized_copy_alloc +// uninitialized_default_alloc_n // ////////////////////////////////////////////////////////////////////////////// //! Effects: //! \code -//! for (; first != last; ++result, ++first) -//! allocator_traits::construct(a, &*result, *first); +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r); //! \endcode //! -//! Returns: result +//! Returns: r +template + // F models ForwardIterator +inline F uninitialized_default_alloc_n(A &a, typename allocator_traits::difference_type n, F r) +{ + F back = r; + BOOST_TRY{ + while (n--) { + allocator_traits::construct(a, container_detail::to_raw_pointer(&*r)); + ++r; + } + } + BOOST_CATCH(...){ + for (; back != r; ++back){ + allocator_traits::destroy(a, container_detail::to_raw_pointer(&*back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END + return r; +} + +////////////////////////////////////////////////////////////////////////////// +// +// uninitialized_fill_alloc +// +////////////////////////////////////////////////////////////////////////////// + +//! Effects: +//! \code +//! for (; f != l; ++r, ++f) +//! allocator_traits::construct(a, &*r, *f); +//! \endcode +//! +//! Returns: r template -void uninitialized_fill_alloc(A &a, F f, F l, const T &t) +inline void uninitialized_fill_alloc(A &a, F f, F l, const T &t) { F back = f; BOOST_TRY{ @@ -379,109 +689,158 @@ void uninitialized_fill_alloc(A &a, F f, F l, const T &t) BOOST_CATCH_END } + ////////////////////////////////////////////////////////////////////////////// // -// uninitialized_copy_or_move_alloc +// uninitialized_fill_alloc_n // ////////////////////////////////////////////////////////////////////////////// +//! Effects: +//! \code +//! for (; n--; ++r, ++f) +//! allocator_traits::construct(a, &*r, v); +//! \endcode +//! +//! Returns: r template - // F models ForwardIterator -F uninitialized_copy_or_move_alloc - (A &a, I f, I l, F r - ,typename boost::container::container_detail::enable_if - < boost::move_detail::is_move_iterator >::type* = 0) + // F models ForwardIterator +inline F uninitialized_fill_alloc_n(A &a, const T &v, typename allocator_traits::difference_type n, F r) { - return ::boost::container::uninitialized_move_alloc(a, f, l, r); -} - -template - // F models ForwardIterator -F uninitialized_copy_or_move_alloc - (A &a, I f, I l, F r - ,typename boost::container::container_detail::disable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - return ::boost::container::uninitialized_copy_alloc(a, f, l, r); + F back = r; + BOOST_TRY{ + while (n--) { + allocator_traits::construct(a, container_detail::to_raw_pointer(&*r), v); + ++r; + } + } + BOOST_CATCH(...){ + for (; back != r; ++back){ + allocator_traits::destroy(a, container_detail::to_raw_pointer(&*back)); + } + BOOST_RETHROW; + } + BOOST_CATCH_END + return r; } ////////////////////////////////////////////////////////////////////////////// // -// uninitialized_copy_or_move_alloc_n +// copy // ////////////////////////////////////////////////////////////////////////////// template - // F models ForwardIterator -F uninitialized_copy_or_move_alloc_n - (A &a, I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::enable_if - < boost::move_detail::is_move_iterator >::type* = 0) + // F models ForwardIterator +inline typename container_detail::disable_if_memcpy_copy_assignable::type + copy(I f, I l, F r) { - return ::boost::container::uninitialized_move_alloc_n(a, f, n, r); + while (f != l) { + *r = *f; + ++f; ++r; + } + return r; } template - // F models ForwardIterator -F uninitialized_copy_or_move_alloc_n - (A &a, I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::disable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - return ::boost::container::uninitialized_copy_alloc_n(a, f, n, r); -} - + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + copy(I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy(f, l, r); } ////////////////////////////////////////////////////////////////////////////// // -// uninitialized_copy_or_move_alloc_n_source -// -////////////////////////////////////////////////////////////////////////////// - -template - // F models ForwardIterator -I uninitialized_copy_or_move_alloc_n_source - (A &a, I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::enable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - return ::boost::container::uninitialized_move_alloc_n_source(a, f, n, r); -} - -template - // F models ForwardIterator -I uninitialized_copy_or_move_alloc_n_source - (A &a, I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::disable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - return ::boost::container::uninitialized_copy_alloc_n_source(a, f, n, r); -} - -////////////////////////////////////////////////////////////////////////////// -// -// copy_or_move +// copy_n // ////////////////////////////////////////////////////////////////////////////// template // F models ForwardIterator -inline F copy_or_move(I f, I l, F r - ,typename boost::container::container_detail::enable_if - < boost::move_detail::is_move_iterator >::type* = 0) +inline typename container_detail::disable_if_memcpy_copy_assignable::type + copy_n(I f, typename std::iterator_traits::difference_type n, F r) +{ + while (n--) { + *r = *f; + ++f; ++r; + } + return r; +} + +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + copy_n(I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// copy_n_source +// +////////////////////////////////////////////////////////////////////////////// + +template + // F models ForwardIterator +inline typename container_detail::disable_if_memcpy_copy_assignable::type + copy_n_source(I f, typename std::iterator_traits::difference_type n, F r) +{ + while (n--) { + *r = *f; + ++f; ++r; + } + return f; +} + +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + copy_n_source(I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n_source(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// copy_n_source_dest +// +////////////////////////////////////////////////////////////////////////////// + +template + // F models ForwardIterator +inline typename container_detail::disable_if_memcpy_copy_assignable::type + copy_n_source_dest(I f, typename std::iterator_traits::difference_type n, F &r) +{ + while (n--) { + *r = *f; + ++f; ++r; + } + return f; +} + +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + copy_n_source_dest(I f, typename std::iterator_traits::difference_type n, F &r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n_source_dest(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// move +// +////////////////////////////////////////////////////////////////////////////// + +template + // F models ForwardIterator +inline typename container_detail::disable_if_memcpy_copy_assignable::type + move(I f, I l, F r) { while (f != l) { *r = ::boost::move(*f); @@ -493,29 +852,21 @@ inline F copy_or_move(I f, I l, F r template // F models ForwardIterator -inline F copy_or_move(I f, I l, F r - ,typename boost::container::container_detail::disable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - while (f != l) { - *r = *f; - ++f; ++r; - } - return r; -} +inline typename container_detail::enable_if_memcpy_copy_assignable::type + move(I f, I l, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy(f, l, r); } ////////////////////////////////////////////////////////////////////////////// // -// copy_or_move_n +// move_n // ////////////////////////////////////////////////////////////////////////////// template // F models ForwardIterator -inline F copy_or_move_n(I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::enable_if - < boost::move_detail::is_move_iterator >::type* = 0) +inline typename container_detail::disable_if_memcpy_copy_assignable::type + move_n(I f, typename std::iterator_traits::difference_type n, F r) { while (n--) { *r = ::boost::move(*f); @@ -527,29 +878,21 @@ inline F copy_or_move_n(I f, typename std::iterator_traits::difference_type n template // F models ForwardIterator -inline F copy_or_move_n(I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::disable_if - < boost::move_detail::is_move_iterator >::type* = 0) -{ - while (n--) { - *r = *f; - ++f; ++r; - } - return r; -} +inline typename container_detail::enable_if_memcpy_copy_assignable::type + move_n(I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n(f, n, r); } ////////////////////////////////////////////////////////////////////////////// // -// copy_or_move_n_source +// move_n_source // ////////////////////////////////////////////////////////////////////////////// template - // F models ForwardIterator -inline I copy_or_move_n_source(I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::enable_if - < boost::move_detail::is_move_iterator >::type* = 0) + // F models ForwardIterator +inline typename container_detail::disable_if_memcpy_copy_assignable::type + move_n_source(I f, typename std::iterator_traits::difference_type n, F r) { while (n--) { *r = ::boost::move(*f); @@ -559,23 +902,240 @@ inline I copy_or_move_n_source(I f, typename std::iterator_traits::difference } template - // F models ForwardIterator -inline I copy_or_move_n_source(I f, typename std::iterator_traits::difference_type n, F r - ,typename boost::container::container_detail::disable_if - < boost::move_detail::is_move_iterator >::type* = 0) + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + move_n_source(I f, typename std::iterator_traits::difference_type n, F r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n_source(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// move_n_source_dest +// +////////////////////////////////////////////////////////////////////////////// + +template + // F models ForwardIterator +inline typename container_detail::disable_if_memcpy_copy_assignable::type + move_n_source_dest(I f, typename std::iterator_traits::difference_type n, F &r) { while (n--) { - *r = *f; + *r = ::boost::move(*f); ++f; ++r; } return f; } +template + // F models ForwardIterator +inline typename container_detail::enable_if_memcpy_copy_assignable::type + move_n_source_dest(I f, typename std::iterator_traits::difference_type n, F &r) BOOST_CONTAINER_NOEXCEPT +{ return container_detail::memcpy_n_source_dest(f, n, r); } + +////////////////////////////////////////////////////////////////////////////// +// +// destroy_n +// +////////////////////////////////////////////////////////////////////////////// + +template + // I models InputIterator +inline void destroy_alloc_n(A &a, I f, typename std::iterator_traits::difference_type n + ,typename boost::container::container_detail::enable_if_c + < !boost::has_trivial_destructor::value_type>::value >::type* = 0) +{ + while(n--){ + allocator_traits::destroy(a, container_detail::addressof(*f++)); + } +} + +template + // I models InputIterator +inline void destroy_alloc_n(A &, I, typename std::iterator_traits::difference_type + ,typename boost::container::container_detail::enable_if_c + < boost::has_trivial_destructor::value_type>::value >::type* = 0) +{} + +////////////////////////////////////////////////////////////////////////////// +// +// deep_swap_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +template + +inline typename container_detail::disable_if_memcpy_copy_assignable::type + deep_swap_alloc_n( A &a, F short_range_f, typename allocator_traits::size_type n_i + , G large_range_f, typename allocator_traits::size_type n_j) +{ + typename allocator_traits::size_type n = 0; + for (; n != n_i ; ++short_range_f, ++large_range_f, ++n){ + boost::container::swap_dispatch(*short_range_f, *large_range_f); + } + boost::container::uninitialized_move_alloc_n(a, large_range_f, n_j - n_i, short_range_f); // may throw + boost::container::destroy_alloc_n(a, large_range_f, n_j - n_i); +} + +static const std::size_t DeepSwapAllocNMaxStorage = std::size_t(1) << std::size_t(11); //2K bytes + +template + +inline typename container_detail::enable_if_c + < container_detail::is_memcpy_copy_assignable::value && (MaxTmpBytes <= DeepSwapAllocNMaxStorage) && false + , void>::type + deep_swap_alloc_n( A &a, F short_range_f, typename allocator_traits::size_type n_i + , G large_range_f, typename allocator_traits::size_type n_j) +{ + typedef typename allocator_traits::value_type value_type; + typedef typename boost::aligned_storage + ::value>::type storage_type; + storage_type storage; + + const std::size_t n_i_bytes = sizeof(value_type)*n_i; + unsigned char *const large_ptr = static_cast(static_cast(container_detail::addressof(*large_range_f))); + unsigned char *const short_ptr = static_cast(static_cast(container_detail::addressof(*short_range_f))); + unsigned char *const stora_ptr = static_cast(static_cast(container_detail::addressof(storage))); + ::memcpy(stora_ptr, large_ptr, n_i_bytes); + ::memcpy(large_ptr, short_ptr, n_i_bytes); + ::memcpy(short_ptr, stora_ptr, n_i_bytes); + std::advance(large_range_f, n_i); + std::advance(short_range_f, n_i); + boost::container::uninitialized_move_alloc_n(a, large_range_f, n_j - n_i, short_range_f); // may throw + boost::container::destroy_alloc_n(a, large_range_f, n_j - n_i); +} + +template + +inline typename container_detail::enable_if_c + < container_detail::is_memcpy_copy_assignable::value && true//(MaxTmpBytes > DeepSwapAllocNMaxStorage) + , void>::type + deep_swap_alloc_n( A &a, F short_range_f, typename allocator_traits::size_type n_i + , G large_range_f, typename allocator_traits::size_type n_j) +{ + typedef typename allocator_traits::value_type value_type; + typedef typename boost::aligned_storage + ::value>::type storage_type; + storage_type storage; + const std::size_t sizeof_storage = sizeof(storage); + + std::size_t n_i_bytes = sizeof(value_type)*n_i; + char *large_ptr = static_cast(static_cast(container_detail::addressof(*large_range_f))); + char *short_ptr = static_cast(static_cast(container_detail::addressof(*short_range_f))); + char *stora_ptr = static_cast(static_cast(container_detail::addressof(storage))); + + std::size_t szt_times = n_i_bytes/sizeof_storage; + const std::size_t szt_rem = n_i_bytes%sizeof_storage; + + //Loop unrolling using Duff's device, as it seems it helps on some architectures + const std::size_t Unroll = 4; + std::size_t n = (szt_times + (Unroll-1))/Unroll; + const std::size_t branch_number = ((!szt_times)*Unroll) + (szt_times % Unroll); + switch(branch_number){ + case 4: + break; + case 0: do{ + ::memcpy(stora_ptr, large_ptr, sizeof_storage); + ::memcpy(large_ptr, short_ptr, sizeof_storage); + ::memcpy(short_ptr, stora_ptr, sizeof_storage); + large_ptr += sizeof_storage; + short_ptr += sizeof_storage; + case 3: + ::memcpy(stora_ptr, large_ptr, sizeof_storage); + ::memcpy(large_ptr, short_ptr, sizeof_storage); + ::memcpy(short_ptr, stora_ptr, sizeof_storage); + large_ptr += sizeof_storage; + short_ptr += sizeof_storage; + case 2: + ::memcpy(stora_ptr, large_ptr, sizeof_storage); + ::memcpy(large_ptr, short_ptr, sizeof_storage); + ::memcpy(short_ptr, stora_ptr, sizeof_storage); + large_ptr += sizeof_storage; + short_ptr += sizeof_storage; + case 1: + ::memcpy(stora_ptr, large_ptr, sizeof_storage); + ::memcpy(large_ptr, short_ptr, sizeof_storage); + ::memcpy(short_ptr, stora_ptr, sizeof_storage); + large_ptr += sizeof_storage; + short_ptr += sizeof_storage; + } while(--n); + } + ::memcpy(stora_ptr, large_ptr, szt_rem); + ::memcpy(large_ptr, short_ptr, szt_rem); + ::memcpy(short_ptr, stora_ptr, szt_rem); + std::advance(large_range_f, n_i); + std::advance(short_range_f, n_i); + boost::container::uninitialized_move_alloc_n(a, large_range_f, n_j - n_i, short_range_f); // may throw + boost::container::destroy_alloc_n(a, large_range_f, n_j - n_i); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// copy_assign_range_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +template + +void copy_assign_range_alloc_n( A &a, I inp_start, typename allocator_traits::size_type n_i + , O out_start, typename allocator_traits::size_type n_o ) +{ + if (n_o < n_i){ + inp_start = boost::container::copy_n_source_dest(inp_start, n_o, out_start); // may throw + boost::container::uninitialized_copy_alloc_n(a, inp_start, n_i - n_o, out_start);// may throw + } + else{ + out_start = boost::container::copy_n(inp_start, n_i, out_start); // may throw + boost::container::destroy_alloc_n(a, out_start, n_o - n_i); + } +} + +////////////////////////////////////////////////////////////////////////////// +// +// move_assign_range_alloc_n +// +////////////////////////////////////////////////////////////////////////////// + +template + +void move_assign_range_alloc_n( A &a, I inp_start, typename allocator_traits::size_type n_i + , O out_start, typename allocator_traits::size_type n_o ) +{ + if (n_o < n_i){ + inp_start = boost::container::move_n_source_dest(inp_start, n_o, out_start); // may throw + boost::container::uninitialized_move_alloc_n(a, inp_start, n_i - n_o, out_start); // may throw + } + else{ + out_start = boost::container::move_n(inp_start, n_i, out_start); // may throw + boost::container::destroy_alloc_n(a, out_start, n_o - n_i); + } +} + } //namespace container { } //namespace boost { - #include #endif //#ifndef BOOST_CONTAINER_DETAIL_UTILITIES_HPP diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index 2dd2210..8bb372f 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -22,13 +22,14 @@ #include #include #include -#include #include #include #include #include +#include #include #include +#include namespace boost { namespace container { @@ -478,7 +479,7 @@ class flat_map { iterator i = this->find(k); if(i == this->end()){ - throw std::out_of_range("key not found"); + throw_out_of_range("flat_map::at key not found"); } return i->second; } @@ -492,7 +493,7 @@ class flat_map { const_iterator i = this->find(k); if(i == this->end()){ - throw std::out_of_range("key not found"); + throw_out_of_range("flat_map::at key not found"); } return i->second; } diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index 571e63a..79f4a6b 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -36,13 +37,11 @@ #include #endif -#include #include #include #include #include #include -#include namespace boost { namespace container { diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index d4ab423..b1faf49 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -30,10 +29,12 @@ #include #include #include +#include #include #include #include #include +#include namespace boost { namespace container { @@ -423,7 +424,7 @@ class map { iterator i = this->find(k); if(i == this->end()){ - throw std::out_of_range("key not found"); + throw_out_of_range("map::at key not found"); } return i->second; } @@ -435,7 +436,7 @@ class map { const_iterator i = this->find(k); if(i == this->end()){ - throw std::out_of_range("key not found"); + throw_out_of_range("map::at key not found"); } return i->second; } diff --git a/include/boost/container/scoped_allocator.hpp b/include/boost/container/scoped_allocator.hpp index 39fd4da..022c73e 100644 --- a/include/boost/container/scoped_allocator.hpp +++ b/include/boost/container/scoped_allocator.hpp @@ -584,6 +584,7 @@ class scoped_allocator_adaptor_base typedef OuterAlloc outer_allocator_type; typedef scoped_allocator_adaptor inner_allocator_type; + typedef allocator_traits inner_traits_type; typedef boost::integral_constant< bool, outer_traits_type::propagate_on_container_copy_assignment::value || @@ -723,6 +724,7 @@ class scoped_allocator_adaptor_base inner_allocator_type; \ + typedef allocator_traits inner_traits_type; \ typedef boost::integral_constant< \ bool, \ outer_traits_type::propagate_on_container_copy_assignment::value || \ @@ -860,6 +862,7 @@ class scoped_allocator_adaptor_base typedef OuterAlloc outer_allocator_type; typedef allocator_traits outer_traits_type; typedef scoped_allocator_adaptor inner_allocator_type; + typedef allocator_traits inner_traits_type; typedef typename outer_traits_type:: propagate_on_container_copy_assignment propagate_on_container_copy_assignment; typedef typename outer_traits_type:: @@ -1029,6 +1032,7 @@ class scoped_allocator_adaptor //! Type: `scoped_allocator_adaptor` if `sizeof...(InnerAllocs)` is zero; otherwise, //! `scoped_allocator_adaptor`. typedef typename base_type::inner_allocator_type inner_allocator_type; + typedef allocator_traits inner_traits_type; typedef typename outer_traits_type::value_type value_type; typedef typename outer_traits_type::size_type size_type; typedef typename outer_traits_type::difference_type difference_type; @@ -1220,7 +1224,7 @@ class scoped_allocator_adaptor return scoped_allocator_adaptor (internal_type_t() ,outer_traits_type::select_on_container_copy_construction(this->outer_allocator()) - ,outer_traits_type::select_on_container_copy_construction(this->inner_allocator()) + ,inner_traits_type::select_on_container_copy_construction(this->inner_allocator()) ); } /// @cond diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index 84cccda..a9a4f67 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -37,7 +38,6 @@ #include #endif -#include #include #include #include @@ -169,7 +169,7 @@ class slist_iterator { return this->m_it->m_data; } pointer operator->() const - { return ::boost::intrusive::pointer_traits::to_pointer(this->m_it->m_data); } + { return ::boost::intrusive::pointer_traits::pointer_to(this->m_it->m_data); } //Increment / Decrement slist_iterator& operator++() diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index 539b2da..3da8c64 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -1,4 +1,4 @@ - +////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost // Software License, Version 1.0. (See accompanying file @@ -29,18 +29,21 @@ #include #include #include +#include #include #include #include #include #include +#include #include +#include #include #include #include #include #include //max -#include + #include #include //placement new @@ -330,7 +333,8 @@ struct index_traits static void readjust_end_node(index_type &index, node_base_type &end_node) { if(!index.empty()){ - node_base_ptr &end_node_idx_ref = *(--index_traits::get_fix_up_end(index)); + index_iterator end_node_it(index_traits::get_fix_up_end(index)); + node_base_ptr &end_node_idx_ref = *(--end_node_it); end_node_idx_ref = node_base_ptr_traits::pointer_to(end_node); end_node.up = node_base_ptr_ptr_traits::pointer_to(end_node_idx_ref); } @@ -942,7 +946,7 @@ class stable_vector size_type size() const BOOST_CONTAINER_NOEXCEPT { const size_type index_size = this->index.size(); - return index_size ? (index_size - ExtraPointers) : 0; + return (index_size - ExtraPointers) & (std::size_t(0u) -std::size_t(index_size != 0)); } //! Effects: Returns the largest possible size of the stable_vector. @@ -998,7 +1002,9 @@ class stable_vector const size_type node_extra_capacity = this->internal_data.pool_size; const size_type extra_capacity = (bucket_extra_capacity < node_extra_capacity) ? bucket_extra_capacity : node_extra_capacity; - return (index_size ? (index_size - ExtraPointers + extra_capacity) : index_size); + const size_type index_offset = + (ExtraPointers + extra_capacity) & (size_type(0u) - size_type(index_size != 0)); + return index_size - index_offset; } //! Effects: If n is less than or equal to capacity(), this call has no @@ -1010,8 +1016,9 @@ class stable_vector void reserve(size_type n) { STABLE_VECTOR_CHECK_INVARIANT; - if(n > this->max_size()) - throw std::bad_alloc(); + if(n > this->max_size()){ + throw_length_error("stable_vector::reserve max_size() exceeded"); + } size_type sz = this->size(); size_type old_capacity = this->capacity(); @@ -1098,7 +1105,7 @@ class stable_vector //! //! Complexity: Constant. reference back() BOOST_CONTAINER_NOEXCEPT - { return static_cast(*this->index[this->size() - ExtraPointers]).value; } + { return static_cast(*this->index[this->size()-1u]).value; } //! Requires: !empty() //! @@ -1109,7 +1116,7 @@ class stable_vector //! //! Complexity: Constant. const_reference back() const BOOST_CONTAINER_NOEXCEPT - { return static_cast(*this->index[this->size() - ExtraPointers]).value; } + { return static_cast(*this->index[this->size()-1u]).value; } //! Requires: size() > n. //! @@ -1120,7 +1127,10 @@ class stable_vector //! //! Complexity: Constant. reference operator[](size_type n) BOOST_CONTAINER_NOEXCEPT - { return static_cast(*this->index[n]).value; } + { + BOOST_ASSERT(n < this->size()); + return static_cast(*this->index[n]).value; + } //! Requires: size() > n. //! @@ -1131,7 +1141,10 @@ class stable_vector //! //! Complexity: Constant. const_reference operator[](size_type n) const BOOST_CONTAINER_NOEXCEPT - { return static_cast(*this->index[n]).value; } + { + BOOST_ASSERT(n < this->size()); + return static_cast(*this->index[n]).value; + } //! Requires: size() > n. //! @@ -1143,8 +1156,9 @@ class stable_vector //! Complexity: Constant. reference at(size_type n) { - if(n>=this->size()) - throw std::out_of_range("invalid subscript at stable_vector::at"); + if(n >= this->size()){ + throw_out_of_range("vector::at invalid subscript"); + } return operator[](n); } @@ -1158,8 +1172,9 @@ class stable_vector //! Complexity: Constant. const_reference at(size_type n)const { - if(n>=this->size()) - throw std::out_of_range("invalid subscript at stable_vector::at"); + if(n >= this->size()){ + throw_out_of_range("vector::at invalid subscript"); + } return operator[](n); } @@ -1705,7 +1720,7 @@ class stable_vector void priv_swap_members(stable_vector &x) { - container_detail::do_swap(this->internal_data.pool_size, x.internal_data.pool_size); + boost::container::swap_dispatch(this->internal_data.pool_size, x.internal_data.pool_size); index_traits_type::readjust_end_node(this->index, this->internal_data.end_node); index_traits_type::readjust_end_node(x.index, x.internal_data.end_node); } diff --git a/include/boost/container/static_vector.hpp b/include/boost/container/static_vector.hpp new file mode 100644 index 0000000..020a208 --- /dev/null +++ b/include/boost/container/static_vector.hpp @@ -0,0 +1,1056 @@ +// Boost.Container static_vector +// +// Copyright (c) 2012-2013 Adam Wulkiewicz, Lodz, Poland. +// Copyright (c) 2011-2013 Andrew Hundt. +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONTAINER_STATIC_VECTOR_HPP +#define BOOST_CONTAINER_STATIC_VECTOR_HPP + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +#include +#include + +namespace boost { namespace container { + +/** + * @defgroup static_vector_non_member static_vector non-member functions + */ + +/** + * @brief A variable-size array container with fixed capacity. + * + * static_vector is a sequence container like boost::container::vector with contiguous storage that can + * change in size, along with the static allocation, low overhead, and fixed capacity of boost::array. + * + * A static_vector is a sequence that supports random access to elements, constant time insertion and + * removal of elements at the end, and linear time insertion and removal of elements at the beginning or + * in the middle. The number of elements in a static_vector may vary dynamically up to a fixed capacity + * because elements are stored within the object itself similarly to an array. However, objects are + * initialized as they are inserted into static_vector unlike C arrays or std::array which must construct + * all elements on instantiation. The behavior of static_vector enables the use of statically allocated + * elements in cases with complex object lifetime requirements that would otherwise not be trivially + * possible. + * + * @par Error Handling + * Insertion beyond the capacity and out of bounds errors results in calling throw_bad_alloc(). + * The reason for this is because unlike vectors, static_vector does not perform allocation. + * + * @tparam Value The type of element that will be stored. + * @tparam Capacity The maximum number of elements static_vector can store, fixed at compile time. + */ + + +namespace container_detail { + +template +class static_storage_allocator +{ + public: + typedef T value_type; + + static_storage_allocator() BOOST_CONTAINER_NOEXCEPT + {} + + static_storage_allocator(const static_storage_allocator &) BOOST_CONTAINER_NOEXCEPT + {} + + static_storage_allocator & operator=(const static_storage_allocator &) BOOST_CONTAINER_NOEXCEPT + {} + + T* internal_storage() const BOOST_CONTAINER_NOEXCEPT + { return const_cast(static_cast(static_cast(&storage))); } + + T* internal_storage() BOOST_CONTAINER_NOEXCEPT + { return static_cast(static_cast(&storage)); } + + static const std::size_t internal_capacity = N; + + typedef boost::container::container_detail::version_type version; + + friend bool operator==(const static_storage_allocator &, const static_storage_allocator &) BOOST_CONTAINER_NOEXCEPT + { return false; } + + friend bool operator!=(const static_storage_allocator &, const static_storage_allocator &) BOOST_CONTAINER_NOEXCEPT + { return true; } + + private: + typename boost::aligned_storage + ::value>::type storage; +}; + +} //namespace container_detail { + + +template +class static_vector + : public vector > +{ + typedef vector > base_t; + + BOOST_COPYABLE_AND_MOVABLE(static_vector) + + template + friend class static_vector; + +public: + //! @brief The type of elements stored in the container. + typedef typename base_t::value_type value_type; + //! @brief The unsigned integral type used by the container. + typedef typename base_t::size_type size_type; + //! @brief The pointers difference type. + typedef typename base_t::difference_type difference_type; + //! @brief The pointer type. + typedef typename base_t::pointer pointer; + //! @brief The const pointer type. + typedef typename base_t::const_pointer const_pointer; + //! @brief The value reference type. + typedef typename base_t::reference reference; + //! @brief The value const reference type. + typedef typename base_t::const_reference const_reference; + //! @brief The iterator type. + typedef typename base_t::iterator iterator; + //! @brief The const iterator type. + typedef typename base_t::const_iterator const_iterator; + //! @brief The reverse iterator type. + typedef typename base_t::reverse_iterator reverse_iterator; + //! @brief The const reverse iterator. + typedef typename base_t::const_reverse_iterator const_reverse_iterator; + + //! @brief Constructs an empty static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + static_vector() BOOST_CONTAINER_NOEXCEPT + : base_t() + {} + + //! @pre count <= capacity() + //! + //! @brief Constructs a static_vector containing count default constructed Values. + //! + //! @param count The number of values which will be contained in the container. + //! + //! @par Throws + //! If Value's default constructor throws. + //! + //! @par Complexity + //! Linear O(N). + explicit static_vector(size_type count) + : base_t(count) + {} + + //! @pre count <= capacity() + //! + //! @brief Constructs a static_vector containing count copies of value. + //! + //! @param count The number of copies of a values that will be contained in the container. + //! @param value The value which will be used to copy construct values. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + static_vector(size_type count, value_type const& value) + : base_t(count, value) + {} + + //! @pre + //! @li distance(first, last) <= capacity() + //! @li Iterator must meet the \c ForwardTraversalIterator concept. + //! + //! @brief Constructs a static_vector containing copy of a range [first, last). + //! + //! @param first The iterator to the first element in range. + //! @param last The iterator to the one after the last element in range. + //! + //! @par Throws + //! If Value's constructor taking a dereferenced Iterator throws. + //! + //! @par Complexity + //! Linear O(N). + template + static_vector(Iterator first, Iterator last) + : base_t(first, last) + {} + + //! @brief Constructs a copy of other static_vector. + //! + //! @param other The static_vector which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + static_vector(static_vector const& other) + : base_t(other) + {} + + //! @pre other.size() <= capacity(). + //! + //! @brief Constructs a copy of other static_vector. + //! + //! @param other The static_vector which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + template + static_vector(static_vector const& other) : base_t(other) {} + + //! @brief Copy assigns Values stored in the other static_vector to this one. + //! + //! @param other The static_vector which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + static_vector & operator=(BOOST_COPY_ASSIGN_REF(static_vector) other) + { + base_t::operator=(static_cast(other)); + return *this; + } + + //! @pre other.size() <= capacity() + //! + //! @brief Copy assigns Values stored in the other static_vector to this one. + //! + //! @param other The static_vector which content will be copied to this one. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + template +// TEMPORARY WORKAROUND +#if defined(BOOST_NO_RVALUE_REFERENCES) + static_vector & operator=(::boost::rv< static_vector > const& other) +#else + static_vector & operator=(static_vector const& other) +#endif + { + base_t::operator=(static_cast const&>(other)); + return *this; + } + + //! @brief Move constructor. Moves Values stored in the other static_vector to this one. + //! + //! @param other The static_vector which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + static_vector(BOOST_RV_REF(static_vector) other) + : base_t(boost::move(static_cast(other))) + {} + + //! @pre other.size() <= capacity() + //! + //! @brief Move constructor. Moves Values stored in the other static_vector to this one. + //! + //! @param other The static_vector which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + template + static_vector(BOOST_RV_REF_BEG static_vector BOOST_RV_REF_END other) + : base_t(boost::move(static_cast::base_t&>(other))) + {} + + //! @brief Move assignment. Moves Values stored in the other static_vector to this one. + //! + //! @param other The static_vector which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + static_vector & operator=(BOOST_RV_REF(static_vector) other) + { + base_t::operator=(boost::move(static_cast(other))); + return *this; + } + + //! @pre other.size() <= capacity() + //! + //! @brief Move assignment. Moves Values stored in the other static_vector to this one. + //! + //! @param other The static_vector which content will be moved to this one. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws. + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + template + static_vector & operator=(BOOST_RV_REF_BEG static_vector BOOST_RV_REF_END other) + { + base_t::operator=(boost::move(static_cast::base_t&>(other))); + return *this; + } + +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + + //! @brief Destructor. Destroys Values stored in this container. + //! + //! @par Throws + //! Nothing + //! + //! @par Complexity + //! Linear O(N). + ~static_vector(); + + //! @brief Swaps contents of the other static_vector and this one. + //! + //! @param other The static_vector which content will be swapped with this one's content. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws, + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws, + //! + //! @par Complexity + //! Linear O(N). + void swap(static_vector & other); + + //! @pre other.size() <= capacity() && size() <= other.capacity() + //! + //! @brief Swaps contents of the other static_vector and this one. + //! + //! @param other The static_vector which content will be swapped with this one's content. + //! + //! @par Throws + //! @li If \c boost::has_nothrow_move::value is \c true and Value's move constructor or move assignment throws, + //! @li If \c boost::has_nothrow_move::value is \c false and Value's copy constructor or copy assignment throws, + //! + //! @par Complexity + //! Linear O(N). + template + void swap(static_vector & other); + + //! @pre count <= capacity() + //! + //! @brief Inserts or erases elements at the end such that + //! the size becomes count. New elements are default constructed. + //! + //! @param count The number of elements which will be stored in the container. + //! + //! @par Throws + //! If Value's default constructor throws. + //! + //! @par Complexity + //! Linear O(N). + void resize(size_type count); + + //! @pre count <= capacity() + //! + //! @brief Inserts or erases elements at the end such that + //! the size becomes count. New elements are copy constructed from value. + //! + //! @param count The number of elements which will be stored in the container. + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Linear O(N). + void resize(size_type count, value_type const& value); + + //! @pre count <= capacity() + //! + //! @brief This call has no effect because the Capacity of this container is constant. + //! + //! @param count The number of elements which the container should be able to contain. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Linear O(N). + void reserve(size_type count) BOOST_CONTAINER_NOEXCEPT; + + //! @pre size() < capacity() + //! + //! @brief Adds a copy of value at the end. + //! + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! If Value's copy constructor throws. + //! + //! @par Complexity + //! Constant O(1). + void push_back(value_type const& value); + + //! @pre size() < capacity() + //! + //! @brief Moves value to the end. + //! + //! @param value The value to move construct the new element. + //! + //! @par Throws + //! If Value's move constructor throws. + //! + //! @par Complexity + //! Constant O(1). + void push_back(BOOST_RV_REF(value_type) value); + + //! @pre !empty() + //! + //! @brief Destroys last value and decreases the size. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + void pop_back(); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li size() < capacity() + //! + //! @brief Inserts a copy of element at position. + //! + //! @param position The position at which the new value will be inserted. + //! @param value The value used to copy construct the new element. + //! + //! @par Throws + //! @li If Value's copy constructor or copy assignment throws + //! @li If Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Constant or linear. + iterator insert(iterator position, value_type const& value); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li size() < capacity() + //! + //! @brief Inserts a move-constructed element at position. + //! + //! @param position The position at which the new value will be inserted. + //! @param value The value used to move construct the new element. + //! + //! @par Throws + //! If Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Constant or linear. + iterator insert(iterator position, BOOST_RV_REF(value_type) value); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li size() + count <= capacity() + //! + //! @brief Inserts a count copies of value at position. + //! + //! @param position The position at which new elements will be inserted. + //! @param count The number of new elements which will be inserted. + //! @param value The value used to copy construct new elements. + //! + //! @par Throws + //! @li If Value's copy constructor or copy assignment throws. + //! @li If Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + iterator insert(iterator position, size_type count, value_type const& value); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()]. + //! @li distance(first, last) <= capacity() + //! @li \c Iterator must meet the \c ForwardTraversalIterator concept. + //! + //! @brief Inserts a copy of a range [first, last) at position. + //! + //! @param position The position at which new elements will be inserted. + //! @param first The iterator to the first element of a range used to construct new elements. + //! @param last The iterator to the one after the last element of a range used to construct new elements. + //! + //! @par Throws + //! @li If Value's constructor and assignment taking a dereferenced \c Iterator. + //! @li If Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + template + iterator insert(iterator position, Iterator first, Iterator last); + + //! @pre \c position must be a valid iterator of \c *this in range [begin(), end()) + //! + //! @brief Erases Value from position. + //! + //! @param position The position of the element which will be erased from the container. + //! + //! @par Throws + //! If Value's move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + iterator erase(iterator position); + + //! @pre + //! @li \c first and \c last must define a valid range + //! @li iterators must be in range [begin(), end()] + //! + //! @brief Erases Values from a range [first, last). + //! + //! @param first The position of the first element of a range which will be erased from the container. + //! @param last The position of the one after the last element of a range which will be erased from the container. + //! + //! @par Throws + //! If Value's move assignment throws. + //! + //! @par Complexity + //! Linear O(N). + iterator erase(iterator first, iterator last); + + //! @pre distance(first, last) <= capacity() + //! + //! @brief Assigns a range [first, last) of Values to this container. + //! + //! @param first The iterator to the first element of a range used to construct new content of this container. + //! @param last The iterator to the one after the last element of a range used to construct new content of this container. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws, + //! + //! @par Complexity + //! Linear O(N). + template + void assign(Iterator first, Iterator last); + + //! @pre count <= capacity() + //! + //! @brief Assigns a count copies of value to this container. + //! + //! @param count The new number of elements which will be container in the container. + //! @param value The value which will be used to copy construct the new content. + //! + //! @par Throws + //! If Value's copy constructor or copy assignment throws. + //! + //! @par Complexity + //! Linear O(N). + void assign(size_type count, value_type const& value); + + //! @pre size() < capacity() + //! + //! @brief Inserts a Value constructed with + //! \c std::forward(args)... in the end of the container. + //! + //! @param args The arguments of the constructor of the new element which will be created at the end of the container. + //! + //! @par Throws + //! If in-place constructor throws or Value's move constructor throws. + //! + //! @par Complexity + //! Constant O(1). + template + void emplace_back(Args &&...args); + + //! @pre + //! @li \c position must be a valid iterator of \c *this in range [begin(), end()] + //! @li size() < capacity() + //! + //! @brief Inserts a Value constructed with + //! \c std::forward(args)... before position + //! + //! @param position The position at which new elements will be inserted. + //! @param args The arguments of the constructor of the new element. + //! + //! @par Throws + //! If in-place constructor throws or if Value's move constructor or move assignment throws. + //! + //! @par Complexity + //! Constant or linear. + template + iterator emplace(iterator position, Args &&...args); + + //! @brief Removes all elements from the container. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + void clear() BOOST_CONTAINER_NOEXCEPT; + + //! @pre i < size() + //! + //! @brief Returns reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! \c std::out_of_range exception by default. + //! + //! @par Complexity + //! Constant O(1). + reference at(size_type i); + + //! @pre i < size() + //! + //! @brief Returns const reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return const reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! \c std::out_of_range exception by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference at(size_type i) const; + + //! @pre i < size() + //! + //! @brief Returns reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference operator[](size_type i); + + //! @pre i < size() + //! + //! @brief Returns const reference to the i-th element. + //! + //! @param i The element's index. + //! + //! @return const reference to the i-th element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference operator[](size_type i) const; + + //! @pre \c !empty() + //! + //! @brief Returns reference to the first element. + //! + //! @return reference to the first element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference front(); + + //! @pre \c !empty() + //! + //! @brief Returns const reference to the first element. + //! + //! @return const reference to the first element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference front() const; + + //! @pre \c !empty() + //! + //! @brief Returns reference to the last element. + //! + //! @return reference to the last element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + reference back(); + + //! @pre \c !empty() + //! + //! @brief Returns const reference to the first element. + //! + //! @return const reference to the last element + //! from the beginning of the container. + //! + //! @par Throws + //! Nothing by default. + //! + //! @par Complexity + //! Constant O(1). + const_reference back() const; + + //! @brief Pointer such that [data(), data() + size()) is a valid range. + //! For a non-empty vector data() == &front(). + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + Value * data() BOOST_CONTAINER_NOEXCEPT; + + //! @brief Const pointer such that [data(), data() + size()) is a valid range. + //! For a non-empty vector data() == &front(). + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const Value * data() const BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns iterator to the first element. + //! + //! @return iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + iterator begin() BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns const iterator to the first element. + //! + //! @return const_iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator begin() const BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns const iterator to the first element. + //! + //! @return const_iterator to the first element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator cbegin() const BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns iterator to the one after the last element. + //! + //! @return iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + iterator end() BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns const iterator to the one after the last element. + //! + //! @return const_iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator end() const BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns const iterator to the one after the last element. + //! + //! @return const_iterator pointing to the one after the last element contained in the vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_iterator cend() const BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns reverse iterator to the first element of the reversed container. + //! + //! @return reverse_iterator pointing to the beginning + //! of the reversed static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + reverse_iterator rbegin() BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns const reverse iterator to the first element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the beginning + //! of the reversed static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator rbegin() const BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns const reverse iterator to the first element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the beginning + //! of the reversed static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator crbegin() const BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns reverse iterator to the one after the last element of the reversed container. + //! + //! @return reverse_iterator pointing to the one after the last element + //! of the reversed static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + reverse_iterator rend() BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns const reverse iterator to the one after the last element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the one after the last element + //! of the reversed static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator rend() const BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns const reverse iterator to the one after the last element of the reversed container. + //! + //! @return const_reverse_iterator pointing to the one after the last element + //! of the reversed static_vector. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + const_reverse_iterator crend() const BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + static size_type capacity() BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + static size_type max_size() BOOST_CONTAINER_NOEXCEPT; + + //! @brief Returns the number of stored elements. + //! + //! @return Number of elements contained in the container. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + size_type size() const BOOST_CONTAINER_NOEXCEPT; + + //! @brief Queries if the container contains elements. + //! + //! @return true if the number of elements contained in the + //! container is equal to 0. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + bool empty() const BOOST_CONTAINER_NOEXCEPT; +#else + + friend void swap(static_vector &x, static_vector &y) + { + x.swap(y); + } + +#endif // BOOST_CONTAINER_DOXYGEN_INVOKED + +}; + +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! @brief Checks if contents of two static_vectors are equal. +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @return \c true if containers have the same size and elements in both containers are equal. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator== (static_vector const& x, static_vector const& y); + +//! @brief Checks if contents of two static_vectors are not equal. +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @return \c true if containers have different size or elements in both containers are not equal. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator!= (static_vector const& x, static_vector const& y); + +//! @brief Lexicographically compares static_vectors. +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @return \c true if x compares lexicographically less than y. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator< (static_vector const& x, static_vector const& y); + +//! @brief Lexicographically compares static_vectors. +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @return \c true if y compares lexicographically less than x. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator> (static_vector const& x, static_vector const& y); + +//! @brief Lexicographically compares static_vectors. +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @return \c true if y don't compare lexicographically less than x. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator<= (static_vector const& x, static_vector const& y); + +//! @brief Lexicographically compares static_vectors. +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @return \c true if x don't compare lexicographically less than y. +//! +//! @par Complexity +//! Linear O(N). +template +bool operator>= (static_vector const& x, static_vector const& y); + +//! @brief Swaps contents of two static_vectors. +//! +//! This function calls static_vector::swap(). +//! +//! @ingroup static_vector_non_member +//! +//! @param x The first static_vector. +//! @param y The second static_vector. +//! +//! @par Complexity +//! Linear O(N). +template +inline void swap(static_vector & x, static_vector & y); + +#else + +template +inline void swap(static_vector & x, static_vector & y + , typename container_detail::enable_if_c< C1 != C2>::type * = 0) +{ + x.swap(y); +} + +#endif // BOOST_CONTAINER_DOXYGEN_INVOKED + +}} // namespace boost::container + +#include + +#endif // BOOST_CONTAINER_STATIC_VECTOR_HPP diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index 40b2397..e97f789 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -54,8 +55,7 @@ #include #include -#include -#include +#include #include #include #include @@ -335,8 +335,9 @@ class basic_string_base this->priv_storage(new_cap); } } - else - throw_length_error(); + else{ + throw_length_error("basic_string::allocate_initial_block max_size() exceeded"); + } } void deallocate_block() @@ -345,13 +346,6 @@ class basic_string_base size_type max_size() const { return allocator_traits_type::max_size(this->alloc()) - 1; } - // Helper functions for exception handling. - void throw_length_error() const - { throw(std::length_error("basic_string")); } - - void throw_out_of_range() const - { throw(std::out_of_range("basic_string")); } - protected: size_type priv_capacity() const { return this->priv_storage() - 1; } @@ -432,7 +426,7 @@ class basic_string_base { if(this->is_short()){ if(other.is_short()){ - container_detail::do_swap(this->members_.m_repr, other.members_.m_repr); + std::swap(this->members_.m_repr, other.members_.m_repr); } else{ short_t short_backup(this->members_.m_repr.short_repr()); @@ -453,7 +447,7 @@ class basic_string_base this->members_.m_repr.short_repr() = short_backup; } else{ - container_detail::do_swap(this->members_.m_repr.long_repr(), other.members_.m_repr.long_repr()); + boost::container::swap_dispatch(this->members_.m_repr.long_repr(), other.members_.m_repr.long_repr()); } } } @@ -663,7 +657,7 @@ class basic_string { this->priv_terminate_string(); if (pos > s.size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::basic_string out of range position"); else this->assign (s.begin() + pos, s.begin() + pos + container_detail::min_value(n, s.size() - pos)); @@ -991,7 +985,7 @@ class basic_string void reserve(size_type res_arg) { if (res_arg > this->max_size()){ - this->throw_length_error(); + throw_length_error("basic_string::reserve max_size() exceeded"); } if (this->capacity() < res_arg){ @@ -1083,7 +1077,7 @@ class basic_string reference at(size_type n) { if (n >= this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::at invalid subscript"); return *(this->priv_addr() + n); } @@ -1097,7 +1091,7 @@ class basic_string //! Complexity: Constant. const_reference at(size_type n) const { if (n >= this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::at invalid subscript"); return *(this->priv_addr() + n); } @@ -1142,7 +1136,7 @@ class basic_string basic_string& append(const basic_string& s, size_type pos, size_type n) { if (pos > s.size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::append out of range position"); return this->append(s.begin() + pos, s.begin() + pos + container_detail::min_value(n, s.size() - pos)); } @@ -1226,7 +1220,7 @@ class basic_string basic_string& assign(const basic_string& s, size_type pos, size_type n) { if (pos > s.size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::assign out of range position"); return this->assign(s.begin() + pos, s.begin() + pos + container_detail::min_value(n, s.size() - pos)); } @@ -1296,9 +1290,9 @@ class basic_string { const size_type sz = this->size(); if (pos > sz) - this->throw_out_of_range(); + throw_out_of_range("basic_string::insert out of range position"); if (sz > this->max_size() - s.size()) - this->throw_length_error(); + throw_length_error("basic_string::insert max_size() exceeded"); this->insert(this->priv_addr() + pos, s.begin(), s.end()); return *this; } @@ -1316,10 +1310,10 @@ class basic_string const size_type sz = this->size(); const size_type str_size = s.size(); if (pos1 > sz || pos2 > str_size) - this->throw_out_of_range(); + throw_out_of_range("basic_string::insert out of range position"); size_type len = container_detail::min_value(n, str_size - pos2); if (sz > this->max_size() - len) - this->throw_length_error(); + throw_length_error("basic_string::insert max_size() exceeded"); const CharT *beg_ptr = container_detail::to_raw_pointer(s.begin()) + pos2; const CharT *end_ptr = beg_ptr + len; this->insert(this->priv_addr() + pos1, beg_ptr, end_ptr); @@ -1340,9 +1334,9 @@ class basic_string basic_string& insert(size_type pos, const CharT* s, size_type n) { if (pos > this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::insert out of range position"); if (this->size() > this->max_size() - n) - this->throw_length_error(); + throw_length_error("basic_string::insert max_size() exceeded"); this->insert(this->priv_addr() + pos, s, s + n); return *this; } @@ -1358,10 +1352,10 @@ class basic_string basic_string& insert(size_type pos, const CharT* s) { if (pos > this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::insert out of range position"); size_type len = Traits::length(s); if (this->size() > this->max_size() - len) - this->throw_length_error(); + throw_length_error("basic_string::insert max_size() exceeded"); this->insert(this->priv_addr() + pos, s, s + len); return *this; } @@ -1375,9 +1369,9 @@ class basic_string basic_string& insert(size_type pos, size_type n, CharT c) { if (pos > this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::insert out of range position"); if (this->size() > this->max_size() - n) - this->throw_length_error(); + throw_length_error("basic_string::insert max_size() exceeded"); this->insert(const_iterator(this->priv_addr() + pos), n, c); return *this; } @@ -1551,7 +1545,7 @@ class basic_string basic_string& erase(size_type pos = 0, size_type n = npos) { if (pos > this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::erase out of range position"); const pointer addr = this->priv_addr(); erase(addr + pos, addr + pos + container_detail::min_value(n, this->size() - pos)); return *this; @@ -1633,10 +1627,10 @@ class basic_string basic_string& replace(size_type pos1, size_type n1, const basic_string& str) { if (pos1 > this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::replace out of range position"); const size_type len = container_detail::min_value(n1, this->size() - pos1); if (this->size() - len >= this->max_size() - str.size()) - this->throw_length_error(); + throw_length_error("basic_string::replace max_size() exceeded"); const pointer addr = this->priv_addr(); return this->replace( const_iterator(addr + pos1) , const_iterator(addr + pos1 + len) @@ -1656,11 +1650,11 @@ class basic_string const basic_string& str, size_type pos2, size_type n2) { if (pos1 > this->size() || pos2 > str.size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::replace out of range position"); const size_type len1 = container_detail::min_value(n1, this->size() - pos1); const size_type len2 = container_detail::min_value(n2, str.size() - pos2); if (this->size() - len1 >= this->max_size() - len2) - this->throw_length_error(); + throw_length_error("basic_string::replace max_size() exceeded"); const pointer addr = this->priv_addr(); const pointer straddr = str.priv_addr(); return this->replace(addr + pos1, addr + pos1 + len1, @@ -1684,10 +1678,10 @@ class basic_string basic_string& replace(size_type pos1, size_type n1, const CharT* s, size_type n2) { if (pos1 > this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::replace out of range position"); const size_type len = container_detail::min_value(n1, this->size() - pos1); if (n2 > this->max_size() || size() - len >= this->max_size() - n2) - this->throw_length_error(); + throw_length_error("basic_string::replace max_size() exceeded"); const pointer addr = this->priv_addr(); return this->replace(addr + pos1, addr + pos1 + len, s, s + n2); } @@ -1709,11 +1703,11 @@ class basic_string basic_string& replace(size_type pos, size_type n1, const CharT* s) { if (pos > this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::replace out of range position"); const size_type len = container_detail::min_value(n1, this->size() - pos); const size_type n2 = Traits::length(s); if (n2 > this->max_size() || this->size() - len >= this->max_size() - n2) - this->throw_length_error(); + throw_length_error("basic_string::replace max_size() exceeded"); const pointer addr = this->priv_addr(); return this->replace(addr + pos, addr + pos + len, s, s + Traits::length(s)); @@ -1730,10 +1724,10 @@ class basic_string basic_string& replace(size_type pos1, size_type n1, size_type n2, CharT c) { if (pos1 > this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::replace out of range position"); const size_type len = container_detail::min_value(n1, this->size() - pos1); if (n2 > this->max_size() || this->size() - len >= this->max_size() - n2) - this->throw_length_error(); + throw_length_error("basic_string::replace max_size() exceeded"); const pointer addr = this->priv_addr(); return this->replace(addr + pos1, addr + pos1 + len, n2, c); } @@ -1858,7 +1852,7 @@ class basic_string size_type copy(CharT* s, size_type n, size_type pos = 0) const { if (pos > this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::copy out of range position"); const size_type len = container_detail::min_value(n, this->size() - pos); Traits::copy(s, container_detail::to_raw_pointer(this->priv_addr() + pos), len); return len; @@ -2230,7 +2224,7 @@ class basic_string basic_string substr(size_type pos = 0, size_type n = npos) const { if (pos > this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::substr out of range position"); const pointer addr = this->priv_addr(); return basic_string(addr + pos, addr + pos + container_detail::min_value(n, size() - pos), this->alloc()); @@ -2263,7 +2257,7 @@ class basic_string int compare(size_type pos1, size_type n1, const basic_string& str) const { if (pos1 > this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::compare out of range position"); const pointer addr = this->priv_addr(); const pointer str_addr = str.priv_addr(); return s_compare(addr + pos1, @@ -2282,7 +2276,7 @@ class basic_string int compare(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2) const { if (pos1 > this->size() || pos2 > str.size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::compare out of range position"); const pointer addr = this->priv_addr(); const pointer str_addr = str.priv_addr(); return s_compare(addr + pos1, @@ -2309,7 +2303,7 @@ class basic_string int compare(size_type pos1, size_type n1, const CharT* s, size_type n2) const { if (pos1 > this->size()) - this->throw_out_of_range(); + throw_out_of_range("basic_string::compare out of range position"); const pointer addr = this->priv_addr(); return s_compare( addr + pos1, addr + pos1 + container_detail::min_value(n1, this->size() - pos1), diff --git a/include/boost/container/throw_exception.hpp b/include/boost/container/throw_exception.hpp new file mode 100644 index 0000000..e22d104 --- /dev/null +++ b/include/boost/container/throw_exception.hpp @@ -0,0 +1,110 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_THROW_EXCEPTION_HPP +#define BOOST_CONTAINER_THROW_EXCEPTION_HPP + +#include +#include + +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#ifndef BOOST_NO_EXCEPTIONS + #include //for std exception types + #include //for std::bad_alloc +#else + #include + #include //for std::abort +#endif + +namespace boost { +namespace container { + +#if defined(BOOST_CONTAINER_USER_DEFINED_THROW_CALLBACKS) + //The user must provide definitions for the following functions + + void throw_bad_alloc(); + + void throw_out_of_range(const char* str); + + void throw_length_error(const char* str); + + void throw_logic_error(const char* str); + + void throw_runtime_error(const char* str); + +#elif defined(BOOST_NO_EXCEPTIONS) + + inline void throw_bad_alloc() + { + BOOST_ASSERT(!"boost::container bad_alloc thrown"); + std::abort(); + } + + inline void throw_out_of_range(const char* str) + { + BOOST_ASSERT_MSG(!"boost::container out_of_range thrown", str); + std::abort(); + } + + inline void throw_length_error(const char* str) + { + BOOST_ASSERT_MSG(!"boost::container length_error thrown", str); + std::abort(); + } + + inline void throw_logic_error(const char* str) + { + BOOST_ASSERT_MSG(!"boost::container logic_error thrown", str); + std::abort(); + } + + inline void throw_runtime_error(const char* str) + { + BOOST_ASSERT_MSG(!"boost::container runtime_error thrown", str); + std::abort(); + } + +#else //defined(BOOST_NO_EXCEPTIONS) + + inline void throw_bad_alloc() + { + throw std::bad_alloc(); + } + + inline void throw_out_of_range(const char* str) + { + throw std::out_of_range(str); + } + + inline void throw_length_error(const char* str) + { + throw std::length_error(str); + } + + inline void throw_logic_error(const char* str) + { + throw std::logic_error(str); + } + + inline void throw_runtime_error(const char* str) + { + throw std::runtime_error(str); + } + +#endif + +}} //namespace boost { namespace container { + +#include + +#endif //#ifndef BOOST_CONTAINER_THROW_EXCEPTION_HPP diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 3c4c9c5..dac536a 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -41,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -55,8 +55,12 @@ namespace container { /// @cond +//#define BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + namespace container_detail { +#ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + //! Const vector_iterator used to iterate through a vector. template class vector_const_iterator @@ -74,75 +78,88 @@ class vector_const_iterator Pointer m_ptr; public: - Pointer get_ptr() const { return m_ptr; } - explicit vector_const_iterator(Pointer ptr) : m_ptr(ptr){} + const Pointer &get_ptr() const BOOST_CONTAINER_NOEXCEPT + { return m_ptr; } + + Pointer &get_ptr() BOOST_CONTAINER_NOEXCEPT + { return m_ptr; } + + explicit vector_const_iterator(Pointer ptr) BOOST_CONTAINER_NOEXCEPT + : m_ptr(ptr) + {} /// @endcond public: //Constructors - vector_const_iterator() : m_ptr(0){} + vector_const_iterator() BOOST_CONTAINER_NOEXCEPT + #ifndef NDEBUG + : m_ptr() + #else + // No value initialization of m_ptr() to speed up things a bit: + #endif + {} //Pointer like operators - reference operator*() const + reference operator*() const BOOST_CONTAINER_NOEXCEPT { return *m_ptr; } - const value_type * operator->() const + const value_type * operator->() const BOOST_CONTAINER_NOEXCEPT { return container_detail::to_raw_pointer(m_ptr); } - reference operator[](difference_type off) const + reference operator[](difference_type off) const BOOST_CONTAINER_NOEXCEPT { return m_ptr[off]; } //Increment / Decrement - vector_const_iterator& operator++() + vector_const_iterator& operator++() BOOST_CONTAINER_NOEXCEPT { ++m_ptr; return *this; } - vector_const_iterator operator++(int) - { Pointer tmp = m_ptr; ++*this; return vector_const_iterator(tmp); } + vector_const_iterator operator++(int) BOOST_CONTAINER_NOEXCEPT + { return vector_const_iterator(m_ptr++); } - vector_const_iterator& operator--() + vector_const_iterator& operator--() BOOST_CONTAINER_NOEXCEPT { --m_ptr; return *this; } - vector_const_iterator operator--(int) - { Pointer tmp = m_ptr; --*this; return vector_const_iterator(tmp); } + vector_const_iterator operator--(int) BOOST_CONTAINER_NOEXCEPT + { return vector_const_iterator(m_ptr--); } //Arithmetic - vector_const_iterator& operator+=(difference_type off) + vector_const_iterator& operator+=(difference_type off) BOOST_CONTAINER_NOEXCEPT { m_ptr += off; return *this; } - vector_const_iterator operator+(difference_type off) const - { return vector_const_iterator(m_ptr+off); } - - friend vector_const_iterator operator+(difference_type off, const vector_const_iterator& right) - { return vector_const_iterator(off + right.m_ptr); } - - vector_const_iterator& operator-=(difference_type off) + vector_const_iterator& operator-=(difference_type off) BOOST_CONTAINER_NOEXCEPT { m_ptr -= off; return *this; } - vector_const_iterator operator-(difference_type off) const - { return vector_const_iterator(m_ptr-off); } + friend vector_const_iterator operator+(const vector_const_iterator &x, difference_type off) BOOST_CONTAINER_NOEXCEPT + { return vector_const_iterator(x.m_ptr+off); } - difference_type operator-(const vector_const_iterator& right) const - { return m_ptr - right.m_ptr; } + friend vector_const_iterator operator+(difference_type off, vector_const_iterator right) BOOST_CONTAINER_NOEXCEPT + { right.m_ptr += off; return right; } + + friend vector_const_iterator operator-(vector_const_iterator left, difference_type off) BOOST_CONTAINER_NOEXCEPT + { left.m_ptr -= off; return left; } + + friend difference_type operator-(const vector_const_iterator &left, const vector_const_iterator& right) BOOST_CONTAINER_NOEXCEPT + { return left.m_ptr - right.m_ptr; } //Comparison operators - bool operator== (const vector_const_iterator& r) const - { return m_ptr == r.m_ptr; } + friend bool operator== (const vector_const_iterator& l, const vector_const_iterator& r) BOOST_CONTAINER_NOEXCEPT + { return l.m_ptr == r.m_ptr; } - bool operator!= (const vector_const_iterator& r) const - { return m_ptr != r.m_ptr; } + friend bool operator!= (const vector_const_iterator& l, const vector_const_iterator& r) BOOST_CONTAINER_NOEXCEPT + { return l.m_ptr != r.m_ptr; } - bool operator< (const vector_const_iterator& r) const - { return m_ptr < r.m_ptr; } + friend bool operator< (const vector_const_iterator& l, const vector_const_iterator& r) BOOST_CONTAINER_NOEXCEPT + { return l.m_ptr < r.m_ptr; } - bool operator<= (const vector_const_iterator& r) const - { return m_ptr <= r.m_ptr; } + friend bool operator<= (const vector_const_iterator& l, const vector_const_iterator& r) BOOST_CONTAINER_NOEXCEPT + { return l.m_ptr <= r.m_ptr; } - bool operator> (const vector_const_iterator& r) const - { return m_ptr > r.m_ptr; } + friend bool operator> (const vector_const_iterator& l, const vector_const_iterator& r) BOOST_CONTAINER_NOEXCEPT + { return l.m_ptr > r.m_ptr; } - bool operator>= (const vector_const_iterator& r) const - { return m_ptr >= r.m_ptr; } + friend bool operator>= (const vector_const_iterator& l, const vector_const_iterator& r) BOOST_CONTAINER_NOEXCEPT + { return l.m_ptr >= r.m_ptr; } }; //! Iterator used to iterate through a vector @@ -150,9 +167,10 @@ template class vector_iterator : public vector_const_iterator { + typedef vector_const_iterator base_t; public: - explicit vector_iterator(Pointer ptr) - : vector_const_iterator(ptr) + explicit vector_iterator(Pointer ptr) BOOST_CONTAINER_NOEXCEPT + : base_t(ptr) {} public: @@ -163,52 +181,101 @@ class vector_iterator typedef value_type& reference; //Constructors - vector_iterator() + vector_iterator() BOOST_CONTAINER_NOEXCEPT + : base_t() {} //Pointer like operators - reference operator*() const + reference operator*() const BOOST_CONTAINER_NOEXCEPT { return *this->m_ptr; } - value_type* operator->() const - { return container_detail::to_raw_pointer(this->m_ptr); } + value_type* operator->() const BOOST_CONTAINER_NOEXCEPT + { return container_detail::to_raw_pointer(this->m_ptr); } - reference operator[](difference_type off) const + reference operator[](difference_type off) const BOOST_CONTAINER_NOEXCEPT { return this->m_ptr[off]; } //Increment / Decrement - vector_iterator& operator++() + vector_iterator& operator++() BOOST_CONTAINER_NOEXCEPT { ++this->m_ptr; return *this; } - vector_iterator operator++(int) - { pointer tmp = this->m_ptr; ++*this; return vector_iterator(tmp); } + vector_iterator operator++(int) BOOST_CONTAINER_NOEXCEPT + { return vector_iterator(this->m_ptr++); } - vector_iterator& operator--() + vector_iterator& operator--() BOOST_CONTAINER_NOEXCEPT { --this->m_ptr; return *this; } - vector_iterator operator--(int) - { vector_iterator tmp = *this; --*this; return vector_iterator(tmp); } + vector_iterator operator--(int) BOOST_CONTAINER_NOEXCEPT + { return vector_iterator(this->m_ptr--); } // Arithmetic - vector_iterator& operator+=(difference_type off) + vector_iterator& operator+=(difference_type off) BOOST_CONTAINER_NOEXCEPT { this->m_ptr += off; return *this; } - vector_iterator operator+(difference_type off) const - { return vector_iterator(this->m_ptr+off); } - - friend vector_iterator operator+(difference_type off, const vector_iterator& right) - { return vector_iterator(off + right.m_ptr); } - - vector_iterator& operator-=(difference_type off) + vector_iterator& operator-=(difference_type off) BOOST_CONTAINER_NOEXCEPT { this->m_ptr -= off; return *this; } - vector_iterator operator-(difference_type off) const - { return vector_iterator(this->m_ptr-off); } + friend vector_iterator operator+(vector_iterator left, difference_type off) BOOST_CONTAINER_NOEXCEPT + { left.m_ptr += off; return left; } - difference_type operator-(const vector_const_iterator& right) const - { return static_cast&>(*this) - right; } + friend vector_iterator operator+(difference_type off, vector_iterator right) BOOST_CONTAINER_NOEXCEPT + { right.m_ptr += off; return right; } + + friend vector_iterator operator-(vector_iterator left, difference_type off) BOOST_CONTAINER_NOEXCEPT + { left.m_ptr -= off; return left; } }; +} //namespace container_detail { + +template +const Pointer &vector_iterator_get_ptr(const container_detail::vector_const_iterator &it) BOOST_CONTAINER_NOEXCEPT +{ return it.get_ptr(); } + +template +Pointer &get_ptr(container_detail::vector_const_iterator &it) BOOST_CONTAINER_NOEXCEPT +{ return it.get_ptr(); } + +namespace container_detail { + +#else //ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + +template< class MaybeConstPointer + , bool ElementTypeIsConst + = is_const< typename boost::intrusive::pointer_traits::element_type>::value > +struct vector_get_ptr_pointer_to_non_const +{ + typedef MaybeConstPointer const_pointer; + typedef boost::intrusive::pointer_traits pointer_traits_t; + typedef typename pointer_traits_t::element_type element_type; + typedef typename remove_const::type non_const_element_type; + typedef typename pointer_traits_t + ::template rebind_pointer::type return_type; + + static return_type get_ptr(const const_pointer &ptr) + { return boost::intrusive::pointer_traits::const_cast_from(ptr); } +}; + +template +struct vector_get_ptr_pointer_to_non_const +{ + typedef const Pointer & return_type; + static return_type get_ptr(const Pointer &ptr) + { return ptr; } +}; + +} //namespace container_detail { + +template +typename container_detail::vector_get_ptr_pointer_to_non_const::return_type + vector_iterator_get_ptr(const MaybeConstPointer &ptr) BOOST_CONTAINER_NOEXCEPT +{ + return container_detail::vector_get_ptr_pointer_to_non_const::get_ptr(ptr); +} + +namespace container_detail { + +#endif //#ifndef BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER + template struct vector_value_traits { @@ -216,15 +283,10 @@ struct vector_value_traits typedef Allocator allocator_type; static const bool trivial_dctr = boost::has_trivial_destructor::value; static const bool trivial_dctr_after_move = ::boost::has_trivial_destructor_after_move::value; - //static const bool trivial_copy = has_trivial_copy::value; - //static const bool nothrow_copy = has_nothrow_copy::value; - //static const bool trivial_assign = has_trivial_assign::value; - //static const bool nothrow_assign = has_nothrow_assign::value; - static const bool trivial_copy = has_trivial_copy::value; - static const bool nothrow_copy = has_nothrow_copy::value; + static const bool nothrow_copy = has_nothrow_copy::value || trivial_copy; static const bool trivial_assign = has_trivial_assign::value; - static const bool nothrow_assign = false; + static const bool nothrow_assign = has_nothrow_assign::value || trivial_assign; //This is the anti-exception array destructor //to deallocate values already constructed @@ -249,43 +311,85 @@ struct vector_value_traits }; //!This struct deallocates and allocated memory -template +template < class Allocator + , class AllocatorVersion = container_detail::integral_constant + < unsigned + , boost::container::container_detail::version::value + > + > struct vector_alloc_holder + : public Allocator { + private: + BOOST_MOVABLE_BUT_NOT_COPYABLE(vector_alloc_holder) + + public: typedef boost::container::allocator_traits allocator_traits_type; typedef typename allocator_traits_type::pointer pointer; typedef typename allocator_traits_type::size_type size_type; typedef typename allocator_traits_type::value_type value_type; - typedef vector_value_traits value_traits; //Constructor, does not throw vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor::value) - : members_() + : Allocator(), m_start(), m_size(), m_capacity() {} //Constructor, does not throw template explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT - : members_(boost::forward(a)) + : Allocator(boost::forward(a)), m_start(), m_size(), m_capacity() {} - //Destructor - ~vector_alloc_holder() + //Constructor, does not throw + template + explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type initial_size) + : Allocator(boost::forward(a)) + , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this { - this->prot_destroy_all(); - this->prot_deallocate(); + m_start = this->allocation_command(allocate_new, initial_size, initial_size, m_capacity, m_start).first; + } + + //Constructor, does not throw + explicit vector_alloc_holder(size_type initial_size) + : Allocator() + , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this + { + m_start = this->allocation_command + (allocate_new, initial_size, initial_size, m_capacity, m_start).first; + } + + vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) BOOST_CONTAINER_NOEXCEPT + : Allocator(boost::move(static_cast(holder))) + , m_start(holder.m_start) + , m_size(holder.m_size) + , m_capacity(holder.m_capacity) + { + holder.m_start = pointer(); + holder.m_size = holder.m_capacity = 0; + } + + void first_allocation(size_type cap) + { + m_start = this->allocation_command + (allocate_new, cap, cap, m_capacity, m_start).first; + } + + void first_allocation_same_allocator_type(size_type cap) + { this->first_allocation(cap); } + + ~vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT + { + if(this->m_capacity){ + this->alloc().deallocate(this->m_start, this->m_capacity); + } } - typedef container_detail::integral_constant allocator_v1; - typedef container_detail::integral_constant allocator_v2; - typedef container_detail::integral_constant::value> alloc_version; std::pair allocation_command(allocation_type command, size_type limit_size, size_type preferred_size, - size_type &received_size, const pointer &reuse = 0) + size_type &received_size, const pointer &reuse = pointer()) { return allocator_version_traits::allocation_command (this->alloc(), command, limit_size, preferred_size, received_size, reuse); @@ -293,76 +397,170 @@ struct vector_alloc_holder size_type next_capacity(size_type additional_objects) const { - std::size_t num_objects = this->members_.m_size + additional_objects; - std::size_t next_cap = this->members_.m_capacity + this->members_.m_capacity/2; + std::size_t num_objects = this->m_size + additional_objects; + std::size_t next_cap = this->m_capacity + this->m_capacity/2; return num_objects > next_cap ? num_objects : next_cap;/* - return get_next_capacity( allocator_traits_type::max_size(this->alloc()) - , this->members_.m_capacity, additional_objects);*/ + return get_next_capacity( allocator_traits_type::max_size(this->m_holder.alloc()) + , this->m_capacity, additional_objects);*/ } - struct members_holder - : public Allocator + pointer m_start; + size_type m_size; + size_type m_capacity; + + void swap(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT { - private: - members_holder(const members_holder&); - - public: - template - explicit members_holder(BOOST_FWD_REF(Alloc) alloc) - : Allocator(boost::forward(alloc)), m_start(0), m_size(0), m_capacity(0) - {} - - members_holder() - : Allocator(), m_start(0), m_size(0), m_capacity(0) - {} - - pointer m_start; - size_type m_size; - size_type m_capacity; - } members_; - - void swap_members(vector_alloc_holder &x) - { - container_detail::do_swap(this->members_.m_start, x.members_.m_start); - container_detail::do_swap(this->members_.m_size, x.members_.m_size); - container_detail::do_swap(this->members_.m_capacity, x.members_.m_capacity); + boost::container::swap_dispatch(this->m_start, x.m_start); + boost::container::swap_dispatch(this->m_size, x.m_size); + boost::container::swap_dispatch(this->m_capacity, x.m_capacity); } - Allocator &alloc() - { return members_; } - - const Allocator &alloc() const - { return members_; } - - protected: - void prot_deallocate() + void move_from_empty(vector_alloc_holder &x) BOOST_CONTAINER_NOEXCEPT { - if(!this->members_.m_capacity) return; - this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); - this->members_.m_start = 0; - this->members_.m_size = 0; - this->members_.m_capacity = 0; + this->m_start = x.m_start; + this->m_size = x.m_size; + this->m_capacity = x.m_capacity; + x.m_start = pointer(); + x.m_size = x.m_capacity = 0; } - void destroy(value_type* p) + Allocator &alloc() BOOST_CONTAINER_NOEXCEPT + { return *this; } + + const Allocator &alloc() const BOOST_CONTAINER_NOEXCEPT + { return *this; } + + const pointer &start() const BOOST_CONTAINER_NOEXCEPT { return m_start; } + const size_type &capacity() const BOOST_CONTAINER_NOEXCEPT { return m_capacity; } + void start(const pointer &p) BOOST_CONTAINER_NOEXCEPT { m_start = p; } + void capacity(const size_type &c) BOOST_CONTAINER_NOEXCEPT { m_capacity = c; } +}; + +//!This struct deallocates and allocated memory +template +struct vector_alloc_holder > + : public Allocator +{ + private: + BOOST_MOVABLE_BUT_NOT_COPYABLE(vector_alloc_holder) + + public: + typedef boost::container::allocator_traits allocator_traits_type; + typedef typename allocator_traits_type::pointer pointer; + typedef typename allocator_traits_type::size_type size_type; + typedef typename allocator_traits_type::value_type value_type; + + template + friend struct vector_alloc_holder; + + //Constructor, does not throw + vector_alloc_holder() + BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor::value) + : Allocator(), m_size() + {} + + //Constructor, does not throw + template + explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a) BOOST_CONTAINER_NOEXCEPT + : Allocator(boost::forward(a)), m_size() + {} + + //Constructor, does not throw + template + explicit vector_alloc_holder(BOOST_FWD_REF(AllocConvertible) a, size_type initial_size) + : Allocator(boost::forward(a)) + , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this { - if(!value_traits::trivial_dctr) - allocator_traits_type::destroy(this->alloc(), p); + this->first_allocation(initial_size); } - void destroy_n(value_type* p, size_type n) + //Constructor, does not throw + explicit vector_alloc_holder(size_type initial_size) + : Allocator() + , m_size(initial_size) //Size is initialized here so vector should only call uninitialized_xxx after this { - if(!value_traits::trivial_dctr){ - for(; n--; ++p){ - allocator_traits_type::destroy(this->alloc(), p); - } + this->first_allocation(initial_size); + } + + vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) + : Allocator(boost::move(static_cast(holder))) + , m_size(holder.m_size) //Size is initialized here so vector should only call uninitialized_xxx after this + { + ::boost::container::uninitialized_move_alloc_n + (this->alloc(), container_detail::to_raw_pointer(holder.start()), m_size, container_detail::to_raw_pointer(this->start())); + } + + template + vector_alloc_holder(BOOST_RV_REF_BEG vector_alloc_holder BOOST_RV_REF_END holder) + : Allocator() + , m_size(holder.m_size) //Initialize it to m_size as first_allocation can only succeed or abort + { + //Different allocator type so we must check we have enough storage + const size_type n = holder.m_size; + this->first_allocation(n); + ::boost::container::uninitialized_move_alloc_n + (this->alloc(), container_detail::to_raw_pointer(holder.start()), n, container_detail::to_raw_pointer(this->start())); + } + + void first_allocation(size_type cap) + { + if(cap > Allocator::internal_capacity){ + throw_bad_alloc(); } } - void prot_destroy_all() + void first_allocation_same_allocator_type(size_type) BOOST_CONTAINER_NOEXCEPT + {} + + //Destructor + ~vector_alloc_holder() BOOST_CONTAINER_NOEXCEPT + {} + + void swap(vector_alloc_holder &x) { - this->destroy_n(container_detail::to_raw_pointer(this->members_.m_start), this->members_.m_size); - this->members_.m_size = 0; + this->priv_swap_members_impl(x); + } + + template + void swap(vector_alloc_holder &x) + { + if(this->m_size > OtherAllocator::internal_capacity || x.m_size > Allocator::internal_capacity){ + throw_bad_alloc(); + } + this->priv_swap_members_impl(x); + } + + void move_from_empty(vector_alloc_holder &) + { //Containers with version 0 allocators can't be moved without move elements one by one + throw_bad_alloc(); + } + + Allocator &alloc() BOOST_CONTAINER_NOEXCEPT + { return *this; } + + const Allocator &alloc() const BOOST_CONTAINER_NOEXCEPT + { return *this; } + + pointer start() const BOOST_CONTAINER_NOEXCEPT { return Allocator::internal_storage(); } + size_type capacity() const BOOST_CONTAINER_NOEXCEPT { return Allocator::internal_capacity; } + size_type m_size; + + private: + + template + void priv_swap_members_impl(vector_alloc_holder &x) + { + const std::size_t MaxTmpStorage = sizeof(value_type)*Allocator::internal_capacity; + value_type *const first_this = container_detail::to_raw_pointer(this->start()); + value_type *const first_x = container_detail::to_raw_pointer(x.start()); + + if(this->m_size < x.m_size){ + boost::container::deep_swap_alloc_n(this->alloc(), first_this, this->m_size, first_x, x.m_size); + } + else{ + boost::container::deep_swap_alloc_n(this->alloc(), first_x, x.m_size, first_this, this->m_size); + } + boost::container::swap_dispatch(this->m_size, x.m_size); } }; @@ -381,11 +579,17 @@ template > #else template #endif -class vector : private container_detail::vector_alloc_holder +class vector { /// @cond + typedef container_detail::integral_constant + ::value > alloc_version; + boost::container::container_detail::vector_alloc_holder m_holder; typedef container_detail::vector_alloc_holder base_t; typedef allocator_traits allocator_traits_type; + template + friend class vector; /// @endcond public: ////////////////////////////////////////////// @@ -403,8 +607,13 @@ class vector : private container_detail::vector_alloc_holder typedef typename ::boost::container::allocator_traits::difference_type difference_type; typedef Allocator allocator_type; typedef Allocator stored_allocator_type; + #if defined BOOST_CONTAINER_VECTOR_ITERATOR_IS_POINTER && !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + typedef BOOST_CONTAINER_IMPDEF(pointer) iterator; + typedef BOOST_CONTAINER_IMPDEF(const_pointer) const_iterator; + #else typedef BOOST_CONTAINER_IMPDEF(container_detail::vector_iterator) iterator; typedef BOOST_CONTAINER_IMPDEF(container_detail::vector_const_iterator) const_iterator; + #endif typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator) reverse_iterator; typedef BOOST_CONTAINER_IMPDEF(std::reverse_iterator) const_reverse_iterator; @@ -413,11 +622,11 @@ class vector : private container_detail::vector_alloc_holder BOOST_COPYABLE_AND_MOVABLE(vector) typedef container_detail::vector_value_traits value_traits; - typedef typename base_t::allocator_v1 allocator_v1; - typedef typename base_t::allocator_v2 allocator_v2; - typedef typename base_t::alloc_version alloc_version; + typedef container_detail::integral_constant allocator_v0; + typedef container_detail::integral_constant allocator_v1; + typedef container_detail::integral_constant allocator_v2; - typedef constant_iterator cvalue_iterator; + typedef constant_iterator cvalue_iterator; /// @endcond public: @@ -434,7 +643,7 @@ class vector : private container_detail::vector_alloc_holder //! Complexity: Constant. vector() BOOST_CONTAINER_NOEXCEPT_IF(::boost::has_nothrow_default_constructor::value) - : base_t() + : m_holder() {} //! Effects: Constructs a vector taking the allocator as parameter. @@ -443,7 +652,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. explicit vector(const Allocator& a) BOOST_CONTAINER_NOEXCEPT - : base_t(a) + : m_holder(a) {} //! Effects: Constructs a vector that will use a copy of allocator a @@ -454,19 +663,50 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Linear to n. explicit vector(size_type n) - : base_t() - { this->resize(n); } + : m_holder(n) + { + boost::container::uninitialized_default_alloc_n(this->m_holder.alloc(), n, container_detail::to_raw_pointer(this->m_holder.start())); + } - //! Effects: Constructs a vector that will use a copy of allocator a + //! Effects: Constructs a vector //! and inserts n copies of value. //! //! Throws: If allocator_type's default constructor or allocation //! throws or T's copy constructor throws. //! //! Complexity: Linear to n. - vector(size_type n, const T& value, const allocator_type& a = allocator_type()) - : base_t(a) - { this->resize(n, value); } + vector(size_type n, const T& value) + : m_holder(n) + { + boost::container::uninitialized_fill_alloc_n + (this->m_holder.alloc(), value, n, container_detail::to_raw_pointer(this->m_holder.start())); + } + + //! Effects: Constructs a vector that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocation + //! throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + vector(size_type n, const T& value, const allocator_type& a) + : m_holder(a, n) + { + boost::container::uninitialized_fill_alloc_n + (this->m_holder.alloc(), value, n, container_detail::to_raw_pointer(this->m_holder.start())); + } + + //! Effects: Constructs a vector + //! and inserts a copy of the range [first, last) in the vector. + //! + //! Throws: If allocator_type's default constructor or allocation + //! throws or T's constructor taking an dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + vector(InIt first, InIt last) + : m_holder() + { this->insert(this->cend(), first, last); } //! Effects: Constructs a vector that will use a copy of allocator a //! and inserts a copy of the range [first, last) in the vector. @@ -476,9 +716,9 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Linear to the range [first, last). template - vector(InIt first, InIt last, const allocator_type& a = allocator_type()) - : base_t(a) - { this->assign(first, last); } + vector(InIt first, InIt last, const allocator_type& a) + : m_holder(a) + { this->insert(this->cend(), first, last); } //! Effects: Copy constructs a vector. //! @@ -489,10 +729,11 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Linear to the elements x contains. vector(const vector &x) - : base_t(allocator_traits_type::select_on_container_copy_construction(x.alloc())) + : m_holder(allocator_traits_type::select_on_container_copy_construction(x.m_holder.alloc()), x.size()) { - this->assign( container_detail::to_raw_pointer(x.members_.m_start) - , container_detail::to_raw_pointer(x.members_.m_start + x.members_.m_size)); + ::boost::container::uninitialized_copy_alloc_n + ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start()) + , x.size(), container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Move constructor. Moves mx's resources to *this. @@ -501,8 +742,24 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. vector(BOOST_RV_REF(vector) mx) BOOST_CONTAINER_NOEXCEPT - : base_t(boost::move(mx.alloc())) - { this->swap_members(mx); } + : m_holder(boost::move(mx.m_holder)) + {} + + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Effects: Move constructor. Moves mx's resources to *this. + //! + //! Throws: If T's move constructor or allocation throws + //! + //! Complexity: Linear. + //! + //! Note: Non-standard extension + template + vector(BOOST_RV_REF_BEG vector BOOST_RV_REF_END mx) + : m_holder(boost::move(mx.m_holder)) + {} + + #endif //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Copy constructs a vector using the specified allocator. //! @@ -513,10 +770,11 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Linear to the elements x contains. vector(const vector &x, const allocator_type &a) - : base_t(a) + : m_holder(a, x.size()) { - this->assign( container_detail::to_raw_pointer(x.members_.m_start) - , container_detail::to_raw_pointer(x.members_.m_start + x.members_.m_size)); + ::boost::container::uninitialized_copy_alloc_n_source + ( this->m_holder.alloc(), container_detail::to_raw_pointer(x.m_holder.start()) + , x.size(), container_detail::to_raw_pointer(this->m_holder.start())); } //! Effects: Move constructor using the specified allocator. @@ -527,14 +785,18 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant if a == mx.get_allocator(), linear otherwise. vector(BOOST_RV_REF(vector) mx, const allocator_type &a) - : base_t(a) + : m_holder(a) { - if(mx.alloc() == a){ - this->swap_members(mx); + if(mx.m_holder.alloc() == a){ + this->m_holder.move_from_empty(mx.m_holder); } else{ - this->assign( container_detail::to_raw_pointer(mx.members_.m_start) - , container_detail::to_raw_pointer(mx.members_.m_start) + mx.members_.m_size); + const size_type n = mx.size(); + this->m_holder.first_allocation_same_allocator_type(n); + ::boost::container::uninitialized_move_alloc_n_source + ( this->m_holder.alloc(), container_detail::to_raw_pointer(mx.m_holder.start()) + , n, container_detail::to_raw_pointer(this->m_holder.start())); + this->m_holder.m_size = n; } } @@ -545,7 +807,11 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Linear to the number of elements. ~vector() BOOST_CONTAINER_NOEXCEPT - {} //vector_alloc_holder clears the data + { + boost::container::destroy_alloc_n + (this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size); + //vector_alloc_holder deallocates the data + } //! Effects: Makes *this contain the same elements as x. //! @@ -558,17 +824,7 @@ class vector : private container_detail::vector_alloc_holder vector& operator=(BOOST_COPY_ASSIGN_REF(vector) x) { if (&x != this){ - allocator_type &this_alloc = this->alloc(); - const allocator_type &x_alloc = x.alloc(); - container_detail::bool_ flag; - if(flag && this_alloc != x_alloc){ - this->clear(); - this->shrink_to_fit(); - } - container_detail::assign_alloc(this_alloc, x_alloc, flag); - this->assign( container_detail::to_raw_pointer(x.members_.m_start) - , container_detail::to_raw_pointer(x.members_.m_start + x.members_.m_size)); + this->priv_copy_assign(boost::move(x), alloc_version()); } return *this; } @@ -585,28 +841,29 @@ class vector : private container_detail::vector_alloc_holder //iG BOOST_CONTAINER_NOEXCEPT_IF(!allocator_type::propagate_on_container_move_assignment::value || is_nothrow_move_assignable::value);) BOOST_CONTAINER_NOEXCEPT { - if (&x != this){ - allocator_type &this_alloc = this->alloc(); - allocator_type &x_alloc = x.alloc(); - //If allocators are equal we can just swap pointers - if(this_alloc == x_alloc){ - //Destroy objects but retain memory in case x reuses it in the future - this->clear(); - this->swap_members(x); - //Move allocator if needed - container_detail::bool_ flag; - container_detail::move_alloc(this_alloc, x_alloc, flag); - } - //If unequal allocators, then do a one by one move - else{ - this->assign( boost::make_move_iterator(container_detail::to_raw_pointer(x.members_.m_start)) - , boost::make_move_iterator(container_detail::to_raw_pointer(x.members_.m_start + x.members_.m_size))); - } - } + this->priv_move_assign(boost::move(x), alloc_version()); return *this; } + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Effects: Move assignment. All mx's values are transferred to *this. + //! + //! Postcondition: x.empty(). *this contains a the elements x had + //! before the function. + //! + //! Throws: If move constructor/assignment of T throws or allocation throws + //! + //! Complexity: Linear. + template + vector& operator=(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x) + { + this->priv_move_assign(boost::move(x), alloc_version()); + return *this; + } + + #endif + //! Effects: Assigns the the range [first, last) to *this. //! //! Throws: If memory allocation throws or T's copy/move constructor/assignment or @@ -625,13 +882,16 @@ class vector : private container_detail::vector_alloc_holder { //Overwrite all elements we can from [first, last) iterator cur = this->begin(); - for ( ; first != last && cur != end(); ++cur, ++first){ + const iterator end_it = this->end(); + for ( ; first != last && cur != end_it; ++cur, ++first){ *cur = *first; } if (first == last){ //There are no more elements in the sequence, erase remaining - this->erase(cur, this->cend()); + T* const end_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; + size_type n = static_cast(end_pos - container_detail::to_raw_pointer(vector_iterator_get_ptr(cur))); + this->priv_destroy_last_n(n); } else{ //There are more elements in the range, insert the remaining ones @@ -654,8 +914,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. allocator_type get_allocator() const BOOST_CONTAINER_NOEXCEPT - { return this->alloc(); } - + { return this->m_holder.alloc(); } //! Effects: Returns a reference to the internal allocator. //! @@ -665,7 +924,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Note: Non-standard extension. stored_allocator_type &get_stored_allocator() BOOST_CONTAINER_NOEXCEPT - { return this->alloc(); } + { return this->m_holder.alloc(); } //! Effects: Returns a reference to the internal allocator. //! @@ -675,7 +934,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Note: Non-standard extension. const stored_allocator_type &get_stored_allocator() const BOOST_CONTAINER_NOEXCEPT - { return this->alloc(); } + { return this->m_holder.alloc(); } ////////////////////////////////////////////// // @@ -689,7 +948,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. iterator begin() BOOST_CONTAINER_NOEXCEPT - { return iterator(this->members_.m_start); } + { return iterator(this->m_holder.start()); } //! Effects: Returns a const_iterator to the first element contained in the vector. //! @@ -697,7 +956,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. const_iterator begin() const BOOST_CONTAINER_NOEXCEPT - { return const_iterator(this->members_.m_start); } + { return const_iterator(this->m_holder.start()); } //! Effects: Returns an iterator to the end of the vector. //! @@ -705,7 +964,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. iterator end() BOOST_CONTAINER_NOEXCEPT - { return iterator(this->members_.m_start + this->members_.m_size); } + { return iterator(this->m_holder.start() + this->m_holder.m_size); } //! Effects: Returns a const_iterator to the end of the vector. //! @@ -757,7 +1016,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. const_iterator cbegin() const BOOST_CONTAINER_NOEXCEPT - { return const_iterator(this->members_.m_start); } + { return const_iterator(this->m_holder.start()); } //! Effects: Returns a const_iterator to the end of the vector. //! @@ -765,7 +1024,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. const_iterator cend() const BOOST_CONTAINER_NOEXCEPT - { return const_iterator(this->members_.m_start + this->members_.m_size); } + { return const_iterator(this->m_holder.start() + this->m_holder.m_size); } //! Effects: Returns a const_reverse_iterator pointing to the beginning //! of the reversed vector. @@ -797,7 +1056,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. bool empty() const BOOST_CONTAINER_NOEXCEPT - { return !this->members_.m_size; } + { return !this->m_holder.m_size; } //! Effects: Returns the number of the elements contained in the vector. //! @@ -805,7 +1064,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. size_type size() const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_size; } + { return this->m_holder.m_size; } //! Effects: Returns the largest possible size of the vector. //! @@ -813,7 +1072,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. size_type max_size() const BOOST_CONTAINER_NOEXCEPT - { return allocator_traits_type::max_size(this->alloc()); } + { return allocator_traits_type::max_size(this->m_holder.alloc()); } //! Effects: Inserts or erases elements at the end such that //! the size becomes n. New elements are default constructed. @@ -823,15 +1082,15 @@ class vector : private container_detail::vector_alloc_holder //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size) { - if (new_size < this->size()){ + const size_type sz = this->size(); + if (new_size < sz){ //Destroy last elements - this->erase(const_iterator(this->members_.m_start + new_size), this->end()); + this->priv_destroy_last_n(sz - new_size); } else{ const size_type n = new_size - this->size(); - this->reserve(new_size); - container_detail::insert_default_constructed_n_proxy proxy(this->alloc()); - this->priv_forward_range_insert(this->cend().get_ptr(), n, proxy); + container_detail::insert_default_constructed_n_proxy proxy(this->m_holder.alloc()); + this->priv_forward_range_insert_at_end(n, proxy, alloc_version()); } } @@ -843,14 +1102,15 @@ class vector : private container_detail::vector_alloc_holder //! Complexity: Linear to the difference between size() and new_size. void resize(size_type new_size, const T& x) { - pointer finish = this->members_.m_start + this->members_.m_size; - if (new_size < size()){ + const size_type sz = this->size(); + if (new_size < sz){ //Destroy last elements - this->erase(const_iterator(this->members_.m_start + new_size), this->end()); + this->priv_destroy_last_n(sz - new_size); } else{ - //Insert new elements at the end - this->insert(const_iterator(finish), new_size - this->size(), x); + const size_type n = new_size - this->size(); + container_detail::insert_n_copies_proxy proxy(this->m_holder.alloc(), x); + this->priv_forward_range_insert_at_end(n, proxy, alloc_version()); } } @@ -861,7 +1121,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. size_type capacity() const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_capacity; } + { return this->m_holder.capacity(); } //! Effects: If n is less than or equal to capacity(), this call has no //! effect. Otherwise, it is a request for allocation of additional memory. @@ -872,54 +1132,7 @@ class vector : private container_detail::vector_alloc_holder void reserve(size_type new_cap) { if (this->capacity() < new_cap){ - //There is not enough memory, allocate a new - //buffer or expand the old one. - bool same_buffer_start; - size_type real_cap = 0; - std::pair ret = - this->allocation_command - (allocate_new | expand_fwd | expand_bwd, - new_cap, new_cap, real_cap, this->members_.m_start); - - //Check for forward expansion - same_buffer_start = ret.second && this->members_.m_start == ret.first; - if(same_buffer_start){ - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_expand_fwd; - #endif - this->members_.m_capacity = real_cap; - } - - //If there is no forward expansion, move objects - else{ - //We will reuse insert code, so create a dummy input iterator - container_detail::insert_range_proxy, T*> - proxy(this->alloc(), ::boost::make_move_iterator((T *)0)); - //Backwards (and possibly forward) expansion - if(alloc_version::value > 1 && ret.second){ - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_expand_bwd; - #endif - this->priv_range_insert_expand_backwards - ( container_detail::to_raw_pointer(ret.first) - , real_cap - , container_detail::to_raw_pointer(this->members_.m_start) - , 0 - , proxy); - } - //New buffer - else{ - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_alloc; - #endif - this->priv_range_insert_new_allocation - ( container_detail::to_raw_pointer(ret.first) - , real_cap - , container_detail::to_raw_pointer(this->members_.m_start) - , 0 - , proxy); - } - } + this->priv_reserve(new_cap, alloc_version()); } } @@ -947,7 +1160,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. reference front() BOOST_CONTAINER_NOEXCEPT - { return *this->members_.m_start; } + { return *this->m_holder.start(); } //! Requires: !empty() //! @@ -958,7 +1171,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. const_reference front() const BOOST_CONTAINER_NOEXCEPT - { return *this->members_.m_start; } + { return *this->m_holder.start(); } //! Requires: !empty() //! @@ -969,7 +1182,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. reference back() BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start[this->members_.m_size - 1]; } + { return this->m_holder.start()[this->m_holder.m_size - 1]; } //! Requires: !empty() //! @@ -980,7 +1193,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. const_reference back() const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start[this->members_.m_size - 1]; } + { return this->m_holder.start()[this->m_holder.m_size - 1]; } //! Requires: size() > n. //! @@ -991,7 +1204,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. reference operator[](size_type n) BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start[n]; } + { return this->m_holder.start()[n]; } //! Requires: size() > n. //! @@ -1002,7 +1215,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. const_reference operator[](size_type n) const BOOST_CONTAINER_NOEXCEPT - { return this->members_.m_start[n]; } + { return this->m_holder.start()[n]; } //! Requires: size() > n. //! @@ -1013,7 +1226,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. reference at(size_type n) - { this->priv_check_range(n); return this->members_.m_start[n]; } + { this->priv_check_range(n); return this->m_holder.start()[n]; } //! Requires: size() > n. //! @@ -1024,7 +1237,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. const_reference at(size_type n) const - { this->priv_check_range(n); return this->members_.m_start[n]; } + { this->priv_check_range(n); return this->m_holder.start()[n]; } ////////////////////////////////////////////// // @@ -1039,7 +1252,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. T* data() BOOST_CONTAINER_NOEXCEPT - { return container_detail::to_raw_pointer(this->members_.m_start); } + { return container_detail::to_raw_pointer(this->m_holder.start()); } //! Returns: Allocator pointer such that [data(),data() + size()) is a valid range. //! For a non-empty vector, data() == &front(). @@ -1048,7 +1261,7 @@ class vector : private container_detail::vector_alloc_holder //! //! Complexity: Constant. const T * data() const BOOST_CONTAINER_NOEXCEPT - { return container_detail::to_raw_pointer(this->members_.m_start); } + { return container_detail::to_raw_pointer(this->m_holder.start()); } ////////////////////////////////////////////// // @@ -1067,16 +1280,16 @@ class vector : private container_detail::vector_alloc_holder template void emplace_back(Args &&...args) { - T* back_pos = container_detail::to_raw_pointer(this->members_.m_start) + this->members_.m_size; - if (this->members_.m_size < this->members_.m_capacity){ + T* back_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; + if (this->m_holder.m_size < this->m_holder.capacity()){ //There is more memory, just construct a new object at the end - allocator_traits_type::construct(this->alloc(), back_pos, ::boost::forward(args)...); - ++this->members_.m_size; + allocator_traits_type::construct(this->m_holder.alloc(), back_pos, ::boost::forward(args)...); + ++this->m_holder.m_size; } else{ typedef container_detail::insert_emplace_proxy type; - this->priv_forward_range_insert - (back_pos, 1, type(this->alloc(), ::boost::forward(args)...)); + this->priv_forward_range_insert_no_capacity + (vector_iterator_get_ptr(this->cend()), 1, type(this->m_holder.alloc(), ::boost::forward(args)...), alloc_version()); } } @@ -1095,41 +1308,42 @@ class vector : private container_detail::vector_alloc_holder { //Just call more general insert(pos, size, value) and return iterator typedef container_detail::insert_emplace_proxy type; - return this->priv_forward_range_insert - (position.get_ptr(), 1, type(this->alloc(), ::boost::forward(args)...)); + return this->priv_forward_range_insert( vector_iterator_get_ptr(position), 1, type(this->m_holder.alloc() + , ::boost::forward(args)...), alloc_version()); } #else - #define BOOST_PP_LOCAL_MACRO(n) \ - BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ - void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ - { \ - T* back_pos = container_detail::to_raw_pointer \ - (this->members_.m_start) + this->members_.m_size; \ - if (this->members_.m_size < this->members_.m_capacity){ \ - allocator_traits_type::construct (this->alloc() \ - , back_pos BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ - ++this->members_.m_size; \ - } \ - else{ \ - container_detail::BOOST_PP_CAT(insert_emplace_proxy_arg, n) \ - proxy \ - (this->alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ - this->priv_forward_range_insert(back_pos, 1, proxy); \ - } \ - } \ - \ - BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ - iterator emplace(const_iterator pos \ - BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ - { \ - container_detail::BOOST_PP_CAT(insert_emplace_proxy_arg, n) \ - proxy \ - (this->alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ - return this->priv_forward_range_insert \ - (container_detail::to_raw_pointer(pos.get_ptr()), 1, proxy); \ - } \ + #define BOOST_PP_LOCAL_MACRO(n) \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + void emplace_back(BOOST_PP_ENUM(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + T* back_pos = container_detail::to_raw_pointer \ + (this->m_holder.start()) + this->m_holder.m_size; \ + if (this->m_holder.m_size < this->m_holder.capacity()){ \ + allocator_traits_type::construct (this->m_holder.alloc() \ + , back_pos BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _) ); \ + ++this->m_holder.m_size; \ + } \ + else{ \ + container_detail::BOOST_PP_CAT(insert_emplace_proxy_arg, n) \ + proxy \ + (this->m_holder.alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ + this->priv_forward_range_insert_no_capacity \ + (vector_iterator_get_ptr(this->cend()), 1, proxy, alloc_version()); \ + } \ + } \ + \ + BOOST_PP_EXPR_IF(n, template<) BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_EXPR_IF(n, >) \ + iterator emplace(const_iterator pos \ + BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_LIST, _)) \ + { \ + container_detail::BOOST_PP_CAT(insert_emplace_proxy_arg, n) \ + proxy \ + (this->m_holder.alloc() BOOST_PP_ENUM_TRAILING(n, BOOST_CONTAINER_PP_PARAM_FORWARD, _)); \ + return this->priv_forward_range_insert \ + (container_detail::to_raw_pointer(vector_iterator_get_ptr(pos)), 1, proxy, alloc_version()); \ + } \ //! #define BOOST_PP_LOCAL_LIMITS (0, BOOST_CONTAINER_MAX_CONSTRUCTOR_PARAMETERS) #include BOOST_PP_LOCAL_ITERATE() @@ -1192,8 +1406,8 @@ class vector : private container_detail::vector_alloc_holder //! Complexity: Linear to n. iterator insert(const_iterator p, size_type n, const T& x) { - container_detail::insert_n_copies_proxy proxy(this->alloc(), x); - return this->priv_forward_range_insert(p.get_ptr(), n, proxy); + container_detail::insert_n_copies_proxy proxy(this->m_holder.alloc(), x); + return this->priv_forward_range_insert(vector_iterator_get_ptr(p), n, proxy, alloc_version()); } //! Requires: p must be a valid iterator of *this. @@ -1217,12 +1431,12 @@ class vector : private container_detail::vector_alloc_holder ) { const size_type n_pos = pos - this->cbegin(); - iterator it(pos.get_ptr()); + iterator it(vector_iterator_get_ptr(pos)); for(;first != last; ++first){ it = this->emplace(it, *first); ++it; } - return iterator(this->members_.m_start + n_pos); + return iterator(this->m_holder.start() + n_pos); } #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -1234,8 +1448,8 @@ class vector : private container_detail::vector_alloc_holder >::type * = 0 ) { - container_detail::insert_range_proxy proxy(this->alloc(), first); - return this->priv_forward_range_insert(pos.get_ptr(), std::distance(first, last), proxy); + container_detail::insert_range_proxy proxy(this->m_holder.alloc(), first); + return this->priv_forward_range_insert(vector_iterator_get_ptr(pos), std::distance(first, last), proxy, alloc_version()); } #endif @@ -1247,8 +1461,8 @@ class vector : private container_detail::vector_alloc_holder void pop_back() BOOST_CONTAINER_NOEXCEPT { //Destroy last element - --this->members_.m_size; - this->destroy(container_detail::to_raw_pointer(this->members_.m_start) + this->members_.m_size); + --this->m_holder.m_size; + this->priv_destroy(container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size); } //! Effects: Erases the element at position pos. @@ -1259,13 +1473,12 @@ class vector : private container_detail::vector_alloc_holder //! last element. Constant if pos is the last element. iterator erase(const_iterator position) { - T *const pos = container_detail::to_raw_pointer(position.get_ptr()); - T *const beg = container_detail::to_raw_pointer(this->members_.m_start); - ::boost::move(pos + 1, beg + this->members_.m_size, pos); - --this->members_.m_size; - //Destroy last element - base_t::destroy(container_detail::to_raw_pointer(this->members_.m_start) + this->members_.m_size); - return iterator(position.get_ptr()); + T *const pos = container_detail::to_raw_pointer(vector_iterator_get_ptr(position)); + T *const beg = container_detail::to_raw_pointer(this->m_holder.start()); + //Move elements forward and destroy last + this->priv_destroy(::boost::move(pos + 1, beg + this->m_holder.m_size, pos)); + --this->m_holder.m_size; + return iterator(vector_iterator_get_ptr(position)); } //! Effects: Erases the elements pointed by [first, last). @@ -1277,17 +1490,17 @@ class vector : private container_detail::vector_alloc_holder iterator erase(const_iterator first, const_iterator last) { if (first != last){ - T* end_pos = container_detail::to_raw_pointer(this->members_.m_start) + this->members_.m_size; - T* ptr = container_detail::to_raw_pointer(boost::move - (container_detail::to_raw_pointer(last.get_ptr()) + T* const end_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; + T* const ptr = container_detail::to_raw_pointer(boost::move + (container_detail::to_raw_pointer(vector_iterator_get_ptr(last)) ,end_pos - ,container_detail::to_raw_pointer(first.get_ptr()) + ,container_detail::to_raw_pointer(vector_iterator_get_ptr(first)) )); const size_type destroyed = (end_pos - ptr); - this->destroy_n(ptr, destroyed); - this->members_.m_size -= destroyed; + boost::container::destroy_alloc_n(this->get_stored_allocator(), ptr, destroyed); + this->m_holder.m_size -= destroyed; } - return iterator(first.get_ptr()); + return iterator(vector_iterator_get_ptr(first)); } //! Effects: Swaps the contents of *this and x. @@ -1295,22 +1508,39 @@ class vector : private container_detail::vector_alloc_holder //! Throws: Nothing. //! //! Complexity: Constant. - void swap(vector& x) + void swap(vector& x) BOOST_CONTAINER_NOEXCEPT_IF((!container_detail::is_same::value)) { - //Just swap internals - this->swap_members(x); + //Just swap internals in case of !allocator_v0. Otherwise, deep swap + this->m_holder.swap(x.m_holder); //And now the allocator container_detail::bool_ flag; - container_detail::swap_alloc(this->alloc(), x.alloc(), flag); + container_detail::swap_alloc(this->m_holder.alloc(), x.m_holder.alloc(), flag); } + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + //! Effects: Swaps the contents of *this and x. + //! + //! Throws: If T's move constructor throws. + //! + //! Complexity: Linear + //! + //! Note: non-standard extension. + template + void swap(vector & x) + { + this->m_holder.swap(x.m_holder); + } + + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + //! Effects: Erases all the elements of the vector. //! //! Throws: Nothing. //! //! Complexity: Linear to the number of elements in the vector. void clear() BOOST_CONTAINER_NOEXCEPT - { this->prot_destroy_all(); } + { this->priv_destroy_all(); } /// @cond @@ -1330,75 +1560,301 @@ class vector : private container_detail::vector_alloc_holder } private: + + template + void priv_move_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x + , AllocVersion + , typename container_detail::enable_if_c + < container_detail::is_same::value && + !container_detail::is_same::value + >::type * = 0) + { + if(this->capacity() < x.size()){ + throw_bad_alloc(); + } + this->priv_move_assign_impl(boost::move(x), AllocVersion()); + } + + template + void priv_move_assign(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x + , AllocVersion + , typename container_detail::enable_if_c + < !container_detail::is_same::value || + container_detail::is_same::value + >::type * = 0) + { + this->priv_move_assign_impl(boost::move(x), AllocVersion()); + } + + template + void priv_move_assign_impl(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x + , AllocVersion + , typename container_detail::enable_if_c + < container_detail::is_same::value + >::type * = 0) + { + T* const this_start = container_detail::to_raw_pointer(m_holder.start()); + T* const other_start = container_detail::to_raw_pointer(x.m_holder.start()); + const size_type this_sz = m_holder.m_size; + const size_type other_sz = static_cast(x.m_holder.m_size); + boost::container::move_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz); + this->m_holder.m_size = other_sz; + } + + template + void priv_move_assign_impl(BOOST_RV_REF_BEG vector BOOST_RV_REF_END x + , AllocVersion + , typename container_detail::enable_if_c + < !container_detail::is_same::value + >::type * = 0) + { + //for move constructor, no aliasing (&x != this) is assummed. + allocator_type &this_alloc = this->m_holder.alloc(); + allocator_type &x_alloc = x.m_holder.alloc(); + //If allocators are equal we can just swap pointers + if(this_alloc == x_alloc){ + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + this->m_holder.swap(x.m_holder); + //Move allocator if needed + container_detail::bool_ flag; + container_detail::move_alloc(this_alloc, x_alloc, flag); + } + //If unequal allocators, then do a one by one move + else{ + //TO-DO: optimize this + this->assign( boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start())) + , boost::make_move_iterator(container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size))); + } + } + + template + void priv_copy_assign(const vector &x, AllocVersion + , typename container_detail::enable_if_c + < container_detail::is_same::value + >::type * = 0) + { + T* const this_start = container_detail::to_raw_pointer(m_holder.start()); + T* const other_start = container_detail::to_raw_pointer(x.m_holder.start()); + const size_type this_sz = m_holder.m_size; + const size_type other_sz = static_cast(x.m_holder.m_size); + boost::container::copy_assign_range_alloc_n(this->m_holder.alloc(), other_start, other_sz, this_start, this_sz); + this->m_holder.m_size = other_sz; + } + + template + void priv_copy_assign(const vector &x, AllocVersion + , typename container_detail::enable_if_c + < !container_detail::is_same::value + >::type * = 0) + { + allocator_type &this_alloc = this->m_holder.alloc(); + const allocator_type &x_alloc = x.m_holder.alloc(); + container_detail::bool_ flag; + if(flag && this_alloc != x_alloc){ + this->clear(); + this->shrink_to_fit(); + } + container_detail::assign_alloc(this_alloc, x_alloc, flag); + this->assign( container_detail::to_raw_pointer(x.m_holder.start()) + , container_detail::to_raw_pointer(x.m_holder.start() + x.m_holder.m_size)); + } + + void priv_reserve(size_type, allocator_v0) + { + throw_bad_alloc(); + } + + void priv_reserve(size_type new_cap, allocator_v1) + { + //There is not enough memory, allocate a new buffer + pointer p = this->m_holder.allocate(new_cap); + //Backwards (and possibly forward) expansion + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + T * const raw_beg = container_detail::to_raw_pointer(this->m_holder.start()); + const size_type sz = m_holder.m_size; + ::boost::container::uninitialized_move_alloc_n_source + ( this->m_holder.alloc(), raw_beg, sz, container_detail::to_raw_pointer(p) ); + boost::container::destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz); + this->m_holder.start(p); + this->m_holder.capacity(new_cap); + } + + void priv_reserve(size_type new_cap, allocator_v2) + { + //There is not enough memory, allocate a new + //buffer or expand the old one. + bool same_buffer_start; + size_type real_cap = 0; + std::pair ret = + this->m_holder.allocation_command + (allocate_new | expand_fwd | expand_bwd, + new_cap, new_cap, real_cap, this->m_holder.start()); + + //Check for forward expansion + same_buffer_start = ret.second && this->m_holder.start() == ret.first; + if(same_buffer_start){ + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_expand_fwd; + #endif + this->m_holder.capacity(real_cap); + } + //If there is no forward expansion, move objects + else{ + //Backwards (and possibly forward) expansion + if(ret.second){ + //We will reuse insert code, so create a dummy input iterator + container_detail::insert_range_proxy, T*> + proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0)); + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_expand_bwd; + #endif + this->priv_forward_range_insert_expand_backwards + ( container_detail::to_raw_pointer(ret.first) + , real_cap + , container_detail::to_raw_pointer(this->m_holder.start()) + , 0 + , proxy); + } + //New buffer + else{ + //Backwards (and possibly forward) expansion + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + T * const raw_beg = container_detail::to_raw_pointer(this->m_holder.start()); + const size_type sz = m_holder.m_size; + ::boost::container::uninitialized_move_alloc_n_source + ( this->m_holder.alloc(), raw_beg, sz, container_detail::to_raw_pointer(ret.first) ); + boost::container::destroy_alloc_n(this->m_holder.alloc(), raw_beg, sz); + this->m_holder.start(ret.first); + this->m_holder.capacity(real_cap); + } + } + } + + template + void priv_uninitialized_fill(Proxy proxy, size_type n) const + { + //Copy first new elements in pos + proxy.uninitialized_copy_n_and_update + (container_detail::to_raw_pointer(this->m_holder.start()), n); + //m_holder.size was already initialized to n in vector_alloc_holder's constructor + } + + void priv_destroy(value_type* p) BOOST_CONTAINER_NOEXCEPT + { + if(!value_traits::trivial_dctr) + allocator_traits_type::destroy(this->get_stored_allocator(), p); + } + + void priv_destroy_last_n(size_type n) BOOST_CONTAINER_NOEXCEPT + { + T* const end_pos = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; + boost::container::destroy_alloc_n(this->get_stored_allocator(), end_pos-n, n); + this->m_holder.m_size -= n; + } + + void priv_destroy_all() BOOST_CONTAINER_NOEXCEPT + { + boost::container::destroy_alloc_n + (this->get_stored_allocator(), container_detail::to_raw_pointer(this->m_holder.start()), this->m_holder.m_size); + this->m_holder.m_size = 0; + } + template iterator priv_insert(const const_iterator &p, BOOST_FWD_REF(U) x) { return this->priv_forward_range_insert - (p.get_ptr(), 1, container_detail::get_insert_value_proxy(this->alloc(), ::boost::forward(x))); + ( vector_iterator_get_ptr(p), 1, container_detail::get_insert_value_proxy(this->m_holder.alloc() + , ::boost::forward(x)), alloc_version()); } - template - void priv_push_back(BOOST_FWD_REF(U) x) + void priv_push_back(const T &x) { - if (this->members_.m_size < this->members_.m_capacity){ + if (this->m_holder.m_size < this->m_holder.capacity()){ //There is more memory, just construct a new object at the end allocator_traits_type::construct - ( this->alloc() - , container_detail::to_raw_pointer(this->members_.m_start + this->members_.m_size) - , ::boost::forward(x) ); - ++this->members_.m_size; + ( this->m_holder.alloc() + , container_detail::to_raw_pointer(this->m_holder.start() + this->m_holder.m_size) + , x ); + ++this->m_holder.m_size; } else{ - this->priv_insert(this->cend(), ::boost::forward(x)); + container_detail::insert_copy_proxy proxy(this->m_holder.alloc(), x); + this->priv_forward_range_insert_no_capacity(vector_iterator_get_ptr(this->cend()), 1, proxy, alloc_version()); } } + void priv_push_back(BOOST_RV_REF(T) x) + { + if (this->m_holder.m_size < this->m_holder.capacity()){ + //There is more memory, just construct a new object at the end + allocator_traits_type::construct + ( this->m_holder.alloc() + , container_detail::to_raw_pointer(this->m_holder.start() + this->m_holder.m_size) + , ::boost::move(x) ); + ++this->m_holder.m_size; + } + else{ + container_detail::insert_move_proxy proxy(this->m_holder.alloc(), x); + this->priv_forward_range_insert_no_capacity(vector_iterator_get_ptr(this->cend()), 1, proxy, alloc_version()); + } + } + + void priv_shrink_to_fit(allocator_v0) BOOST_CONTAINER_NOEXCEPT + {} + void priv_shrink_to_fit(allocator_v1) { - if(this->members_.m_capacity){ - if(!this->size()){ - this->prot_deallocate(); + const size_type cp = this->m_holder.capacity(); + if(cp){ + const size_type sz = this->size(); + if(!sz){ + this->m_holder.alloc().deallocate(this->m_holder.m_start, cp); + this->m_holder.m_start = pointer(); + this->m_holder.m_capacity = 0; } - else{ + else if(sz < cp){ //Allocate a new buffer. - size_type real_cap = 0; - std::pair ret = - this->allocation_command - (allocate_new, this->size(), this->size(), real_cap, this->members_.m_start); - if(real_cap < this->capacity()){ - //We will reuse insert code, so create a dummy input iterator - container_detail::insert_range_proxy, T*> - proxy(this->alloc(), ::boost::make_move_iterator((T *)0)); - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_alloc; - #endif - this->priv_range_insert_new_allocation - ( container_detail::to_raw_pointer(ret.first) - , real_cap - , container_detail::to_raw_pointer(this->members_.m_start) - , 0 - , proxy); - } - else{ - this->alloc().deallocate(ret.first, real_cap); - } + pointer p = this->m_holder.allocate(sz); + + //We will reuse insert code, so create a dummy input iterator + container_detail::insert_range_proxy, T*> + proxy(this->m_holder.alloc(), ::boost::make_move_iterator((T *)0)); + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + this->priv_forward_range_insert_new_allocation + ( container_detail::to_raw_pointer(p) + , sz + , container_detail::to_raw_pointer(this->m_holder.start()) + , 0 + , proxy); } } } - void priv_shrink_to_fit(allocator_v2) + void priv_shrink_to_fit(allocator_v2) BOOST_CONTAINER_NOEXCEPT { - if(this->members_.m_capacity){ - if(!size()){ - this->prot_deallocate(); + const size_type cp = this->m_holder.capacity(); + if(cp){ + const size_type sz = this->size(); + if(!sz){ + this->m_holder.alloc().deallocate(this->m_holder.m_start, cp); + this->m_holder.m_start = pointer(); + this->m_holder.m_capacity = 0; } else{ size_type received_size; - if(this->allocation_command + if(this->m_holder.allocation_command ( shrink_in_place | nothrow_allocation - , this->capacity(), this->size() - , received_size, this->members_.m_start).first){ - this->members_.m_capacity = received_size; + , cp, sz, received_size, this->m_holder.start()).first){ + this->m_holder.capacity(received_size); #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS ++this->num_shrink; #endif @@ -1408,78 +1864,164 @@ class vector : private container_detail::vector_alloc_holder } template - iterator priv_forward_range_insert - (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy) + iterator priv_forward_range_insert_no_capacity + (const pointer &pos, const size_type, const InsertionProxy , allocator_v0) + { + throw_bad_alloc(); + return iterator(pos); + } + + template + iterator priv_forward_range_insert_no_capacity + (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) { //Check if we have enough memory or try to expand current memory - const size_type remaining = this->members_.m_capacity - this->members_.m_size; - const size_type n_pos = pos - this->members_.m_start; + const size_type n_pos = pos - this->m_holder.start(); T *const raw_pos = container_detail::to_raw_pointer(pos); - //Check if we already have room - if(alloc_version::value > 1){ //Version 2 allocator, compile time check - bool same_buffer_start = n <= remaining; - if (!same_buffer_start){ - size_type real_cap = 0; - //There is not enough memory, allocate a new - //buffer or expand the old one. - std::pair ret = (this->allocation_command - (allocate_new | expand_fwd | expand_bwd, - this->members_.m_size + n, this->next_capacity(n), real_cap, this->members_.m_start)); + const size_type new_cap = this->m_holder.next_capacity(n); + T * new_buf = container_detail::to_raw_pointer(this->m_holder.alloc().allocate(new_cap)); + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + this->priv_forward_range_insert_new_allocation + ( new_buf, new_cap, raw_pos, n, insert_range_proxy); + return iterator(this->m_holder.start() + n_pos); + } - //Buffer reallocated - if(ret.second){ - //Forward expansion, delay insertion - if(this->members_.m_start == ret.first){ - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_expand_fwd; - #endif - this->members_.m_capacity = real_cap; - //Expand forward - this->priv_range_insert_expand_forward(raw_pos, n, insert_range_proxy); - } - //Backwards (and possibly forward) expansion - else{ - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_expand_bwd; - #endif - this->priv_range_insert_expand_backwards - ( container_detail::to_raw_pointer(ret.first) - , real_cap, raw_pos, n, insert_range_proxy); - } - } - //New buffer - else{ - #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_alloc; - #endif - this->priv_range_insert_new_allocation - ( container_detail::to_raw_pointer(ret.first) - , real_cap, raw_pos, n, insert_range_proxy); - } - } - else{ - //Expand forward - this->priv_range_insert_expand_forward - (raw_pos, n, insert_range_proxy); - } - } - else{ //Version 1 allocator - if (n <= remaining){ - this->priv_range_insert_expand_forward - (raw_pos, n, insert_range_proxy); - } - else{ - const size_type new_cap = this->next_capacity(n); - T * new_buf = container_detail::to_raw_pointer(this->alloc().allocate(new_cap)); + + template + iterator priv_forward_range_insert_no_capacity + (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v2) + { + //Check if we have enough memory or try to expand current memory + T *const raw_pos = container_detail::to_raw_pointer(pos); + const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start()); + + size_type real_cap = 0; + //There is not enough memory, allocate a new + //buffer or expand the old one. + std::pair ret = (this->m_holder.allocation_command + (allocate_new | expand_fwd | expand_bwd, + this->m_holder.m_size + n, this->m_holder.next_capacity(n), real_cap, this->m_holder.start())); + + //Buffer reallocated + if(ret.second){ + //Forward expansion, delay insertion + if(this->m_holder.start() == ret.first){ #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS - ++this->num_alloc; + ++this->num_expand_fwd; #endif - this->priv_range_insert_new_allocation - ( new_buf, new_cap, raw_pos, n, insert_range_proxy); + this->m_holder.capacity(real_cap); + //Expand forward + this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy); + } + //Backwards (and possibly forward) expansion + else{ + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_expand_bwd; + #endif + this->priv_forward_range_insert_expand_backwards + ( container_detail::to_raw_pointer(ret.first) + , real_cap, raw_pos, n, insert_range_proxy); } } - return iterator(this->members_.m_start + n_pos); + //New buffer + else{ + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + ++this->num_alloc; + #endif + this->priv_forward_range_insert_new_allocation + ( container_detail::to_raw_pointer(ret.first) + , real_cap, raw_pos, n, insert_range_proxy); + } + + return iterator(this->m_holder.start() + n_pos); + } + + template + iterator priv_forward_range_insert + (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v0) + { + //Check if we have enough memory or try to expand current memory + const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; + + if (n > remaining){ + //This will trigger an error + throw_bad_alloc(); + } + const size_type n_pos = pos - this->m_holder.start(); + T *const raw_pos = container_detail::to_raw_pointer(pos); + this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy); + return iterator(this->m_holder.start() + n_pos); + } + + template + iterator priv_forward_range_insert + (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) + { + //Check if we have enough memory or try to expand current memory + const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; + T *const raw_pos = container_detail::to_raw_pointer(pos); + + if (n <= remaining){ + const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start()); + this->priv_forward_range_insert_expand_forward + (raw_pos, n, insert_range_proxy); + return iterator(this->m_holder.start() + n_pos); + } + else{ + return this->priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version()); + } + } + + template + iterator priv_forward_range_insert + (const pointer &pos, const size_type n, const InsertionProxy insert_range_proxy, allocator_v2) + { + //Check if we have enough memory or try to expand current memory + const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; + + bool same_buffer_start = n <= remaining; + if (!same_buffer_start){ + return priv_forward_range_insert_no_capacity(pos, n, insert_range_proxy, alloc_version()); + } + else{ + //Expand forward + T *const raw_pos = container_detail::to_raw_pointer(pos); + const size_type n_pos = raw_pos - container_detail::to_raw_pointer(this->m_holder.start()); + this->priv_forward_range_insert_expand_forward(raw_pos, n, insert_range_proxy); + return iterator(this->m_holder.start() + n_pos); + } + } + + template + iterator priv_forward_range_insert_at_end + (const size_type n, const InsertionProxy insert_range_proxy, allocator_v0) + { + //Check if we have enough memory or try to expand current memory + const size_type remaining = this->m_holder.capacity() - this->m_holder.m_size; + + if (n > remaining){ + //This will trigger an error + throw_bad_alloc(); + } + this->priv_forward_range_insert_at_end_expand_forward(n, insert_range_proxy); + return this->end(); + } + + template + iterator priv_forward_range_insert_at_end + (const size_type n, const InsertionProxy insert_range_proxy, allocator_v1) + { + return this->priv_forward_range_insert(vector_iterator_get_ptr(this->cend()), n, insert_range_proxy, allocator_v1()); + } + + template + iterator priv_forward_range_insert_at_end + (const size_type n, const InsertionProxy insert_range_proxy, allocator_v2) + { + return this->priv_forward_range_insert(vector_iterator_get_ptr(this->cend()), n, insert_range_proxy, allocator_v2()); } //Absolutely experimental. This function might change, disappear or simply crash! @@ -1489,7 +2031,7 @@ class vector : private container_detail::vector_alloc_holder { const size_type old_size_pos = this->size(); this->reserve(old_size_pos + element_count); - T* const begin_ptr = container_detail::to_raw_pointer(this->members_.m_start); + T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.start()); size_type insertions_left = element_count; size_type next_pos = old_size_pos; size_type hole_size = element_count; @@ -1497,7 +2039,7 @@ class vector : private container_detail::vector_alloc_holder //Exception rollback. If any copy throws before the hole is filled, values //already inserted/copied at the end of the buffer will be destroyed. typename value_traits::ArrayDestructor past_hole_values_destroyer - (begin_ptr + old_size_pos + element_count, this->alloc(), size_type(0u)); + (begin_ptr + old_size_pos + element_count, this->m_holder.alloc(), size_type(0u)); //Loop for each insertion backwards, first moving the elements after the insertion point, //then inserting the element. while(insertions_left){ @@ -1518,12 +2060,12 @@ class vector : private container_detail::vector_alloc_holder //The hole was reduced by priv_insert_ordered_at_shift_range so expand exception rollback range backwards past_hole_values_destroyer.increment_size_backwards(next_pos - pos); //Insert the new value in the hole - allocator_traits_type::construct(this->alloc(), begin_ptr + pos + insertions_left - 1, *(--last_value_it)); + allocator_traits_type::construct(this->m_holder.alloc(), begin_ptr + pos + insertions_left - 1, *(--last_value_it)); --new_hole_size; if(new_hole_size == 0){ //Hole was just filled, disable exception rollback and change vector size past_hole_values_destroyer.release(); - this->members_.m_size += element_count; + this->m_holder.m_size += element_count; } else{ //The hole was reduced by the new insertion by one @@ -1534,7 +2076,7 @@ class vector : private container_detail::vector_alloc_holder if(hole_size){ //Hole was just filled by priv_insert_ordered_at_shift_range, disable exception rollback and change vector size past_hole_values_destroyer.release(); - this->members_.m_size += element_count; + this->m_holder.m_size += element_count; } //Insert the new value in the already constructed range begin_ptr[pos + insertions_left - 1] = *(--last_value_it); @@ -1602,7 +2144,7 @@ class vector : private container_detail::vector_alloc_holder BOOST_ASSERT(first_pos <= last_pos); BOOST_ASSERT(last_pos <= limit_pos); // - T* const begin_ptr = container_detail::to_raw_pointer(this->members_.m_start); + T* const begin_ptr = container_detail::to_raw_pointer(this->m_holder.start()); T* const first_ptr = begin_ptr + first_pos; T* const last_ptr = begin_ptr + last_pos; @@ -1615,7 +2157,8 @@ class vector : private container_detail::vector_alloc_holder //Case B: else if((first_pos + shift_count) >= limit_pos){ //All uninitialized_moved - ::boost::container::uninitialized_move_alloc(this->alloc(), first_ptr, last_ptr, first_ptr + shift_count); + ::boost::container::uninitialized_move_alloc + (this->m_holder.alloc(), first_ptr, last_ptr, first_ptr + shift_count); hole_size = last_pos + shift_count - limit_pos; } //Case C: @@ -1623,7 +2166,7 @@ class vector : private container_detail::vector_alloc_holder //Some uninitialized_moved T* const limit_ptr = begin_ptr + limit_pos; T* const boundary_ptr = limit_ptr - shift_count; - ::boost::container::uninitialized_move_alloc(this->alloc(), boundary_ptr, last_ptr, limit_ptr); + ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), boundary_ptr, last_ptr, limit_ptr); //The rest is move assigned boost::move_backward(first_ptr, boundary_ptr, limit_ptr); } @@ -1632,25 +2175,32 @@ class vector : private container_detail::vector_alloc_holder private: template - void priv_range_insert_expand_forward(T* const pos, const size_type n, InsertionProxy insert_range_proxy) + void priv_forward_range_insert_at_end_expand_forward(const size_type n, InsertionProxy insert_range_proxy) + { + T* const old_finish = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; + insert_range_proxy.uninitialized_copy_n_and_update(old_finish, n); + this->m_holder.m_size += n; + } + + template + void priv_forward_range_insert_expand_forward(T* const pos, const size_type n, InsertionProxy insert_range_proxy) { //n can't be 0, because there is nothing to do in that case if(!n) return; //There is enough memory - T* const old_finish = container_detail::to_raw_pointer(this->members_.m_start) + this->members_.m_size; + T* const old_finish = container_detail::to_raw_pointer(this->m_holder.start()) + this->m_holder.m_size; const size_type elems_after = old_finish - pos; if (!elems_after){ - //Copy first new elements in pos - insert_range_proxy.uninitialized_copy_n_and_update(pos, n); - this->members_.m_size += n; + insert_range_proxy.uninitialized_copy_n_and_update(old_finish, n); + this->m_holder.m_size += n; } else if (elems_after >= n){ //New elements can be just copied. //Move to uninitialized memory last objects ::boost::container::uninitialized_move_alloc - (this->alloc(), old_finish - n, old_finish, old_finish); - this->members_.m_size += n; + (this->m_holder.alloc(), old_finish - n, old_finish, old_finish); + this->m_holder.m_size += n; //Copy previous to last objects to the initialized end boost::move_backward(pos, old_finish - n, old_finish); //Insert new objects in the pos @@ -1660,16 +2210,16 @@ class vector : private container_detail::vector_alloc_holder //The new elements don't fit in the [pos, end()) range. //Copy old [pos, end()) elements to the uninitialized memory (a gap is created) - ::boost::container::uninitialized_move_alloc(this->alloc(), pos, old_finish, pos + n); + ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), pos, old_finish, pos + n); BOOST_TRY{ //Copy first new elements in pos (gap is still there) insert_range_proxy.copy_n_and_update(pos, elems_after); //Copy to the beginning of the unallocated zone the last new elements (the gap is closed). insert_range_proxy.uninitialized_copy_n_and_update(old_finish, n - elems_after); - this->members_.m_size += n; + this->m_holder.m_size += n; } BOOST_CATCH(...){ - this->destroy_n(pos + n, elems_after); + boost::container::destroy_alloc_n(this->get_stored_allocator(), pos + n, elems_after); BOOST_RETHROW } BOOST_CATCH_END @@ -1677,22 +2227,22 @@ class vector : private container_detail::vector_alloc_holder } template - void priv_range_insert_new_allocation + void priv_forward_range_insert_new_allocation (T* const new_start, size_type new_cap, T* const pos, const size_type n, InsertionProxy insert_range_proxy) { //n can be zero, if we want to reallocate! T *new_finish = new_start; T *old_finish; //Anti-exception rollbacks - typename value_traits::ArrayDeallocator scoped_alloc(new_start, this->alloc(), new_cap); - typename value_traits::ArrayDestructor constructed_values_destroyer(new_start, this->alloc(), 0u); + typename value_traits::ArrayDeallocator scoped_alloc(new_start, this->m_holder.alloc(), new_cap); + typename value_traits::ArrayDestructor constructed_values_destroyer(new_start, this->m_holder.alloc(), 0u); //Initialize with [begin(), pos) old buffer //the start of the new buffer - T *old_buffer = container_detail::to_raw_pointer(this->members_.m_start); + T *old_buffer = container_detail::to_raw_pointer(this->m_holder.start()); if(old_buffer){ new_finish = ::boost::container::uninitialized_move_alloc - (this->alloc(), container_detail::to_raw_pointer(this->members_.m_start), pos, old_finish = new_finish); + (this->m_holder.alloc(), container_detail::to_raw_pointer(this->m_holder.start()), pos, old_finish = new_finish); constructed_values_destroyer.increment_size(new_finish - old_finish); } //Initialize new objects, starting from previous point @@ -1703,31 +2253,31 @@ class vector : private container_detail::vector_alloc_holder //starting from previous point if(old_buffer){ new_finish = ::boost::container::uninitialized_move_alloc - (this->alloc(), pos, old_buffer + this->members_.m_size, new_finish); + (this->m_holder.alloc(), pos, old_buffer + this->m_holder.m_size, new_finish); //Destroy and deallocate old elements //If there is allocated memory, destroy and deallocate if(!value_traits::trivial_dctr_after_move) - this->destroy_n(old_buffer, this->members_.m_size); - this->alloc().deallocate(this->members_.m_start, this->members_.m_capacity); + boost::container::destroy_alloc_n(this->get_stored_allocator(), old_buffer, this->m_holder.m_size); + this->m_holder.alloc().deallocate(this->m_holder.start(), this->m_holder.capacity()); } - this->members_.m_start = new_start; - this->members_.m_size = new_finish - new_start; - this->members_.m_capacity = new_cap; + this->m_holder.start(new_start); + this->m_holder.m_size = new_finish - new_start; + this->m_holder.capacity(new_cap); //All construction successful, disable rollbacks constructed_values_destroyer.release(); scoped_alloc.release(); } template - void priv_range_insert_expand_backwards + void priv_forward_range_insert_expand_backwards (T* const new_start, const size_type new_capacity, T* const pos, const size_type n, InsertionProxy insert_range_proxy) { //n can be zero to just expand capacity //Backup old data - T* const old_start = container_detail::to_raw_pointer(this->members_.m_start); - T* const old_finish = old_start + this->members_.m_size; - const size_type old_size = this->members_.m_size; + T* const old_start = container_detail::to_raw_pointer(this->m_holder.start()); + T* const old_finish = old_start + this->m_holder.m_size; + const size_type old_size = this->m_holder.m_size; //We can have 8 possibilities: const size_type elemsbefore = static_cast(pos - old_start); @@ -1735,20 +2285,20 @@ class vector : private container_detail::vector_alloc_holder const size_type before_plus_new = elemsbefore + n; //Update the vector buffer information to a safe state - this->members_.m_start = new_start; - this->members_.m_capacity = new_capacity; - this->members_.m_size = 0; + this->m_holder.start(new_start); + this->m_holder.capacity(new_capacity); + this->m_holder.m_size = 0; //If anything goes wrong, this object will destroy //all the old objects to fulfill previous vector state - typename value_traits::OldArrayDestructor old_values_destroyer(old_start, this->alloc(), old_size); + typename value_traits::OldArrayDestructor old_values_destroyer(old_start, this->m_holder.alloc(), old_size); //Check if s_before is big enough to hold the beginning of old data + new data if(s_before >= before_plus_new){ //Copy first old values before pos, after that the new objects - T *const new_elem_pos = ::boost::container::uninitialized_move_alloc(this->alloc(), old_start, pos, new_start); - this->members_.m_size = elemsbefore; + T *const new_elem_pos = ::boost::container::uninitialized_move_alloc(this->m_holder.alloc(), old_start, pos, new_start); + this->m_holder.m_size = elemsbefore; insert_range_proxy.uninitialized_copy_n_and_update(new_elem_pos, n); - this->members_.m_size += n; + this->m_holder.m_size += n; //Check if s_before is so big that even copying the old data + new data //there is a gap between the new data and the old data const size_type new_size = old_size + n; @@ -1765,9 +2315,9 @@ class vector : private container_detail::vector_alloc_holder // //Now initialize the rest of memory with the last old values ::boost::container::uninitialized_move_alloc - (this->alloc(), pos, old_finish, new_start + before_plus_new); + (this->m_holder.alloc(), pos, old_finish, new_start + before_plus_new); //All new elements correctly constructed, avoid new element destruction - this->members_.m_size = new_size; + this->m_holder.m_size = new_size; //Old values destroyed automatically with "old_values_destroyer" //when "old_values_destroyer" goes out of scope unless the have trivial //destructor after move. @@ -1792,9 +2342,9 @@ class vector : private container_detail::vector_alloc_holder //Now initialize the rest of s_before memory with the //first of elements after new values ::boost::container::uninitialized_move_alloc_n - (this->alloc(), pos, raw_gap, new_start + before_plus_new); + (this->m_holder.alloc(), pos, raw_gap, new_start + before_plus_new); //Update size since we have a contiguous buffer - this->members_.m_size = old_size + s_before; + this->m_holder.m_size = old_size + s_before; //All new elements correctly constructed, avoid old element destruction old_values_destroyer.release(); //Now copy remaining last objects in the old buffer begin @@ -1803,8 +2353,8 @@ class vector : private container_detail::vector_alloc_holder //they have trivial destructor after move size_type n_destroy = old_finish - to_destroy; if(!value_traits::trivial_dctr_after_move) - this->destroy_n(to_destroy, n_destroy); - this->members_.m_size -= n_destroy; + boost::container::destroy_alloc_n(this->get_stored_allocator(), to_destroy, n_destroy); + this->m_holder.m_size -= n_destroy; } } else{ @@ -1857,11 +2407,11 @@ class vector : private container_detail::vector_alloc_holder // //Copy the first part of old_begin to raw_mem ::boost::container::uninitialized_move_alloc_n - (this->alloc(), old_start, s_before, new_start); + (this->m_holder.alloc(), old_start, s_before, new_start); //The buffer is all constructed until old_end, //release destroyer and update size old_values_destroyer.release(); - this->members_.m_size = old_size + s_before; + this->m_holder.m_size = old_size + s_before; //Now copy the second part of old_begin overwriting itself T *const next = ::boost::move(old_start + s_before, pos, old_start); if(do_after){ @@ -1877,8 +2427,8 @@ class vector : private container_detail::vector_alloc_holder //they have trivial destructor after being moved const size_type n_destroy = s_before - n; if(!value_traits::trivial_dctr_after_move) - this->destroy_n(move_end, n_destroy); - this->members_.m_size -= n_destroy; + boost::container::destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy); + this->m_holder.m_size -= n_destroy; } } else { @@ -1909,13 +2459,13 @@ class vector : private container_detail::vector_alloc_holder // //First copy whole old_begin and part of new to raw_mem T * const new_pos = ::boost::container::uninitialized_move_alloc - (this->alloc(), old_start, pos, new_start); - this->members_.m_size = elemsbefore; + (this->m_holder.alloc(), old_start, pos, new_start); + this->m_holder.m_size = elemsbefore; const size_type mid_n = s_before - elemsbefore; insert_range_proxy.uninitialized_copy_n_and_update(new_pos, mid_n); //The buffer is all constructed until old_end, //release destroyer - this->members_.m_size = old_size + s_before; + this->m_holder.m_size = old_size + s_before; old_values_destroyer.release(); if(do_after){ @@ -1933,8 +2483,8 @@ class vector : private container_detail::vector_alloc_holder //have trivial destructor after being moved size_type n_destroy = s_before - n; if(!value_traits::trivial_dctr_after_move) - this->destroy_n(move_end, n_destroy); - this->members_.m_size -= n_destroy; + boost::container::destroy_alloc_n(this->get_stored_allocator(), move_end, n_destroy); + this->m_holder.m_size -= n_destroy; } } @@ -1977,8 +2527,8 @@ class vector : private container_detail::vector_alloc_holder //First copy the part of old_end raw_mem T* finish_n = old_finish - n_after; ::boost::container::uninitialized_move_alloc - (this->alloc(), finish_n, old_finish, old_finish); - this->members_.m_size += n_after; + (this->m_holder.alloc(), finish_n, old_finish, old_finish); + this->m_holder.m_size += n_after; //Displace the rest of old_end to the new position boost::move_backward(pos, finish_n, old_finish); //Now overwrite with new_end @@ -2004,17 +2554,17 @@ class vector : private container_detail::vector_alloc_holder //Copy to the old_end part to the uninitialized zone leaving a gap. ::boost::container::uninitialized_move_alloc - (this->alloc(), pos, old_finish, old_finish + mid_last_dist); + (this->m_holder.alloc(), pos, old_finish, old_finish + mid_last_dist); BOOST_TRY{ //Copy the first part to the already constructed old_end zone insert_range_proxy.copy_n_and_update(pos, elemsafter); //Copy the rest to the uninitialized zone filling the gap insert_range_proxy.uninitialized_copy_n_and_update(old_finish, mid_last_dist); - this->members_.m_size += n_after; + this->m_holder.m_size += n_after; } BOOST_CATCH(...){ - this->destroy_n(pos, mid_last_dist); + boost::container::destroy_alloc_n(this->get_stored_allocator(), pos, mid_last_dist); BOOST_RETHROW } BOOST_CATCH_END @@ -2024,10 +2574,10 @@ class vector : private container_detail::vector_alloc_holder //The new_end part is [first + (n - n_after), last) insert_range_proxy.uninitialized_copy_last_and_update(old_finish, elemsafter); - this->members_.m_size += mid_last_dist; + this->m_holder.m_size += mid_last_dist; ::boost::container::uninitialized_move_alloc - (this->alloc(), pos, old_finish, old_finish + mid_last_dist); - this->members_.m_size += n_after - mid_last_dist; + (this->m_holder.alloc(), pos, old_finish, old_finish + mid_last_dist); + this->m_holder.m_size += n_after - mid_last_dist; //Now copy the part of new_end over constructed elements insert_range_proxy.copy_remaining_to(pos);*/ } @@ -2038,8 +2588,9 @@ class vector : private container_detail::vector_alloc_holder void priv_check_range(size_type n) const { //If n is out of range, throw an out_of_range exception - if (n >= this->size()) - throw std::out_of_range("vector::at"); + if (n >= this->size()){ + throw_out_of_range("vector::at out of range"); + } } #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS @@ -2098,6 +2649,20 @@ struct has_trivial_destructor_after_move } +//#define BOOST_CONTAINER_PUT_SWAP_OVERLOAD_IN_NAMESPACE_STD + +#ifdef BOOST_CONTAINER_PUT_SWAP_OVERLOAD_IN_NAMESPACE_STD + +namespace std { + +template +inline void swap(boost::container::vector& x, boost::container::vector& y) +{ x.swap(y); } + +} //namespace std { + +#endif + /// @endcond #include