Skip to content

Commit d822d25

Browse files
committed
[P2283R1] Implement constexpr specialized memory algorithms
1 parent 108a112 commit d822d25

File tree

26 files changed

+1971
-158
lines changed

26 files changed

+1971
-158
lines changed

stl/inc/memory

+243-122
Large diffs are not rendered by default.

stl/inc/xmemory

+49-28
Original file line numberDiff line numberDiff line change
@@ -1579,20 +1579,25 @@ namespace ranges {
15791579
template <input_iterator _It, sentinel_for<_It> _Se, _No_throw_forward_iterator _Out,
15801580
_No_throw_sentinel_for<_Out> _OSe>
15811581
requires constructible_from<iter_value_t<_Out>, iter_rvalue_reference_t<_It>>
1582-
uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked(
1582+
_CONSTEXPR23_DYNALLOC uninitialized_move_result<_It, _Out> _Uninitialized_move_unchecked(
15831583
_It _IFirst, const _Se _ILast, _Out _OFirst, const _OSe _OLast) {
15841584
// clang-format on
1585-
if constexpr (is_same_v<_Se, _It> && _Ptr_move_cat<_It, _Out>::_Really_trivial) {
1586-
return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast);
1587-
} else {
1588-
_Uninitialized_backout _Backout{_STD move(_OFirst)};
1589-
1590-
for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) {
1591-
_Backout._Emplace_back(_RANGES iter_move(_IFirst));
1585+
if constexpr (is_same_v<_Se, _It> && is_same_v<_OSe, _Out> && _Ptr_move_cat<_It, _Out>::_Really_trivial) {
1586+
#ifdef __cpp_lib_constexpr_dynamic_alloc
1587+
if (!_STD is_constant_evaluated())
1588+
#endif // __cpp_lib_constexpr_dynamic_alloc
1589+
{
1590+
return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast);
15921591
}
1592+
}
1593+
1594+
_Uninitialized_backout _Backout{_STD move(_OFirst)};
15931595

1594-
return {_STD move(_IFirst), _Backout._Release()};
1596+
for (; _IFirst != _ILast && _Backout._Last != _OLast; ++_IFirst) {
1597+
_Backout._Emplace_back(_RANGES iter_move(_IFirst));
15951598
}
1599+
1600+
return {_STD move(_IFirst), _Backout._Release()};
15961601
}
15971602
} // namespace ranges
15981603
#endif // __cpp_lib_concepts
@@ -1684,8 +1689,9 @@ _CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_copy_unchecked(
16841689
return _Backout._Release();
16851690
}
16861691

1692+
16871693
template <class _InIt, class _NoThrowFwdIt>
1688-
_NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) {
1694+
_CONSTEXPR20_DYNALLOC _NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) {
16891695
// copy [_First, _Last) to raw [_Dest, ...)
16901696
_Adl_verify_range(_First, _Last);
16911697
auto _UFirst = _Get_unwrapped(_First);
@@ -1759,28 +1765,39 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n(
17591765

17601766
// FUNCTION TEMPLATE uninitialized_fill
17611767
template <class _NoThrowFwdIt, class _Tval>
1762-
void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val) {
1768+
_CONSTEXPR20_DYNALLOC void uninitialized_fill(
1769+
const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val) {
17631770
// copy _Val throughout raw [_First, _Last)
17641771
_Adl_verify_range(_First, _Last);
17651772
auto _UFirst = _Get_unwrapped(_First);
17661773
const auto _ULast = _Get_unwrapped(_Last);
17671774
if constexpr (_Fill_memset_is_safe<_Unwrapped_t<const _NoThrowFwdIt&>, _Tval>) {
1768-
_Fill_memset(_UFirst, _Val, static_cast<size_t>(_ULast - _UFirst));
1769-
} else {
1770-
if constexpr (_Fill_zero_memset_is_safe<_Unwrapped_t<const _NoThrowFwdIt&>, _Tval>) {
1775+
#ifdef __cpp_lib_constexpr_dynamic_alloc
1776+
if (!_STD is_constant_evaluated())
1777+
#endif // __cpp_lib_constexpr_dynamic_alloc
1778+
{
1779+
_Fill_memset(_UFirst, _Val, static_cast<size_t>(_ULast - _UFirst));
1780+
return;
1781+
}
1782+
}
1783+
if constexpr (_Fill_zero_memset_is_safe<_Unwrapped_t<const _NoThrowFwdIt&>, _Tval>) {
1784+
#ifdef __cpp_lib_constexpr_dynamic_alloc
1785+
if (!_STD is_constant_evaluated())
1786+
#endif // __cpp_lib_constexpr_dynamic_alloc
1787+
{
17711788
if (_Is_all_bits_zero(_Val)) {
17721789
_Fill_zero_memset(_UFirst, static_cast<size_t>(_ULast - _UFirst));
17731790
return;
17741791
}
17751792
}
1793+
}
17761794

1777-
_Uninitialized_backout<_Unwrapped_t<const _NoThrowFwdIt&>> _Backout{_UFirst};
1778-
while (_Backout._Last != _ULast) {
1779-
_Backout._Emplace_back(_Val);
1780-
}
1781-
1782-
_Backout._Release();
1795+
_Uninitialized_backout<_Unwrapped_t<const _NoThrowFwdIt&>> _Backout{_UFirst};
1796+
while (_Backout._Last != _ULast) {
1797+
_Backout._Emplace_back(_Val);
17831798
}
1799+
1800+
_Backout._Release();
17841801
}
17851802

17861803
// FUNCTION TEMPLATE _Uninitialized_value_construct_n WITH ALLOCATOR
@@ -1822,19 +1839,23 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n(
18221839
}
18231840

18241841
template <class _NoThrowFwdIt, class _Diff>
1825-
_NoThrowFwdIt _Uninitialized_value_construct_n_unchecked1(_NoThrowFwdIt _UFirst, _Diff _Count) {
1842+
_CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_value_construct_n_unchecked1(_NoThrowFwdIt _UFirst, _Diff _Count) {
18261843
// value-initialize all elements in [_UFirst, _UFirst + _Count_raw)
18271844
_STL_INTERNAL_CHECK(_Count >= 0);
18281845
if constexpr (_Use_memset_value_construct_v<_NoThrowFwdIt>) {
1829-
return _Zero_range(_UFirst, _UFirst + _Count);
1830-
} else {
1831-
_Uninitialized_backout<_NoThrowFwdIt> _Backout{_UFirst};
1832-
for (; 0 < _Count; --_Count) {
1833-
_Backout._Emplace_back();
1846+
#ifdef __cpp_lib_constexpr_dynamic_alloc
1847+
if (!_STD is_constant_evaluated())
1848+
#endif // __cpp_lib_constexpr_dynamic_alloc
1849+
{
1850+
return _Zero_range(_UFirst, _UFirst + _Count);
18341851
}
1835-
1836-
return _Backout._Release();
18371852
}
1853+
_Uninitialized_backout<_NoThrowFwdIt> _Backout{_UFirst};
1854+
for (; 0 < _Count; --_Count) {
1855+
_Backout._Emplace_back();
1856+
}
1857+
1858+
return _Backout._Release();
18381859
}
18391860

18401861
#if _HAS_DEPRECATED_TEMPORARY_BUFFER

stl/inc/xutility

+13-1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,18 @@ _NODISCARD constexpr void* _Voidify_iter(_Iter _It) noexcept {
129129
}
130130
}
131131

132+
// FUNCTION TEMPLATE default_construct_at
133+
#if _HAS_CXX20 // TRANSITION, _HAS_CXX23
134+
template <class _Ty, class = void_t<decltype(::new (_STD declval<void*>()) _Ty)>>
135+
#if 0 // TRANSITION, compiler suport
136+
_CONSTEXPR20_DYNALLOC
137+
#endif // compiler support
138+
_Ty* default_construct_at(_Ty* const _Location) noexcept(
139+
noexcept(::new (_Voidify_iter(_Location)) _Ty)) /* strengthened */ {
140+
return ::new (_Voidify_iter(_Location)) _Ty;
141+
}
142+
#endif // _HAS_CXX20
143+
132144
// FUNCTION TEMPLATE construct_at
133145
#if _HAS_CXX20
134146
template <class _Ty, class... _Types,
@@ -4403,7 +4415,7 @@ void _Fill_zero_memset(_DestTy* const _Dest, const size_t _Count) {
44034415
}
44044416

44054417
template <class _Ty>
4406-
_NODISCARD bool _Is_all_bits_zero(const _Ty& _Val) {
4418+
_NODISCARD _CONSTEXPR23_DYNALLOC bool _Is_all_bits_zero(const _Ty& _Val) {
44074419
// checks if scalar type has all bits set to zero
44084420
_STL_INTERNAL_STATIC_ASSERT(is_scalar_v<_Ty> && !is_member_pointer_v<_Ty>);
44094421
constexpr _Ty _Zero{};

stl/inc/yvals_core.h

+20-7
Original file line numberDiff line numberDiff line change
@@ -1156,13 +1156,19 @@
11561156
#ifndef _M_CEE
11571157
#define __cpp_lib_parallel_algorithm 201603L
11581158
#endif // _M_CEE
1159-
#define __cpp_lib_raw_memory_algorithms 201606L
1160-
#define __cpp_lib_sample 201603L
1161-
#define __cpp_lib_scoped_lock 201703L
1162-
#define __cpp_lib_shared_ptr_weak_type 201606L
1163-
#define __cpp_lib_string_view 201803L
1164-
#define __cpp_lib_to_chars 201611L
1165-
#define __cpp_lib_variant 201606L
1159+
1160+
#if _HAS_CXX20 && defined(__cpp_lib_constexpr_dynamic_alloc) // TRANSITION, enable only in C++23 when available
1161+
#define __cpp_lib_raw_memory_algorithms 202106L
1162+
#else
1163+
#define __cpp_lib_raw_memory_algorithms 202106L
1164+
#endif
1165+
1166+
#define __cpp_lib_sample 201603L
1167+
#define __cpp_lib_scoped_lock 201703L
1168+
#define __cpp_lib_shared_ptr_weak_type 201606L
1169+
#define __cpp_lib_string_view 201803L
1170+
#define __cpp_lib_to_chars 201611L
1171+
#define __cpp_lib_variant 201606L
11661172
#endif // _HAS_CXX17
11671173

11681174
#if _HAS_CXX17
@@ -1314,6 +1320,13 @@
13141320
#define _CONSTEXPR20_CONTAINER inline
13151321
#endif
13161322

1323+
// Functions that became constexpr in C++23 via P2283
1324+
#ifdef __cpp_lib_constexpr_dynamic_alloc // TRANSITION, enable only in C++23 when available
1325+
#define _CONSTEXPR23_DYNALLOC constexpr
1326+
#else
1327+
#define _CONSTEXPR23_DYNALLOC inline
1328+
#endif
1329+
13171330
#ifdef _RTC_CONVERSION_CHECKS_ENABLED
13181331
#ifndef _ALLOW_RTCc_IN_STL
13191332
#error /RTCc rejects conformant code, so it is not supported by the C++ Standard Library. Either remove this \

tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,30 @@ struct memcpy_test {
235235
assert(ranges::equal(input, expected_input_long));
236236
assert(ranges::equal(output, expected_output));
237237
}
238+
239+
{ // Validate no common input range
240+
int input[] = {13, 55, 12345};
241+
int output[] = {-1, -1, -1};
242+
243+
const auto result =
244+
ranges::uninitialized_copy(begin(input), unreachable_sentinel, begin(output), end(output));
245+
assert(result.in == end(input));
246+
assert(result.out == end(output));
247+
assert(ranges::equal(input, expected_input));
248+
assert(ranges::equal(output, expected_output));
249+
}
250+
251+
{ // Validate no common output range
252+
int input[] = {13, 55, 12345};
253+
int output[] = {-1, -1, -1};
254+
255+
const auto result =
256+
ranges::uninitialized_copy(begin(input), end(input), begin(output), unreachable_sentinel);
257+
assert(result.in == end(input));
258+
assert(result.out == end(output));
259+
assert(ranges::equal(input, expected_input));
260+
assert(ranges::equal(output, expected_output));
261+
}
238262
}
239263
};
240264

tests/std/tests/P0896R4_ranges_alg_uninitialized_move/test.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ struct memcpy_test {
209209
int output[] = {-1, -1, -1};
210210

211211
ranges::uninitialized_move(input, output);
212+
assert(result.in == end(input));
213+
assert(result.out == end(output));
212214
assert(ranges::equal(input, expected_input));
213215
assert(ranges::equal(output, expected_output));
214216
}
@@ -234,6 +236,30 @@ struct memcpy_test {
234236
assert(ranges::equal(input, expected_input_long));
235237
assert(ranges::equal(output, expected_output));
236238
}
239+
240+
{ // Validate no common input range
241+
int input[] = {13, 55, 12345};
242+
int output[] = {-1, -1, -1};
243+
244+
const auto result =
245+
ranges::uninitialized_move(begin(input), unreachable_sentinel, begin(output), end(output));
246+
assert(result.in == end(input));
247+
assert(result.out == end(output));
248+
assert(ranges::equal(input, expected_input));
249+
assert(ranges::equal(output, expected_output));
250+
}
251+
252+
{ // Validate no common output range
253+
int input[] = {13, 55, 12345};
254+
int output[] = {-1, -1, -1};
255+
256+
const auto result =
257+
ranges::uninitialized_move(begin(input), end(input), begin(output), unreachable_sentinel);
258+
assert(result.in == end(input));
259+
assert(result.out == end(output));
260+
assert(ranges::equal(input, expected_input));
261+
assert(ranges::equal(output, expected_output));
262+
}
237263
}
238264
};
239265

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
RUNALL_INCLUDE ..\concepts_matrix.lst

0 commit comments

Comments
 (0)