Skip to content

Commit

Permalink
Optimize __insert_with_sentinel Function in std::vector
Browse files Browse the repository at this point in the history
  • Loading branch information
winner245 committed Oct 26, 2024
1 parent ef886a2 commit be9ddb6
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 20 deletions.
40 changes: 20 additions & 20 deletions libcxx/include/__vector/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -1360,27 +1360,27 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
for (; this->__end_ != this->__end_cap() && __first != __last; ++__first) {
__construct_one_at_end(*__first);
}
__split_buffer<value_type, allocator_type&> __v(__a);
if (__first != __last) {
#if _LIBCPP_HAS_EXCEPTIONS
try {
#endif // _LIBCPP_HAS_EXCEPTIONS
__v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last));
difference_type __old_size = __old_last - this->__begin_;
difference_type __old_p = __p - this->__begin_;
reserve(__recommend(size() + __v.size()));
__p = this->__begin_ + __old_p;
__old_last = this->__begin_ + __old_size;
#if _LIBCPP_HAS_EXCEPTIONS
} catch (...) {
erase(__make_iter(__old_last), end());
throw;
}
#endif // _LIBCPP_HAS_EXCEPTIONS

if (__first == __last)
(void)std::rotate(__p, __old_last, this->__end_);
else {
__split_buffer<value_type, allocator_type&> __v(__a);
auto __guard =
std::__make_exception_guard(_AllocatorDestroyRangeReverse<allocator_type, pointer>(__a, __old_last, __end_));
__v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last));
__split_buffer<value_type, allocator_type&> __merged(__recommend(size() + __v.size()), __off, __a);
std::__uninitialized_allocator_relocate(
__a, std::__to_address(__old_last), std::__to_address(__end_), std::__to_address(__merged.__end_));
__merged.__end_ += __end_ - __old_last;
__end_ = __old_last;
__guard.__complete();
std::__uninitialized_allocator_relocate(
__a, std::__to_address(__v.__begin_), std::__to_address(__v.__end_), std::__to_address(__merged.__end_));
__merged.__end_ += __v.size();
__v.__begin_ = __v.__end_;
__p = __swap_out_circular_buffer(__merged, __p);
}
__p = std::rotate(__p, __old_last, this->__end_);
insert(__make_iter(__p), std::make_move_iterator(__v.begin()), std::make_move_iterator(__v.end()));
return begin() + __off;
return __make_iter(__p);
}

template <class _Tp, class _Allocator>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,46 @@ TEST_CONSTEXPR_CXX20 bool tests()
for (; j < 105; ++j)
assert(v[j] == 0);
}
{ // Vector may or may not need to reallocate because of the insertion -- test both cases.
{ // The input range is shorter than the remaining capacity of the vector -- ensure no reallocation happens.
typedef std::vector<int> V;
V v(100);
v.reserve(v.size() + 10);
int a[] = {1, 2, 3, 4, 5};
const int N = sizeof(a) / sizeof(a[0]);
V::iterator i =
v.insert(v.cbegin() + 10, cpp17_input_iterator<const int*>(a), cpp17_input_iterator<const int*>(a + N));
assert(v.size() == 100 + N);
assert(is_contiguous_container_asan_correct(v));
assert(i == v.begin() + 10);
int j;
for (j = 0; j < 10; ++j)
assert(v[j] == 0);
for (std::size_t k = 0; k < N; ++j, ++k)
assert(v[j] == a[k]);
for (; j < 105; ++j)
assert(v[j] == 0);
}
{ // The input range is longer than the remaining capacity of the vector -- ensure reallocation happens.
typedef std::vector<int> V;
V v(100);
v.reserve(v.size() + 2);
int a[] = {1, 2, 3, 4, 5};
const int N = sizeof(a) / sizeof(a[0]);
V::iterator i =
v.insert(v.cbegin() + 10, cpp17_input_iterator<const int*>(a), cpp17_input_iterator<const int*>(a + N));
assert(v.size() == 100 + N);
assert(is_contiguous_container_asan_correct(v));
assert(i == v.begin() + 10);
int j;
for (j = 0; j < 10; ++j)
assert(v[j] == 0);
for (std::size_t k = 0; k < N; ++j, ++k)
assert(v[j] == a[k]);
for (; j < 105; ++j)
assert(v[j] == 0);
}
}
{
typedef std::vector<int> V;
V v(100);
Expand Down

0 comments on commit be9ddb6

Please sign in to comment.