Skip to content

Commit be9ddb6

Browse files
committed
Optimize __insert_with_sentinel Function in std::vector
1 parent ef886a2 commit be9ddb6

File tree

2 files changed

+60
-20
lines changed

2 files changed

+60
-20
lines changed

libcxx/include/__vector/vector.h

+20-20
Original file line numberDiff line numberDiff line change
@@ -1360,27 +1360,27 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
13601360
for (; this->__end_ != this->__end_cap() && __first != __last; ++__first) {
13611361
__construct_one_at_end(*__first);
13621362
}
1363-
__split_buffer<value_type, allocator_type&> __v(__a);
1364-
if (__first != __last) {
1365-
#if _LIBCPP_HAS_EXCEPTIONS
1366-
try {
1367-
#endif // _LIBCPP_HAS_EXCEPTIONS
1368-
__v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last));
1369-
difference_type __old_size = __old_last - this->__begin_;
1370-
difference_type __old_p = __p - this->__begin_;
1371-
reserve(__recommend(size() + __v.size()));
1372-
__p = this->__begin_ + __old_p;
1373-
__old_last = this->__begin_ + __old_size;
1374-
#if _LIBCPP_HAS_EXCEPTIONS
1375-
} catch (...) {
1376-
erase(__make_iter(__old_last), end());
1377-
throw;
1378-
}
1379-
#endif // _LIBCPP_HAS_EXCEPTIONS
1363+
1364+
if (__first == __last)
1365+
(void)std::rotate(__p, __old_last, this->__end_);
1366+
else {
1367+
__split_buffer<value_type, allocator_type&> __v(__a);
1368+
auto __guard =
1369+
std::__make_exception_guard(_AllocatorDestroyRangeReverse<allocator_type, pointer>(__a, __old_last, __end_));
1370+
__v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last));
1371+
__split_buffer<value_type, allocator_type&> __merged(__recommend(size() + __v.size()), __off, __a);
1372+
std::__uninitialized_allocator_relocate(
1373+
__a, std::__to_address(__old_last), std::__to_address(__end_), std::__to_address(__merged.__end_));
1374+
__merged.__end_ += __end_ - __old_last;
1375+
__end_ = __old_last;
1376+
__guard.__complete();
1377+
std::__uninitialized_allocator_relocate(
1378+
__a, std::__to_address(__v.__begin_), std::__to_address(__v.__end_), std::__to_address(__merged.__end_));
1379+
__merged.__end_ += __v.size();
1380+
__v.__begin_ = __v.__end_;
1381+
__p = __swap_out_circular_buffer(__merged, __p);
13801382
}
1381-
__p = std::rotate(__p, __old_last, this->__end_);
1382-
insert(__make_iter(__p), std::make_move_iterator(__v.begin()), std::make_move_iterator(__v.end()));
1383-
return begin() + __off;
1383+
return __make_iter(__p);
13841384
}
13851385

13861386
template <class _Tp, class _Allocator>

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

+40
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)