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

Commit 354589c

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
1 parent 4626eac commit 354589c

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
@@ -1502,6 +1502,12 @@ struct __alloc_traits_difference_type<_Alloc, _Ptr, true>
15021502
typedef typename _Alloc::difference_type type;
15031503
};
15041504

1505+
template <class _Tp>
1506+
struct __is_default_allocator : false_type {};
1507+
1508+
template <class _Tp>
1509+
struct __is_default_allocator<_VSTD::allocator<_Tp> > : true_type {};
1510+
15051511
template <class _Alloc>
15061512
struct _LIBCPP_TEMPLATE_VIS allocator_traits
15071513
{
@@ -1615,7 +1621,7 @@ struct _LIBCPP_TEMPLATE_VIS allocator_traits
16151621
static
16161622
typename enable_if
16171623
<
1618-
(is_same<allocator_type, allocator<_Tp> >::value
1624+
(__is_default_allocator<allocator_type>::value
16191625
|| !__has_construct<allocator_type, _Tp*, _Tp>::value) &&
16201626
is_trivially_move_constructible<_Tp>::value,
16211627
void
@@ -1640,23 +1646,25 @@ struct _LIBCPP_TEMPLATE_VIS allocator_traits
16401646
construct(__a, _VSTD::__to_raw_pointer(__begin2), *__begin1);
16411647
}
16421648

1643-
template <class _Tp>
1649+
template <class _SourceTp, class _DestTp,
1650+
class _RawSourceTp = typename remove_const<_SourceTp>::type,
1651+
class _RawDestTp = typename remove_const<_DestTp>::type>
16441652
_LIBCPP_INLINE_VISIBILITY
16451653
static
16461654
typename enable_if
16471655
<
1648-
(is_same<allocator_type, allocator<_Tp> >::value
1649-
|| !__has_construct<allocator_type, _Tp*, _Tp>::value) &&
1650-
is_trivially_move_constructible<_Tp>::value,
1656+
is_trivially_move_constructible<_DestTp>::value &&
1657+
is_same<_RawSourceTp, _RawDestTp>::value &&
1658+
(__is_default_allocator<allocator_type>::value ||
1659+
!__has_construct<allocator_type, _DestTp*, _SourceTp&>::value),
16511660
void
16521661
>::type
1653-
__construct_range_forward(allocator_type&, _Tp* __begin1, _Tp* __end1, _Tp*& __begin2)
1662+
__construct_range_forward(allocator_type&, _SourceTp* __begin1, _SourceTp* __end1, _DestTp*& __begin2)
16541663
{
1655-
typedef typename remove_const<_Tp>::type _Vp;
16561664
ptrdiff_t _Np = __end1 - __begin1;
16571665
if (_Np > 0)
16581666
{
1659-
_VSTD::memcpy(const_cast<_Vp*>(__begin2), __begin1, _Np * sizeof(_Tp));
1667+
_VSTD::memcpy(const_cast<_RawDestTp*>(__begin2), __begin1, _Np * sizeof(_DestTp));
16601668
__begin2 += _Np;
16611669
}
16621670
}
@@ -1679,7 +1687,7 @@ struct _LIBCPP_TEMPLATE_VIS allocator_traits
16791687
static
16801688
typename enable_if
16811689
<
1682-
(is_same<allocator_type, allocator<_Tp> >::value
1690+
(__is_default_allocator<allocator_type>::value
16831691
|| !__has_construct<allocator_type, _Tp*, _Tp>::value) &&
16841692
is_trivially_move_constructible<_Tp>::value,
16851693
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
@@ -146,9 +146,40 @@ void test_ctor_under_alloc() {
146146
#endif
147147
}
148148

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

150180
int main() {
151181
basic_test_cases();
152182
emplaceable_concept_tests(); // See PR34898
153183
test_ctor_under_alloc();
184+
test_ctor_with_different_value_type();
154185
}

0 commit comments

Comments
 (0)