From 5b29a604c91c96b84b1b8cfdff36d5685c496eed Mon Sep 17 00:00:00 2001 From: ahanamuk Date: Sat, 20 Jun 2020 02:50:20 -0400 Subject: [PATCH] : Implemented ranges::move (#888) Co-authored-by: Casey Carter --- stl/inc/algorithm | 34 ++++++++ tests/std/test.lst | 1 + .../std/tests/P0896R4_ranges_alg_move/env.lst | 4 + .../tests/P0896R4_ranges_alg_move/test.cpp | 82 +++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 tests/std/tests/P0896R4_ranges_alg_move/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_alg_move/test.cpp diff --git a/stl/inc/algorithm b/stl/inc/algorithm index b75832548bc..5afc654c470 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -1260,6 +1260,40 @@ namespace ranges { }; inline constexpr _Copy_if_fn copy_if{_Not_quite_object::_Construct_tag{}}; + + // ALIAS TEMPLATE move_result + template + 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 _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 + requires indirectly_movable, _Out> + constexpr move_result, _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 diff --git a/tests/std/test.lst b/tests/std/test.lst index 89e2d91eb16..c5f71efbff9 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -252,6 +252,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 diff --git a/tests/std/tests/P0896R4_ranges_alg_move/env.lst b/tests/std/tests/P0896R4_ranges_alg_move/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_move/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_move/test.cpp b/tests/std/tests/P0896R4_ranges_alg_move/test.cpp new file mode 100644 index 00000000000..d87ad426610 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_move/test.cpp @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +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, ranges::in_out_result>); + + // Validate dangling story + STATIC_ASSERT( + same_as{}, static_cast(nullptr))), move_result>); + STATIC_ASSERT(same_as{}, static_cast(nullptr))), move_result>); + + 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>, iterator_t>>>); + 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>, iterator_t>>>); + 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 + 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();