@@ -1938,17 +1938,21 @@ class vector
19381938 template <class ...Args>
19391939 inline reference emplace_back (BOOST_FWD_REF (Args)...args )
19401940 {
1941- T* const p = this ->priv_raw_end ();
19421941 if (BOOST_LIKELY (this ->room_enough ())){
1943- // There is more memory, just construct a new object at the end
1942+ // There is more memory, just construct a new object at the end.
1943+ // Deriving the end pointer inside this branch (instead of before the
1944+ // room_enough() test, where the slow path would also use it) lets the
1945+ // optimizer fold 'start + size' into the store's addressing mode and
1946+ // keep size as the sole induction variable in append loops.
1947+ T* const p = this ->priv_raw_end ();
19441948 allocator_traits_type::construct (this ->m_holder .alloc (), p, ::boost::forward<Args>(args)...);
19451949 ++this ->m_holder .m_size ;
19461950 return *p;
19471951 }
19481952 else {
19491953 typedef dtl::insert_emplace_proxy<allocator_type, Args...> proxy_t ;
19501954 return *this ->priv_insert_forward_range_no_capacity
1951- (p , 1 , proxy_t (::boost::forward<Args>(args)...), alloc_version ());
1955+ (this -> priv_raw_end () , 1 , proxy_t (::boost::forward<Args>(args)...), alloc_version ());
19521956 }
19531957 }
19541958
@@ -2019,17 +2023,20 @@ class vector
20192023 BOOST_MOVE_TMPL_LT ##N BOOST_MOVE_CLASS ##N BOOST_MOVE_GT ##N \
20202024 inline reference emplace_back (BOOST_MOVE_UREF ##N)\
20212025 {\
2022- T* const p = this ->priv_raw_end ();\
20232026 if (BOOST_LIKELY (this ->room_enough ())){\
2027+ /* Derive the end pointer inside this branch so the optimizer can fold*/ \
2028+ /* 'start + size' into the store and keep size as the sole induction*/ \
2029+ /* variable in append loops (the slow path recomputes it).*/ \
2030+ T* const p = this ->priv_raw_end ();\
20242031 allocator_traits_type::construct (this ->m_holder .alloc ()\
2025- , this -> priv_raw_end () BOOST_MOVE_I ##N BOOST_MOVE_FWD ##N);\
2032+ , p BOOST_MOVE_I ##N BOOST_MOVE_FWD ##N);\
20262033 ++this ->m_holder .m_size ;\
20272034 return *p;\
20282035 }\
20292036 else {\
20302037 typedef dtl::insert_emplace_proxy_arg##N<allocator_type BOOST_MOVE_I ##N BOOST_MOVE_TARG ##N> proxy_t ;\
20312038 return *this ->priv_insert_forward_range_no_capacity \
2032- ( p , 1 , proxy_t (BOOST_MOVE_FWD ##N), alloc_version ());\
2039+ ( this -> priv_raw_end () , 1 , proxy_t (BOOST_MOVE_FWD ##N), alloc_version ());\
20332040 }\
20342041 }\
20352042 \
@@ -3335,8 +3342,12 @@ class vector
33353342 // There is enough memory
33363343 T* const old_finish = this ->priv_raw_end ();
33373344 allocator_type & a = this ->m_holder .alloc ();
3345+ // Number of trailing elements [raw_pos, old_finish). Expressing the shift
3346+ // length against the end pointer (n_after - 1) lets the compiler bound and
3347+ // fold a near-end shift to inline moves instead of an out-of-line memmove.
3348+ const size_type n_after = size_type (old_finish - raw_pos);
33383349
3339- if (old_finish == raw_pos ){
3350+ if (!n_after ){
33403351 insert_range_proxy.uninitialized_copy_n_and_update (a, old_finish, 1 );
33413352 ++this ->m_holder .m_size ;
33423353 }
@@ -3348,7 +3359,7 @@ class vector
33483359 allocator_traits_type::construct (a, old_finish, ::boost::move (*before_old_finish));
33493360 ++this ->m_holder .m_size ;
33503361 // Copy previous to last objects to the initialized end
3351- boost::container::move_backward (raw_pos, before_old_finish , old_finish);
3362+ boost::container::move_backward_n (before_old_finish, n_after - 1u , old_finish);
33523363 // Insert new objects in the raw_pos
33533364 insert_range_proxy.copy_n_and_update (a, raw_pos, 1 );
33543365 }
0 commit comments