Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions stl/inc/memory
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ namespace ranges {
auto _OFirst = _Get_unwrapped(_STD move(_First2));
const auto _OLast = _Get_unwrapped(_STD move(_Last2));
if constexpr (_Ptr_copy_cat<_It, _Out>::_Really_trivial) {
_OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast);
auto _UResult = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast);
_IFirst = _UResult.in;
_OFirst = _UResult.out;
} else {
_Uninitialized_backout _Backout{_STD move(_OFirst)};

Expand Down Expand Up @@ -283,7 +285,9 @@ namespace ranges {
auto _OFirst = _Get_unwrapped(_STD move(_First2));
const auto _OLast = _Get_unwrapped(_STD move(_Last2));
if constexpr (_Ptr_move_cat<_It, _Out>::_Really_trivial) {
_OFirst = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast);
auto _UResult = _Copy_memcpy_common(_IFirst, _IFirst + _Count, _OFirst, _OLast);
_IFirst = _UResult.in;
_OFirst = _UResult.out;
} else {
_Uninitialized_backout _Backout{_STD move(_OFirst)};

Expand Down
12 changes: 12 additions & 0 deletions stl/inc/xmemory
Original file line number Diff line number Diff line change
Expand Up @@ -1551,6 +1551,18 @@ namespace ranges {
&& _No_throw_forward_iterator<iterator_t<_Rng>>;
// clang-format on

template <class _InIt, class _OutIt>
in_out_result<_InIt, _OutIt> _Copy_memcpy_common(
_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept {
const auto _IFirst_ch = const_cast<char*>(reinterpret_cast<const volatile char*>(_IFirst));
const auto _ILast_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_ILast));
const auto _OFirst_ch = const_cast<char*>(reinterpret_cast<volatile char*>(_OFirst));
const auto _OLast_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_OLast));
const auto _Count = static_cast<size_t>((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch));
_CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count);
return {reinterpret_cast<_InIt>(_IFirst_ch + _Count), reinterpret_cast<_OutIt>(_OFirst_ch + _Count)};
}

// ALIAS TEMPLATE uninitialized_move_result
template <class _In, class _Out>
using uninitialized_move_result = in_out_result<_In, _Out>;
Expand Down
11 changes: 0 additions & 11 deletions stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -4102,17 +4102,6 @@ _OutIt _Copy_memmove(move_iterator<_InIt> _First, move_iterator<_InIt> _Last, _O
return _Copy_memmove(_First.base(), _Last.base(), _Dest);
}

template <class _InIt, class _OutIt>
_OutIt _Copy_memcpy_common(_InIt _IFirst, _InIt _ILast, _OutIt _OFirst, _OutIt _OLast) noexcept {
const auto _IFirst_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_IFirst));
const auto _ILast_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_ILast));
const auto _OFirst_ch = const_cast<char*>(reinterpret_cast<volatile char*>(_OFirst));
const auto _OLast_ch = const_cast<const char*>(reinterpret_cast<const volatile char*>(_OLast));
const auto _Count = static_cast<size_t>((_STD min)(_ILast_ch - _IFirst_ch, _OLast_ch - _OFirst_ch));
_CSTD memcpy(_OFirst_ch, _IFirst_ch, _Count);
return reinterpret_cast<_OutIt>(_OFirst_ch + _Count);
}

// VARIABLE TEMPLATE _Is_vb_iterator
template <class _It, bool _RequiresMutable = false>
_INLINE_VAR constexpr bool _Is_vb_iterator = false;
Expand Down
105 changes: 92 additions & 13 deletions tests/std/tests/P0896R4_ranges_alg_uninitialized_copy/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,21 +76,16 @@ struct holder {
}
};

template <class R>
void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy
for (auto& e : r) {
destroy_at(&e);
}
}

struct instantiator {
static constexpr int expected_output[] = {13, 55, 12345};
static constexpr int expected_input[] = {13, 55, 12345};
static constexpr int expected_output[] = {13, 55, 12345};
static constexpr int expected_output_long[] = {13, 55, 12345, -1};
static constexpr int expected_input[] = {13, 55, 12345};
static constexpr int expected_input_long[] = {13, 55, 12345, 42};

template <ranges::input_range R, ranges::forward_range W>
static void call() {
using ranges::uninitialized_copy, ranges::uninitialized_copy_result, ranges::equal, ranges::equal_to,
ranges::iterator_t;
using ranges::destroy, ranges::uninitialized_copy, ranges::uninitialized_copy_result, ranges::equal,
ranges::equal_to, ranges::iterator_t;

{ // Validate range overload
int_wrapper input[3] = {13, 55, 12345};
Expand All @@ -107,7 +102,7 @@ struct instantiator {
assert(result.out == wrapped_output.end());
assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val));
assert(equal(input, expected_input, equal_to{}, &int_wrapper::val));
not_ranges_destroy(wrapped_output);
destroy(wrapped_output);
assert(int_wrapper::constructions == 3);
assert(int_wrapper::destructions == 3);
}
Expand All @@ -127,10 +122,51 @@ struct instantiator {
assert(result.out == wrapped_output.end());
assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val));
assert(equal(input, expected_input, equal_to{}, &int_wrapper::val));
not_ranges_destroy(wrapped_output);
destroy(wrapped_output);
assert(int_wrapper::constructions == 3);
assert(int_wrapper::destructions == 3);
}

{ // Validate range overload shorter output
int_wrapper input[4] = {13, 55, 12345, 42};
R wrapped_input{input};
holder<int_wrapper, 3> mem;
W wrapped_output{mem.as_span()};

int_wrapper::clear_counts();
same_as<uninitialized_copy_result<iterator_t<R>, iterator_t<W>>> auto result =
uninitialized_copy(wrapped_input, wrapped_output);
assert(int_wrapper::constructions == 3);
assert(int_wrapper::destructions == 0);
assert(++result.in == wrapped_input.end());
assert(result.out == wrapped_output.end());
assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val));
assert(equal(input, expected_input_long, equal_to{}, &int_wrapper::val));
destroy(wrapped_output);
assert(int_wrapper::constructions == 3);
assert(int_wrapper::destructions == 3);
}

{ // Validate range overload shorter input
int_wrapper input[3] = {13, 55, 12345};
R wrapped_input{input};
holder<int_wrapper, 4> mem;
W wrapped_output{mem.as_span()};

int_wrapper::clear_counts();
same_as<uninitialized_copy_result<iterator_t<R>, iterator_t<W>>> auto result =
uninitialized_copy(wrapped_input, wrapped_output);
assert(int_wrapper::constructions == 3);
assert(int_wrapper::destructions == 0);
assert(result.in == wrapped_input.end());
construct_at(addressof(*result.out), -1); // Need to construct non written element for comparison
assert(++result.out == wrapped_output.end());
assert(equal(wrapped_output, expected_output_long, equal_to{}, &int_wrapper::val));
assert(equal(input, expected_input, equal_to{}, &int_wrapper::val));
destroy(wrapped_output);
assert(int_wrapper::constructions == 4);
assert(int_wrapper::destructions == 4);
}
}
};

Expand Down Expand Up @@ -160,6 +196,48 @@ struct throwing_test {
}
};

struct memcpy_test {
static constexpr int expected_output[] = {13, 55, 12345};
static constexpr int expected_output_long[] = {13, 55, 12345, -1};
static constexpr int expected_input[] = {13, 55, 12345};
static constexpr int expected_input_long[] = {13, 55, 12345, 42};

static void call() {
{ // Validate only range overload
int input[] = {13, 55, 12345};
int output[] = {-1, -1, -1};

const auto result = ranges::uninitialized_copy(input, output);
assert(result.in == end(input));
assert(result.out == end(output));
assert(ranges::equal(input, expected_input));
assert(ranges::equal(output, expected_output));
}

{ // Validate input shorter
int input[] = {13, 55, 12345};
int output[] = {-1, -1, -1, -1};

auto result = ranges::uninitialized_copy(input, output);
assert(result.in == end(input));
assert(++result.out == end(output));
assert(ranges::equal(input, expected_input));
assert(ranges::equal(output, expected_output_long));
}

{ // Validate output shorter
int input[] = {13, 55, 12345, 42};
int output[] = {-1, -1, -1};

auto result = ranges::uninitialized_copy(input, output);
assert(++result.in == end(input));
assert(result.out == end(output));
assert(ranges::equal(input, expected_input_long));
assert(ranges::equal(output, expected_output));
}
}
};

template <test::ProxyRef IsProxy>
using test_input = test::range<test::input, int_wrapper, test::Sized::no, test::CanDifference::no, test::Common::no,
test::CanCompare::yes, IsProxy>;
Expand All @@ -174,4 +252,5 @@ int main() {
instantiator::call<test_input<test::ProxyRef::yes>, test_output>();
throwing_test::call<test_input<test::ProxyRef::no>, test_output>();
throwing_test::call<test_input<test::ProxyRef::yes>, test_output>();
memcpy_test::call();
}
141 changes: 114 additions & 27 deletions tests/std/tests/P0896R4_ranges_alg_uninitialized_copy_n/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <ranges>
#include <span>
#include <utility>
#include <vector>

#include <range_algorithm_support.hpp>

Expand Down Expand Up @@ -66,39 +67,77 @@ struct holder {
}
};

template <class R>
void not_ranges_destroy(R&& r) { // TRANSITION, ranges::destroy
for (auto& e : r) {
destroy_at(&e);
}
}

struct instantiator {
static constexpr int expected_output[] = {13, 55, 12345};
static constexpr int expected_input[] = {13, 55, 12345};
static constexpr int expected_output[] = {13, 55, 12345};
static constexpr int expected_output_long[] = {13, 55, 12345, -1};
static constexpr int expected_input[] = {13, 55, 12345};
static constexpr int expected_input_long[] = {13, 55, 12345, 42};

template <ranges::input_range Read, ranges::forward_range Write>
static void call() {
using ranges::uninitialized_copy_n, ranges::uninitialized_copy_n_result, ranges::equal, ranges::equal_to,
ranges::iterator_t;
using ranges::destroy, ranges::uninitialized_copy_n, ranges::uninitialized_copy_n_result, ranges::equal,
ranges::equal_to, ranges::iterator_t;

{ // Validate equal ranges
int_wrapper input[3] = {13, 55, 12345};
Read wrapped_input{input};
holder<int_wrapper, 3> mem;
Write wrapped_output{mem.as_span()};

int_wrapper::clear_counts();
const same_as<uninitialized_copy_n_result<iterator_t<Read>, iterator_t<Write>>> auto result =
uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end());
assert(int_wrapper::constructions == 3);
assert(int_wrapper::destructions == 0);
assert(result.in == wrapped_input.end());
assert(result.out == wrapped_output.end());
assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val));
assert(equal(input, expected_input, equal_to{}, &int_wrapper::val));
destroy(wrapped_output);
assert(int_wrapper::constructions == 3);
assert(int_wrapper::destructions == 3);
}

int_wrapper input[3] = {13, 55, 12345};
Read wrapped_input{input};
holder<int_wrapper, 3> mem;
Write wrapped_output{mem.as_span()};
{ // Validate shorter output
int_wrapper input[4] = {13, 55, 12345, 42};
Read wrapped_input{input};
holder<int_wrapper, 3> mem;
Write wrapped_output{mem.as_span()};

int_wrapper::clear_counts();
same_as<uninitialized_copy_n_result<iterator_t<Read>, iterator_t<Write>>> auto result =
uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end());
assert(int_wrapper::constructions == 3);
assert(int_wrapper::destructions == 0);
assert(++result.in == wrapped_input.end());
assert(result.out == wrapped_output.end());
assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val));
assert(equal(input, expected_input_long, equal_to{}, &int_wrapper::val));
destroy(wrapped_output);
assert(int_wrapper::constructions == 3);
assert(int_wrapper::destructions == 3);
}

int_wrapper::clear_counts();
const same_as<uninitialized_copy_n_result<iterator_t<Read>, iterator_t<Write>>> auto result =
uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end());
assert(int_wrapper::constructions == 3);
assert(int_wrapper::destructions == 0);
assert(result.in == wrapped_input.end());
assert(result.out == wrapped_output.end());
assert(equal(wrapped_output, expected_output, equal_to{}, &int_wrapper::val));
assert(equal(input, expected_input, equal_to{}, &int_wrapper::val));
not_ranges_destroy(wrapped_output);
assert(int_wrapper::constructions == 3);
assert(int_wrapper::destructions == 3);
{ // Validate shorter input
int_wrapper input[3] = {13, 55, 12345};
Read wrapped_input{input};
holder<int_wrapper, 4> mem;
Write wrapped_output{mem.as_span()};

int_wrapper::clear_counts();
same_as<uninitialized_copy_n_result<iterator_t<Read>, iterator_t<Write>>> auto result =
uninitialized_copy_n(wrapped_input.begin(), 3, wrapped_output.begin(), wrapped_output.end());
assert(int_wrapper::constructions == 3);
assert(int_wrapper::destructions == 0);
assert(result.in == wrapped_input.end());
construct_at(addressof(*result.out), -1); // Need to construct non written element for comparison
assert(++result.out == wrapped_output.end());
assert(equal(wrapped_output, expected_output_long, equal_to{}, &int_wrapper::val));
assert(equal(input, expected_input, equal_to{}, &int_wrapper::val));
destroy(wrapped_output);
assert(int_wrapper::constructions == 4);
assert(int_wrapper::destructions == 4);
}
}
};

Expand Down Expand Up @@ -126,6 +165,53 @@ struct throwing_test {
}
};

struct memcpy_test {
static constexpr int expected_output[] = {13, 55, 12345, -1};
static constexpr int expected_output_long[] = {13, 55, -1, -1};
static constexpr int expected_input[] = {13, 55, 12345, 42};
static constexpr int expected_input_short[] = {13, 55};
static constexpr int expected_input_long[] = {13, 55, 12345, 42};

static void call() {
using ranges::uninitialized_copy_n, ranges::uninitialized_copy_n_result, ranges::equal, ranges::iterator_t;
{ // Validate range overload
vector<int> input = {13, 55, 12345, 42};
vector<int> output = {-1, -1, -1, -1};

const same_as<uninitialized_copy_n_result<iterator_t<vector<int>>, iterator_t<vector<int>>>> auto result =
uninitialized_copy_n(input.begin(), 3, output.begin(), output.end());
assert(next(result.in) == input.end());
assert(next(result.out) == output.end());
assert(equal(input, expected_input));
assert(equal(output, expected_output));
}

{ // Validate shorter input
vector<int> input = {13, 55};
vector<int> output = {-1, -1, -1, -1};

const same_as<uninitialized_copy_n_result<iterator_t<vector<int>>, iterator_t<vector<int>>>> auto result =
uninitialized_copy_n(input.begin(), 2, output.begin(), output.end());
assert(result.in == input.end());
assert(next(result.out, 2) == output.end());
assert(equal(input, expected_input_short));
assert(equal(output, expected_output_long));
}

{ // Validate shorter output
vector<int> input = {13, 55, 12345, 42};
vector<int> output = {-1, -1};

const same_as<uninitialized_copy_n_result<iterator_t<vector<int>>, iterator_t<vector<int>>>> auto result =
uninitialized_copy_n(input.begin(), 2, output.begin(), output.end());
assert(next(result.in, 2) == input.end());
assert(result.out == output.end());
assert(equal(input, expected_input));
assert(equal(output, expected_input_short));
}
}
};

template <test::ProxyRef IsProxy>
using test_input = test::range<test::input, int_wrapper, test::Sized::no, test::CanDifference::no, test::Common::no,
test::CanCompare::yes, IsProxy>;
Expand All @@ -140,4 +226,5 @@ int main() {
instantiator::call<test_input<test::ProxyRef::yes>, test_output>();
throwing_test::call<test_input<test::ProxyRef::no>, test_output>();
throwing_test::call<test_input<test::ProxyRef::yes>, test_output>();
memcpy_test::call();
}
Loading