Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 13fe960

Browse files
committed
[libcxx] Optimize vectors construction of trivial types from an iterator range with const-ness mismatch.
We already have a specialization that will use memcpy for construction of trivial types from an iterator range like std::vector<int>(int *, int *); But if we have const-ness mismatch like std::vector<int>(const int *, const int *); we would use a slow path that copies each element individually. This change enables the optimal specialization for const-ness mismatch. Fixes PR37574. Contributions to the patch are made by Arthur O'Dwyer, Louis Dionne. rdar://problem/40485845 Reviewers: mclow.lists, EricWF, ldionne, scanon Reviewed By: ldionne Subscribers: christof, ldionne, howard.hinnant, cfe-commits Differential Revision: https://reviews.llvm.org/D48342 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@350583 91177308-0d34-0410-b5e6-96231b3b80d8 (cherry picked from commit 354589c)
1 parent 1bd2d77 commit 13fe960

File tree

2 files changed

+48
-9
lines changed

2 files changed

+48
-9
lines changed

include/memory

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,6 +1501,12 @@ struct __alloc_traits_difference_type<_Alloc, _Ptr, true>
15011501
typedef typename _Alloc::difference_type type;
15021502
};
15031503

1504+
template <class _Tp>
1505+
struct __is_default_allocator : false_type {};
1506+
1507+
template <class _Tp>
1508+
struct __is_default_allocator<_VSTD::allocator<_Tp> > : true_type {};
1509+
15041510
template <class _Alloc>
15051511
struct _LIBCPP_TEMPLATE_VIS allocator_traits
15061512
{
@@ -1614,7 +1620,7 @@ struct _LIBCPP_TEMPLATE_VIS allocator_traits
16141620
static
16151621
typename enable_if
16161622
<
1617-
(is_same<allocator_type, allocator<_Tp> >::value
1623+
(__is_default_allocator<allocator_type>::value
16181624
|| !__has_construct<allocator_type, _Tp*, _Tp>::value) &&
16191625
is_trivially_move_constructible<_Tp>::value,
16201626
void
@@ -1639,23 +1645,25 @@ struct _LIBCPP_TEMPLATE_VIS allocator_traits
16391645
construct(__a, _VSTD::__to_raw_pointer(__begin2), *__begin1);
16401646
}
16411647

1642-
template <class _Tp>
1648+
template <class _SourceTp, class _DestTp,
1649+
class _RawSourceTp = typename remove_const<_SourceTp>::type,
1650+
class _RawDestTp = typename remove_const<_DestTp>::type>
16431651
_LIBCPP_INLINE_VISIBILITY
16441652
static
16451653
typename enable_if
16461654
<
1647-
(is_same<allocator_type, allocator<_Tp> >::value
1648-
|| !__has_construct<allocator_type, _Tp*, _Tp>::value) &&
1649-
is_trivially_move_constructible<_Tp>::value,
1655+
is_trivially_move_constructible<_DestTp>::value &&
1656+
is_same<_RawSourceTp, _RawDestTp>::value &&
1657+
(__is_default_allocator<allocator_type>::value ||
1658+
!__has_construct<allocator_type, _DestTp*, _SourceTp&>::value),
16501659
void
16511660
>::type
1652-
__construct_range_forward(allocator_type&, _Tp* __begin1, _Tp* __end1, _Tp*& __begin2)
1661+
__construct_range_forward(allocator_type&, _SourceTp* __begin1, _SourceTp* __end1, _DestTp*& __begin2)
16531662
{
1654-
typedef typename remove_const<_Tp>::type _Vp;
16551663
ptrdiff_t _Np = __end1 - __begin1;
16561664
if (_Np > 0)
16571665
{
1658-
_VSTD::memcpy(const_cast<_Vp*>(__begin2), __begin1, _Np * sizeof(_Tp));
1666+
_VSTD::memcpy(const_cast<_RawDestTp*>(__begin2), __begin1, _Np * sizeof(_DestTp));
16591667
__begin2 += _Np;
16601668
}
16611669
}
@@ -1678,7 +1686,7 @@ struct _LIBCPP_TEMPLATE_VIS allocator_traits
16781686
static
16791687
typename enable_if
16801688
<
1681-
(is_same<allocator_type, allocator<_Tp> >::value
1689+
(__is_default_allocator<allocator_type>::value
16821690
|| !__has_construct<allocator_type, _Tp*, _Tp>::value) &&
16831691
is_trivially_move_constructible<_Tp>::value,
16841692
void

test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,40 @@ void test_ctor_under_alloc() {
148148
#endif
149149
}
150150

151+
// Initialize a vector with a different value type.
152+
void test_ctor_with_different_value_type() {
153+
{
154+
// Make sure initialization is performed with each element value, not with
155+
// a memory blob.
156+
float array[3] = {0.0f, 1.0f, 2.0f};
157+
std::vector<int> v(array, array + 3);
158+
assert(v[0] == 0);
159+
assert(v[1] == 1);
160+
assert(v[2] == 2);
161+
}
162+
struct X { int x; };
163+
struct Y { int y; };
164+
struct Z : X, Y { int z; };
165+
{
166+
Z z;
167+
Z *array[1] = { &z };
168+
// Though the types Z* and Y* are very similar, initialization still cannot
169+
// be done with `memcpy`.
170+
std::vector<Y*> v(array, array + 1);
171+
assert(v[0] == &z);
172+
}
173+
{
174+
// Though the types are different, initialization can be done with `memcpy`.
175+
int32_t array[1] = { -1 };
176+
std::vector<uint32_t> v(array, array + 1);
177+
assert(v[0] == 4294967295);
178+
}
179+
}
180+
151181

152182
int main() {
153183
basic_test_cases();
154184
emplaceable_concept_tests(); // See PR34898
155185
test_ctor_under_alloc();
186+
test_ctor_with_different_value_type();
156187
}

0 commit comments

Comments
 (0)