This commit is contained in:
Casey Carter 2020-08-05 00:09:55 -07:00 коммит произвёл GitHub
Родитель 0eb754dedd
Коммит 5d00b606b4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 243 добавлений и 0 удалений

Просмотреть файл

@ -7089,6 +7089,90 @@ _FwdIt3 merge(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2
_REQUIRE_PARALLEL_ITERATOR(_FwdIt3);
return _STD merge(_First1, _Last1, _First2, _Last2, _Dest);
}
#ifdef __cpp_lib_concepts
namespace ranges {
// ALIAS TEMPLATE merge_result
template <class _In1, class _In2, class _Out>
using merge_result = in_in_out_result<_In1, _In2, _Out>;
// VARIABLE ranges::merge
class _Merge_fn : private _Not_quite_object {
public:
using _Not_quite_object::_Not_quite_object;
// clang-format off
template <input_iterator _It1, sentinel_for<_It1> _Se1, input_iterator _It2, sentinel_for<_It2> _Se2,
weakly_incrementable _Out, class _Pr = ranges::less, class _Pj1 = identity, class _Pj2 = identity>
requires mergeable<_It1, _It2, _Out, _Pr, _Pj1, _Pj2>
constexpr merge_result<_It1, _It2, _Out> operator()(_It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2,
_Out _Result, _Pr _Pred = {}, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const {
// clang-format on
_Adl_verify_range(_First1, _Last1);
_Adl_verify_range(_First2, _Last2);
auto _UResult = _Merge_unchecked(_Get_unwrapped(_STD move(_First1)), _Get_unwrapped(_STD move(_Last1)),
_Get_unwrapped(_STD move(_First2)), _Get_unwrapped(_STD move(_Last2)), _STD move(_Result),
_Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
_Seek_wrapped(_First1, _STD move(_UResult.in1));
_Seek_wrapped(_First2, _STD move(_UResult.in2));
return {_STD move(_First1), _STD move(_First2), _STD move(_UResult.out)};
}
// clang-format off
template <input_range _Rng1, input_range _Rng2, weakly_incrementable _Out, class _Pr = ranges::less,
class _Pj1 = identity, class _Pj2 = identity>
requires mergeable<iterator_t<_Rng1>, iterator_t<_Rng2>, _Out, _Pr, _Pj1, _Pj2>
constexpr merge_result<borrowed_iterator_t<_Rng1>, borrowed_iterator_t<_Rng2>, _Out> operator()(
_Rng1&& _Range1, _Rng2&& _Range2, _Out _Result, _Pr _Pred = {}, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const {
// clang-format on
auto _First1 = _RANGES begin(_Range1);
auto _First2 = _RANGES begin(_Range2);
auto _UResult =
_Merge_unchecked(_Get_unwrapped(_STD move(_First1)), _Uend(_Range1), _Get_unwrapped(_STD move(_First2)),
_Uend(_Range2), _STD move(_Result), _Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
_Seek_wrapped(_First1, _STD move(_UResult.in1));
_Seek_wrapped(_First2, _STD move(_UResult.in2));
return {_STD move(_First1), _STD move(_First2), _STD move(_UResult.out)};
}
private:
template <class _It1, class _Se1, class _It2, class _Se2, class _Out, class _Pr, class _Pj1, class _Pj2>
_NODISCARD static constexpr merge_result<_It1, _It2, _Out> _Merge_unchecked(_It1 _First1, const _Se1 _Last1,
_It2 _First2, const _Se2 _Last2, _Out _Result, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) {
_STL_INTERNAL_STATIC_ASSERT(input_iterator<_It1>);
_STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se1, _It1>);
_STL_INTERNAL_STATIC_ASSERT(input_iterator<_It2>);
_STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se2, _It2>);
_STL_INTERNAL_STATIC_ASSERT(weakly_incrementable<_Out>);
_STL_INTERNAL_STATIC_ASSERT(mergeable<_It1, _It2, _Out, _Pr, _Pj1, _Pj2>);
for (;; ++_Result) {
if (_First1 == _Last1) {
auto _Copy_result =
_RANGES _Copy_unchecked(_STD move(_First2), _STD move(_Last2), _STD move(_Result));
return {_STD move(_First1), _STD move(_Copy_result.in), _STD move(_Copy_result.out)};
}
if (_First2 == _Last2) {
auto _Copy_result =
_RANGES _Copy_unchecked(_STD move(_First1), _STD move(_Last1), _STD move(_Result));
return {_STD move(_Copy_result.in), _STD move(_First2), _STD move(_Copy_result.out)};
}
if (_STD invoke(_Pred, _STD invoke(_Proj2, *_First2), _STD invoke(_Proj1, *_First1))) {
*_Result = *_First2;
++_First2;
} else {
*_Result = *_First1;
++_First1;
}
}
}
};
inline constexpr _Merge_fn merge{_Not_quite_object::_Construct_tag{}};
} // namespace ranges
#endif // __cpp_lib_concepts
#endif // _HAS_CXX17
// FUNCTION TEMPLATE inplace_merge

Просмотреть файл

@ -265,6 +265,7 @@ tests\P0896R4_ranges_alg_heap
tests\P0896R4_ranges_alg_includes
tests\P0896R4_ranges_alg_is_permutation
tests\P0896R4_ranges_alg_is_sorted
tests\P0896R4_ranges_alg_merge
tests\P0896R4_ranges_alg_minmax
tests\P0896R4_ranges_alg_mismatch
tests\P0896R4_ranges_alg_move

Просмотреть файл

@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
RUNALL_INCLUDE ..\concepts_matrix.lst

Просмотреть файл

@ -0,0 +1,154 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <algorithm>
#include <cassert>
#include <concepts>
#include <ranges>
#include <utility>
#include <range_algorithm_support.hpp>
using namespace std;
using P = pair<int, int>;
// Validate that merge_result aliases in_in_out_result
STATIC_ASSERT(same_as<ranges::merge_result<int, void*, double>, ranges::in_in_out_result<int, void*, double>>);
// Validate dangling story
STATIC_ASSERT(same_as<decltype(ranges::merge(borrowed<false>{}, borrowed<false>{}, nullptr_to<int>)),
ranges::merge_result<ranges::dangling, ranges::dangling, int*>>);
STATIC_ASSERT(same_as<decltype(ranges::merge(borrowed<false>{}, borrowed<true>{}, nullptr_to<int>)),
ranges::merge_result<ranges::dangling, int*, int*>>);
STATIC_ASSERT(same_as<decltype(ranges::merge(borrowed<true>{}, borrowed<false>{}, nullptr_to<int>)),
ranges::merge_result<int*, ranges::dangling, int*>>);
STATIC_ASSERT(same_as<decltype(ranges::merge(borrowed<true>{}, borrowed<true>{}, nullptr_to<int>)),
ranges::merge_result<int*, int*, int*>>);
struct instantiator {
static constexpr P elements1[] = {{0, 10}, {0, 11}, {0, 12}, {1, 10}, {1, 11}, {3, 10}};
static constexpr P elements2[] = {{13, 0}, {14, 0}, {10, 2}, {11, 3}, {12, 3}};
static constexpr P expected[] = {
{0, 10}, {0, 11}, {0, 12}, {13, 0}, {14, 0}, {1, 10}, {1, 11}, {10, 2}, {3, 10}, {11, 3}, {12, 3}};
static constexpr auto counting_compare(size_t& counter) {
return [&counter](auto&& x, auto&& y) {
++counter;
return ranges::less{}(x, y);
};
}
template <ranges::input_range R1, ranges::input_range R2, weakly_incrementable O>
static constexpr void call() {
using ranges::merge, ranges::merge_result, ranges::end, ranges::equal, ranges::iterator_t, ranges::size;
{ // Validate range overload
P output[size(expected)]{};
R1 range1{elements1};
R2 range2{elements2};
size_t counter = 0;
const same_as<merge_result<iterator_t<R1>, iterator_t<R2>, O>> auto result =
merge(range1, range2, O{output}, counting_compare(counter), get_first, get_second);
assert(result.in1 == range1.end());
assert(result.in2 == range2.end());
assert(result.out.peek() == end(output));
assert(equal(output, expected));
assert(counter <= size(elements1) + size(elements2) - 1);
}
{ // Validate iterator overload
P output[size(expected)]{};
R1 range1{elements1};
R2 range2{elements2};
size_t counter = 0;
const same_as<merge_result<iterator_t<R1>, iterator_t<R2>, O>> auto result =
merge(range1.begin(), range1.end(), range2.begin(), range2.end(), O{output}, counting_compare(counter),
get_first, get_second);
assert(result.in1 == range1.end());
assert(result.in2 == range2.end());
assert(result.out.peek() == end(output));
assert(equal(output, expected));
assert(counter <= size(elements1) + size(elements2) - 1);
}
{ // Validate range overload, empty range1
P output[size(elements2)]{};
R1 range1{};
R2 range2{elements2};
size_t counter = 0;
const same_as<merge_result<iterator_t<R1>, iterator_t<R2>, O>> auto result =
merge(range1, range2, O{output}, counting_compare(counter), get_first, get_second);
assert(result.in1 == range1.end());
assert(result.in2 == range2.end());
assert(result.out.peek() == end(output));
assert(equal(output, elements2));
assert(counter == 0);
}
{ // Validate iterator overload, empty range2
P output[size(elements1)]{};
R1 range1{elements1};
R2 range2{};
size_t counter = 0;
const same_as<merge_result<iterator_t<R1>, iterator_t<R2>, O>> auto result =
merge(range1.begin(), range1.end(), range2.begin(), range2.end(), O{output}, counting_compare(counter),
get_first, get_second);
assert(result.in1 == range1.end());
assert(result.in2 == range2.end());
assert(result.out.peek() == end(output));
assert(equal(output, elements1));
assert(counter == 0);
}
}
};
template <class Continuation>
struct generate_readable_ranges {
template <class... Args>
static constexpr void call() {
using namespace test;
using test::range;
// The algorithm is completely oblivious to:
// * categories stronger than input
// * whether the end sentinel is an iterator
// * size information
// * iterator and/or sentinel differencing
// so let's vary proxyness for coverage and call it good.
Continuation::template call<Args...,
range<input, const P, Sized::no, CanDifference::no, Common::no, CanCompare::no, ProxyRef::no>>();
Continuation::template call<Args...,
range<input, const P, Sized::no, CanDifference::no, Common::no, CanCompare::no, ProxyRef::yes>>();
}
};
template <class Continuation>
struct generate_writable_iterators {
template <class... Args>
static constexpr void call() {
using namespace test;
using test::iterator;
// The algorithm is completely oblivious to all properties except for proxyness,
// so again we'll vary that property, and we'll also get coverage from input iterators to ensure the algorithm
// doesn't inadvertently depend on the output_iterator-only `*i++ = meow` expression.
Continuation::template call<Args..., iterator<output, P, CanDifference::no, CanCompare::no, ProxyRef::no>>();
Continuation::template call<Args..., iterator<output, P, CanDifference::no, CanCompare::no, ProxyRef::yes>>();
Continuation::template call<Args..., iterator<input, P, CanDifference::no, CanCompare::no, ProxyRef::no>>();
Continuation::template call<Args..., iterator<input, P, CanDifference::no, CanCompare::no, ProxyRef::yes>>();
}
};
constexpr void run_tests() {
generate_readable_ranges<generate_readable_ranges<generate_writable_iterators<instantiator>>>::call();
}
int main() {
STATIC_ASSERT((run_tests(), true));
run_tests();
}