From 2db9e8b60fe742d4c022692b9ca5ade8204a5022 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 28 Jul 2020 12:24:06 -0700 Subject: [PATCH 1/4] Implement ranges::next_permutation and ranges::prev_permutation --- stl/inc/algorithm | 146 ++++++++++++++ tests/std/test.lst | 1 + .../P0896R4_ranges_alg_permutations/env.lst | 4 + .../P0896R4_ranges_alg_permutations/test.cpp | 188 ++++++++++++++++++ 4 files changed, 339 insertions(+) create mode 100644 tests/std/tests/P0896R4_ranges_alg_permutations/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 6b93938c314..3c27750aa5e 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -8503,6 +8503,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 + 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 _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 + requires sortable, _Pr, _Pj> + constexpr next_permutation_result> 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 + _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(_Next1, _Last); + return true; + } + + if (_Next == _First) { // pure descending, flip all + _Reverse_common(_First, _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 _CONSTEXPR20 bool prev_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred) { @@ -8541,6 +8614,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 + 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 _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 + requires sortable, _Pr, _Pj> + constexpr prev_permutation_result> 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 + _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(_Next1, _Last); + return true; + } + + if (_Next == _First) { // pure ascending, flip all + _Reverse_common(_First, _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 _NODISCARD _CONSTEXPR20 _FwdIt is_sorted_until(const _FwdIt _First, _FwdIt _Last, _Pr _Pred) { diff --git a/tests/std/test.lst b/tests/std/test.lst index 12dbf4d64a4..fe08005247f 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -270,6 +270,7 @@ tests\P0896R4_ranges_alg_none_of 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 diff --git a/tests/std/tests/P0896R4_ranges_alg_permutations/env.lst b/tests/std/tests/P0896R4_ranges_alg_permutations/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_permutations/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_permutations/test.cpp b/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp new file mode 100644 index 00000000000..4427a22615d --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp @@ -0,0 +1,188 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include +using namespace std; + +// Validate that (next|prev)_permutation_result alias in_found_result +STATIC_ASSERT(same_as, ranges::in_found_result>); +STATIC_ASSERT(same_as, ranges::in_found_result>); + +// Validate dangling story +STATIC_ASSERT( + same_as{})), ranges::next_permutation_result>); +STATIC_ASSERT(same_as{})), ranges::next_permutation_result>); +STATIC_ASSERT( + same_as{})), ranges::prev_permutation_result>); +STATIC_ASSERT(same_as{})), ranges::prev_permutation_result>); + +constexpr int perm4[24][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[120][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}}; + +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(x).val; }; + +template +struct next_perm_instantiator { + template + static constexpr void call() { + using ranges::next_permutation, ranges::next_permutation_result, ranges::equal, ranges::is_sorted, + ranges::iterator_t; + + constexpr auto count = static_cast(ranges::size(Expected)); + + { // Validate range overload + int_wrapper input[ranges::size(Expected[0])]; + ranges::copy(Expected[0], input); + + for (int i = 1; i < count; ++i) { + R range{input}; + const same_as>> 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>> 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 < count; ++i) { + R range{input}; + const same_as>> 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>> 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 +struct prev_perm_instantiator { + template + static constexpr void call() { + using ranges::prev_permutation, ranges::prev_permutation_result, ranges::equal, ranges::is_sorted, + ranges::iterator_t; + + constexpr auto count = static_cast(ranges::size(Expected)); + + { // Validate range overload + int_wrapper input[ranges::size(Expected[0])]; + ranges::copy(Expected[count - 1], input); + + for (int i = count - 1; i-- > 0;) { + R range{input}; + const same_as>> 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>> auto result = + prev_permutation(range, ranges::less{}, get_val); + assert(result.in == range.end()); + assert(!result.found); + assert(equal(input, Expected[count - 1])); + } + + { // Validate iterator overload + int_wrapper input[ranges::size(Expected[0])]; + ranges::copy(Expected[count - 1], input); + + for (int i = count - 1; i-- > 0;) { + R range{input}; + const same_as>> 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>> auto result = + prev_permutation(range.begin(), range.end(), ranges::less{}, get_val); + assert(result.in == range.end()); + assert(!result.found); + assert(equal(input, Expected[count - 1])); + } + } +}; + +int main() { +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 + STATIC_ASSERT((test_bidi, int_wrapper>(), true)); +#endif // TRANSITION, VSO-938163 + test_bidi, int_wrapper>(); + test_bidi, int_wrapper>(); + +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 + STATIC_ASSERT((test_bidi, int_wrapper>(), true)); +#endif // TRANSITION, VSO-938163 + test_bidi, int_wrapper>(); + test_bidi, int_wrapper>(); +} From d675fa2afbbef8cd0b7a605c8bcc9f025b1ba8ae Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 28 Jul 2020 22:27:10 -0700 Subject: [PATCH 2/4] statementreply's comments --- stl/inc/algorithm | 8 +- .../P0896R4_ranges_alg_permutations/test.cpp | 87 +++++++++++++++++-- 2 files changed, 86 insertions(+), 9 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 3c27750aa5e..e6ee65bd4fb 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -8560,12 +8560,12 @@ namespace ranges { } while (!_STD invoke(_Pred, _STD invoke(_Proj, *_Next), _STD invoke(_Proj, *_Mid))); _RANGES iter_swap(_Next, _Mid); - _Reverse_common(_Next1, _Last); + _Reverse_common(_STD move(_Next1), _STD move(_Last)); return true; } if (_Next == _First) { // pure descending, flip all - _Reverse_common(_First, _Last); + _Reverse_common(_STD move(_First), _STD move(_Last)); return false; } } @@ -8671,12 +8671,12 @@ namespace ranges { } while (!_STD invoke(_Pred, _STD invoke(_Proj, *_Mid), _STD invoke(_Proj, *_Next))); _RANGES iter_swap(_Next, _Mid); - _Reverse_common(_Next1, _Last); + _Reverse_common(_STD move(_Next1), _STD move(_Last)); return true; } if (_Next == _First) { // pure ascending, flip all - _Reverse_common(_First, _Last); + _Reverse_common(_STD move(_First), _STD move(_Last)); return false; } } diff --git a/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp b/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp index 4427a22615d..ff1195fcf5a 100644 --- a/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp @@ -12,6 +12,8 @@ #include 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::in_found_result>); STATIC_ASSERT(same_as, ranges::in_found_result>); @@ -24,11 +26,12 @@ STATIC_ASSERT( same_as{})), ranges::prev_permutation_result>); STATIC_ASSERT(same_as{})), ranges::prev_permutation_result>); -constexpr int perm4[24][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}, +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[120][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}, +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}, @@ -49,6 +52,26 @@ constexpr int perm5[120][5] = {{0, 1, 2, 3, 4}, {0, 1, 2, 4, 3}, {0, 1, 3, 2, 4} {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] = {{}}; struct int_wrapper { int val = 10; @@ -173,16 +196,70 @@ struct prev_perm_instantiator { } }; +struct empty_range_test { + template + static constexpr void call() { + using ranges::next_permutation, ranges::next_permutation_result, ranges::prev_permutation, + ranges::prev_permutation_result, ranges::equal, ranges::is_sorted, ranges::iterator_t; + + { // Validate range overload, next_permutation + R range{}; + const same_as>> 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>> 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>> 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>> 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(), true)); + + STATIC_ASSERT((test_bidi, int_wrapper>(), true)); STATIC_ASSERT((test_bidi, int_wrapper>(), true)); + STATIC_ASSERT((test_bidi, int_wrapper>(), true)); + + STATIC_ASSERT((test_bidi, int_wrapper>(), true)); + STATIC_ASSERT((test_bidi, int_wrapper>(), true)); + STATIC_ASSERT((test_bidi, int_wrapper>(), true)); #endif // TRANSITION, VSO-938163 + + test_bidi(); + + test_bidi, int_wrapper>(); test_bidi, int_wrapper>(); test_bidi, int_wrapper>(); + test_bidi, int_wrapper>(); + test_bidi, int_wrapper>(); -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 - STATIC_ASSERT((test_bidi, int_wrapper>(), true)); -#endif // TRANSITION, VSO-938163 + test_bidi, int_wrapper>(); test_bidi, int_wrapper>(); test_bidi, int_wrapper>(); + test_bidi, int_wrapper>(); + test_bidi, int_wrapper>(); } From c0c2a291c4e80ea9090f65b3be88f042b3e12c66 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Wed, 29 Jul 2020 12:08:53 -0700 Subject: [PATCH 3/4] STL's review comments --- .../P0896R4_ranges_alg_permutations/test.cpp | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp b/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp index ff1195fcf5a..c523009d963 100644 --- a/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp @@ -81,29 +81,29 @@ struct int_wrapper { 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) { + + 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(x).val; }; +constexpr auto get_val = [](auto&& x) { return static_cast(x).val; }; template struct next_perm_instantiator { template static constexpr void call() { - using ranges::next_permutation, ranges::next_permutation_result, ranges::equal, ranges::is_sorted, - ranges::iterator_t; + using ranges::next_permutation, ranges::next_permutation_result, ranges::equal, ranges::iterator_t; - constexpr auto count = static_cast(ranges::size(Expected)); + constexpr auto number_of_permutations = static_cast(ranges::size(Expected)); { // Validate range overload int_wrapper input[ranges::size(Expected[0])]; ranges::copy(Expected[0], input); - for (int i = 1; i < count; ++i) { + for (int i = 1; i < number_of_permutations; ++i) { R range{input}; const same_as>> auto result = next_permutation(range, ranges::less{}, get_val); @@ -124,7 +124,7 @@ struct next_perm_instantiator { int_wrapper input[ranges::size(Expected[0])]; ranges::copy(Expected[0], input); - for (int i = 1; i < count; ++i) { + for (int i = 1; i < number_of_permutations; ++i) { R range{input}; const same_as>> auto result = next_permutation(range.begin(), range.end(), ranges::less{}, get_val); @@ -147,16 +147,15 @@ template struct prev_perm_instantiator { template static constexpr void call() { - using ranges::prev_permutation, ranges::prev_permutation_result, ranges::equal, ranges::is_sorted, - ranges::iterator_t; + using ranges::prev_permutation, ranges::prev_permutation_result, ranges::equal, ranges::iterator_t; - constexpr auto count = static_cast(ranges::size(Expected)); + constexpr auto number_of_permutations = static_cast(ranges::size(Expected)); { // Validate range overload int_wrapper input[ranges::size(Expected[0])]; - ranges::copy(Expected[count - 1], input); + ranges::copy(Expected[number_of_permutations - 1], input); - for (int i = count - 1; i-- > 0;) { + for (int i = number_of_permutations - 1; i-- > 0;) { R range{input}; const same_as>> auto result = prev_permutation(range, ranges::less{}, get_val); @@ -170,14 +169,14 @@ struct prev_perm_instantiator { prev_permutation(range, ranges::less{}, get_val); assert(result.in == range.end()); assert(!result.found); - assert(equal(input, Expected[count - 1])); + assert(equal(input, Expected[number_of_permutations - 1])); } { // Validate iterator overload int_wrapper input[ranges::size(Expected[0])]; - ranges::copy(Expected[count - 1], input); + ranges::copy(Expected[number_of_permutations - 1], input); - for (int i = count - 1; i-- > 0;) { + for (int i = number_of_permutations - 1; i-- > 0;) { R range{input}; const same_as>> auto result = prev_permutation(range.begin(), range.end(), ranges::less{}, get_val); @@ -191,7 +190,7 @@ struct prev_perm_instantiator { prev_permutation(range.begin(), range.end(), ranges::less{}, get_val); assert(result.in == range.end()); assert(!result.found); - assert(equal(input, Expected[count - 1])); + assert(equal(input, Expected[number_of_permutations - 1])); } } }; From db72d928b0c690e979d24a0750579edac50b4b30 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 4 Aug 2020 18:45:54 -0700 Subject: [PATCH 4/4] Miya's review comments --- tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp b/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp index c523009d963..6b8cd0037e5 100644 --- a/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_permutations/test.cpp @@ -71,7 +71,7 @@ constexpr int perm6[][6] = {{0, 0, 1, 1, 2, 2}, {0, 0, 1, 2, 1, 2}, {0, 0, 1, 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] = {{}}; +constexpr int perm8[][8] = {{0, 0, 0, 0, 0, 0, 0, 0}}; struct int_wrapper { int val = 10; @@ -199,7 +199,7 @@ struct empty_range_test { template static constexpr void call() { using ranges::next_permutation, ranges::next_permutation_result, ranges::prev_permutation, - ranges::prev_permutation_result, ranges::equal, ranges::is_sorted, ranges::iterator_t; + ranges::prev_permutation_result, ranges::iterator_t; { // Validate range overload, next_permutation R range{};