Skip to content

Commit ae7a50e

Browse files
committed
Optimize __insert_with_sentinel Function in std::vector
1 parent 7475156 commit ae7a50e

File tree

2 files changed

+62
-23
lines changed

2 files changed

+62
-23
lines changed

libcxx/include/__vector/vector.h

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,32 +1264,31 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Alloca
12641264
vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last) {
12651265
difference_type __off = __position - begin();
12661266
pointer __p = this->__begin_ + __off;
1267-
allocator_type& __a = this->__alloc();
1267+
allocator_type& __a = this->__alloc_;
12681268
pointer __old_last = this->__end_;
1269-
for (; this->__end_ != this->__end_cap() && __first != __last; ++__first) {
1269+
for (; this->__end_ != this->__cap_ && __first != __last; ++__first)
12701270
__construct_one_at_end(*__first);
1271+
1272+
if (__first == __last)
1273+
(void)std::rotate(__p, __old_last, this->__end_);
1274+
else {
1275+
__split_buffer<value_type, allocator_type&> __v(__a);
1276+
auto __guard = std::__make_exception_guard(
1277+
_AllocatorDestroyRangeReverse<allocator_type, pointer>(__a, __old_last, this->__end_));
1278+
__v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last));
1279+
__split_buffer<value_type, allocator_type&> __merged(__recommend(size() + __v.size()), __off, __a);
1280+
std::__uninitialized_allocator_relocate(
1281+
__a, std::__to_address(__old_last), std::__to_address(this->__end_), std::__to_address(__merged.__end_));
1282+
__guard.__complete(); // Release the guard once objects in [__old_last_, __end_) have been successfully relocated.
1283+
__merged.__end_ += this->__end_ - __old_last;
1284+
this->__end_ = __old_last;
1285+
std::__uninitialized_allocator_relocate(
1286+
__a, std::__to_address(__v.__begin_), std::__to_address(__v.__end_), std::__to_address(__merged.__end_));
1287+
__merged.__end_ += __v.size();
1288+
__v.__end_ = __v.__begin_;
1289+
__p = __swap_out_circular_buffer(__merged, __p);
12711290
}
1272-
__split_buffer<value_type, allocator_type&> __v(__a);
1273-
if (__first != __last) {
1274-
#if _LIBCPP_HAS_EXCEPTIONS
1275-
try {
1276-
#endif // _LIBCPP_HAS_EXCEPTIONS
1277-
__v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last));
1278-
difference_type __old_size = __old_last - this->__begin_;
1279-
difference_type __old_p = __p - this->__begin_;
1280-
reserve(__recommend(size() + __v.size()));
1281-
__p = this->__begin_ + __old_p;
1282-
__old_last = this->__begin_ + __old_size;
1283-
#if _LIBCPP_HAS_EXCEPTIONS
1284-
} catch (...) {
1285-
erase(__make_iter(__old_last), end());
1286-
throw;
1287-
}
1288-
#endif // _LIBCPP_HAS_EXCEPTIONS
1289-
}
1290-
__p = std::rotate(__p, __old_last, this->__end_);
1291-
insert(__make_iter(__p), std::make_move_iterator(__v.begin()), std::make_move_iterator(__v.end()));
1292-
return begin() + __off;
1291+
return __make_iter(__p);
12931292
}
12941293

12951294
template <class _Tp, class _Allocator>

libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_iter_iter.pass.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,46 @@ TEST_CONSTEXPR_CXX20 bool tests()
4646
for (; j < 105; ++j)
4747
assert(v[j] == 0);
4848
}
49+
{ // Vector may or may not need to reallocate because of the insertion -- test both cases.
50+
{ // The input range is shorter than the remaining capacity of the vector -- ensure no reallocation happens.
51+
typedef std::vector<int> V;
52+
V v(100);
53+
v.reserve(v.size() + 10);
54+
int a[] = {1, 2, 3, 4, 5};
55+
const int N = sizeof(a) / sizeof(a[0]);
56+
V::iterator i =
57+
v.insert(v.cbegin() + 10, cpp17_input_iterator<const int*>(a), cpp17_input_iterator<const int*>(a + N));
58+
assert(v.size() == 100 + N);
59+
assert(is_contiguous_container_asan_correct(v));
60+
assert(i == v.begin() + 10);
61+
int j;
62+
for (j = 0; j < 10; ++j)
63+
assert(v[j] == 0);
64+
for (std::size_t k = 0; k < N; ++j, ++k)
65+
assert(v[j] == a[k]);
66+
for (; j < 105; ++j)
67+
assert(v[j] == 0);
68+
}
69+
{ // The input range is longer than the remaining capacity of the vector -- ensure reallocation happens.
70+
typedef std::vector<int> V;
71+
V v(100);
72+
v.reserve(v.size() + 2);
73+
int a[] = {1, 2, 3, 4, 5};
74+
const int N = sizeof(a) / sizeof(a[0]);
75+
V::iterator i =
76+
v.insert(v.cbegin() + 10, cpp17_input_iterator<const int*>(a), cpp17_input_iterator<const int*>(a + N));
77+
assert(v.size() == 100 + N);
78+
assert(is_contiguous_container_asan_correct(v));
79+
assert(i == v.begin() + 10);
80+
int j;
81+
for (j = 0; j < 10; ++j)
82+
assert(v[j] == 0);
83+
for (std::size_t k = 0; k < N; ++j, ++k)
84+
assert(v[j] == a[k]);
85+
for (; j < 105; ++j)
86+
assert(v[j] == 0);
87+
}
88+
}
4989
{
5090
typedef std::vector<int> V;
5191
V v(100);

0 commit comments

Comments
 (0)