Skip to content

Commit 1049fcc

Browse files
committed
Optimize __insert_with_sentinel Function in std::vector
1 parent 9e33387 commit 1049fcc

File tree

2 files changed

+61
-22
lines changed

2 files changed

+61
-22
lines changed

libcxx/include/__vector/vector.h

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,30 +1250,29 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
12501250
difference_type __off = __position - begin();
12511251
pointer __p = this->__begin_ + __off;
12521252
pointer __old_last = this->__end_;
1253-
for (; this->__end_ != this->__cap_ && __first != __last; ++__first) {
1253+
for (; this->__end_ != this->__cap_ && __first != __last; ++__first)
12541254
__construct_one_at_end(*__first);
1255+
1256+
if (__first == __last)
1257+
(void)std::rotate(__p, __old_last, this->__end_);
1258+
else {
1259+
__split_buffer<value_type, allocator_type&> __v(__alloc_);
1260+
auto __guard = std::__make_exception_guard(
1261+
_AllocatorDestroyRangeReverse<allocator_type, pointer>(__alloc_, __old_last, this->__end_));
1262+
__v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last));
1263+
__split_buffer<value_type, allocator_type&> __merged(__recommend(size() + __v.size()), __off, __alloc_);
1264+
std::__uninitialized_allocator_relocate(
1265+
__alloc_, std::__to_address(__old_last), std::__to_address(this->__end_), std::__to_address(__merged.__end_));
1266+
__guard.__complete(); // Release the guard once objects in [__old_last_, __end_) have been successfully relocated.
1267+
__merged.__end_ += this->__end_ - __old_last;
1268+
this->__end_ = __old_last;
1269+
std::__uninitialized_allocator_relocate(
1270+
__alloc_, std::__to_address(__v.__begin_), std::__to_address(__v.__end_), std::__to_address(__merged.__end_));
1271+
__merged.__end_ += __v.size();
1272+
__v.__end_ = __v.__begin_;
1273+
__p = __swap_out_circular_buffer(__merged, __p);
12551274
}
1256-
__split_buffer<value_type, allocator_type&> __v(this->__alloc_);
1257-
if (__first != __last) {
1258-
#if _LIBCPP_HAS_EXCEPTIONS
1259-
try {
1260-
#endif // _LIBCPP_HAS_EXCEPTIONS
1261-
__v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last));
1262-
difference_type __old_size = __old_last - this->__begin_;
1263-
difference_type __old_p = __p - this->__begin_;
1264-
reserve(__recommend(size() + __v.size()));
1265-
__p = this->__begin_ + __old_p;
1266-
__old_last = this->__begin_ + __old_size;
1267-
#if _LIBCPP_HAS_EXCEPTIONS
1268-
} catch (...) {
1269-
erase(__make_iter(__old_last), end());
1270-
throw;
1271-
}
1272-
#endif // _LIBCPP_HAS_EXCEPTIONS
1273-
}
1274-
__p = std::rotate(__p, __old_last, this->__end_);
1275-
insert(__make_iter(__p), std::make_move_iterator(__v.begin()), std::make_move_iterator(__v.end()));
1276-
return begin() + __off;
1275+
return __make_iter(__p);
12771276
}
12781277

12791278
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)