diff --git a/doc/container.qbk b/doc/container.qbk index bfcaa54..3f3812e 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1252,6 +1252,7 @@ use [*Boost.Container]? There are several reasons for that: * Fixed bugs: * [@https://svn.boost.org/trac/boost/ticket/13533 Trac #13533: ['"Boost vector resize causes assert(false)"]]. * [@https://github.com/boostorg/container/issues/73 GitHub #73: ['"triviality of pair"]]. + * [@https://github.com/boostorg/container/issues/74 GitHub #74: ['"vector assignment not using memcpy"]]. * Fixed race condition bug in [classref boost::container::pmr::unsynchronized_pool_resource unsynchronized_pool_resource] found by Arthur O'Dowyer in his blog post [@https://quuxplusone.github.io/blog/2018/06/05/libcpp-memory-resource/ for libc++] diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index ff9977a..a1f4b03 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -1192,6 +1192,7 @@ class vector //! Complexity: Linear to n. template void assign(InIt first, InIt last + //Input iterators or version 0 allocator BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or < void BOOST_MOVE_I dtl::is_convertible @@ -1241,6 +1242,7 @@ class vector //! Complexity: Linear to n. template void assign(FwdIt first, FwdIt last + //Forward iterators and version > 0 allocator BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename dtl::disable_if_or < void BOOST_MOVE_I dtl::is_same @@ -1280,21 +1282,9 @@ class vector //Forward expansion, use assignment + back deletion/construction that comes later } } - //Overwrite all elements we can from [first, last) - iterator cur = this->begin(); - const iterator end_it = this->end(); - for ( ; first != last && cur != end_it; ++cur, ++first){ - *cur = *first; - } - if (first == last){ - //There are no more elements in the sequence, erase remaining - this->priv_destroy_last_n(this->size() - input_sz); - } - else{ - //Uninitialized construct at end the remaining range - this->priv_uninitialized_construct_at_end(first, last); - } + boost::container::copy_assign_range_alloc_n(this->m_holder.alloc(), first, input_sz, this->priv_raw_begin(), this->size()); + this->m_holder.m_size = input_sz; } //! Effects: Assigns the n copies of val to *this. diff --git a/test/vector_test.hpp b/test/vector_test.hpp index a2573cf..016da1a 100644 --- a/test/vector_test.hpp +++ b/test/vector_test.hpp @@ -203,6 +203,45 @@ bool vector_copyable_only(MyBoostVector &boostvector, MyStdVector &stdvector, bo boostvectorp->resize(100, IntType(9)); if(!test::CheckEqualContainers(*boostvectorp, *stdvectorp)) return 1; } + //operator= + { + //Copy constructor test + MyBoostVector bcopy((const MyBoostVector&) boostvector); + MyStdVector scopy((const MyStdVector&) stdvector); + MyBoostVector bcopy2(boostvector); + MyStdVector scopy2(stdvector); + + if(!test::CheckEqualContainers(bcopy, scopy)) return false; + if(!test::CheckEqualContainers(bcopy2, scopy2)) return false; + + //Assignment from a smaller vector + bcopy2.erase(bcopy2.begin() + bcopy2.size()/2, bcopy2.end()); + scopy2.erase(scopy2.begin() + scopy2.size()/2, scopy2.end()); + bcopy = bcopy2; + scopy = scopy2; + if(!test::CheckEqualContainers(bcopy, scopy)) return false; + + //Assignment from a bigger vector with capacity + bcopy2 = boostvector; + scopy2 = stdvector; + if(!test::CheckEqualContainers(bcopy2, scopy2)) return false; + + //Assignment from bigger vector with no capacity + bcopy2.erase(bcopy2.begin() + bcopy2.size()/2, bcopy2.end()); + scopy2.erase(scopy2.begin() + scopy2.size()/2, scopy2.end()); + bcopy2.shrink_to_fit(); + MyStdVector(scopy2).swap(scopy2); + + bcopy2 = boostvector; + scopy2 = stdvector; + if(!test::CheckEqualContainers(bcopy, scopy)) return false; + + //Assignment with equal capacity + bcopy2 = boostvector; + scopy2 = stdvector; + if(!test::CheckEqualContainers(bcopy2, scopy2)) return false; + } + return true; }