Skip to content

Commit 43fa0b5

Browse files
committed
Improve _Copy_memcpy_common return type
1 parent 48c9cdd commit 43fa0b5

File tree

6 files changed

+370
-118
lines changed

6 files changed

+370
-118
lines changed

stl/inc/memory

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,19 @@ namespace ranges {
5757
&& _No_throw_forward_iterator<iterator_t<_Rng>>;
5858
// clang-format on
5959

60+
// FUNCTION TEMPLATE _Copy_memcpy_common
61+
template <class _InIt, class _OutIt>
62+
in_out_result<_InIt, _OutIt> _Copy_memcpy_common(
63+
_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept {
64+
const auto _IFirst_ch = const_cast<char*>(reinterpret_cast<const volatile char*>(_IFirst));
65+
const auto _ILast_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_ILast));
66+
const auto _OFirst_ch = const_cast<char*>(reinterpret_cast<volatile char*>(_OFirst));
67+
const auto _OLast_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_OLast));
68+
const auto _Count = static_cast<size_t>((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch));
69+
_CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count);
70+
return {reinterpret_cast<_InIt>(_IFirst_ch + _Count), reinterpret_cast<_OutIt>(_OFirst_ch + _Count)};
71+
}
72+
6073
// ALIAS TEMPLATE uninitialized_copy_result
6174
template <class _In, class _Out>
6275
using uninitialized_copy_result = in_out_result<_In, _Out>;
@@ -108,7 +121,7 @@ namespace ranges {
108121
_STL_INTERNAL_STATIC_ASSERT(constructible_from<iter_value_t<_Out>, iter_reference_t<_It>>);
109122

110123
if constexpr (is_same_v<_Se, _It> && _Ptr_copy_cat<_It, _Out>::_Really_trivial) {
111-
return {_STD move(_ILast), _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast)};
124+
return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast);
112125
} else {
113126
_Uninitialized_backout _Backout{_STD move(_OFirst)};
114127

@@ -178,7 +191,7 @@ namespace ranges {
178191
auto _OFirst = _Get_unwrapped(_STD move(_First2));
179192
const auto _OLast = _Get_unwrapped(_STD move(_Last2));
180193
if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial) {
181-
_OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast);
194+
return _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast);
182195
} else {
183196
_Uninitialized_backout _Backout{_STD move(_OFirst)};
184197

@@ -265,7 +278,7 @@ namespace ranges {
265278
_STL_INTERNAL_STATIC_ASSERT(constructible_from<iter_value_t<_Out>, iter_rvalue_reference_t<_It>>);
266279

267280
if constexpr (is_same_v<_Se, _It> && _Ptr_move_cat<_It, _Out>::_Really_trivial) {
268-
return {_STD move(_ILast), _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast)};
281+
return _Copy_memcpy_common(_IFirst, _ILast, _OFirst, _OLast);
269282
} else {
270283
_Uninitialized_backout _Backout{_STD move(_OFirst)};
271284

@@ -339,7 +352,7 @@ namespace ranges {
339352
auto _OFirst = _Get_unwrapped(_STD move(_First2));
340353
const auto _OLast = _Get_unwrapped(_STD move(_Last2));
341354
if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial) {
342-
_OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast);
355+
return _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast);
343356
} else {
344357
_Uninitialized_backout _Backout{_STD move(_OFirst)};
345358

stl/inc/xutility

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4094,17 +4094,6 @@ _OutIt _Copy_memmove(move_iterator<_InIt> _First, move_iterator<_InIt> _Last, _O
40944094
return _Copy_memmove(_First.base(), _Last.base(), _Dest);
40954095
}
40964096

4097-
template <class _InIt, class _OutIt>
4098-
_OutIt _Copy_memcpy_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept {
4099-
const auto _IFirst_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_IFirst));
4100-
const auto _ILast_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_ILast));
4101-
const auto _OFirst_ch = const_cast<char*>(reinterpret_cast<volatile char*>(_OFirst));
4102-
const auto _OLast_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_OLast));
4103-
const auto _Count = static_cast<size_t>((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch));
4104-
_CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count);
4105-
return reinterpret_cast<_OutIt>(_OFirst_ch + _Count);
4106-
}
4107-
41084097
// VARIABLE TEMPLATE _Is_vb_iterator
41094098
template <class _It, bool _RequiresMutable = false>
41104099
_INLINE_VAR constexpr bool _Is_vb_iterator = false;

tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp

Lines changed: 84 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -76,21 +76,16 @@ struct holder {
7676
}
7777
};
7878

79-
template <class R>
80-
void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy
81-
for (auto& e : r) {
82-
destroy_at(&e);
83-
}
84-
}
85-
8679
struct instantiator {
87-
static constexpr int expected_output[] = {13, 55, 12345};
88-
static constexpr int expected_input[] = {13, 55, 12345};
80+
static constexpr int expected_output[] = {13, 55, 12345};
81+
static constexpr int expected_output_long[] = {13, 55, 12345, -1};
82+
static constexpr int expected_input[] = {13, 55, 12345};
83+
static constexpr int expected_input_long[] = {13, 55, 12345, 42};
8984

9085
template <ranges::input_range R, ranges::forward_range W>
9186
static void call() {
92-
using ranges::uninitialized_copy, ranges::uninitialized_copy_result, ranges::equal, ranges::equal_to,
93-
ranges::iterator_t;
87+
using ranges::destroy, ranges::uninitialized_copy, ranges::uninitialized_copy_result, ranges::equal,
88+
ranges::equal_to, ranges::iterator_t;
9489

9590
{ // Validate range overload
9691
int_wrapper input[3] = {13, 55, 12345};
@@ -107,7 +102,7 @@ struct instantiator {
107102
assert(result.out == wrapped_output.end());
108103
assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val));
109104
assert(equal(input, expected_input, equal_to{}, &int_wrapper::val));
110-
not_ranges_destroy(wrapped_output);
105+
destroy(wrapped_output);
111106
assert(int_wrapper::constructions == 3);
112107
assert(int_wrapper::destructions == 3);
113108
}
@@ -127,10 +122,51 @@ struct instantiator {
127122
assert(result.out == wrapped_output.end());
128123
assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val));
129124
assert(equal(input, expected_input, equal_to{}, &int_wrapper::val));
130-
not_ranges_destroy(wrapped_output);
125+
destroy(wrapped_output);
126+
assert(int_wrapper::constructions == 3);
127+
assert(int_wrapper::destructions == 3);
128+
}
129+
130+
{ // Validate range overload shorter output
131+
int_wrapper input[4] = {13, 55, 12345, 42};
132+
R wrapped_input{input};
133+
holder<int_wrapper, 3> mem;
134+
W wrapped_output{mem.as_span()};
135+
136+
int_wrapper::clear_counts();
137+
same_as<uninitialized_copy_result<iterator_t<R>, iterator_t<W>>> auto result =
138+
uninitialized_copy(wrapped_input, wrapped_output);
139+
assert(int_wrapper::constructions == 3);
140+
assert(int_wrapper::destructions == 0);
141+
assert(++result.in == wrapped_input.end());
142+
assert(result.out == wrapped_output.end());
143+
assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val));
144+
assert(equal(input, expected_input_long, equal_to{}, &int_wrapper::val));
145+
destroy(wrapped_output);
131146
assert(int_wrapper::constructions == 3);
132147
assert(int_wrapper::destructions == 3);
133148
}
149+
150+
{ // Validate range overload shorter input
151+
int_wrapper input[3] = {13, 55, 12345};
152+
R wrapped_input{input};
153+
holder<int_wrapper, 4> mem;
154+
W wrapped_output{mem.as_span()};
155+
156+
int_wrapper::clear_counts();
157+
same_as<uninitialized_copy_result<iterator_t<R>, iterator_t<W>>> auto result =
158+
uninitialized_copy(wrapped_input, wrapped_output);
159+
assert(int_wrapper::constructions == 3);
160+
assert(int_wrapper::destructions == 0);
161+
assert(result.in == wrapped_input.end());
162+
construct_at(addressof(*result.out), -1); // Need to construct non written element for comparison
163+
assert(++result.out == wrapped_output.end());
164+
assert(equal(wrapped_output, expected_output_long, equal_to{}, &int_wrapper::val));
165+
assert(equal(input, expected_input, equal_to{}, &int_wrapper::val));
166+
destroy(wrapped_output);
167+
assert(int_wrapper::constructions == 4);
168+
assert(int_wrapper::destructions == 4);
169+
}
134170
}
135171
};
136172

@@ -161,17 +197,44 @@ struct throwing_test {
161197
};
162198

163199
struct memcopy_test {
164-
static constexpr int expected_output[] = {13, 55, 12345};
165-
static constexpr int expected_input[] = {13, 55, 12345};
200+
static constexpr int expected_output[] = {13, 55, 12345};
201+
static constexpr int expected_output_long[] = {13, 55, 12345, -1};
202+
static constexpr int expected_input[] = {13, 55, 12345};
203+
static constexpr int expected_input_long[] = {13, 55, 12345, 42};
166204

167205
static void call() {
168-
// Validate only range overload (one is plenty since they both use the same backend)
169-
int input[] = {13, 55, 12345};
170-
int output[] = {-1, -1, -1};
206+
{ // Validate only range overload
207+
int input[] = {13, 55, 12345};
208+
int output[] = {-1, -1, -1};
209+
210+
const auto result = ranges::uninitialized_copy(input, output);
211+
assert(result.in == end(input));
212+
assert(result.out == end(output));
213+
assert(ranges::equal(input, expected_input));
214+
assert(ranges::equal(output, expected_output));
215+
}
216+
217+
{ // Validate input shorter
218+
int input[] = {13, 55, 12345};
219+
int output[] = {-1, -1, -1, -1};
171220

172-
ranges::uninitialized_copy(input, output);
173-
assert(ranges::equal(input, expected_input));
174-
assert(ranges::equal(output, expected_output));
221+
auto result = ranges::uninitialized_copy(input, output);
222+
assert(result.in == end(input));
223+
assert(++result.out == end(output));
224+
assert(ranges::equal(input, expected_input));
225+
assert(ranges::equal(output, expected_output_long));
226+
}
227+
228+
{ // Validate output shorter
229+
int input[] = {13, 55, 12345, 42};
230+
int output[] = {-1, -1, -1};
231+
232+
auto result = ranges::uninitialized_copy(input, output);
233+
assert(++result.in == end(input));
234+
assert(result.out == end(output));
235+
assert(ranges::equal(input, expected_input_long));
236+
assert(ranges::equal(output, expected_output));
237+
}
175238
}
176239
};
177240

tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp

Lines changed: 95 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -66,39 +66,77 @@ struct holder {
6666
}
6767
};
6868

69-
template <class R>
70-
void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy
71-
for (auto& e : r) {
72-
destroy_at(&e);
73-
}
74-
}
75-
7669
struct instantiator {
77-
static constexpr int expected_output[] = {13, 55, 12345};
78-
static constexpr int expected_input[] = {13, 55, 12345};
70+
static constexpr int expected_output[] = {13, 55, 12345};
71+
static constexpr int expected_output_long[] = {13, 55, 12345, -1};
72+
static constexpr int expected_input[] = {13, 55, 12345};
73+
static constexpr int expected_input_long[] = {13, 55, 12345, 42};
7974

8075
template <ranges::input_range Read, ranges::forward_range Write>
8176
static void call() {
82-
using ranges::uninitialized_copy_n, ranges::uninitialized_copy_n_result, ranges::equal, ranges::equal_to,
83-
ranges::iterator_t;
77+
using ranges::destroy, ranges::uninitialized_copy_n, ranges::uninitialized_copy_n_result, ranges::equal,
78+
ranges::equal_to, ranges::iterator_t;
79+
80+
{ // Validate equal ranges
81+
int_wrapper input[3] = {13, 55, 12345};
82+
Read wrapped_input{input};
83+
holder<int_wrapper, 3> mem;
84+
Write wrapped_output{mem.as_span()};
85+
86+
int_wrapper::clear_counts();
87+
const same_as<uninitialized_copy_n_result<iterator_t<Read>, iterator_t<Write>>> auto result =
88+
uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end());
89+
assert(int_wrapper::constructions == 3);
90+
assert(int_wrapper::destructions == 0);
91+
assert(result.in == wrapped_input.end());
92+
assert(result.out == wrapped_output.end());
93+
assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val));
94+
assert(equal(input, expected_input, equal_to{}, &int_wrapper::val));
95+
destroy(wrapped_output);
96+
assert(int_wrapper::constructions == 3);
97+
assert(int_wrapper::destructions == 3);
98+
}
8499

85-
int_wrapper input[3] = {13, 55, 12345};
86-
Read wrapped_input{input};
87-
holder<int_wrapper, 3> mem;
88-
Write wrapped_output{mem.as_span()};
100+
{ // Validate shorter output
101+
int_wrapper input[4] = {13, 55, 12345, 42};
102+
Read wrapped_input{input};
103+
holder<int_wrapper, 3> mem;
104+
Write wrapped_output{mem.as_span()};
105+
106+
int_wrapper::clear_counts();
107+
same_as<uninitialized_copy_n_result<iterator_t<Read>, iterator_t<Write>>> auto result =
108+
uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end());
109+
assert(int_wrapper::constructions == 3);
110+
assert(int_wrapper::destructions == 0);
111+
assert(++result.in == wrapped_input.end());
112+
assert(result.out == wrapped_output.end());
113+
assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val));
114+
assert(equal(input, expected_input_long, equal_to{}, &int_wrapper::val));
115+
destroy(wrapped_output);
116+
assert(int_wrapper::constructions == 3);
117+
assert(int_wrapper::destructions == 3);
118+
}
89119

90-
int_wrapper::clear_counts();
91-
const same_as<uninitialized_copy_n_result<iterator_t<Read>, iterator_t<Write>>> auto result =
92-
uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end());
93-
assert(int_wrapper::constructions == 3);
94-
assert(int_wrapper::destructions == 0);
95-
assert(result.in == wrapped_input.end());
96-
assert(result.out == wrapped_output.end());
97-
assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val));
98-
assert(equal(input, expected_input, equal_to{}, &int_wrapper::val));
99-
not_ranges_destroy(wrapped_output);
100-
assert(int_wrapper::constructions == 3);
101-
assert(int_wrapper::destructions == 3);
120+
{ // Validate shorter input
121+
int_wrapper input[3] = {13, 55, 12345};
122+
Read wrapped_input{input};
123+
holder<int_wrapper, 4> mem;
124+
Write wrapped_output{mem.as_span()};
125+
126+
int_wrapper::clear_counts();
127+
same_as<uninitialized_copy_n_result<iterator_t<Read>, iterator_t<Write>>> auto result =
128+
uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end());
129+
assert(int_wrapper::constructions == 3);
130+
assert(int_wrapper::destructions == 0);
131+
assert(result.in == wrapped_input.end());
132+
construct_at(addressof(*result.out), -1); // Need to construct non written element for comparison
133+
assert(++result.out == wrapped_output.end());
134+
assert(equal(wrapped_output, expected_output_long, equal_to{}, &int_wrapper::val));
135+
assert(equal(input, expected_input, equal_to{}, &int_wrapper::val));
136+
destroy(wrapped_output);
137+
assert(int_wrapper::constructions == 4);
138+
assert(int_wrapper::destructions == 4);
139+
}
102140
}
103141
};
104142

@@ -127,17 +165,39 @@ struct throwing_test {
127165
};
128166

129167
struct memcopy_test {
130-
static constexpr int expected_output[] = {13, 55, 12345, -1};
131-
static constexpr int expected_input[] = {13, 55, 12345, 42};
168+
static constexpr int expected_output[] = {13, 55, 12345, -1};
169+
static constexpr int expected_output_long[] = {13, 55, -1, -1};
170+
static constexpr int expected_input[] = {13, 55, 12345, 42};
171+
static constexpr int expected_input_short[] = {13, 55};
172+
static constexpr int expected_input_long[] = {13, 55, 12345, 42};
132173

133174
static void call() {
134-
// Validate only range overload (one is plenty since they both use the same backend)
135-
int input[] = {13, 55, 12345, 42};
136-
int output[] = {-1, -1, -1, -1};
175+
{ // Validate range overload
176+
int input[] = {13, 55, 12345, 42};
177+
int output[] = {-1, -1, -1, -1};
178+
179+
ranges::uninitialized_copy_n(input, 3, begin(output), end(output));
180+
assert(ranges::equal(input, expected_input));
181+
assert(ranges::equal(output, expected_output));
182+
}
183+
184+
{ // Validate shorter input
185+
int input[] = {13, 55};
186+
int output[] = {-1, -1, -1, -1};
137187

138-
ranges::uninitialized_copy_n(input, 3, output, output + 4);
139-
assert(ranges::equal(input, expected_input));
140-
assert(ranges::equal(output, expected_output));
188+
ranges::uninitialized_copy_n(input, 2, begin(output), end(output));
189+
assert(ranges::equal(input, expected_input_short));
190+
assert(ranges::equal(output, expected_output_long));
191+
}
192+
193+
{ // Validate shorter output
194+
int input[] = {13, 55, 12345, 42};
195+
int output[] = {-1, -1};
196+
197+
ranges::uninitialized_copy_n(input, 3, begin(output), end(output));
198+
assert(ranges::equal(input, expected_input));
199+
assert(ranges::equal(output, expected_input_short));
200+
}
141201
}
142202
};
143203

0 commit comments

Comments
 (0)