diff --git a/include/boost/container/small_vector.hpp b/include/boost/container/small_vector.hpp index 2ad0410..66b3195 100644 --- a/include/boost/container/small_vector.hpp +++ b/include/boost/container/small_vector.hpp @@ -345,7 +345,7 @@ class small_vector_base public: //Make it public as it will be inherited by small_vector and container //must have this public member - typedef typename real_allocator::type secondary_allocator_t; + typedef typename real_allocator::type secondary_allocator_t; typedef typename allocator_traits:: template portable_rebind_alloc::type void_allocator_t; typedef typename dtl::get_small_vector_opt::type options_t; @@ -387,6 +387,24 @@ class small_vector_base : base_type(initial_capacity_t(), this->internal_storage(), capacity, ::boost::forward(a)) {} + BOOST_CONTAINER_FORCEINLINE explicit small_vector_base(maybe_initial_capacity_t, std::size_t initial_capacity, std::size_t initial_size) + : base_type( maybe_initial_capacity_t() + , (initial_capacity >= initial_size) ? this->internal_storage() : pointer() + , (initial_capacity >= initial_size) ? initial_capacity : initial_size + ) + {} + + template + BOOST_CONTAINER_FORCEINLINE explicit small_vector_base(maybe_initial_capacity_t, std::size_t initial_capacity, std::size_t initial_size, BOOST_FWD_REF(AllocFwd) a) + : base_type(maybe_initial_capacity_t() + , (initial_capacity >= initial_size) ? this->internal_storage() : pointer() + , (initial_capacity >= initial_size) ? initial_capacity : initial_size + , ::boost::forward(a) + ) + {} + + using base_type::protected_set_size; + //~small_vector_base(){} #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -408,9 +426,10 @@ class small_vector_base this->steal_resources(x); } else{ - this->assign( boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.begin())) - , boost::make_move_iterator(boost::movelib::iterator_to_raw_pointer(x.end ())) - ); + const typename base_type::size_type sz = x.size(); + ::boost::container::uninitialized_move_alloc_n_source + (this->base_type::get_stored_allocator(), x.begin(), sz, this->begin()); + this->protected_set_size(sz); x.clear(); } } @@ -546,28 +565,28 @@ class small_vector {} BOOST_CONTAINER_FORCEINLINE explicit small_vector(size_type n) - : base_type(initial_capacity_t(), internal_capacity()) - { this->resize(n); } + : base_type(maybe_initial_capacity_t(), internal_capacity(), n) + { this->protected_init_n(n, value_init); } BOOST_CONTAINER_FORCEINLINE small_vector(size_type n, const allocator_type &a) - : base_type(initial_capacity_t(), internal_capacity(), a) - { this->resize(n); } + : base_type(maybe_initial_capacity_t(), internal_capacity(), n, a) + { this->protected_init_n(n, value_init); } BOOST_CONTAINER_FORCEINLINE small_vector(size_type n, default_init_t) - : base_type(initial_capacity_t(), internal_capacity()) - { this->resize(n, default_init_t()); } + : base_type(maybe_initial_capacity_t(), internal_capacity(), n) + { this->protected_init_n(n, default_init_t()); } BOOST_CONTAINER_FORCEINLINE small_vector(size_type n, default_init_t, const allocator_type &a) - : base_type(initial_capacity_t(), internal_capacity(), a) - { this->resize(n, default_init_t()); } + : base_type(maybe_initial_capacity_t(), internal_capacity(), n, a) + { this->protected_init_n(n, default_init_t()); } BOOST_CONTAINER_FORCEINLINE small_vector(size_type n, const value_type &v) - : base_type(initial_capacity_t(), internal_capacity()) - { this->resize(n, v); } + : base_type(maybe_initial_capacity_t(), internal_capacity(), n) + { this->protected_init_n(n, v); } BOOST_CONTAINER_FORCEINLINE small_vector(size_type n, const value_type &v, const allocator_type &a) - : base_type(initial_capacity_t(), internal_capacity(), a) - { this->resize(n, v); } + : base_type(maybe_initial_capacity_t(), internal_capacity(), n, a) + { this->protected_init_n(n, v); } template BOOST_CONTAINER_FORCEINLINE small_vector(InIt first, InIt last diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 1795922..d5d2f1e 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -257,8 +257,6 @@ struct vector_insert_ordered_cursor BiDirValueIt last_value_it; }; -struct initial_capacity_t{}; - template BOOST_CONTAINER_FORCEINLINE const Pointer &vector_iterator_get_ptr(const vec_iterator &it) BOOST_NOEXCEPT_OR_NOTHROW { return it.get_ptr(); } @@ -267,9 +265,13 @@ template BOOST_CONTAINER_FORCEINLINE Pointer &get_ptr(vec_iterator &it) BOOST_NOEXCEPT_OR_NOTHROW { return it.get_ptr(); } +struct initial_capacity_t {}; + struct vector_uninitialized_size_t {}; static const vector_uninitialized_size_t vector_uninitialized_size = vector_uninitialized_size_t(); +struct maybe_initial_capacity_t {}; + template struct vector_value_traits_base { @@ -312,6 +314,43 @@ struct vector_alloc_holder typedef typename allocator_traits_type::size_type size_type; typedef typename allocator_traits_type::value_type value_type; + + private: + + template + void do_initial_capacity(SizeType initial_capacity) + { + if (BOOST_UNLIKELY(initial_capacity > size_type(-1))) { + boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); + } + else if (initial_capacity) { + pointer reuse = pointer(); + size_type final_cap = static_cast(initial_capacity); + m_start = this->allocation_command(allocate_new, final_cap, final_cap, reuse); + this->set_stored_capacity(final_cap); + } + } + + template + void do_maybe_initial_capacity(pointer p, SizeType initial_capacity) + { + if (BOOST_UNLIKELY(initial_capacity > size_type(-1))) { + boost::container::throw_length_error("get_next_capacity, allocator's max size reached"); + } + else if (p) { + m_start = p; + } + else { + BOOST_ASSERT(initial_capacity > 0); + pointer reuse = pointer(); + size_type final_cap = static_cast(initial_capacity); + m_start = this->allocation_command(allocate_new, final_cap, final_cap, reuse); + this->set_stored_capacity(final_cap); + } + } + + public: + BOOST_CONTAINER_FORCEINLINE static bool is_propagable_from(const allocator_type &from_alloc, pointer p, const allocator_type &to_alloc, bool const propagate_allocator) { @@ -343,7 +382,7 @@ struct vector_alloc_holder : allocator_type(boost::forward(a)), m_start(), m_size(), m_capacity() {} - //Constructor, does not throw + template vector_alloc_holder(vector_uninitialized_size_t, BOOST_FWD_REF(AllocConvertible) a, SizeType initial_size) : allocator_type(boost::forward(a)) @@ -351,19 +390,8 @@ struct vector_alloc_holder //Size is initialized here so vector should only call uninitialized_xxx after this , m_size(static_cast(initial_size)) , m_capacity() - { - 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){ - pointer reuse = pointer(); - size_type final_cap = static_cast(initial_size); - m_start = this->allocation_command(allocate_new, final_cap, final_cap, reuse); - this->set_stored_capacity(final_cap); - } - } + { this->do_initial_capacity(initial_size); } - //Constructor, does not throw template vector_alloc_holder(vector_uninitialized_size_t, SizeType initial_size) : allocator_type() @@ -371,27 +399,7 @@ struct vector_alloc_holder //Size is initialized here so vector should only call uninitialized_xxx after this , m_size(static_cast(initial_size)) , m_capacity() - { - 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){ - pointer reuse = pointer(); - size_type final_cap = initial_size; - m_start = this->allocation_command(allocate_new, final_cap, final_cap, reuse); - this->set_stored_capacity(final_cap); - } - } - - vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) BOOST_NOEXCEPT_OR_NOTHROW - : allocator_type(BOOST_MOVE_BASE(allocator_type, 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; - } + { this->do_initial_capacity(initial_size); } vector_alloc_holder(initial_capacity_t, pointer p, size_type n) BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible::value) @@ -410,6 +418,34 @@ struct vector_alloc_holder , m_capacity(n) {} + template + vector_alloc_holder(maybe_initial_capacity_t, pointer p, SizeType initial_capacity, BOOST_FWD_REF(AllocConvertible) a) + : allocator_type(boost::forward(a)) + //, m_start() + //Size is initialized here so vector should only call uninitialized_xxx after this + , m_size() + , m_capacity(static_cast(initial_capacity)) + { this->do_maybe_initial_capacity(p, initial_capacity); } + + template + vector_alloc_holder(maybe_initial_capacity_t, pointer p, SizeType initial_capacity) + : allocator_type() + //, m_start() + //Size is initialized here so vector should only call uninitialized_xxx after this + , m_size() + , m_capacity(static_cast(initial_capacity)) + { this->do_maybe_initial_capacity(p, initial_capacity); } + + vector_alloc_holder(BOOST_RV_REF(vector_alloc_holder) holder) BOOST_NOEXCEPT_OR_NOTHROW + : allocator_type(BOOST_MOVE_BASE(allocator_type, 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; + } + BOOST_CONTAINER_FORCEINLINE ~vector_alloc_holder() BOOST_NOEXCEPT_OR_NOTHROW { if(this->m_capacity){ @@ -822,6 +858,9 @@ private: BOOST_CONTAINER_FORCEINLINE void steal_resources(vector &x) { return this->m_holder.steal_resources(x.m_holder); } + BOOST_CONTAINER_FORCEINLINE void protected_set_size(size_type n) + { this->m_holder.m_size = static_cast(n); } + template BOOST_CONTAINER_FORCEINLINE vector(initial_capacity_t, pointer initial_memory, size_type cap, BOOST_FWD_REF(AllocFwd) a) : m_holder(initial_capacity_t(), initial_memory, cap, ::boost::forward(a)) @@ -831,6 +870,32 @@ private: : m_holder(initial_capacity_t(), initial_memory, cap) {} + template + BOOST_CONTAINER_FORCEINLINE vector(maybe_initial_capacity_t, pointer p, SizeType initial_capacity, BOOST_FWD_REF(AllocFwd) a) + : m_holder(maybe_initial_capacity_t(), p, initial_capacity, ::boost::forward(a)) + { + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + this->num_alloc += size_type(p != pointer()); + #endif + } + + template + BOOST_CONTAINER_FORCEINLINE vector(maybe_initial_capacity_t, pointer p, SizeType initial_capacity) + : m_holder(maybe_initial_capacity_t(), p, initial_capacity) + { + #ifdef BOOST_CONTAINER_VECTOR_ALLOC_STATS + this->num_alloc += size_type(p != pointer()); + #endif + } + + template + void protected_init_n(const size_type new_size, const U& u) + { + BOOST_ASSERT(this->empty()); + this->priv_resize_proxy(u).uninitialized_copy_n_and_update(this->m_holder.alloc(), this->priv_raw_begin(), new_size); + this->m_holder.set_stored_size(new_size); + } + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED public: diff --git a/test/movable_int.hpp b/test/movable_int.hpp index f49de3b..beab5b3 100644 --- a/test/movable_int.hpp +++ b/test/movable_int.hpp @@ -31,7 +31,19 @@ struct is_copyable static const bool value = true; }; +template +struct is_move_assignable +{ + static const bool value = true; +}; + + +///////////////////////// +// +// movable_int +// +///////////////////////// class movable_int { BOOST_MOVABLE_BUT_NOT_COPYABLE(movable_int) @@ -122,13 +134,8 @@ inline movable_int produce_movable_int() { return movable_int(); } template -std::basic_ostream & operator<< - (std::basic_ostream & os, movable_int const & p) - -{ - os << p.get_int(); - return os; -} +std::basic_ostream & operator<<(std::basic_ostream & os, movable_int const & p) +{ os << p.get_int(); return os; } template<> struct is_copyable @@ -136,6 +143,150 @@ struct is_copyable static const bool value = false; }; +///////////////////////// +// +// moveconstruct_int +// +///////////////////////// +class moveconstruct_int +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(moveconstruct_int) + + moveconstruct_int& operator= (BOOST_RV_REF(moveconstruct_int) mmi); + +public: + + static unsigned int count; + + moveconstruct_int() + : m_int(0) + { + ++count; + } + + explicit moveconstruct_int(int a) + : m_int(a) + { + //Disallow INT_MIN + BOOST_ASSERT(this->m_int != INT_MIN); + ++count; + } + + moveconstruct_int(BOOST_RV_REF(moveconstruct_int) mmi) + : m_int(mmi.m_int) + { + BOOST_ASSERT(&mmi != this); + mmi.m_int = 0; ++count; + } + + moveconstruct_int& operator= (int i) + { + this->m_int = i; BOOST_ASSERT(this->m_int != INT_MIN); return *this; + } + + ~moveconstruct_int() + { + //Double destructor called + BOOST_ASSERT(this->m_int != INT_MIN); + this->m_int = INT_MIN; + --count; + } + + friend bool operator ==(const moveconstruct_int& l, const moveconstruct_int& r) + { + return l.m_int == r.m_int; + } + + friend bool operator !=(const moveconstruct_int& l, const moveconstruct_int& r) + { + return l.m_int != r.m_int; + } + + friend bool operator <(const moveconstruct_int& l, const moveconstruct_int& r) + { + return l.m_int < r.m_int; + } + + friend bool operator <=(const moveconstruct_int& l, const moveconstruct_int& r) + { + return l.m_int <= r.m_int; + } + + friend bool operator >=(const moveconstruct_int& l, const moveconstruct_int& r) + { + return l.m_int >= r.m_int; + } + + friend bool operator >(const moveconstruct_int& l, const moveconstruct_int& r) + { + return l.m_int > r.m_int; + } + + int get_int() const + { + return m_int; + } + + friend bool operator==(const moveconstruct_int& l, int r) + { + return l.get_int() == r; + } + + friend bool operator==(int l, const moveconstruct_int& r) + { + return l == r.get_int(); + } + + friend bool operator<(const moveconstruct_int& l, int r) + { + return l.get_int() < r; + } + + friend bool operator<(int l, const moveconstruct_int& r) + { + return l < r.get_int(); + } + + friend std::size_t hash_value(const moveconstruct_int& v) + { + return (std::size_t)v.get_int(); + } + +private: + int m_int; +}; + +unsigned int moveconstruct_int::count = 0; + +inline moveconstruct_int produce_movableconstruct_int() +{ + return moveconstruct_int(); +} + +template +std::basic_ostream& operator<<(std::basic_ostream& os, moveconstruct_int const& p) +{ + os << p.get_int(); return os; +} + +template<> +struct is_copyable +{ + static const bool value = false; +}; + +template<> +struct is_move_assignable +{ + static const bool value = false; +}; + + +///////////////////////// +// +// movable_and_copyable_int +// +///////////////////////// class movable_and_copyable_int { BOOST_COPYABLE_AND_MOVABLE(movable_and_copyable_int) @@ -236,13 +387,8 @@ inline movable_and_copyable_int produce_movable_and_copyable_int() { return movable_and_copyable_int(); } template -std::basic_ostream & operator<< - (std::basic_ostream & os, movable_and_copyable_int const & p) - -{ - os << p.get_int(); - return os; -} +std::basic_ostream & operator<< (std::basic_ostream & os, movable_and_copyable_int const & p) +{ os << p.get_int(); return os; } template<> struct is_copyable @@ -250,6 +396,12 @@ struct is_copyable static const bool value = true; }; + +///////////////////////// +// +// copyable_int +// +///////////////////////// class copyable_int { public: @@ -332,13 +484,8 @@ inline copyable_int produce_copyable_int() { return copyable_int(); } template -std::basic_ostream & operator<< - (std::basic_ostream & os, copyable_int const & p) - -{ - os << p.get_int(); - return os; -} +std::basic_ostream & operator<< (std::basic_ostream & os, copyable_int const & p) +{ os << p.get_int(); return os; } template<> struct is_copyable @@ -346,6 +493,11 @@ struct is_copyable static const bool value = true; }; +///////////////////////// +// +// non_copymovable_int +// +///////////////////////// class non_copymovable_int { non_copymovable_int(const non_copymovable_int& mmi); diff --git a/test/small_vector_test.cpp b/test/small_vector_test.cpp index 315d64d..55d737c 100644 --- a/test/small_vector_test.cpp +++ b/test/small_vector_test.cpp @@ -15,6 +15,7 @@ #include "../../intrusive/test/iterator_test.hpp" #include +#include #include @@ -149,6 +150,43 @@ bool test_swap() return true; } +template +struct GetAllocatorCont +{ + template + struct apply + { + typedef boost::container::small_vector< ValueType, 10 + , typename boost::container::allocator_traits + ::template portable_rebind_alloc::type + > type; + }; +}; + +template +int test_cont_variants() +{ + using namespace boost::container; + typedef typename GetAllocatorCont::template apply::type MyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; + typedef typename GetAllocatorCont::template apply::type MyCopyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; + + if (test::vector_test()) + return 1; + if (test::vector_test()) + return 1; + if (test::vector_test()) + return 1; + if (test::vector_test()) + return 1; + if (test::vector_test()) + return 1; + + return 0; +} + int main() { using namespace boost::container; @@ -162,6 +200,9 @@ int main() if(test::vector_test< small_vector >()) return 1; + if (test_cont_variants< new_allocator >()) + return 1; + //////////////////////////////////// // Default init test //////////////////////////////////// diff --git a/test/vector_test.cpp b/test/vector_test.cpp index e72f62c..5dc3631 100644 --- a/test/vector_test.cpp +++ b/test/vector_test.cpp @@ -127,6 +127,7 @@ int test_cont_variants() typedef typename GetAllocatorCont::template apply::type MyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyMoveCont; typedef typename GetAllocatorCont::template apply::type MyCopyCont; + typedef typename GetAllocatorCont::template apply::type MyMoveConstructCont; if(test::vector_test()) return 1; @@ -136,6 +137,8 @@ int test_cont_variants() return 1; if(test::vector_test()) return 1; + if (test::vector_test()) + return 1; return 0; } diff --git a/test/vector_test.hpp b/test/vector_test.hpp index a8f0ae8..ded1360 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -271,49 +271,23 @@ bool vector_copyable_only(MyBoostVector &boostvector, MyStdVector &stdvector, bo } template -int vector_test() +int vector_move_assignable_only(boost::container::dtl::false_type) { + return 0; +} + +//Function to check if both sets are equal +template +int vector_move_assignable_only(boost::container::dtl::true_type) +{ + const int max = 100; typedef std::vector MyStdVector; typedef typename MyBoostVector::value_type IntType; typedef typename MyBoostVector::difference_type difference_type; - const int max = 100; - if(!test_range_insertion()){ return 1; } - { //Vector(n) - ::boost::movelib::unique_ptr const boostvectorp = - ::boost::movelib::make_unique(100u); - ::boost::movelib::unique_ptr const stdvectorp = - ::boost::movelib::make_unique(100u); - if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1; - } - { //Vector(n, alloc) - ::boost::movelib::unique_ptr const boostvectorp = - ::boost::movelib::make_unique(100u, typename MyBoostVector::allocator_type()); - ::boost::movelib::unique_ptr const stdvectorp = - ::boost::movelib::make_unique(100u); - if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1; - } - { //Vector(Vector &&) - ::boost::movelib::unique_ptr const stdvectorp = - ::boost::movelib::make_unique(100u); - ::boost::movelib::unique_ptr const boostvectorp = - ::boost::movelib::make_unique(100u); - ::boost::movelib::unique_ptr const boostvectorp2 = - ::boost::movelib::make_unique(::boost::move(*boostvectorp)); - if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; - } - { //Vector(Vector &&, alloc) - ::boost::movelib::unique_ptr const stdvectorp = - ::boost::movelib::make_unique(100u); - ::boost::movelib::unique_ptr const boostvectorp = - ::boost::movelib::make_unique(100u); - ::boost::movelib::unique_ptr const boostvectorp2 = - ::boost::movelib::make_unique - (::boost::move(*boostvectorp), typename MyBoostVector::allocator_type()); - if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; - } + { //Vector operator=(Vector &&) ::boost::movelib::unique_ptr const stdvectorp = ::boost::movelib::make_unique(100u); @@ -521,7 +495,7 @@ int vector_test() stdvector.assign(l.begin(), l.end()); if(!test::CheckEqualContainers(boostvector, stdvector)) return 1; } - + if(!vector_capacity_test(boostvector, stdvector, dtl::bool_::value>())) return 1; @@ -534,8 +508,53 @@ int vector_test() boostvector.resize(100u); if(!test_nth_index_of(boostvector)) return 1; - } + return 0; +} + +template +int vector_test() +{ + typedef std::vector MyStdVector; + typedef typename MyBoostVector::value_type IntType; + + { //Vector(n) + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100u); + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100u); + if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1; + } + { //Vector(n, alloc) + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100u, typename MyBoostVector::allocator_type()); + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100u); + if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1; + } + { //Vector(Vector &&) + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100u); + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100u); + ::boost::movelib::unique_ptr const boostvectorp2 = + ::boost::movelib::make_unique(::boost::move(*boostvectorp)); + if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; + } + { //Vector(Vector &&, alloc) + ::boost::movelib::unique_ptr const stdvectorp = + ::boost::movelib::make_unique(100u); + ::boost::movelib::unique_ptr const boostvectorp = + ::boost::movelib::make_unique(100u); + ::boost::movelib::unique_ptr const boostvectorp2 = + ::boost::movelib::make_unique + (::boost::move(*boostvectorp), typename MyBoostVector::allocator_type()); + if(!test::CheckEqualContainers(*boostvectorp2, *stdvectorp)) return 1; + } + + if (0 != vector_move_assignable_only< MyBoostVector>(dtl::bool_::value>())) + return 1; + std::cout << std::endl << "Test OK!" << std::endl; return 0; }