Skip to content

Commit

Permalink
<algorithm>: Implemented ranges::move (microsoft#888)
Browse files Browse the repository at this point in the history
Co-authored-by: Casey Carter <Casey@Carter.net>
  • Loading branch information
ahanamuk and CaseyCarter committed Jun 26, 2020
1 parent dbe8335 commit 74adb37
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 0 deletions.
34 changes: 34 additions & 0 deletions stl/inc/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,40 @@ namespace ranges {
};

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

// 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 {
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) {
*_Result = _RANGES iter_move(_UFirst);
}

_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 {
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
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,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>
#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[] = {-2, -2, -2};
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[] = {-2, -2, -2};
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>();

0 comments on commit 74adb37

Please sign in to comment.