Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<algorithm>: Implemented ranges::move #888

Merged
merged 24 commits into from
Jun 20, 2020
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
35 changes: 35 additions & 0 deletions stl/inc/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,41 @@ namespace ranges {
};

inline constexpr _Copy_if_fn copy_if{_Not_quite_object::_Construct_tag{}};

ahanamuk marked this conversation as resolved.
Show resolved Hide resolved
// ALIAS TEMPLATE move_result
template <class _In, class _Out>
using move_result = in_out_result<_In, _Out>;

// VARIABLE ranges::move
class _Move_fn : private _Not_quite_object {
ahanamuk marked this conversation as resolved.
Show resolved Hide resolved
public:
using _Not_quite_object::_Not_quite_object;

// clang-format off
template <input_iterator _It, sentinel_for<_It> _Se, weakly_incrementable _Out>
requires indirectly_movable<_It, _Out>
constexpr move_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) {
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
*_Result = _RANGES iter_move(_UFirst);
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
}

_Seek_wrapped(_First, _STD move(_UFirst));
return {_STD move(_First), _STD move(_Result)};
}

template <input_range _Rng, weakly_incrementable _Out>
requires indirectly_movable<iterator_t<_Rng>, _Out>
constexpr move_result<borrowed_iterator_t<_Rng>, _Out>
operator()(_Rng&& _Range, _Out _Result) const {
ahanamuk marked this conversation as resolved.
Show resolved Hide resolved
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _STD move(_Result));
}
// clang-format on
};

inline constexpr _Move_fn move{_Not_quite_object::_Construct_tag{}};
} // namespace ranges
#endif // __cpp_lib_concepts

Expand Down
5 changes: 3 additions & 2 deletions tests/std/include/range_algorithm_support.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,9 @@ namespace test {
++ptr_;
}

[[nodiscard]] constexpr friend std::remove_cv_t<Element> iter_move(iterator const& i) requires at_least<input> {
return ranges::iter_move(i.ptr_);
[[nodiscard]] constexpr friend std::remove_cv_t<Element> iter_move(iterator const& i)
requires at_least<input> && std::constructible_from<std::remove_cv_t<Element>, Element> {
return std::move(*i.ptr_);
}

constexpr friend void iter_swap(iterator const& x, iterator const& y) requires at_least<input> {
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ tests\P0896R4_ranges_alg_find_if_not
tests\P0896R4_ranges_alg_for_each
tests\P0896R4_ranges_alg_for_each_n
tests\P0896R4_ranges_alg_mismatch
tests\P0896R4_ranges_alg_move
tests\P0896R4_ranges_alg_none_of
tests\P0896R4_ranges_iterator_machinery
tests\P0896R4_ranges_range_machinery
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P0896R4_ranges_alg_move/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\concepts_matrix.lst
82 changes: 82 additions & 0 deletions tests/std/tests/P0896R4_ranges_alg_move/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <algorithm>
ahanamuk marked this conversation as resolved.
Show resolved Hide resolved
#include <cassert>
#include <concepts>
#include <range_algorithm_support.hpp>
#include <ranges>
#include <utility>

struct int_wrapper {
int val = 10;
constexpr int_wrapper() = default;
constexpr int_wrapper(int x) : val{x} {}
constexpr int_wrapper(int_wrapper&& that) : val{std::exchange(that.val, -1)} {}
constexpr int_wrapper& operator=(int_wrapper&& that) {
val = std::exchange(that.val, -1);
return *this;
}
};

constexpr void smoke_test() {
using ranges::move, ranges::move_result, ranges::iterator_t;
using std::same_as;

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

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

int const input[] = {13, 53, 12435};
{
int output[] = {-1, -1, -1};
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
auto result = move(move_only_range{input}, move_only_range{output}.begin());
STATIC_ASSERT(same_as<decltype(result),
move_result<iterator_t<move_only_range<int const>>, iterator_t<move_only_range<int>>>>);
assert(result.in == move_only_range{input}.end());
assert(result.out == move_only_range{output}.end());
assert(ranges::equal(output, input));
}
{
int output[] = {-1, -1, -1};
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
move_only_range wrapped_input{input};
auto result = move(wrapped_input.begin(), wrapped_input.end(), move_only_range{output}.begin());
STATIC_ASSERT(same_as<decltype(result),
move_result<iterator_t<move_only_range<int const>>, iterator_t<move_only_range<int>>>>);
assert(result.in == wrapped_input.end());
assert(result.out == move_only_range{output}.end());
assert(ranges::equal(output, input));
}
{
int_wrapper input1[3] = {13, 55, 1234};
int const expected_output[3] = {13, 55, 1234};
int_wrapper actual_output[3] = {-2, -2, -2};
move_only_range wrapped_input{input1};
auto result = move(wrapped_input.begin(), wrapped_input.end(), move_only_range{actual_output}.begin());
assert(result.in == wrapped_input.end());
assert(result.out == move_only_range{actual_output}.end());
for (int i = 0; i < 3; ++i) {
assert(input1[i].val == -1);
assert(actual_output[i].val == expected_output[i]);
}
}
}

int main() {
STATIC_ASSERT((smoke_test(), true));
smoke_test();
}

struct instantiator {
template <class In, class Out>
static void call(In&& in = {}, Out out = {}) {
(void) ranges::move(in, std::move(out));
(void) ranges::move(ranges::begin(in), ranges::end(in), std::move(out));
}
};

template void test_in_write<instantiator>();