Index: libcxx/include/__config =================================================================== --- libcxx/include/__config +++ libcxx/include/__config @@ -1372,6 +1372,10 @@ #define _LIBCPP_HAS_NO_SPACESHIP_OPERATOR #endif +#if !defined(__cpp_concepts) || __cpp_concepts < 201811L +#define _LIBCPP_HAS_NO_CONCEPTS +#endif + // Decide whether to use availability macros. #if !defined(_LIBCPP_BUILDING_LIBRARY) && \ !defined(_LIBCXXABI_BUILDING_LIBRARY) && \ Index: libcxx/include/algorithm =================================================================== --- libcxx/include/algorithm +++ libcxx/include/algorithm @@ -615,6 +615,17 @@ lexicographical_compare(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, Compare comp); +template + constexpr auto + lexicographical_compare_three_way(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2); + +template + constexpr auto + lexicographical_compare_three_way(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, Compare comp) + -> decltype(comp(*first1, *first2)); + template bool next_permutation(BidirectionalIterator first, BidirectionalIterator last); @@ -638,6 +649,7 @@ #include <__config> #include #include +#include #include #include // needed to provide swap_ranges. #include @@ -5608,6 +5620,41 @@ typename iterator_traits<_InputIterator2>::value_type>()); } +// lexicographical_compare_three_way +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + +template +using __alg_three_way_result = + enable_if_t::reference, typename iterator_traits<_InputIterator2>::reference>>, void>, + invoke_result_t<_Compare&, typename iterator_traits<_InputIterator1>::reference, typename iterator_traits<_InputIterator2>::reference>>; + +template +constexpr auto lexicographical_compare_three_way(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _Compare __comp) + -> __alg_three_way_result<_Compare, _InputIterator1, _InputIterator2> +{ + for (; __first1 != __last1 && __first2 != __last2; void(++__first1), void(++__first2)) { + if (auto __cmp = __comp(*__first1, *__first2); __cmp != 0) { + return __cmp; + } + } + return __first1 != __last1 ? strong_ordering::greater : + __first2 != __last2 ? strong_ordering::less : + strong_ordering::equal; +} + +template +constexpr auto lexicographical_compare_three_way(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2) +{ + return _VSTD::lexicographical_compare_three_way(__first1, __last1, __first2, __last2, + compare_three_way()); +} + +#endif // _LIBCPP_HAS_NO_SPACESHIP_OPERATOR + // next_permutation template Index: libcxx/include/compare =================================================================== --- libcxx/include/compare +++ libcxx/include/compare @@ -47,8 +47,8 @@ */ #include <__config> +#include #include -#include #ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER #pragma GCC system_header @@ -618,10 +618,10 @@ template constexpr _ClassifyCompCategory -__compute_comp_type(std::array<_ClassifyCompCategory, _Size> __types) { - std::array __seen = {}; - for (auto __type : __types) - ++__seen[__type]; +__compute_comp_type(const _ClassifyCompCategory* __types) { + int __seen[_CCC_Size] = {}; + for (size_t __i = 0; __i < _Size; ++__i) + ++__seen[__types[__i]]; if (__seen[_None]) return _None; if (__seen[_WeakEq]) @@ -640,9 +640,9 @@ template constexpr auto __get_comp_type() { using _CCC = _ClassifyCompCategory; - constexpr array<_CCC, sizeof...(_Ts)> __type_kinds{{__comp_detail::__type_to_enum<_Ts>()...}}; + constexpr _CCC __type_kinds[sizeof...(_Ts)] = {__comp_detail::__type_to_enum<_Ts>()...}; constexpr _CCC _Cat = sizeof...(_Ts) == 0 ? _StrongOrd - : __compute_comp_type(__type_kinds); + : __compute_comp_type(__type_kinds); if constexpr (_Cat == _None) return void(); else if constexpr (_Cat == _WeakEq) Index: libcxx/include/concepts =================================================================== --- libcxx/include/concepts +++ libcxx/include/concepts @@ -147,7 +147,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if _LIBCPP_STD_VER > 17 && defined(__cpp_concepts) && __cpp_concepts >= 201811L +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) // [concept.same] @@ -157,7 +157,7 @@ template concept same_as = __same_as_impl<_Tp, _Up> && __same_as_impl<_Up, _Tp>; -#endif //_LIBCPP_STD_VER > 17 && defined(__cpp_concepts) && __cpp_concepts >= 201811L +#endif //_LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) _LIBCPP_END_NAMESPACE_STD Index: libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp @@ -0,0 +1,116 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// constexpr auto +// lexicographical_compare(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2); + +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" + +template +constexpr void test_less(std::array& a, std::array& b) { + assert(std::lexicographical_compare_three_way( + Iter1(b.begin()), Iter1(b.end() - 1), Iter2(a.begin()), + Iter2(a.end())) == std::strong_ordering::less); + + assert(std::lexicographical_compare_three_way( + Iter1(b.begin()), Iter1(b.end()), Iter2(a.begin()), + Iter2(a.end())) == std::strong_ordering::less); + + assert(std::lexicographical_compare_three_way( + Iter1(a.begin()), Iter1(a.end()), Iter2(b.begin() + 1), + Iter2(b.end())) == std::strong_ordering::less); +} + +template +constexpr void test_equal(R& a, R& b) { + assert(std::lexicographical_compare_three_way( + Iter1(b.begin()), Iter1(b.end()), Iter2(a.begin()), + Iter2(a.end())) == std::strong_ordering::equal); +} + +template +constexpr void test_greater(std::array& a, std::array& b) { + assert(std::lexicographical_compare_three_way( + Iter1(a.begin()), Iter1(a.end()), Iter2(b.begin()), + Iter2(b.end() - 1)) == std::strong_ordering::greater); + + assert(std::lexicographical_compare_three_way( + Iter1(a.begin()), Iter1(a.end()), Iter2(b.begin()), + Iter2(b.end())) == std::strong_ordering::greater); + + assert(std::lexicographical_compare_three_way( + Iter1(b.begin() + 1), Iter1(b.end()), Iter2(a.begin()), + Iter2(a.end())) == std::strong_ordering::greater); +} + +template +constexpr void test() { + std::array a{1, 2, 3, 4}; + std::array b{1, 2, 3}; + + test_less(a, b); + test_equal(a, a); + test_equal(b, b); + test_greater(a, b); +} + +constexpr bool test() { + test, input_iterator >(); + test, forward_iterator >(); + test, bidirectional_iterator >(); + test, random_access_iterator >(); + test, const int*>(); + + test, input_iterator >(); + test, forward_iterator >(); + test, bidirectional_iterator >(); + test, random_access_iterator >(); + test, const int*>(); + + test, input_iterator >(); + test, forward_iterator >(); + test, + bidirectional_iterator >(); + test, + random_access_iterator >(); + test, const int*>(); + + test, input_iterator >(); + test, forward_iterator >(); + test, + bidirectional_iterator >(); + test, + random_access_iterator >(); + test, const int*>(); + + test >(); + test >(); + test >(); + test >(); + test(); + + return true; +} + +int main(int, char**) { + static_assert(test()); + test(); + + return 0; +} Index: libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way_comp.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way_comp.pass.cpp @@ -0,0 +1,130 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template +// constexpr auto +// lexicographical_compare_three_way(Iter1 first1, Iter1 last1, +// Iter2 first2, Iter2 last2, Compare comp) +// -> decltype(comp(*first1, *first2)); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" + +// "simulates" use of std::greater in lex.comparison comp test +auto comp = [](int x, int y) { + return static_cast(y <=> x); +}; + +template +constexpr void test_less() { + std::array a{1, 2, 3, 4}; + std::array b{1, 2, 3}; + assert(std::lexicographical_compare_three_way( + Iter1(b.begin()), Iter1(b.end() - 1), Iter2(a.begin()), + Iter2(a.end()), comp) == std::weak_ordering::less); + + assert(std::lexicographical_compare_three_way( + Iter1(b.begin()), Iter1(b.end() - 1), Iter2(a.begin()), + Iter2(a.end()), comp) == std::weak_ordering::less); + + assert(std::lexicographical_compare_three_way( + Iter1(b.begin()), Iter1(b.end()), Iter1(a.begin()), Iter1(a.end()), + comp) == std::weak_ordering::less); +} + +template +constexpr void test_equal() { + std::array a{1, 2, 3, 4}; + std::array b = a; + assert(std::lexicographical_compare_three_way( + Iter1(b.begin()), Iter1(b.end()), Iter2(a.begin()), Iter2(a.end()), + comp) == std::weak_ordering::equivalent); + + std::array x{99, 64, 128}; + std::array y = x; + assert(std::lexicographical_compare_three_way( + Iter1(x.begin()), Iter1(x.end()), Iter2(y.begin()), Iter2(y.end()), + comp) == std::weak_ordering::equivalent); +} + +template +constexpr void test_greater() { + std::array a{1, 2, 3, 4}; + std::array b{1, 2, 3}; + assert(std::lexicographical_compare_three_way( + Iter1(a.begin()), Iter1(a.end()), Iter2(b.begin()), + Iter2(b.end() - 1), comp) == std::weak_ordering::greater); + + assert(std::lexicographical_compare_three_way( + Iter1(a.begin()), Iter1(a.end()), Iter2(b.begin()), Iter2(b.end()), + comp) == std::weak_ordering::greater); + + assert(std::lexicographical_compare_three_way( + Iter1(b.begin() + 1), Iter1(b.end()), Iter2(a.begin()), + Iter2(a.end()), comp) == std::weak_ordering::less); +} + +template +constexpr void test() { + test_less(); + test_equal(); + test_equal(); + test_greater(); +} + +constexpr bool test() { + test, input_iterator >(); + test, forward_iterator >(); + test, bidirectional_iterator >(); + test, random_access_iterator >(); + test, const int*>(); + + test, input_iterator >(); + test, forward_iterator >(); + test, bidirectional_iterator >(); + test, random_access_iterator >(); + test, const int*>(); + + test, input_iterator >(); + test, forward_iterator >(); + test, + bidirectional_iterator >(); + test, + random_access_iterator >(); + test, const int*>(); + + test, input_iterator >(); + test, forward_iterator >(); + test, + bidirectional_iterator >(); + test, + random_access_iterator >(); + test, const int*>(); + + test >(); + test >(); + test >(); + test >(); + test(); + + return true; +} + +int main(int, char**) { + static_assert(test()); + test(); + + return 0; +}