зеркало из https://github.com/microsoft/STL.git
Implement ranges::next_permutation and ranges::prev_permutation (#1099)
This commit is contained in:
Родитель
622b62a777
Коммит
0eb754dedd
|
@ -9471,6 +9471,79 @@ _CONSTEXPR20 bool next_permutation(_BidIt _First, _BidIt _Last) {
|
|||
return _STD next_permutation(_First, _Last, less<>{});
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// ALIAS TEMPLATE next_permutation_result
|
||||
template <class _In>
|
||||
using next_permutation_result = in_found_result<_In>;
|
||||
|
||||
// VARIABLE ranges::next_permutation
|
||||
class _Next_permutation_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
// clang-format off
|
||||
template <bidirectional_iterator _It, sentinel_for<_It> _Se, class _Pr = ranges::less, class _Pj = identity>
|
||||
requires sortable<_It, _Pr, _Pj>
|
||||
constexpr next_permutation_result<_It> operator()(_It _First, _Se _Last, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
// clang-format on
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last));
|
||||
_Seek_wrapped(_First, _ULast);
|
||||
const bool _Found =
|
||||
_Next_permutation_common(_STD move(_UFirst), _STD move(_ULast), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return {_STD move(_First), _Found};
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <bidirectional_range _Rng, class _Pr = ranges::less, class _Pj = identity>
|
||||
requires sortable<iterator_t<_Rng>, _Pr, _Pj>
|
||||
constexpr next_permutation_result<borrowed_iterator_t<_Rng>> operator()(
|
||||
_Rng&& _Range, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
// clang-format on
|
||||
auto _ULast = _Get_final_iterator_unwrapped(_Range);
|
||||
const bool _Found = _Next_permutation_common(_Ubegin(_Range), _ULast, _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return {_Rewrap_iterator(_Range, _STD move(_ULast)), _Found};
|
||||
}
|
||||
|
||||
private:
|
||||
template <class _It, class _Pr, class _Pj>
|
||||
_NODISCARD static constexpr bool _Next_permutation_common(_It _First, _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
_STL_INTERNAL_STATIC_ASSERT(bidirectional_iterator<_It>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>);
|
||||
|
||||
auto _Next = _Last;
|
||||
if (_First == _Last || _First == --_Next) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (;;) { // find rightmost element smaller than successor
|
||||
auto _Next1 = _Next;
|
||||
if (_STD invoke(_Pred, _STD invoke(_Proj, *--_Next), _STD invoke(_Proj, *_Next1))) {
|
||||
// swap with rightmost element that's smaller, flip suffix
|
||||
auto _Mid = _Last;
|
||||
do {
|
||||
--_Mid;
|
||||
} while (!_STD invoke(_Pred, _STD invoke(_Proj, *_Next), _STD invoke(_Proj, *_Mid)));
|
||||
|
||||
_RANGES iter_swap(_Next, _Mid);
|
||||
_Reverse_common(_STD move(_Next1), _STD move(_Last));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_Next == _First) { // pure descending, flip all
|
||||
_Reverse_common(_STD move(_First), _STD move(_Last));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr _Next_permutation_fn next_permutation{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE prev_permutation
|
||||
template <class _BidIt, class _Pr>
|
||||
_CONSTEXPR20 bool prev_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred) {
|
||||
|
@ -9509,6 +9582,79 @@ _CONSTEXPR20 bool prev_permutation(_BidIt _First, _BidIt _Last) {
|
|||
return _STD prev_permutation(_First, _Last, less<>{});
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// ALIAS TEMPLATE prev_permutation_result
|
||||
template <class _In>
|
||||
using prev_permutation_result = in_found_result<_In>;
|
||||
|
||||
// VARIABLE ranges::prev_permutation
|
||||
class _Prev_permutation_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
// clang-format off
|
||||
template <bidirectional_iterator _It, sentinel_for<_It> _Se, class _Pr = ranges::less, class _Pj = identity>
|
||||
requires sortable<_It, _Pr, _Pj>
|
||||
constexpr prev_permutation_result<_It> operator()(_It _First, _Se _Last, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
// clang-format on
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last));
|
||||
_Seek_wrapped(_First, _ULast);
|
||||
const bool _Found =
|
||||
_Prev_permutation_common(_STD move(_UFirst), _STD move(_ULast), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return {_STD move(_First), _Found};
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <bidirectional_range _Rng, class _Pr = ranges::less, class _Pj = identity>
|
||||
requires sortable<iterator_t<_Rng>, _Pr, _Pj>
|
||||
constexpr prev_permutation_result<borrowed_iterator_t<_Rng>> operator()(
|
||||
_Rng&& _Range, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
// clang-format on
|
||||
auto _ULast = _Get_final_iterator_unwrapped(_Range);
|
||||
const bool _Found = _Prev_permutation_common(_Ubegin(_Range), _ULast, _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return {_Rewrap_iterator(_Range, _STD move(_ULast)), _Found};
|
||||
}
|
||||
|
||||
private:
|
||||
template <class _It, class _Pr, class _Pj>
|
||||
_NODISCARD static constexpr bool _Prev_permutation_common(_It _First, _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
_STL_INTERNAL_STATIC_ASSERT(bidirectional_iterator<_It>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>);
|
||||
|
||||
auto _Next = _Last;
|
||||
if (_First == _Last || _First == --_Next) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (;;) { // find rightmost element not smaller than successor
|
||||
auto _Next1 = _Next;
|
||||
if (_STD invoke(_Pred, _STD invoke(_Proj, *_Next1), _STD invoke(_Proj, *--_Next))) {
|
||||
// swap with rightmost element that's not smaller, flip suffix
|
||||
auto _Mid = _Last;
|
||||
do {
|
||||
--_Mid;
|
||||
} while (!_STD invoke(_Pred, _STD invoke(_Proj, *_Mid), _STD invoke(_Proj, *_Next)));
|
||||
|
||||
_RANGES iter_swap(_Next, _Mid);
|
||||
_Reverse_common(_STD move(_Next1), _STD move(_Last));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_Next == _First) { // pure ascending, flip all
|
||||
_Reverse_common(_STD move(_First), _STD move(_Last));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr _Prev_permutation_fn prev_permutation{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATES is_sorted AND is_sorted_until
|
||||
template <class _FwdIt, class _Pr>
|
||||
_NODISCARD _CONSTEXPR20 _FwdIt is_sorted_until(const _FwdIt _First, _FwdIt _Last, _Pr _Pred) {
|
||||
|
|
|
@ -274,6 +274,7 @@ tests\P0896R4_ranges_alg_nth_element
|
|||
tests\P0896R4_ranges_alg_partition
|
||||
tests\P0896R4_ranges_alg_partition_copy
|
||||
tests\P0896R4_ranges_alg_partition_point
|
||||
tests\P0896R4_ranges_alg_permutations
|
||||
tests\P0896R4_ranges_alg_remove
|
||||
tests\P0896R4_ranges_alg_remove_copy
|
||||
tests\P0896R4_ranges_alg_remove_copy_if
|
||||
|
|
|
@ -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,264 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <cstdio>
|
||||
#include <random>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
#include <range_algorithm_support.hpp>
|
||||
using namespace std;
|
||||
|
||||
#pragma warning(disable : 6294) // Ill-defined for-loop: initial condition does not satisfy test. Loop body not executed
|
||||
|
||||
// Validate that (next|prev)_permutation_result alias in_found_result
|
||||
STATIC_ASSERT(same_as<ranges::next_permutation_result<int>, ranges::in_found_result<int>>);
|
||||
STATIC_ASSERT(same_as<ranges::prev_permutation_result<int>, ranges::in_found_result<int>>);
|
||||
|
||||
// Validate dangling story
|
||||
STATIC_ASSERT(
|
||||
same_as<decltype(ranges::next_permutation(borrowed<false>{})), ranges::next_permutation_result<ranges::dangling>>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::next_permutation(borrowed<true>{})), ranges::next_permutation_result<int*>>);
|
||||
STATIC_ASSERT(
|
||||
same_as<decltype(ranges::prev_permutation(borrowed<false>{})), ranges::prev_permutation_result<ranges::dangling>>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::prev_permutation(borrowed<true>{})), ranges::prev_permutation_result<int*>>);
|
||||
|
||||
constexpr int perm1[][1] = {{0}};
|
||||
constexpr int perm4[][4] = {{0, 1, 2, 3}, {0, 1, 3, 2}, {0, 2, 1, 3}, {0, 2, 3, 1}, {0, 3, 1, 2}, {0, 3, 2, 1},
|
||||
{1, 0, 2, 3}, {1, 0, 3, 2}, {1, 2, 0, 3}, {1, 2, 3, 0}, {1, 3, 0, 2}, {1, 3, 2, 0}, {2, 0, 1, 3}, {2, 0, 3, 1},
|
||||
{2, 1, 0, 3}, {2, 1, 3, 0}, {2, 3, 0, 1}, {2, 3, 1, 0}, {3, 0, 1, 2}, {3, 0, 2, 1}, {3, 1, 0, 2}, {3, 1, 2, 0},
|
||||
{3, 2, 0, 1}, {3, 2, 1, 0}};
|
||||
constexpr int perm5[][5] = {{0, 1, 2, 3, 4}, {0, 1, 2, 4, 3}, {0, 1, 3, 2, 4}, {0, 1, 3, 4, 2}, {0, 1, 4, 2, 3},
|
||||
{0, 1, 4, 3, 2}, {0, 2, 1, 3, 4}, {0, 2, 1, 4, 3}, {0, 2, 3, 1, 4}, {0, 2, 3, 4, 1}, {0, 2, 4, 1, 3},
|
||||
{0, 2, 4, 3, 1}, {0, 3, 1, 2, 4}, {0, 3, 1, 4, 2}, {0, 3, 2, 1, 4}, {0, 3, 2, 4, 1}, {0, 3, 4, 1, 2},
|
||||
{0, 3, 4, 2, 1}, {0, 4, 1, 2, 3}, {0, 4, 1, 3, 2}, {0, 4, 2, 1, 3}, {0, 4, 2, 3, 1}, {0, 4, 3, 1, 2},
|
||||
{0, 4, 3, 2, 1}, {1, 0, 2, 3, 4}, {1, 0, 2, 4, 3}, {1, 0, 3, 2, 4}, {1, 0, 3, 4, 2}, {1, 0, 4, 2, 3},
|
||||
{1, 0, 4, 3, 2}, {1, 2, 0, 3, 4}, {1, 2, 0, 4, 3}, {1, 2, 3, 0, 4}, {1, 2, 3, 4, 0}, {1, 2, 4, 0, 3},
|
||||
{1, 2, 4, 3, 0}, {1, 3, 0, 2, 4}, {1, 3, 0, 4, 2}, {1, 3, 2, 0, 4}, {1, 3, 2, 4, 0}, {1, 3, 4, 0, 2},
|
||||
{1, 3, 4, 2, 0}, {1, 4, 0, 2, 3}, {1, 4, 0, 3, 2}, {1, 4, 2, 0, 3}, {1, 4, 2, 3, 0}, {1, 4, 3, 0, 2},
|
||||
{1, 4, 3, 2, 0}, {2, 0, 1, 3, 4}, {2, 0, 1, 4, 3}, {2, 0, 3, 1, 4}, {2, 0, 3, 4, 1}, {2, 0, 4, 1, 3},
|
||||
{2, 0, 4, 3, 1}, {2, 1, 0, 3, 4}, {2, 1, 0, 4, 3}, {2, 1, 3, 0, 4}, {2, 1, 3, 4, 0}, {2, 1, 4, 0, 3},
|
||||
{2, 1, 4, 3, 0}, {2, 3, 0, 1, 4}, {2, 3, 0, 4, 1}, {2, 3, 1, 0, 4}, {2, 3, 1, 4, 0}, {2, 3, 4, 0, 1},
|
||||
{2, 3, 4, 1, 0}, {2, 4, 0, 1, 3}, {2, 4, 0, 3, 1}, {2, 4, 1, 0, 3}, {2, 4, 1, 3, 0}, {2, 4, 3, 0, 1},
|
||||
{2, 4, 3, 1, 0}, {3, 0, 1, 2, 4}, {3, 0, 1, 4, 2}, {3, 0, 2, 1, 4}, {3, 0, 2, 4, 1}, {3, 0, 4, 1, 2},
|
||||
{3, 0, 4, 2, 1}, {3, 1, 0, 2, 4}, {3, 1, 0, 4, 2}, {3, 1, 2, 0, 4}, {3, 1, 2, 4, 0}, {3, 1, 4, 0, 2},
|
||||
{3, 1, 4, 2, 0}, {3, 2, 0, 1, 4}, {3, 2, 0, 4, 1}, {3, 2, 1, 0, 4}, {3, 2, 1, 4, 0}, {3, 2, 4, 0, 1},
|
||||
{3, 2, 4, 1, 0}, {3, 4, 0, 1, 2}, {3, 4, 0, 2, 1}, {3, 4, 1, 0, 2}, {3, 4, 1, 2, 0}, {3, 4, 2, 0, 1},
|
||||
{3, 4, 2, 1, 0}, {4, 0, 1, 2, 3}, {4, 0, 1, 3, 2}, {4, 0, 2, 1, 3}, {4, 0, 2, 3, 1}, {4, 0, 3, 1, 2},
|
||||
{4, 0, 3, 2, 1}, {4, 1, 0, 2, 3}, {4, 1, 0, 3, 2}, {4, 1, 2, 0, 3}, {4, 1, 2, 3, 0}, {4, 1, 3, 0, 2},
|
||||
{4, 1, 3, 2, 0}, {4, 2, 0, 1, 3}, {4, 2, 0, 3, 1}, {4, 2, 1, 0, 3}, {4, 2, 1, 3, 0}, {4, 2, 3, 0, 1},
|
||||
{4, 2, 3, 1, 0}, {4, 3, 0, 1, 2}, {4, 3, 0, 2, 1}, {4, 3, 1, 0, 2}, {4, 3, 1, 2, 0}, {4, 3, 2, 0, 1},
|
||||
{4, 3, 2, 1, 0}};
|
||||
constexpr int perm6[][6] = {{0, 0, 1, 1, 2, 2}, {0, 0, 1, 2, 1, 2}, {0, 0, 1, 2, 2, 1}, {0, 0, 2, 1, 1, 2},
|
||||
{0, 0, 2, 1, 2, 1}, {0, 0, 2, 2, 1, 1}, {0, 1, 0, 1, 2, 2}, {0, 1, 0, 2, 1, 2}, {0, 1, 0, 2, 2, 1},
|
||||
{0, 1, 1, 0, 2, 2}, {0, 1, 1, 2, 0, 2}, {0, 1, 1, 2, 2, 0}, {0, 1, 2, 0, 1, 2}, {0, 1, 2, 0, 2, 1},
|
||||
{0, 1, 2, 1, 0, 2}, {0, 1, 2, 1, 2, 0}, {0, 1, 2, 2, 0, 1}, {0, 1, 2, 2, 1, 0}, {0, 2, 0, 1, 1, 2},
|
||||
{0, 2, 0, 1, 2, 1}, {0, 2, 0, 2, 1, 1}, {0, 2, 1, 0, 1, 2}, {0, 2, 1, 0, 2, 1}, {0, 2, 1, 1, 0, 2},
|
||||
{0, 2, 1, 1, 2, 0}, {0, 2, 1, 2, 0, 1}, {0, 2, 1, 2, 1, 0}, {0, 2, 2, 0, 1, 1}, {0, 2, 2, 1, 0, 1},
|
||||
{0, 2, 2, 1, 1, 0}, {1, 0, 0, 1, 2, 2}, {1, 0, 0, 2, 1, 2}, {1, 0, 0, 2, 2, 1}, {1, 0, 1, 0, 2, 2},
|
||||
{1, 0, 1, 2, 0, 2}, {1, 0, 1, 2, 2, 0}, {1, 0, 2, 0, 1, 2}, {1, 0, 2, 0, 2, 1}, {1, 0, 2, 1, 0, 2},
|
||||
{1, 0, 2, 1, 2, 0}, {1, 0, 2, 2, 0, 1}, {1, 0, 2, 2, 1, 0}, {1, 1, 0, 0, 2, 2}, {1, 1, 0, 2, 0, 2},
|
||||
{1, 1, 0, 2, 2, 0}, {1, 1, 2, 0, 0, 2}, {1, 1, 2, 0, 2, 0}, {1, 1, 2, 2, 0, 0}, {1, 2, 0, 0, 1, 2},
|
||||
{1, 2, 0, 0, 2, 1}, {1, 2, 0, 1, 0, 2}, {1, 2, 0, 1, 2, 0}, {1, 2, 0, 2, 0, 1}, {1, 2, 0, 2, 1, 0},
|
||||
{1, 2, 1, 0, 0, 2}, {1, 2, 1, 0, 2, 0}, {1, 2, 1, 2, 0, 0}, {1, 2, 2, 0, 0, 1}, {1, 2, 2, 0, 1, 0},
|
||||
{1, 2, 2, 1, 0, 0}, {2, 0, 0, 1, 1, 2}, {2, 0, 0, 1, 2, 1}, {2, 0, 0, 2, 1, 1}, {2, 0, 1, 0, 1, 2},
|
||||
{2, 0, 1, 0, 2, 1}, {2, 0, 1, 1, 0, 2}, {2, 0, 1, 1, 2, 0}, {2, 0, 1, 2, 0, 1}, {2, 0, 1, 2, 1, 0},
|
||||
{2, 0, 2, 0, 1, 1}, {2, 0, 2, 1, 0, 1}, {2, 0, 2, 1, 1, 0}, {2, 1, 0, 0, 1, 2}, {2, 1, 0, 0, 2, 1},
|
||||
{2, 1, 0, 1, 0, 2}, {2, 1, 0, 1, 2, 0}, {2, 1, 0, 2, 0, 1}, {2, 1, 0, 2, 1, 0}, {2, 1, 1, 0, 0, 2},
|
||||
{2, 1, 1, 0, 2, 0}, {2, 1, 1, 2, 0, 0}, {2, 1, 2, 0, 0, 1}, {2, 1, 2, 0, 1, 0}, {2, 1, 2, 1, 0, 0},
|
||||
{2, 2, 0, 0, 1, 1}, {2, 2, 0, 1, 0, 1}, {2, 2, 0, 1, 1, 0}, {2, 2, 1, 0, 0, 1}, {2, 2, 1, 0, 1, 0},
|
||||
{2, 2, 1, 1, 0, 0}};
|
||||
constexpr int perm8[][8] = {{0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
|
||||
struct int_wrapper {
|
||||
int val = 10;
|
||||
|
||||
constexpr int_wrapper() = default;
|
||||
constexpr int_wrapper(int x) : val{x} {}
|
||||
constexpr int_wrapper(const int_wrapper&) = default;
|
||||
constexpr int_wrapper(int_wrapper&& that) : val{exchange(that.val, -1)} {}
|
||||
constexpr int_wrapper& operator=(const int_wrapper&) = default;
|
||||
|
||||
constexpr int_wrapper& operator=(int_wrapper&& that) {
|
||||
val = exchange(that.val, -1);
|
||||
return *this;
|
||||
}
|
||||
auto operator<=>(const int_wrapper&) const = default;
|
||||
};
|
||||
|
||||
constexpr auto get_val = [](auto&& x) { return static_cast<const int_wrapper&>(x).val; };
|
||||
|
||||
template <auto& Expected>
|
||||
struct next_perm_instantiator {
|
||||
template <ranges::bidirectional_range R>
|
||||
static constexpr void call() {
|
||||
using ranges::next_permutation, ranges::next_permutation_result, ranges::equal, ranges::iterator_t;
|
||||
|
||||
constexpr auto number_of_permutations = static_cast<int>(ranges::size(Expected));
|
||||
|
||||
{ // Validate range overload
|
||||
int_wrapper input[ranges::size(Expected[0])];
|
||||
ranges::copy(Expected[0], input);
|
||||
|
||||
for (int i = 1; i < number_of_permutations; ++i) {
|
||||
R range{input};
|
||||
const same_as<next_permutation_result<iterator_t<R>>> auto result =
|
||||
next_permutation(range, ranges::less{}, get_val);
|
||||
assert(result.in == range.end());
|
||||
assert(result.found);
|
||||
assert(equal(input, Expected[i], ranges::equal_to{}, get_val));
|
||||
}
|
||||
|
||||
R range{input};
|
||||
const same_as<next_permutation_result<iterator_t<R>>> auto result =
|
||||
next_permutation(range, ranges::less{}, get_val);
|
||||
assert(result.in == range.end());
|
||||
assert(!result.found);
|
||||
assert(equal(input, Expected[0]));
|
||||
}
|
||||
|
||||
{ // Validate iterator overload
|
||||
int_wrapper input[ranges::size(Expected[0])];
|
||||
ranges::copy(Expected[0], input);
|
||||
|
||||
for (int i = 1; i < number_of_permutations; ++i) {
|
||||
R range{input};
|
||||
const same_as<next_permutation_result<iterator_t<R>>> auto result =
|
||||
next_permutation(range.begin(), range.end(), ranges::less{}, get_val);
|
||||
assert(result.in == range.end());
|
||||
assert(result.found);
|
||||
assert(equal(input, Expected[i]));
|
||||
}
|
||||
|
||||
R range{input};
|
||||
const same_as<next_permutation_result<iterator_t<R>>> auto result =
|
||||
next_permutation(range.begin(), range.end(), ranges::less{}, get_val);
|
||||
assert(result.in == range.end());
|
||||
assert(!result.found);
|
||||
assert(equal(input, Expected[0]));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <auto& Expected>
|
||||
struct prev_perm_instantiator {
|
||||
template <ranges::bidirectional_range R>
|
||||
static constexpr void call() {
|
||||
using ranges::prev_permutation, ranges::prev_permutation_result, ranges::equal, ranges::iterator_t;
|
||||
|
||||
constexpr auto number_of_permutations = static_cast<int>(ranges::size(Expected));
|
||||
|
||||
{ // Validate range overload
|
||||
int_wrapper input[ranges::size(Expected[0])];
|
||||
ranges::copy(Expected[number_of_permutations - 1], input);
|
||||
|
||||
for (int i = number_of_permutations - 1; i-- > 0;) {
|
||||
R range{input};
|
||||
const same_as<prev_permutation_result<iterator_t<R>>> auto result =
|
||||
prev_permutation(range, ranges::less{}, get_val);
|
||||
assert(result.in == range.end());
|
||||
assert(result.found);
|
||||
assert(equal(input, Expected[i]));
|
||||
}
|
||||
|
||||
R range{input};
|
||||
const same_as<prev_permutation_result<iterator_t<R>>> auto result =
|
||||
prev_permutation(range, ranges::less{}, get_val);
|
||||
assert(result.in == range.end());
|
||||
assert(!result.found);
|
||||
assert(equal(input, Expected[number_of_permutations - 1]));
|
||||
}
|
||||
|
||||
{ // Validate iterator overload
|
||||
int_wrapper input[ranges::size(Expected[0])];
|
||||
ranges::copy(Expected[number_of_permutations - 1], input);
|
||||
|
||||
for (int i = number_of_permutations - 1; i-- > 0;) {
|
||||
R range{input};
|
||||
const same_as<prev_permutation_result<iterator_t<R>>> auto result =
|
||||
prev_permutation(range.begin(), range.end(), ranges::less{}, get_val);
|
||||
assert(result.in == range.end());
|
||||
assert(result.found);
|
||||
assert(equal(input, Expected[i]));
|
||||
}
|
||||
|
||||
R range{input};
|
||||
const same_as<prev_permutation_result<iterator_t<R>>> auto result =
|
||||
prev_permutation(range.begin(), range.end(), ranges::less{}, get_val);
|
||||
assert(result.in == range.end());
|
||||
assert(!result.found);
|
||||
assert(equal(input, Expected[number_of_permutations - 1]));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct empty_range_test {
|
||||
template <ranges::bidirectional_range R>
|
||||
static constexpr void call() {
|
||||
using ranges::next_permutation, ranges::next_permutation_result, ranges::prev_permutation,
|
||||
ranges::prev_permutation_result, ranges::iterator_t;
|
||||
|
||||
{ // Validate range overload, next_permutation
|
||||
R range{};
|
||||
const same_as<next_permutation_result<iterator_t<R>>> auto result =
|
||||
next_permutation(range, ranges::less{}, get_val);
|
||||
assert(result.in == range.end());
|
||||
assert(!result.found);
|
||||
}
|
||||
|
||||
{ // Validate iterator overload, next_permutation
|
||||
R range{};
|
||||
const same_as<next_permutation_result<iterator_t<R>>> auto result =
|
||||
next_permutation(range.begin(), range.end(), ranges::less{}, get_val);
|
||||
assert(result.in == range.end());
|
||||
assert(!result.found);
|
||||
}
|
||||
|
||||
{ // Validate range overload, prev_permutation
|
||||
R range{};
|
||||
const same_as<prev_permutation_result<iterator_t<R>>> auto result =
|
||||
prev_permutation(range, ranges::less{}, get_val);
|
||||
assert(result.in == range.end());
|
||||
assert(!result.found);
|
||||
}
|
||||
|
||||
{ // Validate iterator overload, prev_permutation
|
||||
R range{};
|
||||
const same_as<prev_permutation_result<iterator_t<R>>> auto result =
|
||||
prev_permutation(range.begin(), range.end(), ranges::less{}, get_val);
|
||||
assert(result.in == range.end());
|
||||
assert(!result.found);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163
|
||||
STATIC_ASSERT((test_bidi<empty_range_test, int_wrapper>(), true));
|
||||
|
||||
STATIC_ASSERT((test_bidi<next_perm_instantiator<perm1>, int_wrapper>(), true));
|
||||
STATIC_ASSERT((test_bidi<next_perm_instantiator<perm4>, int_wrapper>(), true));
|
||||
STATIC_ASSERT((test_bidi<next_perm_instantiator<perm8>, int_wrapper>(), true));
|
||||
|
||||
STATIC_ASSERT((test_bidi<prev_perm_instantiator<perm1>, int_wrapper>(), true));
|
||||
STATIC_ASSERT((test_bidi<prev_perm_instantiator<perm4>, int_wrapper>(), true));
|
||||
STATIC_ASSERT((test_bidi<prev_perm_instantiator<perm8>, int_wrapper>(), true));
|
||||
#endif // TRANSITION, VSO-938163
|
||||
|
||||
test_bidi<empty_range_test, int_wrapper>();
|
||||
|
||||
test_bidi<next_perm_instantiator<perm1>, int_wrapper>();
|
||||
test_bidi<next_perm_instantiator<perm4>, int_wrapper>();
|
||||
test_bidi<next_perm_instantiator<perm5>, int_wrapper>();
|
||||
test_bidi<next_perm_instantiator<perm6>, int_wrapper>();
|
||||
test_bidi<next_perm_instantiator<perm8>, int_wrapper>();
|
||||
|
||||
test_bidi<prev_perm_instantiator<perm1>, int_wrapper>();
|
||||
test_bidi<prev_perm_instantiator<perm4>, int_wrapper>();
|
||||
test_bidi<prev_perm_instantiator<perm5>, int_wrapper>();
|
||||
test_bidi<prev_perm_instantiator<perm6>, int_wrapper>();
|
||||
test_bidi<prev_perm_instantiator<perm8>, int_wrapper>();
|
||||
}
|
Загрузка…
Ссылка в новой задаче