Skip to content
36 changes: 27 additions & 9 deletions libcxx/include/__vector/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#include <__type_traits/is_same.h>
#include <__type_traits/is_trivially_relocatable.h>
#include <__type_traits/type_identity.h>
#include <__utility/declval.h>
#include <__utility/exception_guard.h>
#include <__utility/forward.h>
#include <__utility/is_pointer_in_range.h>
Expand Down Expand Up @@ -602,6 +603,30 @@ class _LIBCPP_TEMPLATE_VIS vector {
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
__assign_with_size(_Iterator __first, _Sentinel __last, difference_type __n);

template <class _Iterator,
__enable_if_t<!is_same<decltype(*std::declval<_Iterator&>())&&, value_type&&>::value, int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
__insert_assign_n_unchecked(_Iterator __first, difference_type __n, pointer __position) {
for (pointer __end_position = __position + __n; __position != __end_position; ++__position, (void)++__first) {
__temp_value<value_type, _Allocator> __tmp(this->__alloc_, *__first);
*__position = std::move(__tmp.get());
}
}

template <class _Iterator,
__enable_if_t<is_same<decltype(*std::declval<_Iterator&>())&&, value_type&&>::value, int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
__insert_assign_n_unchecked(_Iterator __first, difference_type __n, pointer __position) {
#if _LIBCPP_STD_VER >= 23
if constexpr (!forward_iterator<_Iterator>) {
ranges::copy_n(std::move(__first), __n, __position);
} else
#endif
{
std::copy_n(__first, __n, __position);
}
}

template <class _InputIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator
__insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last);
Expand Down Expand Up @@ -1322,19 +1347,12 @@ vector<_Tp, _Allocator>::__insert_with_size(
__construct_at_end(__m, __last, __n - __dx);
if (__dx > 0) {
__move_range(__p, __old_last, __p + __n);
std::copy(__first, __m, __p);
__insert_assign_n_unchecked(__first, __dx, __p);
}
}
} else {
__move_range(__p, __old_last, __p + __n);
#if _LIBCPP_STD_VER >= 23
if constexpr (!forward_iterator<_Iterator>) {
ranges::copy_n(std::move(__first), __n, __p);
} else
#endif
{
std::copy_n(__first, __n, __p);
}
__insert_assign_n_unchecked(std::move(__first), __n, __p);
}
} else {
__split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
// template <class Iter>
// iterator insert(const_iterator position, Iter first, Iter last);

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

#include <vector>
#include <cassert>
#include <cstddef>
Expand Down Expand Up @@ -161,6 +163,24 @@ TEST_CONSTEXPR_CXX20 bool tests() {
for (; j < 105; ++j)
assert(v[j] == 0);
}
{
struct Wrapper {
TEST_CONSTEXPR Wrapper(int n) : n_(n) {}

int n_;

private:
void operator=(int);
};

int a[] = {1, 2, 3, 4, 5};
const std::size_t count = sizeof(a) / sizeof(a[0]);
std::vector<Wrapper> v;
v.insert(v.end(), a, a + count);
assert(v.size() == count);
for (std::size_t i = 0; i != count; ++i)
assert(v[i].n_ == a[i]);
}
#if TEST_STD_VER >= 11
{
typedef std::vector<int, min_allocator<int> > V;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ constexpr bool test() {
}
}

{ // Ensure that insert_range doesn't use unexpected assignment.
struct Wrapper {
constexpr Wrapper(int n) : n_(n) {}
void operator=(int) = delete;

int n_;
};

int a[]{1, 2, 3, 4, 5};
std::vector<Wrapper> v;
v.insert_range(v.end(), a);
assert(v.size() == std::size(a));
for (std::size_t i = 0; i != std::size(a); ++i)
assert(v[i].n_ == a[i]);
}

return true;
}

Expand Down