From ad702c9544d3d7f155669a3d91f84a251a8aa4bc Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 23 Jul 2020 13:53:02 -0700 Subject: [PATCH 1/2] Implement ranges::lexicographical_compare --- stl/inc/algorithm | 53 ++++++++ tests/std/test.lst | 1 + .../std/tests/P0896R4_ranges_alg_lexi/env.lst | 4 + .../tests/P0896R4_ranges_alg_lexi/test.cpp | 123 ++++++++++++++++++ 4 files changed, 181 insertions(+) create mode 100644 tests/std/tests/P0896R4_ranges_alg_lexi/env.lst create mode 100644 tests/std/tests/P0896R4_ranges_alg_lexi/test.cpp diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 9f5ea0f97cf..505368174a5 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -8237,6 +8237,59 @@ namespace ranges { }; inline constexpr _Clamp_fn clamp{_Not_quite_object::_Construct_tag{}}; + + // VARIABLE ranges::lexicographical_compare + class _Lexicographical_compare_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + template _Se1, input_iterator _It2, sentinel_for<_It2> _Se2, + class _Pj1 = identity, class _Pj2 = identity, + indirect_strict_weak_order, projected<_It2, _Pj2>> _Pr = ranges::less> + _NODISCARD constexpr bool operator()(_It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2, _Pr _Pred = {}, + _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const { + _Adl_verify_range(_First1, _Last1); + _Adl_verify_range(_First2, _Last2); + + return _Lexicographical_compare_unchecked(_Get_unwrapped(_STD move(_First1)), + _Get_unwrapped(_STD move(_Last1)), _Get_unwrapped(_STD move(_First2)), + _Get_unwrapped(_STD move(_Last2)), _Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2)); + } + + template , _Pj1>, projected, _Pj2>> _Pr = + ranges::less> + _NODISCARD constexpr bool operator()( + _Rng1&& _Range1, _Rng2&& _Range2, _Pr _Pred = {}, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const { + return _Lexicographical_compare_unchecked(_Ubegin(_Range1), _Uend(_Range1), _Ubegin(_Range2), + _Uend(_Range2), _Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2)); + } + + private: + template + _NODISCARD static constexpr bool _Lexicographical_compare_unchecked( + _It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2, _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(indirect_strict_weak_order<_Pr, projected<_It1, _Pj1>, projected<_It2, _Pj2>>); + + for (;; ++_First1, (void) ++_First2) { + if (_First2 == _Last2) { + return false; + } else if (_First1 == _Last1) { + return true; + } else if (_STD invoke(_Pred, _STD invoke(_Proj1, *_First1), _STD invoke(_Proj2, *_First2))) { + return true; + } else if (_STD invoke(_Pred, _STD invoke(_Proj2, *_First2), _STD invoke(_Proj1, *_First1))) { + return false; + } + } + } + }; + + inline constexpr _Lexicographical_compare_fn lexicographical_compare{_Not_quite_object::_Construct_tag{}}; } // namespace ranges #endif // __cpp_lib_concepts #endif // _HAS_CXX17 diff --git a/tests/std/test.lst b/tests/std/test.lst index c30028652af..a0d950ba9be 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -262,6 +262,7 @@ tests\P0896R4_ranges_alg_generate_n tests\P0896R4_ranges_alg_heap tests\P0896R4_ranges_alg_is_permutation tests\P0896R4_ranges_alg_is_sorted +tests\P0896R4_ranges_alg_lexi tests\P0896R4_ranges_alg_minmax tests\P0896R4_ranges_alg_mismatch tests\P0896R4_ranges_alg_move diff --git a/tests/std/tests/P0896R4_ranges_alg_lexi/env.lst b/tests/std/tests/P0896R4_ranges_alg_lexi/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_lexi/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_lexi/test.cpp b/tests/std/tests/P0896R4_ranges_alg_lexi/test.cpp new file mode 100644 index 00000000000..d4ec3c91dd6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_lexi/test.cpp @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using P = pair; + +struct instantiator { + static constexpr P left[] = {{0, 10}, {1, 20}, {2, 30}}; + static constexpr P right_shorter[] = {{300, 0}, {200, 1}}; + static constexpr P right_longer[] = {{300, 0}, {200, 1}, {100, 2}, {0, 3}}; + static constexpr P right_less[] = {{300, 0}, {200, 1}, {100, 1}}; + static constexpr P right_equal[] = {{300, 0}, {200, 1}, {100, 2}}; + static constexpr P right_greater[] = {{300, 0}, {200, 1}, {100, 3}}; + + template + static constexpr void call() { + using ranges::lexicographical_compare, ranges::less; + + // Validate range overload + { + In1 range1{left}; + In2 range2{right_shorter}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_longer}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(result); + } + { + In1 range1{left}; + In2 range2{right_less}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_equal}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_greater}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(result); + } + + // Validate iterator overload + { + In1 range1{left}; + In2 range2{right_shorter}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_longer}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(result); + } + { + In1 range1{left}; + In2 range2{right_less}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_equal}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_greater}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(result); + } + } +}; + +#ifdef TEST_EVERYTHING +int main() { + // No constexpr tests here: we hit the constexpr step limits too quickly. + test_in_in(); +} +#else // ^^^ test all range combinations / test only interesting combinations vvv +template +using range_type = test::range; + +constexpr void run_tests() { + // The algorithm is very much oblivious to any properties above the minimum requirements: category, size, + // difference, none of it matters. Let's test input ranges with and without proxy references. + using test::ProxyRef; + + instantiator::call, range_type>(); + instantiator::call, range_type>(); + instantiator::call, range_type>(); + instantiator::call, range_type>(); +} + +int main() { + STATIC_ASSERT((run_tests(), true)); + run_tests(); +} +#endif // TEST_EVERYTHING From 8183310e42eba94051d25c4b51b28d094a7a0d32 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Sat, 25 Jul 2020 19:01:08 -0700 Subject: [PATCH 2/2] Stephan's review comments --- tests/std/test.lst | 2 +- .../tests/P0896R4_ranges_alg_lexi/test.cpp | 123 ---------- .../env.lst | 0 .../test.cpp | 224 ++++++++++++++++++ 4 files changed, 225 insertions(+), 124 deletions(-) delete mode 100644 tests/std/tests/P0896R4_ranges_alg_lexi/test.cpp rename tests/std/tests/{P0896R4_ranges_alg_lexi => P0896R4_ranges_alg_lexicographical_compare}/env.lst (100%) create mode 100644 tests/std/tests/P0896R4_ranges_alg_lexicographical_compare/test.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index a0d950ba9be..9d57bcd7571 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -262,7 +262,7 @@ tests\P0896R4_ranges_alg_generate_n tests\P0896R4_ranges_alg_heap tests\P0896R4_ranges_alg_is_permutation tests\P0896R4_ranges_alg_is_sorted -tests\P0896R4_ranges_alg_lexi +tests\P0896R4_ranges_alg_lexicographical_compare tests\P0896R4_ranges_alg_minmax tests\P0896R4_ranges_alg_mismatch tests\P0896R4_ranges_alg_move diff --git a/tests/std/tests/P0896R4_ranges_alg_lexi/test.cpp b/tests/std/tests/P0896R4_ranges_alg_lexi/test.cpp deleted file mode 100644 index d4ec3c91dd6..00000000000 --- a/tests/std/tests/P0896R4_ranges_alg_lexi/test.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include -#include -#include -#include -#include - -#include - -using namespace std; -using P = pair; - -struct instantiator { - static constexpr P left[] = {{0, 10}, {1, 20}, {2, 30}}; - static constexpr P right_shorter[] = {{300, 0}, {200, 1}}; - static constexpr P right_longer[] = {{300, 0}, {200, 1}, {100, 2}, {0, 3}}; - static constexpr P right_less[] = {{300, 0}, {200, 1}, {100, 1}}; - static constexpr P right_equal[] = {{300, 0}, {200, 1}, {100, 2}}; - static constexpr P right_greater[] = {{300, 0}, {200, 1}, {100, 3}}; - - template - static constexpr void call() { - using ranges::lexicographical_compare, ranges::less; - - // Validate range overload - { - In1 range1{left}; - In2 range2{right_shorter}; - const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); - assert(!result); - } - { - In1 range1{left}; - In2 range2{right_longer}; - const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); - assert(result); - } - { - In1 range1{left}; - In2 range2{right_less}; - const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); - assert(!result); - } - { - In1 range1{left}; - In2 range2{right_equal}; - const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); - assert(!result); - } - { - In1 range1{left}; - In2 range2{right_greater}; - const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); - assert(result); - } - - // Validate iterator overload - { - In1 range1{left}; - In2 range2{right_shorter}; - const same_as auto result = lexicographical_compare( - range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); - assert(!result); - } - { - In1 range1{left}; - In2 range2{right_longer}; - const same_as auto result = lexicographical_compare( - range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); - assert(result); - } - { - In1 range1{left}; - In2 range2{right_less}; - const same_as auto result = lexicographical_compare( - range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); - assert(!result); - } - { - In1 range1{left}; - In2 range2{right_equal}; - const same_as auto result = lexicographical_compare( - range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); - assert(!result); - } - { - In1 range1{left}; - In2 range2{right_greater}; - const same_as auto result = lexicographical_compare( - range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); - assert(result); - } - } -}; - -#ifdef TEST_EVERYTHING -int main() { - // No constexpr tests here: we hit the constexpr step limits too quickly. - test_in_in(); -} -#else // ^^^ test all range combinations / test only interesting combinations vvv -template -using range_type = test::range; - -constexpr void run_tests() { - // The algorithm is very much oblivious to any properties above the minimum requirements: category, size, - // difference, none of it matters. Let's test input ranges with and without proxy references. - using test::ProxyRef; - - instantiator::call, range_type>(); - instantiator::call, range_type>(); - instantiator::call, range_type>(); - instantiator::call, range_type>(); -} - -int main() { - STATIC_ASSERT((run_tests(), true)); - run_tests(); -} -#endif // TEST_EVERYTHING diff --git a/tests/std/tests/P0896R4_ranges_alg_lexi/env.lst b/tests/std/tests/P0896R4_ranges_alg_lexicographical_compare/env.lst similarity index 100% rename from tests/std/tests/P0896R4_ranges_alg_lexi/env.lst rename to tests/std/tests/P0896R4_ranges_alg_lexicographical_compare/env.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_lexicographical_compare/test.cpp b/tests/std/tests/P0896R4_ranges_alg_lexicographical_compare/test.cpp new file mode 100644 index 00000000000..3d37682ccd9 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_lexicographical_compare/test.cpp @@ -0,0 +1,224 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using P = pair; + +struct instantiator { + static constexpr P left[] = {{0, 10}, {1, 20}, {2, 30}}; + static constexpr P right_shorter_less[] = {{300, 0}, {200, 0}}; + static constexpr P right_shorter_same[] = {{300, 0}, {200, 1}}; + static constexpr P right_shorter_greater[] = {{300, 0}, {200, 2}}; + static constexpr P right_less[] = {{300, 0}, {200, 1}, {100, 1}}; + static constexpr P right_equal[] = {{300, 0}, {200, 1}, {100, 2}}; + static constexpr P right_greater[] = {{300, 0}, {200, 1}, {100, 3}}; + static constexpr P right_longer_less[] = {{300, 0}, {200, 1}, {100, 1}, {0, 3}}; + static constexpr P right_longer_same[] = {{300, 0}, {200, 1}, {100, 2}, {0, 3}}; + static constexpr P right_longer_greater[] = {{300, 0}, {200, 1}, {100, 3}, {0, 3}}; + + template + static constexpr void call() { + using ranges::lexicographical_compare, ranges::less; + + // Validate range overload + { + In1 range1{left}; + In2 range2{right_shorter_less}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_shorter_same}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_shorter_greater}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(result); + } + + { + In1 range1{left}; + In2 range2{right_less}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_equal}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_greater}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(result); + } + + { + In1 range1{left}; + In2 range2{right_longer_less}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_longer_same}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(result); + } + { + In1 range1{left}; + In2 range2{right_longer_greater}; + const same_as auto result = lexicographical_compare(range1, range2, less{}, get_first, get_second); + assert(result); + } + + { + In1 empty1{}; + In2 range2{right_equal}; + const same_as auto result = lexicographical_compare(empty1, range2, less{}, get_first, get_second); + assert(result); + } + { + In1 range1{left}; + In2 empty2{}; + const same_as auto result = lexicographical_compare(range1, empty2, less{}, get_first, get_second); + assert(!result); + } + { + In1 empty1{}; + In2 empty2{}; + const same_as auto result = lexicographical_compare(empty1, empty2, less{}, get_first, get_second); + assert(!result); + } + + // Validate iterator overload + { + In1 range1{left}; + In2 range2{right_shorter_less}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_shorter_same}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_shorter_greater}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(result); + } + + { + In1 range1{left}; + In2 range2{right_less}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_equal}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_greater}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(result); + } + + { + In1 range1{left}; + In2 range2{right_longer_less}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(!result); + } + { + In1 range1{left}; + In2 range2{right_longer_same}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(result); + } + { + In1 range1{left}; + In2 range2{right_longer_greater}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(result); + } + + { + In1 empty1{}; + In2 range2{right_equal}; + const same_as auto result = lexicographical_compare( + empty1.begin(), empty1.end(), range2.begin(), range2.end(), less{}, get_first, get_second); + assert(result); + } + { + In1 range1{left}; + In2 empty2{}; + const same_as auto result = lexicographical_compare( + range1.begin(), range1.end(), empty2.begin(), empty2.end(), less{}, get_first, get_second); + assert(!result); + } + { + In1 empty1{}; + In2 empty2{}; + const same_as auto result = lexicographical_compare( + empty1.begin(), empty1.end(), empty2.begin(), empty2.end(), less{}, get_first, get_second); + assert(!result); + } + } +}; + +#ifdef TEST_EVERYTHING +int main() { + // No constexpr tests here: we hit the constexpr step limits too quickly. + test_in_in(); +} +#else // ^^^ test all range combinations / test only interesting combinations vvv +template +using range_type = test::range; + +constexpr void run_tests() { + // The algorithm is very much oblivious to any properties above the minimum requirements: category, size, + // difference, none of it matters. Let's test input ranges with and without proxy references. + using test::ProxyRef; + + instantiator::call, range_type>(); + instantiator::call, range_type>(); + instantiator::call, range_type>(); + instantiator::call, range_type>(); +} + +int main() { + STATIC_ASSERT((run_tests(), true)); + run_tests(); +} +#endif // TEST_EVERYTHING