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
29 changes: 20 additions & 9 deletions stl/inc/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,18 @@ namespace ranges {
using copy_result = in_out_result<_In, _Out>;

// VARIABLE ranges::copy
// clang-format off
template <input_iterator _It, sentinel_for<_It> _Se, weakly_incrementable _Out>
requires indirectly_copyable<_It, _Out>
_NODISCARD constexpr copy_result<_It, _Out> _Copy_unchecked(_It _First, const _Se _Last, _Out _Result) {
for (; _First != _Last; ++_First, (void) ++_Result) {
*_Result = *_First;
}

return {_STD move(_First), _STD move(_Result)};
}
// clang-format on

class _Copy_fn : private _Not_quite_object {
public:
using _Not_quite_object::_Not_quite_object;
Expand All @@ -1516,20 +1528,19 @@ namespace ranges {
requires indirectly_copyable<_It, _Out>
constexpr copy_result<_It, _Out> operator()(_It _First, _Se _Last, _Out _Result) const {
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_STD move(_First));
const auto _ULast = _Get_unwrapped(_STD move(_Last));
for (; _UFirst != _ULast; ++_UFirst, (void) ++_Result) {
*_Result = *_UFirst;
}

_Seek_wrapped(_First, _STD move(_UFirst));
return {_STD move(_First), _STD move(_Result)};
auto _UResult = _RANGES _Copy_unchecked(
_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _STD move(_Result));
_Seek_wrapped(_First, _STD move(_UResult.in));
return {_STD move(_First), _STD move(_UResult.out)};
}

template <input_range _Rng, weakly_incrementable _Out>
requires indirectly_copyable<iterator_t<_Rng>, _Out>
constexpr copy_result<borrowed_iterator_t<_Rng>, _Out> operator()(_Rng&& _Range, _Out _Result) const {
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _STD move(_Result));
auto _First = _RANGES begin(_Range);
auto _UResult = _RANGES _Copy_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), _STD move(_Result));
_Seek_wrapped(_First, _STD move(_UResult.in));
return {_STD move(_First), _STD move(_UResult.out)};
}
// clang-format on
};
Expand Down
80 changes: 38 additions & 42 deletions tests/std/tests/P0896R4_ranges_alg_copy/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,51 +9,47 @@

#include <range_algorithm_support.hpp>

constexpr void smoke_test() {
using ranges::copy, ranges::copy_result, ranges::iterator_t;
using std::same_as;

// Validate that copy_result aliases in_out_result
STATIC_ASSERT(same_as<copy_result<int, double>, ranges::in_out_result<int, double>>);

// Validate dangling story
STATIC_ASSERT(
same_as<decltype(copy(borrowed<false>{}, static_cast<int*>(nullptr))), copy_result<ranges::dangling, int*>>);
STATIC_ASSERT(same_as<decltype(copy(borrowed<true>{}, static_cast<int*>(nullptr))), copy_result<int*, int*>>);

int const input[] = {13, 42, 1729};
{ // Validate range overload
int output[] = {-1, -1, -1};
auto result = copy(basic_borrowed_range{input}, basic_borrowed_range{output}.begin());
STATIC_ASSERT(same_as<decltype(result),
copy_result<iterator_t<basic_borrowed_range<int const>>, iterator_t<basic_borrowed_range<int>>>>);
assert(result.in == basic_borrowed_range{input}.end());
assert(result.out == basic_borrowed_range{output}.end());
assert(ranges::equal(output, input));
}
{ // Validate iterator + sentinel overload
int output[] = {-1, -1, -1};
basic_borrowed_range wrapped_input{input};
auto result = copy(wrapped_input.begin(), wrapped_input.end(), basic_borrowed_range{output}.begin());
STATIC_ASSERT(same_as<decltype(result),
copy_result<iterator_t<basic_borrowed_range<int const>>, iterator_t<basic_borrowed_range<int>>>>);
assert(result.in == wrapped_input.end());
assert(result.out == basic_borrowed_range{output}.end());
assert(ranges::equal(output, input));
}
}
using namespace std;

int main() {
STATIC_ASSERT((smoke_test(), true));
smoke_test();
}
// Validate that copy_result aliases in_out_result
STATIC_ASSERT(same_as<ranges::copy_result<int, double>, ranges::in_out_result<int, double>>);

// Validate dangling story
STATIC_ASSERT(same_as<decltype(ranges::copy(borrowed<false>{}, static_cast<int*>(nullptr))),
ranges::copy_result<ranges::dangling, int*>>);
STATIC_ASSERT(
same_as<decltype(ranges::copy(borrowed<true>{}, static_cast<int*>(nullptr))), ranges::copy_result<int*, int*>>);

struct instantiator {
template <class In, class Out>
static void call(In&& in = {}, Out out = {}) {
(void) ranges::copy(in, std::move(out));
(void) ranges::copy(ranges::begin(in), ranges::end(in), std::move(out));
static constexpr int input[3] = {13, 42, 1729};

template <ranges::input_range Read, indirectly_writable<ranges::range_reference_t<Read>> Write>
static constexpr void call() {
using ranges::copy, ranges::copy_result, ranges::iterator_t;
{ // Validate iterator + sentinel overload
int output[3] = {-1, -1, -1};
Read wrapped_input{input};

auto result = copy(wrapped_input.begin(), wrapped_input.end(), Write{output});
STATIC_ASSERT(same_as<decltype(result), copy_result<iterator_t<Read>, Write>>);
assert(result.in == wrapped_input.end());
assert(result.out.peek() == output + 3);
assert(ranges::equal(output, input));
}
{ // Validate range overload
int output[3] = {-1, -1, -1};
Read wrapped_input{input};

auto result = copy(wrapped_input, Write{output});
STATIC_ASSERT(same_as<decltype(result), copy_result<iterator_t<Read>, Write>>);
assert(result.in == wrapped_input.end());
assert(result.out.peek() == output + 3);
assert(ranges::equal(output, input));
}
}
};

template void test_in_write<instantiator, const int, int>();
int main() {
STATIC_ASSERT((test_in_write<instantiator, int const, int>(), true));
test_in_write<instantiator, int const, int>();
}