Skip to content

Commit a27d894

Browse files
AdamBuciorCaseyCarterStephanTLavavej
authored
Use memset in even more cases (#1273)
Co-authored-by: Casey Carter <cartec69@gmail.com> Co-authored-by: Stephan T. Lavavej <stl@microsoft.com>
1 parent ae31b78 commit a27d894

11 files changed

Lines changed: 217 additions & 44 deletions

File tree

stl/inc/algorithm

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3929,16 +3929,19 @@ namespace ranges {
39293929
_Adl_verify_range(_First, _Last);
39303930
auto _UFirst = _Get_unwrapped(_STD move(_First));
39313931
const auto _ULast = _Get_unwrapped(_STD move(_Last));
3932-
if constexpr (_Fill_memset_is_safe<decltype(_UFirst), _Ty>) {
3933-
#ifdef __cpp_lib_is_constant_evaluated
3934-
if (!_STD is_constant_evaluated())
3935-
#endif // __cpp_lib_is_constant_evaluated
3936-
{
3932+
if (!_STD is_constant_evaluated()) {
3933+
if constexpr (_Fill_memset_is_safe<decltype(_UFirst), _Ty>) {
39373934
const auto _Distance = static_cast<size_t>(_ULast - _UFirst);
39383935
_Fill_memset(_UFirst, _Value, _Distance);
3939-
_UFirst += _Distance;
3940-
_Seek_wrapped(_First, _UFirst);
3936+
_Seek_wrapped(_First, _UFirst + _Distance);
39413937
return _First;
3938+
} else if constexpr (_Fill_zero_memset_is_safe<decltype(_UFirst), _Ty>) {
3939+
if (_Is_all_bits_zero(_Value)) {
3940+
const auto _Distance = static_cast<size_t>(_ULast - _UFirst);
3941+
_Fill_zero_memset(_UFirst, _Distance);
3942+
_Seek_wrapped(_First, _UFirst + _Distance);
3943+
return _First;
3944+
}
39423945
}
39433946
}
39443947

@@ -3969,15 +3972,17 @@ namespace ranges {
39693972
constexpr _It operator()(_It _First, iter_difference_t<_It> _Count, const _Ty& _Value) const {
39703973
if (_Count > 0) {
39713974
auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count);
3972-
if constexpr (_Fill_memset_is_safe<decltype(_UFirst), _Ty>) {
3973-
#ifdef __cpp_lib_is_constant_evaluated
3974-
if (!_STD is_constant_evaluated())
3975-
#endif // __cpp_lib_is_constant_evaluated
3976-
{
3975+
if (!_STD is_constant_evaluated()) {
3976+
if constexpr (_Fill_memset_is_safe<decltype(_UFirst), _Ty>) {
39773977
_Fill_memset(_UFirst, _Value, static_cast<size_t>(_Count));
3978-
_UFirst += _Count;
3979-
_Seek_wrapped(_First, _UFirst); // no need to move since _UFirst is a pointer
3978+
_Seek_wrapped(_First, _UFirst + _Count); // no need to move since _UFirst is a pointer
39803979
return _First;
3980+
} else if constexpr (_Fill_zero_memset_is_safe<decltype(_UFirst), _Ty>) {
3981+
if (_Is_all_bits_zero(_Value)) {
3982+
_Fill_zero_memset(_UFirst, static_cast<size_t>(_Count));
3983+
_Seek_wrapped(_First, _UFirst + _Count); // no need to move since _UFirst is a pointer
3984+
return _First;
3985+
}
39813986
}
39823987
}
39833988

stl/inc/memory

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -428,10 +428,17 @@ namespace ranges {
428428

429429
if constexpr (_Fill_memset_is_safe<_It, _Ty>) {
430430
const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast));
431-
const auto _Diff = static_cast<size_t>(_OFinal - _OFirst);
432-
_Fill_memset(_OFirst, _Val, _Diff);
431+
_Fill_memset(_OFirst, _Val, static_cast<size_t>(_OFinal - _OFirst));
433432
return _OFinal;
434433
} else {
434+
if constexpr (_Fill_zero_memset_is_safe<_It, _Ty>) {
435+
if (_Is_all_bits_zero(_Val)) {
436+
const auto _OFinal = _RANGES next(_OFirst, _STD move(_OLast));
437+
_Fill_zero_memset(_OFirst, static_cast<size_t>(_OFinal - _OFirst));
438+
return _OFinal;
439+
}
440+
}
441+
435442
_Uninitialized_backout _Backout{_STD move(_OFirst)};
436443

437444
while (_Backout._Last != _OLast) {
@@ -458,11 +465,19 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw,
458465
}
459466

460467
auto _UFirst = _Get_unwrapped_n(_First, _Count);
461-
if constexpr (_Fill_memset_is_safe<_Unwrapped_n_t<const _NoThrowFwdIt&>, _Tval>) {
468+
if constexpr (_Fill_memset_is_safe<decltype(_UFirst), _Tval>) {
462469
_Fill_memset(_UFirst, _Val, static_cast<size_t>(_Count));
463470
_UFirst += _Count;
464471
} else {
465-
_Uninitialized_backout<_Unwrapped_n_t<const _NoThrowFwdIt&>> _Backout{_UFirst};
472+
if constexpr (_Fill_zero_memset_is_safe<decltype(_UFirst), _Tval>) {
473+
if (_Is_all_bits_zero(_Val)) {
474+
_Fill_zero_memset(_UFirst, static_cast<size_t>(_Count));
475+
_Seek_wrapped(_First, _UFirst + _Count);
476+
return _First;
477+
}
478+
}
479+
480+
_Uninitialized_backout<decltype(_UFirst)> _Backout{_UFirst};
466481

467482
for (; _Count > 0; --_Count) {
468483
_Backout._Emplace_back(_Val);
@@ -527,10 +542,18 @@ namespace ranges {
527542
}
528543

529544
auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count);
530-
if constexpr (_Fill_memset_is_safe<_It, _Ty>) {
545+
if constexpr (_Fill_memset_is_safe<decltype(_UFirst), _Ty>) {
531546
_Fill_memset(_UFirst, _Val, static_cast<size_t>(_Count));
532547
_Seek_wrapped(_First, _UFirst + _Count);
533548
} else {
549+
if constexpr (_Fill_zero_memset_is_safe<decltype(_UFirst), _Ty>) {
550+
if (_Is_all_bits_zero(_Val)) {
551+
_Fill_zero_memset(_UFirst, static_cast<size_t>(_Count));
552+
_Seek_wrapped(_First, _UFirst + _Count);
553+
return _First;
554+
}
555+
}
556+
534557
_Uninitialized_backout _Backout{_STD move(_UFirst)};
535558

536559
for (; _Count > 0; --_Count) {
@@ -2386,6 +2409,12 @@ void _Uninitialized_fill_multidimensional_n(_Ty* const _Out, const size_t _Size,
23862409
} else if constexpr (_Fill_memset_is_safe<_Ty*, _Ty>) {
23872410
_Fill_memset(_Out, _Val, _Size);
23882411
} else {
2412+
if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty>) {
2413+
if (_Is_all_bits_zero(_Val)) {
2414+
_Fill_zero_memset(_Out, _Size);
2415+
return;
2416+
}
2417+
}
23892418
_Uninitialized_rev_destroying_backout _Backout{_Out};
23902419
for (size_t _Idx = 0; _Idx < _Size; ++_Idx) {
23912420
_Backout._Emplace_back(_Val);
@@ -2730,6 +2759,13 @@ void _Uninitialized_fill_multidimensional_n_al(_Ty* const _Out, const size_t _Si
27302759
} else if constexpr (_Fill_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, const _Ty&>::value) {
27312760
_Fill_memset(_Out, _Val, _Size);
27322761
} else {
2762+
if constexpr (_Fill_zero_memset_is_safe<_Ty*,
2763+
_Ty> && _Uses_default_construct<_Alloc, _Ty*, const _Ty&>::value) {
2764+
if (_Is_all_bits_zero(_Val)) {
2765+
_Fill_zero_memset(_Out, _Size);
2766+
return;
2767+
}
2768+
}
27332769
_Uninitialized_rev_destroying_backout_al _Backout{_Out, _Al};
27342770
for (size_t _Idx = 0; _Idx < _Size; ++_Idx) {
27352771
_Backout._Emplace_back(_Val);

stl/inc/xmemory

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1737,6 +1737,12 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n(
17371737
_Fill_memset(_Unfancy(_First), _Val, static_cast<size_t>(_Count));
17381738
return _First + _Count;
17391739
} else {
1740+
if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) {
1741+
if (_Is_all_bits_zero(_Val)) {
1742+
_Fill_zero_memset(_Unfancy(_First), static_cast<size_t>(_Count));
1743+
return _First + _Count;
1744+
}
1745+
}
17401746
_Uninitialized_backout_al<_Alloc> _Backout{_First, _Al};
17411747
for (; 0 < _Count; --_Count) {
17421748
_Backout._Emplace_back(_Val);
@@ -1787,6 +1793,12 @@ void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, c
17871793
if constexpr (_Fill_memset_is_safe<_Unwrapped_t<const _NoThrowFwdIt&>, _Tval>) {
17881794
_Fill_memset(_UFirst, _Val, static_cast<size_t>(_ULast - _UFirst));
17891795
} else {
1796+
if constexpr (_Fill_zero_memset_is_safe<_Unwrapped_t<const _NoThrowFwdIt&>, _Tval>) {
1797+
if (_Is_all_bits_zero(_Val)) {
1798+
_Fill_zero_memset(_UFirst, static_cast<size_t>(_ULast - _UFirst));
1799+
return;
1800+
}
1801+
}
17901802
_Uninitialized_backout<_Unwrapped_t<const _NoThrowFwdIt&>> _Backout{_UFirst};
17911803
while (_Backout._Last != _ULast) {
17921804
_Backout._Emplace_back(_Val);

stl/inc/xutility

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,10 +1485,6 @@ _NODISCARD constexpr _Ty* _Get_unwrapped_n(_Ty* const _Src, _Diff) {
14851485
}
14861486
#endif // _HAS_IF_CONSTEXPR
14871487

1488-
template <class _Iter>
1489-
using _Unwrapped_n_t =
1490-
_Remove_cvref_t<decltype(_Get_unwrapped_n(_STD declval<_Iter>(), _Iter_diff_t<_Remove_cvref_t<_Iter>>{}))>;
1491-
14921488
// FUNCTION TEMPLATE _Seek_wrapped
14931489
template <class _Iter, class _UIter, class = void>
14941490
_INLINE_VAR constexpr bool _Wrapped_seekable_v = false;
@@ -4813,12 +4809,33 @@ _INLINE_VAR constexpr bool _Fill_memset_is_safe = conjunction_v<is_scalar<_Ty>,
48134809
template <class _FwdIt, class _Ty>
48144810
_INLINE_VAR constexpr bool _Fill_memset_is_safe<_FwdIt, _Ty, false> = false;
48154811

4812+
template <class _FwdIt, class _Ty, bool = is_pointer_v<_FwdIt>>
4813+
_INLINE_VAR constexpr bool _Fill_zero_memset_is_safe =
4814+
conjunction_v<is_scalar<_Ty>, is_scalar<_Iter_value_t<_FwdIt>>, negation<is_member_pointer<_Iter_value_t<_FwdIt>>>,
4815+
negation<is_volatile<remove_reference_t<_Iter_ref_t<_FwdIt>>>>, is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>;
4816+
4817+
template <class _FwdIt, class _Ty>
4818+
_INLINE_VAR constexpr bool _Fill_zero_memset_is_safe<_FwdIt, _Ty, false> = false;
4819+
48164820
template <class _DestTy, class _Ty>
48174821
void _Fill_memset(_DestTy* const _Dest, const _Ty _Val, const size_t _Count) {
48184822
_DestTy _Dest_val = _Val; // implicitly convert (a cast would suppress warnings); also handles _DestTy being bool
48194823
_CSTD memset(_Dest, static_cast<unsigned char>(_Dest_val), _Count);
48204824
}
48214825

4826+
template <class _DestTy>
4827+
void _Fill_zero_memset(_DestTy* const _Dest, const size_t _Count) {
4828+
_CSTD memset(_Dest, 0, _Count * sizeof(_DestTy));
4829+
}
4830+
4831+
template <class _Ty>
4832+
_NODISCARD bool _Is_all_bits_zero(const _Ty& _Val) {
4833+
// checks if scalar type has all bits set to zero
4834+
_STL_INTERNAL_STATIC_ASSERT(is_scalar_v<_Ty> && !is_member_pointer_v<_Ty>);
4835+
constexpr _Ty _Zero{};
4836+
return _CSTD memcmp(&_Val, &_Zero, sizeof(_Ty)) == 0;
4837+
}
4838+
48224839
#if _HAS_IF_CONSTEXPR
48234840
template <class _FwdIt, class _Ty>
48244841
_CONSTEXPR20 void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) {
@@ -4829,13 +4846,18 @@ _CONSTEXPR20 void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val)
48294846
} else {
48304847
auto _UFirst = _Get_unwrapped(_First);
48314848
const auto _ULast = _Get_unwrapped(_Last);
4832-
if constexpr (_Fill_memset_is_safe<decltype(_UFirst), _Ty>) {
48334849
#ifdef __cpp_lib_is_constant_evaluated
4834-
if (!_STD is_constant_evaluated())
4850+
if (!_STD is_constant_evaluated())
48354851
#endif // __cpp_lib_is_constant_evaluated
4836-
{
4852+
{
4853+
if constexpr (_Fill_memset_is_safe<decltype(_UFirst), _Ty>) {
48374854
_Fill_memset(_UFirst, _Val, static_cast<size_t>(_ULast - _UFirst));
48384855
return;
4856+
} else if constexpr (_Fill_zero_memset_is_safe<decltype(_UFirst), _Ty>) {
4857+
if (_Is_all_bits_zero(_Val)) {
4858+
_Fill_zero_memset(_UFirst, static_cast<size_t>(_ULast - _UFirst));
4859+
return;
4860+
}
48394861
}
48404862
}
48414863

@@ -4890,15 +4912,20 @@ _CONSTEXPR20 _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val
48904912
return _Last;
48914913
} else {
48924914
auto _UDest = _Get_unwrapped_n(_Dest, _Count);
4893-
if constexpr (_Fill_memset_is_safe<decltype(_UDest), _Ty>) {
48944915
#ifdef __cpp_lib_is_constant_evaluated
4895-
if (!_STD is_constant_evaluated())
4916+
if (!_STD is_constant_evaluated())
48964917
#endif // __cpp_lib_is_constant_evaluated
4897-
{
4918+
{
4919+
if constexpr (_Fill_memset_is_safe<decltype(_UDest), _Ty>) {
48984920
_Fill_memset(_UDest, _Val, static_cast<size_t>(_Count));
4899-
_UDest += _Count;
4900-
_Seek_wrapped(_Dest, _UDest);
4921+
_Seek_wrapped(_Dest, _UDest + _Count);
49014922
return _Dest;
4923+
} else if constexpr (_Fill_zero_memset_is_safe<decltype(_UDest), _Ty>) {
4924+
if (_Is_all_bits_zero(_Val)) {
4925+
_Fill_zero_memset(_UDest, static_cast<size_t>(_Count));
4926+
_Seek_wrapped(_Dest, _UDest + _Count);
4927+
return _Dest;
4928+
}
49024929
}
49034930
}
49044931

tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ void test_make_shared_array_known_bounds() {
221221
test_make_init_destruct_order<ReportAddress[2][2][2]>(); // success multidimensional
222222

223223
test_make_init_destruct_order<ReportAddress[3][3][3]>(); // failure multidimensional
224+
225+
shared_ptr<int[7]> p7 = make_shared<int[7]>(0);
226+
for (int i = 0; i < 7; ++i) {
227+
assert(p7[i] == 0);
228+
}
224229
}
225230

226231
void test_make_shared_array_unknown_bounds() {
@@ -286,6 +291,11 @@ void test_make_shared_array_unknown_bounds() {
286291
test_make_init_destruct_order<ReportAddress[][2][2]>(2u); // success multidimensional
287292

288293
test_make_init_destruct_order<ReportAddress[][3][3]>(3u); // failure multidimensional
294+
295+
shared_ptr<int[]> p8 = make_shared<int[]>(7u, 0);
296+
for (int i = 0; i < 7; ++i) {
297+
assert(p8[i] == 0);
298+
}
289299
}
290300

291301
int constructCount = 0;
@@ -506,6 +516,12 @@ void test_allocate_shared_array_known_bounds() {
506516
test_allocate_init_destruct_order<ReportAddress[2][2][2]>(); // success multidimensional
507517

508518
test_allocate_init_destruct_order<ReportAddress[3][3][3]>(); // failure multidimensional
519+
520+
allocator<int> a7;
521+
shared_ptr<int[7]> p7 = allocate_shared<int[7]>(a7, 0);
522+
for (int i = 0; i < 7; ++i) {
523+
assert(p7[i] == 0);
524+
}
509525
}
510526

511527
void test_allocate_shared_array_unknown_bounds() {
@@ -599,6 +615,12 @@ void test_allocate_shared_array_unknown_bounds() {
599615
test_allocate_init_destruct_order<ReportAddress[][2][2]>(2u); // success multidimensional
600616

601617
test_allocate_init_destruct_order<ReportAddress[][3][3]>(3u); // failure multidimensional
618+
619+
allocator<int> a8;
620+
shared_ptr<int[]> p8 = allocate_shared<int[]>(a8, 7u, 0);
621+
for (int i = 0; i < 7; ++i) {
622+
assert(p8[i] == 0);
623+
}
602624
}
603625

604626
int main() {

tests/std/tests/P0896R4_ranges_alg_fill/test.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,19 @@ struct instantiator {
3333
}
3434
{ // Validate int is properly converted to bool
3535
bool output[] = {false, true, false};
36-
fill(ranges::begin(output), ranges::end(output), 5);
36+
fill(output, 5);
3737
for (const bool& elem : output) {
3838
assert(elem == true);
3939
}
4040
}
41+
{ // Validate zero-ing
42+
int output[] = {13, 42, 1367};
43+
auto result = fill(output, 0);
44+
for (const auto& elem : output) {
45+
assert(elem == 0);
46+
}
47+
assert(result == ranges::end(output));
48+
}
4149
}
4250
};
4351

tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ struct instantiator {
4343
assert(elem == true);
4444
}
4545
}
46+
{ // Validate zero-ing
47+
int output[] = {13, 42, 1367};
48+
auto result = fill_n(ranges::begin(output), ranges::distance(output), 0);
49+
for (const auto& elem : output) {
50+
assert(elem == 0);
51+
}
52+
assert(result == ranges::end(output));
53+
}
4654
}
4755
};
4856

tests/std/tests/P0896R4_ranges_alg_uninitialized_fill/test.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,23 @@ struct instantiator {
100100
assert(int_wrapper::constructions == 3);
101101
assert(int_wrapper::destructions == 3);
102102
}
103+
104+
{ // Validate int is properly converted to bool
105+
bool output[] = {false, true, false};
106+
uninitialized_fill(output, 5);
107+
for (const bool& elem : output) {
108+
assert(elem == true);
109+
}
110+
}
111+
112+
{ // Validate zero-ing
113+
int output[] = {13, 42, 1367};
114+
auto result = uninitialized_fill(output, 0);
115+
for (const auto& elem : output) {
116+
assert(elem == 0);
117+
}
118+
assert(result == ranges::end(output));
119+
}
103120
}
104121
};
105122

0 commit comments

Comments
 (0)