diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2022-12-29 14:23:17 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2022-12-29 14:23:17 +0300 |
commit | 9d79f37dd74e285180318d1e2b4b0beaf4fee9fa (patch) | |
tree | 657aa7de3c01766376542ef8df72a131c9dd6671 /contrib | |
parent | f3c5bbbd24345e6b826e143843b07d416e34a2b4 (diff) | |
download | ydb-9d79f37dd74e285180318d1e2b4b0beaf4fee9fa.tar.gz |
Update contrib/restricted/boost/container to 1.81.0
Diffstat (limited to 'contrib')
10 files changed, 1038 insertions, 486 deletions
diff --git a/contrib/restricted/boost/container/include/boost/container/container_fwd.hpp b/contrib/restricted/boost/container/include/boost/container/container_fwd.hpp index 9e82fdef66..df0fc1208a 100644 --- a/contrib/restricted/boost/container/include/boost/container/container_fwd.hpp +++ b/contrib/restricted/boost/container/include/boost/container/container_fwd.hpp @@ -186,6 +186,35 @@ template <class Key ,class Allocator = void > class flat_multimap; +//Experimental forward declarations, not implemented yet! +template <class Key + ,class Hash //= hash<Key>, + ,class Pred = std::equal_to<Key> + ,class Compare = std::less<Key> + ,class Allocator = void + ,class Options = void> +class hash_set; + +template <class Key + ,class Compare = std::less<Key> + ,class Allocator = void + ,class Options = void > +class hash_multiset; + +template <class Key + ,class T + ,class Compare = std::less<Key> + ,class Allocator = void + ,class Options = void > +class hash_map; + +template <class Key + ,class T + ,class Compare = std::less<Key> + ,class Allocator = void + ,class Options = void > +class hash_multimap; + #ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES //! Alias templates for small_flat_[multi]{set|map} using small_vector as container diff --git a/contrib/restricted/boost/container/include/boost/container/detail/advanced_insert_int.hpp b/contrib/restricted/boost/container/include/boost/container/detail/advanced_insert_int.hpp index 18c7935639..39df13f812 100644 --- a/contrib/restricted/boost/container/include/boost/container/detail/advanced_insert_int.hpp +++ b/contrib/restricted/boost/container/include/boost/container/detail/advanced_insert_int.hpp @@ -45,7 +45,7 @@ namespace boost { namespace container { namespace dtl { -template<class Allocator, class FwdIt, class Iterator> +template<class Allocator, class FwdIt> struct move_insert_range_proxy { typedef typename allocator_traits<Allocator>::value_type value_type; @@ -54,12 +54,14 @@ struct move_insert_range_proxy : first_(first) {} + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, std::size_t n) { this->first_ = ::boost::container::uninitialized_move_alloc_n_source (a, this->first_, n, p); } + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator p, std::size_t n) { this->first_ = ::boost::container::move_n_source(this->first_, n, p); @@ -69,7 +71,7 @@ struct move_insert_range_proxy }; -template<class Allocator, class FwdIt, class Iterator> +template<class Allocator, class FwdIt> struct insert_range_proxy { typedef typename allocator_traits<Allocator>::value_type value_type; @@ -78,11 +80,13 @@ struct insert_range_proxy : first_(first) {} + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, std::size_t n) { this->first_ = ::boost::container::uninitialized_copy_alloc_n_source(a, this->first_, n, p); } + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator p, std::size_t n) { this->first_ = ::boost::container::copy_n_source(this->first_, n, p); @@ -92,7 +96,7 @@ struct insert_range_proxy }; -template<class Allocator, class Iterator> +template<class Allocator> struct insert_n_copies_proxy { typedef typename allocator_traits<Allocator>::value_type value_type; @@ -101,9 +105,11 @@ struct insert_n_copies_proxy : v_(v) {} + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, std::size_t n) const { boost::container::uninitialized_fill_alloc_n(a, v_, n, p); } + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator p, std::size_t n) const { while (n){ @@ -116,16 +122,18 @@ struct insert_n_copies_proxy const value_type &v_; }; -template<class Allocator, class Iterator> +template<class Allocator> struct insert_value_initialized_n_proxy { typedef ::boost::container::allocator_traits<Allocator> alloc_traits; typedef typename allocator_traits<Allocator>::value_type value_type; typedef typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type storage_t; + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, std::size_t n) const { boost::container::uninitialized_value_init_alloc_n(a, n, p); } + template<class Iterator> void copy_n_and_update(Allocator &a, Iterator p, std::size_t n) const { while (n){ @@ -140,16 +148,18 @@ struct insert_value_initialized_n_proxy } }; -template<class Allocator, class Iterator> +template<class Allocator> struct insert_default_initialized_n_proxy { typedef ::boost::container::allocator_traits<Allocator> alloc_traits; typedef typename allocator_traits<Allocator>::value_type value_type; typedef typename dtl::aligned_storage<sizeof(value_type), dtl::alignment_of<value_type>::value>::type storage_t; + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, std::size_t n) const { boost::container::uninitialized_default_init_alloc_n(a, n, p); } + template<class Iterator> void copy_n_and_update(Allocator &a, Iterator p, std::size_t n) const { if(!is_pod<value_type>::value){ @@ -166,7 +176,7 @@ struct insert_default_initialized_n_proxy } }; -template<class Allocator, class Iterator> +template<class Allocator> struct insert_copy_proxy { typedef boost::container::allocator_traits<Allocator> alloc_traits; @@ -178,12 +188,14 @@ struct insert_copy_proxy : v_(v) {} + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, std::size_t n) const { BOOST_ASSERT(n == 1); (void)n; alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), v_); } + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator p, std::size_t n) const { BOOST_ASSERT(n == 1); (void)n; @@ -194,7 +206,7 @@ struct insert_copy_proxy }; -template<class Allocator, class Iterator> +template<class Allocator> struct insert_move_proxy { typedef boost::container::allocator_traits<Allocator> alloc_traits; @@ -206,12 +218,14 @@ struct insert_move_proxy : v_(v) {} + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, std::size_t n) const { BOOST_ASSERT(n == 1); (void)n; alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), ::boost::move(v_) ); } + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator p, std::size_t n) const { BOOST_ASSERT(n == 1); (void)n; @@ -222,15 +236,15 @@ struct insert_move_proxy }; template<class It, class Allocator> -BOOST_CONTAINER_FORCEINLINE insert_move_proxy<Allocator, It> get_insert_value_proxy(BOOST_RV_REF(typename boost::container::iterator_traits<It>::value_type) v) +BOOST_CONTAINER_FORCEINLINE insert_move_proxy<Allocator> get_insert_value_proxy(BOOST_RV_REF(typename boost::container::iterator_traits<It>::value_type) v) { - return insert_move_proxy<Allocator, It>(v); + return insert_move_proxy<Allocator>(v); } template<class It, class Allocator> -BOOST_CONTAINER_FORCEINLINE insert_copy_proxy<Allocator, It> get_insert_value_proxy(const typename boost::container::iterator_traits<It>::value_type &v) +BOOST_CONTAINER_FORCEINLINE insert_copy_proxy<Allocator> get_insert_value_proxy(const typename boost::container::iterator_traits<It>::value_type &v) { - return insert_copy_proxy<Allocator, It>(v); + return insert_copy_proxy<Allocator>(v); } }}} //namespace boost { namespace container { namespace dtl { @@ -244,7 +258,7 @@ namespace boost { namespace container { namespace dtl { -template<class Allocator, class Iterator, class ...Args> +template<class Allocator, class ...Args> struct insert_nonmovable_emplace_proxy { typedef boost::container::allocator_traits<Allocator> alloc_traits; @@ -257,11 +271,12 @@ struct insert_nonmovable_emplace_proxy : args_(args...) {} + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, std::size_t n) { this->priv_uninitialized_copy_some_and_update(a, index_tuple_t(), p, n); } private: - template<std::size_t ...IdxPack> + template<std::size_t ...IdxPack, class Iterator> BOOST_CONTAINER_FORCEINLINE void priv_uninitialized_copy_some_and_update(Allocator &a, const index_tuple<IdxPack...>&, Iterator p, std::size_t n) { BOOST_ASSERT(n == 1); (void)n; @@ -272,11 +287,11 @@ struct insert_nonmovable_emplace_proxy tuple<Args&...> args_; }; -template<class Allocator, class Iterator, class ...Args> +template<class Allocator, class ...Args> struct insert_emplace_proxy - : public insert_nonmovable_emplace_proxy<Allocator, Iterator, Args...> + : public insert_nonmovable_emplace_proxy<Allocator, Args...> { - typedef insert_nonmovable_emplace_proxy<Allocator, Iterator, Args...> base_t; + typedef insert_nonmovable_emplace_proxy<Allocator, Args...> base_t; typedef boost::container::allocator_traits<Allocator> alloc_traits; typedef typename base_t::value_type value_type; typedef typename base_t::index_tuple_t index_tuple_t; @@ -287,12 +302,13 @@ struct insert_emplace_proxy : base_t(::boost::forward<Args>(args)...) {} + template<class Iterator> BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &a, Iterator p, std::size_t n) { this->priv_copy_some_and_update(a, index_tuple_t(), p, n); } private: - template<std::size_t ...IdxPack> + template<std::size_t ...IdxPack, class Iterator> BOOST_CONTAINER_FORCEINLINE void priv_copy_some_and_update(Allocator &a, const index_tuple<IdxPack...>&, Iterator p, std::size_t n) { BOOST_ASSERT(n ==1); (void)n; @@ -312,55 +328,55 @@ struct insert_emplace_proxy }; //Specializations to avoid an unneeded temporary when emplacing from a single argument o type value_type -template<class Allocator, class Iterator> -struct insert_emplace_proxy<Allocator, Iterator, typename boost::container::allocator_traits<Allocator>::value_type> - : public insert_move_proxy<Allocator, Iterator> +template<class Allocator> +struct insert_emplace_proxy<Allocator, typename boost::container::allocator_traits<Allocator>::value_type> + : public insert_move_proxy<Allocator> { static const bool single_value = true; BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy(typename boost::container::allocator_traits<Allocator>::value_type &&v) - : insert_move_proxy<Allocator, Iterator>(v) + : insert_move_proxy<Allocator>(v) {} }; //We use "add_const" here as adding "const" only confuses MSVC12(and maybe later) provoking //compiler error C2752 ("more than one partial specialization matches"). //Any problem is solvable with an extra layer of indirection? ;-) -template<class Allocator, class Iterator> -struct insert_emplace_proxy<Allocator, Iterator +template<class Allocator> +struct insert_emplace_proxy<Allocator , typename boost::container::dtl::add_const<typename boost::container::allocator_traits<Allocator>::value_type>::type > - : public insert_copy_proxy<Allocator, Iterator> + : public insert_copy_proxy<Allocator> { static const bool single_value = true; BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy(const typename boost::container::allocator_traits<Allocator>::value_type &v) - : insert_copy_proxy<Allocator, Iterator>(v) + : insert_copy_proxy<Allocator>(v) {} }; -template<class Allocator, class Iterator> -struct insert_emplace_proxy<Allocator, Iterator, typename boost::container::allocator_traits<Allocator>::value_type &> - : public insert_copy_proxy<Allocator, Iterator> +template<class Allocator> +struct insert_emplace_proxy<Allocator, typename boost::container::allocator_traits<Allocator>::value_type &> + : public insert_copy_proxy<Allocator> { static const bool single_value = true; BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy(const typename boost::container::allocator_traits<Allocator>::value_type &v) - : insert_copy_proxy<Allocator, Iterator>(v) + : insert_copy_proxy<Allocator>(v) {} }; -template<class Allocator, class Iterator> -struct insert_emplace_proxy<Allocator, Iterator +template<class Allocator> +struct insert_emplace_proxy<Allocator , typename boost::container::dtl::add_const<typename boost::container::allocator_traits<Allocator>::value_type>::type & > - : public insert_copy_proxy<Allocator, Iterator> + : public insert_copy_proxy<Allocator> { static const bool single_value = true; BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy(const typename boost::container::allocator_traits<Allocator>::value_type &v) - : insert_copy_proxy<Allocator, Iterator>(v) + : insert_copy_proxy<Allocator>(v) {} }; @@ -375,7 +391,7 @@ namespace container { namespace dtl { #define BOOST_CONTAINER_ADVANCED_INSERT_INT_CODE(N) \ -template< class Allocator, class Iterator BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ +template< class Allocator BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ struct insert_nonmovable_emplace_proxy##N\ {\ typedef boost::container::allocator_traits<Allocator> alloc_traits;\ @@ -386,12 +402,14 @@ struct insert_nonmovable_emplace_proxy##N\ BOOST_CONTAINER_FORCEINLINE explicit insert_nonmovable_emplace_proxy##N(BOOST_MOVE_UREF##N)\ BOOST_MOVE_COLON##N BOOST_MOVE_FWD_INIT##N {}\ \ + template<class Iterator>\ BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, std::size_t n)\ {\ BOOST_ASSERT(n == 1); (void)n;\ alloc_traits::construct(a, boost::movelib::iterator_to_raw_pointer(p) BOOST_MOVE_I##N BOOST_MOVE_MFWD##N);\ }\ \ + template<class Iterator>\ BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator, std::size_t)\ { BOOST_ASSERT(false); }\ \ @@ -399,12 +417,12 @@ struct insert_nonmovable_emplace_proxy##N\ BOOST_MOVE_MREF##N\ };\ \ -template< class Allocator, class Iterator BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ +template< class Allocator BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ struct insert_emplace_proxy_arg##N\ - : insert_nonmovable_emplace_proxy##N< Allocator, Iterator BOOST_MOVE_I##N BOOST_MOVE_TARG##N >\ + : insert_nonmovable_emplace_proxy##N< Allocator BOOST_MOVE_I##N BOOST_MOVE_TARG##N >\ {\ typedef insert_nonmovable_emplace_proxy##N\ - < Allocator, Iterator BOOST_MOVE_I##N BOOST_MOVE_TARG##N > base_t;\ + < Allocator BOOST_MOVE_I##N BOOST_MOVE_TARG##N > base_t;\ typedef typename base_t::value_type value_type;\ typedef boost::container::allocator_traits<Allocator> alloc_traits;\ \ @@ -413,6 +431,7 @@ struct insert_emplace_proxy_arg##N\ BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg##N(BOOST_MOVE_UREF##N)\ : base_t(BOOST_MOVE_FWD##N){}\ \ + template<class Iterator>\ BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &a, Iterator p, std::size_t n)\ {\ BOOST_ASSERT(n == 1); (void)n;\ @@ -437,79 +456,79 @@ BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_ADVANCED_INSERT_INT_CODE) #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) //Specializations to avoid an unneeded temporary when emplacing from a single argument o type value_type -template<class Allocator, class Iterator> -struct insert_emplace_proxy_arg1<Allocator, Iterator, ::boost::rv<typename boost::container::allocator_traits<Allocator>::value_type> > - : public insert_move_proxy<Allocator, Iterator> +template<class Allocator> +struct insert_emplace_proxy_arg1<Allocator, ::boost::rv<typename boost::container::allocator_traits<Allocator>::value_type> > + : public insert_move_proxy<Allocator> { static const bool single_value = true; BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg1(typename boost::container::allocator_traits<Allocator>::value_type &v) - : insert_move_proxy<Allocator, Iterator>(v) + : insert_move_proxy<Allocator>(v) {} }; -template<class Allocator, class Iterator> -struct insert_emplace_proxy_arg1<Allocator, Iterator, typename boost::container::allocator_traits<Allocator>::value_type> - : public insert_copy_proxy<Allocator, Iterator> +template<class Allocator> +struct insert_emplace_proxy_arg1<Allocator, typename boost::container::allocator_traits<Allocator>::value_type> + : public insert_copy_proxy<Allocator> { static const bool single_value = true; BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits<Allocator>::value_type &v) - : insert_copy_proxy<Allocator, Iterator>(v) + : insert_copy_proxy<Allocator>(v) {} }; #else //e.g. MSVC10 & MSVC11 //Specializations to avoid an unneeded temporary when emplacing from a single argument o type value_type -template<class Allocator, class Iterator> -struct insert_emplace_proxy_arg1<Allocator, Iterator, typename boost::container::allocator_traits<Allocator>::value_type> - : public insert_move_proxy<Allocator, Iterator> +template<class Allocator> +struct insert_emplace_proxy_arg1<Allocator, typename boost::container::allocator_traits<Allocator>::value_type> + : public insert_move_proxy<Allocator> { static const bool single_value = true; BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg1(typename boost::container::allocator_traits<Allocator>::value_type &&v) - : insert_move_proxy<Allocator, Iterator>(v) + : insert_move_proxy<Allocator>(v) {} }; //We use "add_const" here as adding "const" only confuses MSVC10&11 provoking //compiler error C2752 ("more than one partial specialization matches"). //Any problem is solvable with an extra layer of indirection? ;-) -template<class Allocator, class Iterator> -struct insert_emplace_proxy_arg1<Allocator, Iterator +template<class Allocator> +struct insert_emplace_proxy_arg1<Allocator , typename boost::container::dtl::add_const<typename boost::container::allocator_traits<Allocator>::value_type>::type > - : public insert_copy_proxy<Allocator, Iterator> + : public insert_copy_proxy<Allocator> { static const bool single_value = true; BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits<Allocator>::value_type &v) - : insert_copy_proxy<Allocator, Iterator>(v) + : insert_copy_proxy<Allocator>(v) {} }; -template<class Allocator, class Iterator> -struct insert_emplace_proxy_arg1<Allocator, Iterator, typename boost::container::allocator_traits<Allocator>::value_type &> - : public insert_copy_proxy<Allocator, Iterator> +template<class Allocator> +struct insert_emplace_proxy_arg1<Allocator, typename boost::container::allocator_traits<Allocator>::value_type &> + : public insert_copy_proxy<Allocator> { static const bool single_value = true; BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits<Allocator>::value_type &v) - : insert_copy_proxy<Allocator, Iterator>(v) + : insert_copy_proxy<Allocator>(v) {} }; -template<class Allocator, class Iterator> -struct insert_emplace_proxy_arg1<Allocator, Iterator +template<class Allocator> +struct insert_emplace_proxy_arg1<Allocator , typename boost::container::dtl::add_const<typename boost::container::allocator_traits<Allocator>::value_type>::type & > - : public insert_copy_proxy<Allocator, Iterator> + : public insert_copy_proxy<Allocator> { static const bool single_value = true; BOOST_CONTAINER_FORCEINLINE explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits<Allocator>::value_type &v) - : insert_copy_proxy<Allocator, Iterator>(v) + : insert_copy_proxy<Allocator>(v) {} }; @@ -519,40 +538,6 @@ struct insert_emplace_proxy_arg1<Allocator, Iterator #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) -namespace boost { namespace container { namespace dtl { - -template <class T> -struct has_single_value -{ - private: - struct two {char array_[2];}; - template<bool Arg> struct wrapper; - template <class U> static two test(int, ...); - template <class U> static char test(int, const wrapper<U::single_value>*); - public: - static const bool value = sizeof(test<T>(0, 0)) == 1; - void dummy(){} -}; - -template<class InsertionProxy, bool = has_single_value<InsertionProxy>::value> -struct is_single_value_proxy_impl -{ - static const bool value = InsertionProxy::single_value; -}; - -template<class InsertionProxy> -struct is_single_value_proxy_impl<InsertionProxy, false> -{ - static const bool value = false; -}; - -template<class InsertionProxy> -struct is_single_value_proxy - : is_single_value_proxy_impl<InsertionProxy> -{}; - -}}} //namespace boost { namespace container { namespace dtl { - #include <boost/container/detail/config_end.hpp> #endif //#ifndef BOOST_CONTAINER_ADVANCED_INSERT_INT_HPP diff --git a/contrib/restricted/boost/container/include/boost/container/detail/config_begin.hpp b/contrib/restricted/boost/container/include/boost/container/detail/config_begin.hpp index 172e685c73..17d9e80e48 100644 --- a/contrib/restricted/boost/container/include/boost/container/detail/config_begin.hpp +++ b/contrib/restricted/boost/container/include/boost/container/detail/config_begin.hpp @@ -48,3 +48,13 @@ #pragma warning (disable : 4996) // "function": was declared deprecated #endif //BOOST_MSVC + + +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +#pragma GCC diagnostic push +//Sign conversion warnings broken before GCC 9.3 +//(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87519) +#if BOOST_GCC < 90300 +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif +#endif diff --git a/contrib/restricted/boost/container/include/boost/container/detail/config_end.hpp b/contrib/restricted/boost/container/include/boost/container/detail/config_end.hpp index f93c8f6f79..65643ea1e1 100644 --- a/contrib/restricted/boost/container/include/boost/container/detail/config_end.hpp +++ b/contrib/restricted/boost/container/include/boost/container/detail/config_end.hpp @@ -11,3 +11,6 @@ #pragma warning (pop) #endif +#if defined(BOOST_GCC) && (BOOST_GCC >= 40600) +#pragma GCC diagnostic pop +#endif diff --git a/contrib/restricted/boost/container/include/boost/container/detail/copy_move_algo.hpp b/contrib/restricted/boost/container/include/boost/container/detail/copy_move_algo.hpp index 9c76f8d69c..47660aa756 100644 --- a/contrib/restricted/boost/container/include/boost/container/detail/copy_move_algo.hpp +++ b/contrib/restricted/boost/container/include/boost/container/detail/copy_move_algo.hpp @@ -32,6 +32,7 @@ #include <boost/move/adl_move_swap.hpp> #include <boost/move/iterator.hpp> #include <boost/move/utility_core.hpp> +#include <boost/move/traits.hpp> // other #include <boost/core/no_exceptions_support.hpp> // std @@ -112,6 +113,7 @@ struct are_elements_contiguous<boost::container::vec_iterator<Pointer, IsConst> static const bool value = true; }; + ///////////////////////// // offset_ptr ///////////////////////// @@ -169,6 +171,46 @@ struct disable_if_memtransfer_copy_assignable : disable_if<dtl::is_memtransfer_copy_assignable<I, O>, R> {}; +template <class T> +struct has_single_value +{ +private: + struct two { char array_[2]; }; + template<bool Arg> struct wrapper; + template <class U> static two test(int, ...); + template <class U> static char test(int, const wrapper<U::single_value>*); +public: + static const bool value = sizeof(test<T>(0, 0)) == 1; + void dummy() {} +}; + +template<class InsertionProxy, bool = has_single_value<InsertionProxy>::value> +struct is_single_value_proxy_impl +{ + static const bool value = InsertionProxy::single_value; +}; + +template<class InsertionProxy> +struct is_single_value_proxy_impl<InsertionProxy, false> +{ + static const bool value = false; +}; + +template<class InsertionProxy> +struct is_single_value_proxy + : is_single_value_proxy_impl<InsertionProxy> +{}; + +template <typename P, typename R = void> +struct enable_if_single_value_proxy + : enable_if<is_single_value_proxy<P>, R> +{}; + +template <typename P, typename R = void> +struct disable_if_single_value_proxy + : disable_if<is_single_value_proxy<P>, R> +{}; + template <typename I, // I models InputIterator typename F> // F models ForwardIterator @@ -978,6 +1020,19 @@ BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_memtransfer_copy_assignable< move_n_source(I f, std::size_t n, F r) BOOST_NOEXCEPT_OR_NOTHROW { return dtl::memmove_n_source(f, n, r); } +template<typename F> // F models ForwardIterator +BOOST_CONTAINER_FORCEINLINE F move_forward_overlapping(F f, F l, F r) +{ + return (f != r) ? (move)(f, l, r) : l; +} + +template<typename B> // B models BidirIterator +BOOST_CONTAINER_FORCEINLINE B move_backward_overlapping(B f, B l, B rl) +{ + return (l != rl) ? (move_backward)(f, l, rl) : f; +} + + ////////////////////////////////////////////////////////////////////////////// // // destroy_alloc_n @@ -1008,6 +1063,31 @@ BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_trivially_destructible<I, vo ////////////////////////////////////////////////////////////////////////////// // +// destroy_alloc +// +////////////////////////////////////////////////////////////////////////////// + +template + <typename Allocator + ,typename I> // I models InputIterator +inline typename dtl::disable_if_trivially_destructible<I, void>::type + destroy_alloc(Allocator &a, I f, I l) +{ + while(f != l){ + allocator_traits<Allocator>::destroy(a, boost::movelib::iterator_to_raw_pointer(f)); + ++f; + } +} + +template + <typename Allocator + ,typename I > // I models InputIterator +BOOST_CONTAINER_FORCEINLINE typename dtl::enable_if_trivially_destructible<I, void>::type + destroy_alloc(Allocator &, I, I) +{} + +////////////////////////////////////////////////////////////////////////////// +// // deep_swap_alloc_n // ////////////////////////////////////////////////////////////////////////////// @@ -1088,7 +1168,7 @@ inline typename dtl::enable_if_c //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); + const std::size_t branch_number = (szt_times == 0)*Unroll + (szt_times % Unroll); switch(branch_number){ case 4: break; @@ -1177,10 +1257,10 @@ void move_assign_range_alloc_n( Allocator &a, I inp_start, std::size_t n_i, O ou } } -template<class Allocator, class Iterator> +template<class Allocator> struct array_destructor { - typedef typename ::boost::container::iterator_traits<Iterator>::value_type value_type; + typedef typename ::boost::container::allocator_traits<Allocator>::value_type value_type; typedef typename dtl::if_c <dtl::is_trivially_destructible<value_type>::value ,dtl::null_scoped_destructor_range<Allocator> @@ -1188,6 +1268,17 @@ struct array_destructor >::type type; }; +template<class Allocator> +struct value_destructor +{ + typedef typename ::boost::container::allocator_traits<Allocator>::value_type value_type; + typedef typename dtl::if_c + <dtl::is_trivially_destructible<value_type>::value + , dtl::null_scoped_destructor<Allocator> + , dtl::scoped_destructor<Allocator> + >::type type; +}; + template <typename Allocator ,typename F // F models ForwardIterator @@ -1201,9 +1292,9 @@ void uninitialized_move_and_insert_alloc , F last , O d_first , std::size_t n - , InsertionProxy insert_range_proxy) + , InsertionProxy insertion_proxy) { - typedef typename array_destructor<Allocator, F>::type array_destructor_t; + typedef typename array_destructor<Allocator>::type array_destructor_t; //Anti-exception rollbacks array_destructor_t new_values_destroyer(d_first, d_first, a); @@ -1213,7 +1304,7 @@ void uninitialized_move_and_insert_alloc O d_last = ::boost::container::uninitialized_move_alloc(a, first, pos, d_first); new_values_destroyer.set_end(d_last); //Initialize new objects, starting from previous point - insert_range_proxy.uninitialized_copy_n_and_update(a, d_last, n); + insertion_proxy.uninitialized_copy_n_and_update(a, d_last, n); d_last += n; new_values_destroyer.set_end(d_last); //Initialize from the rest of the old buffer, @@ -1223,53 +1314,666 @@ void uninitialized_move_and_insert_alloc new_values_destroyer.release(); } + + + +template + <typename Allocator + ,typename F // F models ForwardIterator + ,typename InsertionProxy + > +typename dtl::enable_if_c<dtl::is_single_value_proxy<InsertionProxy>::value, void>::type + expand_backward_and_insert_nonempty_middle_alloc + ( Allocator &a + , F const first + , F const pos + , std::size_t const + , InsertionProxy insertion_proxy) +{ + BOOST_ASSERT(first != pos); + + typedef typename value_destructor<Allocator>::type value_destructor_t; + F aux = first; --aux; + allocator_traits<Allocator>::construct(a, boost::movelib::iterator_to_raw_pointer(aux), boost::move(*first)); + value_destructor_t on_exception(a, boost::movelib::iterator_to_raw_pointer(aux)); + //Copy previous to last objects to the initialized end + aux = first; ++aux; + aux = boost::container::move(aux, pos, first); + //Insert new objects in the pos + insertion_proxy.copy_n_and_update(a, aux, 1u); + on_exception.release(); +} + template <typename Allocator ,typename F // F models ForwardIterator ,typename InsertionProxy > -void expand_forward_and_insert_alloc +typename dtl::disable_if_c<dtl::is_single_value_proxy<InsertionProxy>::value, void>::type + expand_backward_and_insert_nonempty_middle_alloc + ( Allocator &a + , F first + , F pos + , std::size_t const n + , InsertionProxy insertion_proxy) +{ + BOOST_ASSERT(first != pos); + BOOST_ASSERT(n != 0); + + typedef typename array_destructor<Allocator>::type array_destructor_t; + const std::size_t elems_before = iterator_udistance(first, pos); + if(elems_before >= n){ + //New elements can be just copied. + //Move to uninitialized memory last objects + F const first_less_n = first - n; + F nxt = ::boost::container::uninitialized_move_alloc_n_source(a, first, n, first_less_n); + array_destructor_t on_exception(first_less_n, first, a); + //Copy previous to last objects to the initialized end + nxt = boost::container::move(nxt, pos, first); + //Insert new objects in the pos + insertion_proxy.copy_n_and_update(a, nxt, n); + on_exception.release(); + } + else { + //The new elements don't fit in the [pos, end()) range. + //Copy old [pos, end()) elements to the uninitialized memory (a gap is created) + F aux = ::boost::container::uninitialized_move_alloc(a, first, pos, first - n); + array_destructor_t on_exception(first -n, aux, a); + //Copy to the beginning of the unallocated zone the last new elements (the gap is closed). + insertion_proxy.uninitialized_copy_n_and_update(a, aux, std::size_t(n - elems_before)); + insertion_proxy.copy_n_and_update(a, first, elems_before); + on_exception.release(); + } +} + + +template + <typename Allocator + ,typename F // F models ForwardIterator + ,typename InsertionProxy + > +typename dtl::enable_if_c<dtl::is_single_value_proxy<InsertionProxy>::value, void>::type + expand_forward_and_insert_nonempty_middle_alloc ( Allocator &a , F pos , F last - , std::size_t n - , InsertionProxy insert_range_proxy) + , std::size_t const + , InsertionProxy insertion_proxy) +{ + BOOST_ASSERT(last != pos); + + typedef typename value_destructor<Allocator>::type value_destructor_t; + F last_m_n = last; --last_m_n; + allocator_traits<Allocator>::construct(a, boost::movelib::iterator_to_raw_pointer(last), boost::move(*last_m_n)); + value_destructor_t on_exception(a, boost::movelib::iterator_to_raw_pointer(last)); + //Copy previous to last objects to the initialized end + boost::container::move_backward(pos, last_m_n, last); + //Insert new objects in the pos + insertion_proxy.copy_n_and_update(a, pos, 1); + on_exception.release(); +} + +template + <typename Allocator + ,typename F // F models ForwardIterator + ,typename InsertionProxy + > +typename dtl::disable_if_c<dtl::is_single_value_proxy<InsertionProxy>::value, void>::type + expand_forward_and_insert_nonempty_middle_alloc + ( Allocator &a + , F pos + , F last + , std::size_t const n + , InsertionProxy insertion_proxy) +{ + BOOST_ASSERT(last != pos); + BOOST_ASSERT(n != 0); + + typedef typename array_destructor<Allocator>::type array_destructor_t; + const std::size_t elems_after = iterator_udistance(pos, last); + if(elems_after >= n){ + //New elements can be just copied. + //Move to uninitialized memory last objects + F const last_m_n = last - n; + F const nxt = ::boost::container::uninitialized_move_alloc_n(a, last_m_n, n, last); + array_destructor_t on_exception(last, nxt, a); + //Copy previous to last objects to the initialized end + boost::container::move_backward(pos, last_m_n, last); + //Insert new objects in the pos + insertion_proxy.copy_n_and_update(a, pos, n); + on_exception.release(); + } + else { + //The new elements don't fit in the [pos, end()) range. + //Copy old [pos, end()) elements to the uninitialized memory (a gap is created) + F new_last = ::boost::container::uninitialized_move_alloc(a, pos, last, pos + n); + array_destructor_t on_exception(pos + n, new_last, a); + //Copy first new elements in pos (gap is still there) + insertion_proxy.copy_n_and_update(a, pos, elems_after); + //Copy to the beginning of the unallocated zone the last new elements (the gap is closed). + insertion_proxy.uninitialized_copy_n_and_update(a, last, std::size_t(n - elems_after)); + on_exception.release(); + } +} + +template +<typename Allocator + , typename F // F models ForwardIterator + , typename InsertionProxy +> +BOOST_CONTAINER_FORCEINLINE void expand_forward_and_insert_alloc + ( Allocator& a + , F pos + , F last + , std::size_t const n + , InsertionProxy insertion_proxy) +{ + if (last == pos) { + insertion_proxy.uninitialized_copy_n_and_update(a, last, n); + } + else{ + const bool single_value = dtl::is_single_value_proxy<InsertionProxy>::value; + BOOST_IF_CONSTEXPR(!single_value){ + if (BOOST_UNLIKELY(!n)) { + return; + } + } + expand_forward_and_insert_nonempty_middle_alloc(a, pos, last, n, insertion_proxy); + } +} + +template <class B, class InsertionProxy, class Allocator> +void expand_backward_forward_and_insert_alloc_move_backward +( B const old_start +, std::size_t const old_size +, B const new_start +, B const pos +, std::size_t const n +, InsertionProxy insertion_proxy +, Allocator& a) { - typedef typename array_destructor<Allocator, F>::type array_destructor_t; + typedef std::size_t size_type; + typedef typename allocator_traits<Allocator>::value_type value_type; + static const bool trivial_dctr_after_move = has_trivial_destructor_after_move<value_type>::value; + static const bool trivial_dctr = dtl::is_trivially_destructible<value_type>::value; + + typedef typename dtl::if_c + <trivial_dctr + , dtl::null_scoped_destructor_n<Allocator, B> + , dtl::scoped_destructor_n<Allocator, B> + >::type array_destructor_t; + + //n can be zero to just expand capacity + B old_finish = make_iterator_uadvance(old_start, old_size); + + //We can have 8 possibilities: + const size_type elemsbefore = static_cast<size_type>(iterator_udistance(old_start, pos)); + const size_type raw_before = static_cast<size_type>(iterator_udistance(new_start, old_start)); + const size_type before_plus_new = size_type(elemsbefore + n); + + //Check if raw_before is big enough to hold the beginning of old data + new data + if (raw_before >= before_plus_new) { + //If anything goes wrong, this object will destroy + //all the old objects to fulfill previous vector state + array_destructor_t old_values_destroyer(old_start, a, old_size); + // _________________________________________________________ + //| raw_mem | old_begin | old_end | //Old situation + //| __________________________________|___________|_________| + // _________________________________________________________ + //| old_begin | new | raw_mem | old_begin | old_end | //First step + //|___________|__________|____________|___________|_________| + + //Copy first old values before pos, after that the new objects + B const new_elem_pos = ::boost::container::uninitialized_move_alloc(a, old_start, pos, new_start); + array_destructor_t new_values_destroyer(new_start, a, elemsbefore); + insertion_proxy.uninitialized_copy_n_and_update(a, new_elem_pos, n); + new_values_destroyer.set_size(before_plus_new); + const size_type new_size = size_type(old_size + n); + //Check if raw_before is so big that even copying the old data + new data + //there is a gap between the new data and the old data + if (raw_before >= new_size) { + // _______________________________________________________ + //| raw_mem | old_begin | old_end | //Old situation + //|_________________________________|___________|_________| + // _______________________________________________________ + //| old_begin | new | raw_mem | old_begin | old_end | //First step + //|___________|________|____________|___________|_________| + // _______________________________________________________ + //| old_begin | new | old_end | raw_mem | //New situation + //|___________|________|_________|________________________| + // + //Now initialize the rest of memory with the last old values + if (before_plus_new != new_size) { //Special case to avoid operations in back insertion + B new_start_end(make_iterator_uadvance(new_start, before_plus_new)); + ::boost::container::uninitialized_move_alloc(a, pos, old_finish, new_start_end); + } + //All new elements correctly constructed, avoid new element destruction + new_values_destroyer.release(); + //Old values destroyed automatically with "old_values_destroyer" + //when "old_values_destroyer" goes out of scope unless the have trivial + //destructor after move. + if(trivial_dctr_after_move) + old_values_destroyer.release(); + } + //raw_before is so big that divides old_end + else { + // _________________________________________________ + //| raw | old_beg | old_end | //Old situation + //|_____________________________|_________|_________| + // _________________________________________________ + //| old_begin | new | raw | old_beg | old_end | //First step + //|___________|__________|______|_________|_________| + // _________________________________________________ + //| old_begin | new | old_end | raw_mem | //New situation + //|___________|__________|_________|________________| + + //Now initialize the rest of memory with the last old values + //All new elements correctly constructed, avoid new element destruction + BOOST_IF_CONSTEXPR(!trivial_dctr) { + //Now initialize the rest of raw_before memory with the + //first of elements after new values + const size_type raw_gap = raw_before - before_plus_new; + B new_start_plus(make_iterator_uadvance(new_start, before_plus_new)); + ::boost::container::uninitialized_move_alloc_n(a, pos, raw_gap, new_start_plus); + new_values_destroyer.release(); + old_values_destroyer.increment_size_backwards(raw_before); + //Now move remaining last objects in the old buffer begin + B remaining_pos(make_iterator_uadvance(pos, raw_gap)); + remaining_pos = ::boost::container::move_forward_overlapping(remaining_pos, old_finish, old_start); + (void)remaining_pos; + //Once moved, avoid calling the destructors if trivial after move + if(!trivial_dctr_after_move) { + boost::container::destroy_alloc(a, remaining_pos, old_finish); + } + } + else { //If trivial destructor, we can uninitialized copy + copy in a single uninitialized copy + ::boost::container::uninitialized_move_alloc_n + (a, pos, static_cast<size_type>(old_finish - pos), make_iterator_uadvance(new_start, before_plus_new)); + } + old_values_destroyer.release(); + } + } + else { + //If anything goes wrong, this object will destroy + //all the old objects to fulfill previous vector state + array_destructor_t old_values_destroyer(old_start, a, old_size); + + //Check if we have to do the insertion in two phases + //since maybe raw_before is not big enough and + //the buffer was expanded both sides + // _________________________________________________ + //| raw_mem | old_begin + old_end | raw_mem | //Old situation + //|_________|_____________________|_________________| + // _________________________________________________ + //| old_begin + new + old_end | raw_mem | //New situation with do_after + //|___________________________________|_____________| + // _________________________________________________ + //| old_begin + new + old_end | raw_mem | //New without do_after + //|____________________________|____________________| + // + const bool do_after = n > raw_before; + + //Now we can have two situations: the raw_mem of the + //beginning divides the old_begin, or the new elements: + if (raw_before <= elemsbefore) { + //The raw memory divides the old_begin group: + // + //If we need two phase construction (do_after) + //new group is divided in new = new_beg + new_end groups + //In this phase only new_beg will be inserted + // + // _________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | //Old situation + //|_________|___________|_________|_________________| + // _________________________________________________ + //| old_begin | new_beg | old_end | raw_mem | //New situation with do_after(1), + //|___________|_________|_________|_________________| //not definitive, pending operations + // _________________________________________________ + //| old_begin | new | old_end | raw_mem | //New situation without do_after, + //|___________|_____|_________|_____________________| //definitive. + // + //Copy the first part of old_begin to raw_mem + ::boost::container::uninitialized_move_alloc_n(a, old_start, raw_before, new_start); + //The buffer is all constructed until old_end, + //so program trailing destruction and assign final size + //if !do_after, raw_before+n otherwise. + size_type new_1st_range; + old_values_destroyer.increment_size_backwards(raw_before); + new_1st_range = do_after ? raw_before : n; + + //Now copy the second part of old_begin overwriting itself + B const old_next(make_iterator_uadvance(old_start, raw_before)); + B const next = ::boost::container::move(old_next, pos, old_start); + //Now copy the new_beg elements + insertion_proxy.copy_n_and_update(a, next, new_1st_range); + + //If there is no after work and the last old part needs to be moved to front, do it + if (!do_after) { + //Now displace old_end elements and destroy trailing + B const new_first(make_iterator_uadvance(next, new_1st_range)); + B const p = ::boost::container::move_forward_overlapping(pos, old_finish, new_first); + (void)p; + if(!trivial_dctr_after_move) + boost::container::destroy_alloc(a, p, old_finish); + } + } + else { + //If we have to expand both sides, + //we will play if the first new values so + //calculate the upper bound of new values + + //The raw memory divides the new elements + // + //If we need two phase construction (do_after) + //new group is divided in new = new_beg + new_end groups + //In this phase only new_beg will be inserted + // + // ____________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | //Old situation + //|_______________|___________|_________|______________| + // ____________________________________________________ + //| old_begin | new_beg | old_end | raw_mem | //New situation with do_after(), + //|___________|_______________|_________|______________| //not definitive, pending operations + // ____________________________________________________ + //| old_begin | new | old_end | raw_mem | //New situation without do_after, + //|___________|_____|_________|________________________| //definitive + // + //First copy whole old_begin and part of new to raw_mem + B const new_pos = ::boost::container::uninitialized_move_alloc(a, old_start, pos, new_start); + array_destructor_t new_values_destroyer(new_start, a, elemsbefore); + const size_type mid_n = size_type(raw_before - elemsbefore); + insertion_proxy.uninitialized_copy_n_and_update(a, new_pos, mid_n); + new_values_destroyer.release(); + //The buffer is all constructed until old_end + old_values_destroyer.increment_size_backwards(raw_before); + + if (do_after) { + //Copy new_beg part + insertion_proxy.copy_n_and_update(a, old_start, elemsbefore); + } + else { + //Copy all new elements + const size_type rest_new = size_type(n - mid_n); + insertion_proxy.copy_n_and_update(a, old_start, rest_new); + + B move_start(make_iterator_uadvance(old_start, rest_new)); + + //Displace old_end, but make sure data has to be moved + B const move_end = ::boost::container::move_forward_overlapping(pos, old_finish, move_start); + (void)move_end; //To avoid warnings of unused initialization for move_end in case + //trivial_dctr_after_move is true + //Destroy remaining moved elements from old_end except if they + //have trivial destructor after being moved + if(!trivial_dctr_after_move) { + boost::container::destroy_alloc(a, move_end, old_finish); + } + } + } - if (BOOST_UNLIKELY(!n)){ - return; + //This is only executed if two phase construction is needed + if (do_after) { + //The raw memory divides the new elements + // ______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | //Old situation + //|______________|___________|____________|______________| + // _______________________________________________________ + //| old_begin + new_beg | new_end |old_end | rawmem | //New situation with do_after(1) + //|__________________________|_________|________|________| + // ______________________________________________________ + //| old_begin + new | old_end |raw | //New situation with do_after(2) + //|_______________________________________|_________|____| + const size_type n_after = size_type(n - raw_before); + const size_type elemsafter = size_type(old_size - elemsbefore); + + //We can have two situations: + if (elemsafter >= n_after) { + //The raw_mem from end will divide displaced old_end + // + //Old situation: + // ______________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | + //|______________|___________|____________|______________| + // + //New situation with do_after(1): + // _______________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | + //|__________________________|_________|________|_________| + // + //First copy the part of old_end raw_mem + B finish_n = make_iterator_advance(old_finish, -std::ptrdiff_t(n_after)); + ::boost::container::uninitialized_move_alloc(a, finish_n, old_finish, old_finish); + old_values_destroyer.increment_size(n_after); + //Displace the rest of old_end to the new position + boost::container::move_backward_overlapping(pos, finish_n, old_finish); + //Now overwrite with new_end + //The new_end part is [first + (n - n_after), last) + insertion_proxy.copy_n_and_update(a, pos, n_after); + } + else { + //The raw_mem from end will divide new_end part + // _____________________________________________________________ + //| raw_mem | old_begin | old_end | raw_mem | //Old situation + //|______________|___________|____________|_____________________| + // _____________________________________________________________ + //| old_begin + new_beg | new_end |old_end | raw_mem | //New situation with do_after(2) + //|__________________________|_______________|________|_________| + + //First initialize data in raw memory + const size_type mid_last_dist = size_type(n_after - elemsafter); + + //Copy to the old_end part to the uninitialized zone leaving a gap. + B const mid_last(make_iterator_uadvance(old_finish, mid_last_dist)); + ::boost::container::uninitialized_move_alloc(a, pos, old_finish, mid_last); + + array_destructor_t old_end_destroyer(mid_last, a, iterator_udistance(pos, old_finish)); + + //Copy the first part to the already constructed old_end zone + insertion_proxy.copy_n_and_update(a, pos, elemsafter); + //Copy the rest to the uninitialized zone filling the gap + insertion_proxy.uninitialized_copy_n_and_update(a, old_finish, mid_last_dist); + old_end_destroyer.release(); + } + } + old_values_destroyer.release(); } - else if (last == pos){ - insert_range_proxy.uninitialized_copy_n_and_update(a, last, n); +} + +template +<typename Allocator + , typename B // B models BidirIterator + , typename InsertionProxy +> +BOOST_CONTAINER_FORCEINLINE void expand_backward_forward_and_insert_alloc_move_forward + ( B const old_start + , std::size_t const old_size + , B const new_start + , B const pos + , std::size_t const n + , InsertionProxy insertion_proxy + , Allocator& a) +{ + typedef std::size_t size_type; + typedef typename allocator_traits<Allocator>::value_type value_type; + static const bool trivial_dctr_after_move = has_trivial_destructor_after_move<value_type>::value; + static const bool trivial_dctr = dtl::is_trivially_destructible<value_type>::value; + + typedef typename dtl::if_c + <trivial_dctr + , dtl::null_scoped_destructor_n<Allocator, B> + , dtl::scoped_destructor_n<Allocator, B> + >::type array_destructor_t; + + //n can be zero to just expand capacity + + B const old_finish = make_iterator_uadvance(old_start, old_size); + const size_type new_size = size_type(old_size + n); + B const new_finish = make_iterator_uadvance(new_start, new_size); + + //We can have 8 possibilities: + + const size_type elemsafter = static_cast<size_type>(iterator_udistance(pos, old_finish)); + const size_type raw_after = static_cast<size_type>(iterator_udistance(old_finish, new_finish)); + + const size_type after_plus_new = size_type(elemsafter + n); + + //Check if raw_before is big enough to hold the new data + the end of old data + if (raw_after >= after_plus_new) { + //If anything goes wrong, this object will destroy + //all the old objects to fulfill previous vector state + array_destructor_t old_values_destroyer(old_start, a, old_size); + //______________________ __________________________________ + //| old_begin | old_end | raw_mem //Old situation + //|___________|_________|__________________________________ + // _____________________ _________________________________ + //| old_begin | old_end | raw_mem | new | old_end | //First step + //|___________|_________|__________|__________|___________| + + //Copy first new objects, after that old values after pos + B new_elem_pos = new_finish - after_plus_new; + insertion_proxy.uninitialized_copy_n_and_update(a, new_elem_pos, n); + array_destructor_t new_values_destroyer(new_elem_pos, a, n); + ::boost::container::uninitialized_move_alloc(a, pos, old_finish, new_elem_pos+n); + new_values_destroyer.set_size(after_plus_new); + + //Check if raw_before is so big that even copying the old data + new data + //there is a gap between the new data and the old data + if (raw_after >= new_size) { + //______________________ __________________________________ + //| old_begin | old_end | raw_mem //Old situation + //|___________|_________|__________________________________ + // _____________________ _________________________________ + //| old_begin | old_end | raw_mem | new | old_end | //First step + //|___________|_________|______________|________|_________| + // _____________________V_________________________________ + //| raw_mem | old_begin | new | old_end | //New situation + //|________________________|___________|________|_________| + // + //Now initialize the rest of memory with the last old values + ::boost::container::uninitialized_move_alloc(a, old_start, pos, new_start); + //All new elements correctly constructed, avoid new element destruction + new_values_destroyer.release(); + //Old values destroyed automatically with "old_values_destroyer" + //when "old_values_destroyer" goes out of scope unless the have trivial + //destructor after move. + if(trivial_dctr_after_move) + old_values_destroyer.release(); + } + //raw_before is so big that divides old_end + else { + //______________________ ____________________________ + //| old_begin | old_end | raw_mem //Old situation + //|___________|_________|____________________________ + // _____________________ ____________________________ + //| old_begin | old_end | raw_mem | new | old_end | //First step + //|___________|_________|_________|________|_________| + // _________________________________________________ + //| raw_mem | old_begin | new | old_end | //New situation + //|___________________|___________|________|_________| + + //Now initialize the rest of raw_before memory with the + //last elements before new values + const size_type raw_gap = raw_after - after_plus_new; + B const pre_pos_raw = pos - raw_gap; + ::boost::container::uninitialized_move_alloc_n(a, pre_pos_raw, raw_gap, old_finish); + new_values_destroyer.release(); + old_values_destroyer.increment_size(raw_after); + //Now move remaining last objects in the old buffer begin + BOOST_ASSERT(old_start != old_finish); + boost::container::move_backward_overlapping(old_start, pre_pos_raw, old_finish); + old_values_destroyer.release(); + if (!trivial_dctr_after_move) { + boost::container::destroy_alloc(a, old_start, new_start); + } + } } else{ - const std::size_t elems_after = static_cast<std::size_t>(last - pos); - if(elems_after >= n){ - //New elements can be just copied. - //Move to uninitialized memory last objects - ::boost::container::uninitialized_move_alloc_n(a, last - n, n, last); - array_destructor_t on_exception(last, last, a); - //Copy previous to last objects to the initialized end - boost::container::move_backward(pos, last - n, last); - //Insert new objects in the pos - insert_range_proxy.copy_n_and_update(a, pos, n); - on_exception.release(); + //If anything goes wrong, this object will destroy + //all the old objects to fulfill previous vector state + array_destructor_t old_values_destroyer(old_start, a, old_size); + + //Now we can have two situations: the raw_mem of the + //end divides the new elements or the old_end + if (raw_after > elemsafter) { + //The raw memory divides the new elements + //__________________________________ + //| old_begin | old_end | raw | //Old situation + //|___________|_________|___________| + // _____ ___________________________ + //| raw | old_begin | new | old_end | //New situation + //|_____|___________|_____|_________| + + //First copy whole old_end and part of new to raw_mem + B p = new_finish - elemsafter; + ::boost::container::uninitialized_move_alloc(a, pos, old_finish, p); + array_destructor_t new_values_destroyer(p, a, elemsafter); + //Copy all new elements + const size_type mid_n = size_type(raw_after - elemsafter); + const size_type rest_new = size_type(n - mid_n); + B new_rng_start = old_finish - rest_new; + insertion_proxy.copy_n_and_update(a, new_rng_start, rest_new); + insertion_proxy.uninitialized_copy_n_and_update(a, old_finish, mid_n); + new_values_destroyer.release(); + old_values_destroyer.increment_size_backwards(raw_after); + //Displace old_end, but make sure data has to be moved + p = ::boost::container::move_backward_overlapping(old_start, pos, new_rng_start); + + //Destroy remaining moved elements from old_begin except if they + //have trivial destructor after being moved + old_values_destroyer.release(); + if (!trivial_dctr_after_move) { + boost::container::destroy_alloc(a, old_start, p); + } } else { - //The new elements don't fit in the [pos, end()) range. - //Copy old [pos, end()) elements to the uninitialized memory (a gap is created) - F new_last = ::boost::container::uninitialized_move_alloc(a, pos, last, pos + n); - array_destructor_t on_exception(pos + n, new_last, a); - //Copy first new elements in pos (gap is still there) - insert_range_proxy.copy_n_and_update(a, 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(a, last, std::size_t(n - elems_after)); - on_exception.release(); + //The raw memory divides the old_end group: + //________________________________________ + //| old_begin | old_end | raw | //Old situation + //|___________|_______________|___________| + // _____ __________________________________ + //| raw | old_begin | new | old_end | //New situation + //|_____|___________|_____|_______________| + // + //Copy the last part of old_end to raw_mem + const B old_end_pivot = old_finish - raw_after; + ::boost::container::uninitialized_move_alloc_n(a, old_end_pivot, raw_after, old_finish); + //The buffer is all constructed + old_values_destroyer.increment_size_backwards(raw_after); + + //Now copy the first part of old_end overwriting itself + B const new_end_pos = ::boost::container::move_backward_overlapping(pos, old_end_pivot, old_finish); + B const new_beg_pos = new_end_pos - n; + + //Now copy the new_beg elements + insertion_proxy.copy_n_and_update(a, new_beg_pos, n); + B const p = ::boost::container::move_backward_overlapping(old_start, pos, new_beg_pos); + old_values_destroyer.release(); + + if (!trivial_dctr_after_move) { + (void)p; + boost::container::destroy_alloc(a, old_start, p); + } } } } +template <class R, class InsertionProxy, class Allocator> +void expand_backward_forward_and_insert_alloc + ( R const old_start + , std::size_t const old_size + , R const new_start + , R const pos + , std::size_t const n + , InsertionProxy insertion_proxy + , Allocator& a) +{ + if(new_start < old_start){ + expand_backward_forward_and_insert_alloc_move_backward(old_start, old_size, new_start, pos, n, insertion_proxy, a); + } + else{ + expand_backward_forward_and_insert_alloc_move_forward(old_start, old_size, new_start, pos, n, insertion_proxy, a); + } +} + } //namespace container { } //namespace boost { diff --git a/contrib/restricted/boost/container/include/boost/container/detail/destroyers.hpp b/contrib/restricted/boost/container/include/boost/container/detail/destroyers.hpp index 45bc431ce2..f00ac6d6ed 100644 --- a/contrib/restricted/boost/container/include/boost/container/detail/destroyers.hpp +++ b/contrib/restricted/boost/container/include/boost/container/detail/destroyers.hpp @@ -27,6 +27,7 @@ #include <boost/container/allocator_traits.hpp> #include <boost/move/detail/to_raw_pointer.hpp> #include <boost/container/detail/version_type.hpp> +#include <boost/move/detail/iterator_to_raw_pointer.hpp> namespace boost { namespace container { @@ -172,19 +173,19 @@ struct scoped_node_destroy_deallocator //!A deleter for scoped_ptr that destroys //!an object using a STL allocator. -template <class Allocator> +template <class Allocator, class Ptr = typename allocator_traits<Allocator>::pointer> struct scoped_destructor_n { typedef boost::container::allocator_traits<Allocator> AllocTraits; - typedef typename AllocTraits::pointer pointer; + typedef Ptr pointer; typedef typename AllocTraits::value_type value_type; - BOOST_CONTAINER_FORCEINLINE scoped_destructor_n(pointer p, Allocator& a, std::size_t n) - : m_p(p), m_a(a), m_n(n) + BOOST_CONTAINER_FORCEINLINE scoped_destructor_n(Ptr p, Allocator& a, std::size_t n) + : m_p(p), m_n(n), m_a(a) {} BOOST_CONTAINER_FORCEINLINE void release() - { m_p = 0; m_n = 0; } + { m_p = Ptr(); m_n = 0; } BOOST_CONTAINER_FORCEINLINE void increment_size(std::size_t inc) { m_n += inc; } @@ -195,10 +196,13 @@ struct scoped_destructor_n BOOST_CONTAINER_FORCEINLINE void shrink_forward(std::size_t inc) { m_n -= inc; m_p += std::ptrdiff_t(inc); } + BOOST_CONTAINER_FORCEINLINE void set_size(std::size_t sz) + { m_n = sz; } + ~scoped_destructor_n() { if(m_n){ - value_type *raw_ptr = boost::movelib::to_raw_pointer(m_p); + value_type *raw_ptr = boost::movelib::iterator_to_raw_pointer(m_p); do { --m_n; AllocTraits::destroy(m_a, raw_ptr); @@ -209,19 +213,19 @@ struct scoped_destructor_n private: pointer m_p; - Allocator & m_a; std::size_t m_n; + Allocator& m_a; }; //!A deleter for scoped_ptr that destroys //!an object using a STL allocator. -template <class Allocator> +template <class Allocator, class Ptr = typename allocator_traits<Allocator>::pointer> struct null_scoped_destructor_n { typedef boost::container::allocator_traits<Allocator> AllocTraits; - typedef typename AllocTraits::pointer pointer; + typedef Ptr pointer; - BOOST_CONTAINER_FORCEINLINE null_scoped_destructor_n(pointer, Allocator&, std::size_t) + BOOST_CONTAINER_FORCEINLINE null_scoped_destructor_n(Ptr, Allocator&, std::size_t) {} BOOST_CONTAINER_FORCEINLINE void increment_size(std::size_t) @@ -230,6 +234,9 @@ struct null_scoped_destructor_n BOOST_CONTAINER_FORCEINLINE void increment_size_backwards(std::size_t) {} + BOOST_CONTAINER_FORCEINLINE void set_size(std::size_t ) + {} + BOOST_CONTAINER_FORCEINLINE void shrink_forward(std::size_t) {} @@ -333,6 +340,27 @@ class scoped_destructor Allocator &a_; }; +template<class Allocator> +class null_scoped_destructor +{ + typedef boost::container::allocator_traits<Allocator> AllocTraits; + public: + typedef typename Allocator::value_type value_type; + BOOST_CONTAINER_FORCEINLINE null_scoped_destructor(Allocator &, value_type *) + {} + + BOOST_CONTAINER_FORCEINLINE ~null_scoped_destructor() + {} + + BOOST_CONTAINER_FORCEINLINE void release() + {} + + BOOST_CONTAINER_FORCEINLINE void set(value_type *) { } + + BOOST_CONTAINER_FORCEINLINE value_type *get() const { return 0; } +}; + + template<class Allocator, class Value = typename Allocator::value_type> class value_destructor diff --git a/contrib/restricted/boost/container/include/boost/container/detail/iterator.hpp b/contrib/restricted/boost/container/include/boost/container/detail/iterator.hpp index ce37adcfff..9d2e1c8f3c 100644 --- a/contrib/restricted/boost/container/include/boost/container/detail/iterator.hpp +++ b/contrib/restricted/boost/container/include/boost/container/detail/iterator.hpp @@ -37,6 +37,8 @@ using ::boost::intrusive::iterator_distance; using ::boost::intrusive::iterator_udistance; using ::boost::intrusive::iterator_advance; using ::boost::intrusive::iterator_uadvance; +using ::boost::intrusive::make_iterator_advance; +using ::boost::intrusive::make_iterator_uadvance; using ::boost::intrusive::iterator; using ::boost::intrusive::iterator_enable_if_tag; using ::boost::intrusive::iterator_disable_if_tag; diff --git a/contrib/restricted/boost/container/include/boost/container/detail/workaround.hpp b/contrib/restricted/boost/container/include/boost/container/detail/workaround.hpp index 3cb731f0ee..d1c4824e83 100644 --- a/contrib/restricted/boost/container/include/boost/container/detail/workaround.hpp +++ b/contrib/restricted/boost/container/include/boost/container/detail/workaround.hpp @@ -98,12 +98,11 @@ #define BOOST_CONTAINER_FORCEINLINE inline #elif defined(BOOST_CONTAINER_FORCEINLINE_IS_BOOST_FORCELINE) #define BOOST_CONTAINER_FORCEINLINE BOOST_FORCEINLINE -#elif defined(BOOST_MSVC) && (_MSC_VER < 1900 || defined(_DEBUG)) +#elif defined(BOOST_MSVC) && (_MSC_VER <= 1900 || defined(_DEBUG)) //"__forceinline" and MSVC seems to have some bugs in old versions and in debug mode #define BOOST_CONTAINER_FORCEINLINE inline -//#elif defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ < 5))) -#elif defined(__GNUC__) && (__GNUC__ <= 5) - //Older GCCs have problems with forceinline +#elif defined(BOOST_GCC) && ((__GNUC__ <= 5) || defined(__MINGW32__)) + //Older GCCs and MinGw have problems with forceinline #define BOOST_CONTAINER_FORCEINLINE inline #else #define BOOST_CONTAINER_FORCEINLINE BOOST_FORCEINLINE diff --git a/contrib/restricted/boost/container/include/boost/container/options.hpp b/contrib/restricted/boost/container/include/boost/container/options.hpp index 4bdd33e891..c58ff82a22 100644 --- a/contrib/restricted/boost/container/include/boost/container/options.hpp +++ b/contrib/restricted/boost/container/include/boost/container/options.hpp @@ -200,6 +200,20 @@ struct default_if_void<void, Default> typedef Default type; }; +template<std::size_t N, std::size_t DefaultN> +struct default_if_zero +{ + static const std::size_t value = N; +}; + +template<std::size_t DefaultN> +struct default_if_zero<0u, DefaultN> +{ + static const std::size_t value = DefaultN; +}; + + + #endif #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) @@ -232,24 +246,17 @@ class default_next_capacity; typedef vector_opt<void, void> vector_null_opt; -template<class GrowthType, class StoredSizeType> -struct devector_opt - : vector_opt<GrowthType, StoredSizeType> -{}; - -typedef devector_opt<void, void> devector_null_opt; - #else //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED) -//!This growth factor argument specifies that the container should increase it's +//!This growth factor argument specifies that the container should increase its //!capacity a 50% when existing capacity is exhausted. struct growth_factor_50{}; -//!This growth factor argument specifies that the container should increase it's +//!This growth factor argument specifies that the container should increase its //!capacity a 60% when existing capacity is exhausted. struct growth_factor_60{}; -//!This growth factor argument specifies that the container should increase it's +//!This growth factor argument specifies that the container should increase its //!capacity a 100% (doubling its capacity) when existing capacity is exhausted. struct growth_factor_100{}; @@ -466,9 +473,92 @@ using static_vector_options_t = typename boost::container::static_vector_options #endif + +//////////////////////////////////////////////////////////////// +// +// +// OPTIONS FOR DEVECTOR CONTAINER +// +// +//////////////////////////////////////////////////////////////// + +//!Thse options specify the relocation strategy of devector. +//! +//!Predefined relocation limits that can be passed as arguments to this option are: +//!\c boost::container::relocate_on_66 +//!\c boost::container::relocate_on_75 +//!\c boost::container::relocate_on_80 +//!\c boost::container::relocate_on_85 +//!\c boost::container::relocate_on_90 +//! +//!If this option is not specified, a default will be used by the container. +//! +//!Note: Repeated insertions at only one end (only back insertions or only front insertions) usually will +//!lead to a single relocation when `relocate_on_66` is used and two relocations when `relocate_on_90` +//!is used. + +#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +BOOST_INTRUSIVE_OPTION_CONSTANT(relocate_on, std::size_t, Fraction, free_fraction) + +struct relocate_on_66 : public relocate_on<3U>{}; + +struct relocate_on_75 : public relocate_on<4U> {}; + +struct relocate_on_80 : public relocate_on<5U> {}; + +struct relocate_on_85 : public relocate_on<7U> {}; + +struct relocate_on_90 : public relocate_on<10U> {}; + +template<class GrowthType, class StoredSizeType, std::size_t FreeFraction> +struct devector_opt + : vector_opt<GrowthType, StoredSizeType> +{ + static const std::size_t free_fraction = FreeFraction; +}; + +typedef devector_opt<void, void, 0u> devector_null_opt; + +#else + +//!This relocation condition option specifies that the container will never relocate +//!elements when there is no space at the side the insertion should +//!take place +struct relocate_never; + +//!This relocation condition option specifies that the container will relocate +//!all elements when there is no space at the side the insertion should +//!take place and memory usage is below 66% (2/3) +struct relocate_on_66; + +//!This relocation condition option specifies that the container will relocate +//!all elements when there is no space at the side the insertion should +//!take place and memory usage is below 75% (3/4) +struct relocate_on_75; + +//!This relocation condition option specifies that the container will relocate +//!all elements when there is no space at the side the insertion should +//!take place and memory usage is below 80% (4/5) +struct relocate_on_80; + +//!This relocation condition option specifies that the container will relocate +//!all elements when there is no space at the side the insertion should +//!take place and memory usage is below 85% (6/7) +struct relocate_on_85; + +//!This relocation condition option specifies that the container will relocate +//!all elements when there is no space at the side the insertion should +//!take place and memory usage is below 90% (9/10) +struct relocate_on_90; + +#endif + + //! Helper metafunction to combine options into a single type to be used //! by \c boost::container::devector. -//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size +//! Supported options are: \c boost::container::growth_factor, \c boost::container::stored_size +//! and \c boost::container::relocate_on #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES) template<class ...Options> #else @@ -486,7 +576,9 @@ struct devector_options #endif >::type packed_options; typedef devector_opt< typename packed_options::growth_factor_type - , typename packed_options::stored_size_type> implementation_defined; + , typename packed_options::stored_size_type + , packed_options::free_fraction + > implementation_defined; /// @endcond typedef implementation_defined type; }; diff --git a/contrib/restricted/boost/container/include/boost/container/vector.hpp b/contrib/restricted/boost/container/include/boost/container/vector.hpp index 80df0ce518..a1f3fb1c4f 100644 --- a/contrib/restricted/boost/container/include/boost/container/vector.hpp +++ b/contrib/restricted/boost/container/include/boost/container/vector.hpp @@ -353,7 +353,7 @@ struct vector_alloc_holder , m_size(static_cast<stored_size_type>(initial_size)) , m_capacity() { - if (initial_size > size_type(-1)){ + if (BOOST_UNLIKELY(initial_size > size_type(-1))){ boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); } else if(initial_size){ @@ -373,7 +373,7 @@ struct vector_alloc_holder , m_size(static_cast<stored_size_type>(initial_size)) , m_capacity() { - if (initial_size > size_type(-1)){ + if (BOOST_UNLIKELY(initial_size > size_type(-1))){ boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); } else if(initial_size){ @@ -437,11 +437,11 @@ struct vector_alloc_holder return this->priv_allocation_command(alloc_version(), command, limit_size, prefer_in_recvd_out_size, reuse); } - pointer allocate(size_type n) + BOOST_CONTAINER_FORCEINLINE pointer allocate(size_type n) { const size_type max_alloc = allocator_traits_type::max_size(this->alloc()); const size_type max = max_alloc <= stored_size_type(-1) ? max_alloc : stored_size_type(-1); - if ( max < n ) + if (BOOST_UNLIKELY(max < n) ) boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); return allocator_traits_type::allocate(this->alloc(), n); @@ -544,7 +544,7 @@ struct vector_alloc_holder BOOST_ASSERT( (command & allocate_new)); BOOST_ASSERT(!(command & nothrow_allocation)); //First detect overflow on smaller stored_size_types - if (limit_size > stored_size_type(-1)){ + if (BOOST_UNLIKELY(limit_size > stored_size_type(-1))){ boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); } (clamp_by_stored_size_type<size_type>)(prefer_in_recvd_out_size, stored_size_type()); @@ -559,7 +559,7 @@ struct vector_alloc_holder pointer &reuse) { //First detect overflow on smaller stored_size_types - if (limit_size > stored_size_type(-1)){ + if (BOOST_UNLIKELY(limit_size > stored_size_type(-1))){ boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); } (clamp_by_stored_size_type<size_type>)(prefer_in_recvd_out_size, stored_size_type()); @@ -724,6 +724,7 @@ struct vector_alloc_holder<Allocator, StoredSizeType, version_0> }; struct growth_factor_60; +struct growth_factor_100; template<class Options, class AllocatorSizeType> struct get_vector_opt @@ -1296,7 +1297,7 @@ private: //For Fwd iterators the standard only requires EmplaceConstructible and assignable from *first //so we can't do any backwards allocation const it_size_type sz = boost::container::iterator_udistance(first, last); - if (sz > size_type(-1)){ + if (BOOST_UNLIKELY(sz > size_type(-1))){ boost::container::throw_length_error("vector::assign, FwdIt's max length reached"); } @@ -1819,7 +1820,7 @@ private: return *p; } else{ - typedef dtl::insert_emplace_proxy<allocator_type, T*, Args...> proxy_t; + typedef dtl::insert_emplace_proxy<allocator_type, Args...> proxy_t; return *this->priv_insert_forward_range_no_capacity (p, 1, proxy_t(::boost::forward<Args>(args)...), alloc_version()); } @@ -1860,7 +1861,7 @@ private: { BOOST_ASSERT(this->priv_in_range_or_end(position)); //Just call more general insert(pos, size, value) and return iterator - typedef dtl::insert_emplace_proxy<allocator_type, T*, Args...> proxy_t; + typedef dtl::insert_emplace_proxy<allocator_type, Args...> proxy_t; return this->priv_insert_forward_range( vector_iterator_get_ptr(position), 1 , proxy_t(::boost::forward<Args>(args)...)); } @@ -1879,7 +1880,7 @@ private: return *p;\ }\ else{\ - typedef dtl::insert_emplace_proxy_arg##N<allocator_type, T* BOOST_MOVE_I##N BOOST_MOVE_TARG##N> proxy_t;\ + typedef dtl::insert_emplace_proxy_arg##N<allocator_type BOOST_MOVE_I##N BOOST_MOVE_TARG##N> proxy_t;\ return *this->priv_insert_forward_range_no_capacity\ ( p, 1, proxy_t(BOOST_MOVE_FWD##N), alloc_version());\ }\ @@ -1901,7 +1902,7 @@ private: BOOST_CONTAINER_FORCEINLINE iterator emplace(const_iterator pos BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ {\ BOOST_ASSERT(this->priv_in_range_or_end(pos));\ - typedef dtl::insert_emplace_proxy_arg##N<allocator_type, T* BOOST_MOVE_I##N BOOST_MOVE_TARG##N> proxy_t;\ + typedef dtl::insert_emplace_proxy_arg##N<allocator_type BOOST_MOVE_I##N BOOST_MOVE_TARG##N> proxy_t;\ return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), 1, proxy_t(BOOST_MOVE_FWD##N));\ }\ // @@ -1967,7 +1968,7 @@ private: BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, size_type n, const T& x) { BOOST_ASSERT(this->priv_in_range_or_end(p)); - dtl::insert_n_copies_proxy<allocator_type, T*> proxy(x); + dtl::insert_n_copies_proxy<allocator_type> proxy(x); return this->priv_insert_forward_range(vector_iterator_get_ptr(p), n, proxy); } @@ -2015,11 +2016,11 @@ private: typedef typename iter_size<FwdIt>::type it_size_type; BOOST_ASSERT(this->priv_in_range_or_end(pos)); const it_size_type sz = boost::container::iterator_udistance(first, last); - if (sz > size_type(-1)){ + if (BOOST_UNLIKELY(sz > size_type(-1))){ boost::container::throw_length_error("vector::insert, FwdIt's max length reached"); } - dtl::insert_range_proxy<allocator_type, FwdIt, T*> proxy(first); + dtl::insert_range_proxy<allocator_type, FwdIt> proxy(first); return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), static_cast<size_type>(sz), proxy); } #endif @@ -2047,7 +2048,7 @@ private: BOOST_ASSERT(dtl::is_input_iterator<InIt>::value || num == boost::container::iterator_udistance(first, last)); (void)last; - dtl::insert_range_proxy<allocator_type, InIt, T*> proxy(first); + dtl::insert_range_proxy<allocator_type, InIt> proxy(first); return this->priv_insert_forward_range(vector_iterator_get_ptr(pos), num, proxy); } #endif @@ -2591,9 +2592,9 @@ private: BOOST_CONTAINER_FORCEINLINE void priv_move_to_new_buffer(size_type, version_0) { alloc_holder_t::on_capacity_overflow(); } - BOOST_CONTAINER_FORCEINLINE dtl::insert_range_proxy<allocator_type, boost::move_iterator<T*>, T*> priv_dummy_empty_proxy() + BOOST_CONTAINER_FORCEINLINE dtl::insert_range_proxy<allocator_type, boost::move_iterator<T*> > priv_dummy_empty_proxy() { - return dtl::insert_range_proxy<allocator_type, boost::move_iterator<T*>, T*> + return dtl::insert_range_proxy<allocator_type, boost::move_iterator<T*> > (::boost::make_move_iterator((T *)0)); } @@ -2688,14 +2689,14 @@ private: BOOST_CONTAINER_FORCEINLINE iterator priv_insert(const_iterator, ::boost::move_detail::nat) { return iterator(); } - BOOST_CONTAINER_FORCEINLINE dtl::insert_n_copies_proxy<allocator_type, T*> priv_resize_proxy(const T &x) - { return dtl::insert_n_copies_proxy<allocator_type, T*>(x); } + BOOST_CONTAINER_FORCEINLINE dtl::insert_n_copies_proxy<allocator_type> priv_resize_proxy(const T &x) + { return dtl::insert_n_copies_proxy<allocator_type>(x); } - BOOST_CONTAINER_FORCEINLINE dtl::insert_default_initialized_n_proxy<allocator_type, T*> priv_resize_proxy(default_init_t) - { return dtl::insert_default_initialized_n_proxy<allocator_type, T*>(); } + BOOST_CONTAINER_FORCEINLINE dtl::insert_default_initialized_n_proxy<allocator_type> priv_resize_proxy(default_init_t) + { return dtl::insert_default_initialized_n_proxy<allocator_type>(); } - BOOST_CONTAINER_FORCEINLINE dtl::insert_value_initialized_n_proxy<allocator_type, T*> priv_resize_proxy(value_init_t) - { return dtl::insert_value_initialized_n_proxy<allocator_type, T*>(); } + BOOST_CONTAINER_FORCEINLINE dtl::insert_value_initialized_n_proxy<allocator_type> priv_resize_proxy(value_init_t) + { return dtl::insert_value_initialized_n_proxy<allocator_type>(); } BOOST_CONTAINER_FORCEINLINE void priv_shrink_to_fit(version_0) BOOST_NOEXCEPT_OR_NOTHROW {} @@ -2986,7 +2987,8 @@ private: } template <class InsertionProxy> - BOOST_CONTAINER_FORCEINLINE void priv_insert_forward_range_expand_forward(T* const raw_pos, const size_type n, InsertionProxy insert_range_proxy, dtl::false_type) + BOOST_CONTAINER_FORCEINLINE void priv_insert_forward_range_expand_forward + (T* const raw_pos, const size_type n, InsertionProxy insert_range_proxy, dtl::false_type) { //There is enough memory boost::container::expand_forward_and_insert_alloc @@ -3024,321 +3026,19 @@ private: (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 = this->priv_raw_begin(); + T* const old_start = this->priv_raw_begin(); const size_type old_size = this->m_holder.m_size; - T* const old_finish = old_start + old_size; - allocator_type &a = this->m_holder.alloc(); + allocator_type& a = this->m_holder.alloc(); //Update the vector buffer information to a safe state this->m_holder.start(new_start); this->m_holder.capacity(new_capacity); this->m_holder.m_size = 0; - //We can have 8 possibilities: - const size_type elemsbefore = static_cast<size_type>(pos - old_start); - const size_type s_before = static_cast<size_type>(old_start - new_start); - const size_type before_plus_new = size_type(elemsbefore + n); - - typedef typename value_traits::ArrayDestructor array_destructor_t; - - //If anything goes wrong, this object will destroy - //all the old objects to fulfill previous vector state - array_destructor_t old_values_destroyer(old_start, a, 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(a, old_start, pos, new_start); - this->m_holder.set_stored_size(elemsbefore); - insert_range_proxy.uninitialized_copy_n_and_update(a, new_elem_pos, n); - this->m_holder.set_stored_size(before_plus_new); - const size_type new_size = size_type(old_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 - if(s_before >= new_size){ - //Old situation: - // _________________________________________________________ - //| raw_mem | old_begin | old_end | - //| __________________________________|___________|_________| - // - //New situation: - // _________________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|__________|_________|________________________| - // - //Now initialize the rest of memory with the last old values - if(before_plus_new != new_size){ //Special case to avoid operations in back insertion - ::boost::container::uninitialized_move_alloc(a, pos, old_finish, new_start + before_plus_new); - //All new elements correctly constructed, avoid new element destruction - this->m_holder.set_stored_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. - BOOST_IF_CONSTEXPR(value_traits::trivial_dctr_after_move) - old_values_destroyer.release(); - } - //s_before is so big that divides old_end - else{ - //Old situation: - // __________________________________________________ - //| raw_mem | old_begin | old_end | - //| ___________________________|___________|_________| - // - //New situation: - // __________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|__________|_________|_________________| - // - //Now initialize the rest of memory with the last old values - //All new elements correctly constructed, avoid new element destruction - BOOST_IF_CONSTEXPR(!value_traits::trivial_dctr){ - const size_type raw_gap = s_before - before_plus_new; - //Now initialize the rest of s_before memory with the - //first of elements after new values - ::boost::container::uninitialized_move_alloc_n(a, pos, raw_gap, new_start + before_plus_new); - //Now we have a contiguous buffer so program trailing element destruction - //and update size to the final size. - old_values_destroyer.shrink_forward(new_size-s_before); - this->m_holder.set_stored_size(new_size); - //Now move remaining last objects in the old buffer begin - T * const remaining_pos = pos + raw_gap; - if(remaining_pos != old_start){ //Make sure data has to be moved - ::boost::container::move(remaining_pos, old_finish, old_start); - } - //Once moved, avoid calling the destructors if trivial after move - BOOST_IF_CONSTEXPR(value_traits::trivial_dctr_after_move){ - old_values_destroyer.release(); - } - } - else{ //If trivial destructor, we can uninitialized copy + copy in a single uninitialized copy - ::boost::container::uninitialized_move_alloc_n - (a, pos, static_cast<size_type>(old_finish - pos), new_start + before_plus_new); - this->m_holder.set_stored_size(new_size); - old_values_destroyer.release(); - } - } - } - else{ - //Check if we have to do the insertion in two phases - //since maybe s_before is not big enough and - //the buffer was expanded both sides - // - //Old situation: - // _________________________________________________ - //| raw_mem | old_begin + old_end | raw_mem | - //|_________|_____________________|_________________| - // - //New situation with do_after: - // _________________________________________________ - //| old_begin + new + old_end | raw_mem | - //|___________________________________|_____________| - // - //New without do_after: - // _________________________________________________ - //| old_begin + new + old_end | raw_mem | - //|____________________________|____________________| - // - const bool do_after = n > s_before; - - //Now we can have two situations: the raw_mem of the - //beginning divides the old_begin, or the new elements: - if (s_before <= elemsbefore) { - //The raw memory divides the old_begin group: - // - //If we need two phase construction (do_after) - //new group is divided in new = new_beg + new_end groups - //In this phase only new_beg will be inserted - // - //Old situation: - // _________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|_________|___________|_________|_________________| - // - //New situation with do_after(1): - //This is not definitive situation, the second phase - //will include - // _________________________________________________ - //| old_begin | new_beg | old_end | raw_mem | - //|___________|_________|_________|_________________| - // - //New situation without do_after: - // _________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|_____|_________|_____________________| - // - //Copy the first part of old_begin to raw_mem - ::boost::container::uninitialized_move_alloc_n(a, old_start, s_before, new_start); - //The buffer is all constructed until old_end, - //so program trailing destruction and assign final size - //if !do_after, s_before+n otherwise. - size_type new_1st_range; - if(do_after){ - new_1st_range = s_before; - //release destroyer and update size - old_values_destroyer.release(); - } - else{ - new_1st_range = n; - BOOST_IF_CONSTEXPR(value_traits::trivial_dctr_after_move){ - old_values_destroyer.release(); - } - else{ - old_values_destroyer.shrink_forward(old_size - (s_before - n)); - } - } - this->m_holder.set_stored_size(size_type(old_size + new_1st_range)); - //Now copy the second part of old_begin overwriting itself - T *const next = ::boost::container::move(old_start + s_before, pos, old_start); - //Now copy the new_beg elements - insert_range_proxy.copy_n_and_update(a, next, new_1st_range); - - //If there is no after work and the last old part needs to be moved to front, do it - if(!do_after && (n != s_before)){ - //Now displace old_end elements - ::boost::container::move(pos, old_finish, next + new_1st_range); - } - } - else { - //If we have to expand both sides, - //we will play if the first new values so - //calculate the upper bound of new values - - //The raw memory divides the new elements - // - //If we need two phase construction (do_after) - //new group is divided in new = new_beg + new_end groups - //In this phase only new_beg will be inserted - // - //Old situation: - // _______________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|_______________|___________|_________|_________________| - // - //New situation with do_after(): - // ____________________________________________________ - //| old_begin | new_beg | old_end | raw_mem | - //|___________|_______________|_________|______________| - // - //New situation without do_after: - // ______________________________________________________ - //| old_begin | new | old_end | raw_mem | - //|___________|_____|_________|__________________________| - // - //First copy whole old_begin and part of new to raw_mem - T * const new_pos = ::boost::container::uninitialized_move_alloc - (a, old_start, pos, new_start); - this->m_holder.set_stored_size(elemsbefore); - const size_type mid_n = size_type(s_before - elemsbefore); - insert_range_proxy.uninitialized_copy_n_and_update(a, new_pos, mid_n); - //The buffer is all constructed until old_end, - //release destroyer - this->m_holder.set_stored_size(size_type(old_size + s_before)); - old_values_destroyer.release(); - - if(do_after){ - //Copy new_beg part - insert_range_proxy.copy_n_and_update(a, old_start, elemsbefore); - } - else{ - //Copy all new elements - const size_type rest_new = size_type(n - mid_n); - insert_range_proxy.copy_n_and_update(a, old_start, rest_new); - - T* const move_start = old_start + rest_new; - //Displace old_end, but make sure data has to be moved - T* const move_end = move_start != pos ? ::boost::container::move(pos, old_finish, move_start) - : old_finish; - (void)move_end; //To avoid warnings of unused initialization for move_end in case - //trivial_dctr_after_move is true - //Destroy remaining moved elements from old_end except if they - //have trivial destructor after being moved - const size_type n_destroy = size_type(s_before - n); - BOOST_IF_CONSTEXPR(!value_traits::trivial_dctr_after_move){ - boost::container::destroy_alloc_n(a, move_end, n_destroy); - } - this->m_holder.dec_stored_size(n_destroy); - } - } + expand_backward_forward_and_insert_alloc(old_start, old_size, new_start, pos, n, insert_range_proxy, a); - //This is only executed if two phase construction is needed - if(do_after){ - //The raw memory divides the new elements - // - //Old situation: - // ______________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|______________|___________|____________|______________| - // - //New situation with do_after(1): - // _______________________________________________________ - //| old_begin + new_beg | new_end |old_end | raw_mem | - //|__________________________|_________|________|_________| - // - //New situation with do_after(2): - // ______________________________________________________ - //| old_begin + new | old_end |raw | - //|_______________________________________|_________|____| - // - const size_type n_after = size_type(n - s_before); - const size_type elemsafter = size_type(old_size - elemsbefore); - - //We can have two situations: - if (elemsafter >= n_after){ - //The raw_mem from end will divide displaced old_end - // - //Old situation: - // ______________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|______________|___________|____________|______________| - // - //New situation with do_after(1): - // _______________________________________________________ - //| old_begin + new_beg | new_end |old_end | raw_mem | - //|__________________________|_________|________|_________| - // - //First copy the part of old_end raw_mem - T* finish_n = old_finish - n_after; - ::boost::container::uninitialized_move_alloc(a, finish_n, old_finish, old_finish); - this->m_holder.inc_stored_size(n_after); - //Displace the rest of old_end to the new position - boost::container::move_backward(pos, finish_n, old_finish); - //Now overwrite with new_end - //The new_end part is [first + (n - n_after), last) - insert_range_proxy.copy_n_and_update(a, pos, n_after); - } - else { - //The raw_mem from end will divide new_end part - // - //Old situation: - // _____________________________________________________________ - //| raw_mem | old_begin | old_end | raw_mem | - //|______________|___________|____________|_____________________| - // - //New situation with do_after(2): - // _____________________________________________________________ - //| old_begin + new_beg | new_end |old_end | raw_mem | - //|__________________________|_______________|________|_________| - - //First initialize data in raw memory - const size_type mid_last_dist = size_type(n_after - elemsafter); - - //Copy to the old_end part to the uninitialized zone leaving a gap. - ::boost::container::uninitialized_move_alloc(a, pos, old_finish, old_finish + mid_last_dist); - - array_destructor_t old_end_destroyer(old_finish + mid_last_dist, a, static_cast<size_type>(old_finish - pos)); - - //Copy the first part to the already constructed old_end zone - insert_range_proxy.copy_n_and_update(a, pos, elemsafter); - //Copy the rest to the uninitialized zone filling the gap - insert_range_proxy.uninitialized_copy_n_and_update(a, old_finish, mid_last_dist); - this->m_holder.inc_stored_size(n_after); - old_end_destroyer.release(); - } - } - } + //Update the vector buffer information to a safe state + this->m_holder.m_size = stored_size_type(old_size + n); } void priv_throw_if_out_of_range(size_type n) const |