diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv --- a/libcxx/docs/Status/RangesAlgorithms.csv +++ b/libcxx/docs/Status/RangesAlgorithms.csv @@ -9,7 +9,7 @@ Search,adjacent_find,Nikolas Klauser,`D126610 `_,✅ Search,mismatch,Nikolas Klauser,`D117817 `_,✅ Search,equal,Nikolas Klauser,`D123681 `_,✅ -Search,lexicographical_compare,Nikolas Klauser,`D127130 `_,Under review +Search,lexicographical_compare,Nikolas Klauser,`D127130 `_,✅ Search,partition_point,Christopher Di Bella,`D105794 `_,Under review Search,lower_bound,Nikolas Klauser,`D121964 `_,✅ Search,upper_bound,Nikolas Klauser,`D121964 `_,✅ diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -89,6 +89,7 @@ __algorithm/ranges_is_partitioned.h __algorithm/ranges_is_sorted.h __algorithm/ranges_is_sorted_until.h + __algorithm/ranges_lexicographical_compare.h __algorithm/ranges_lower_bound.h __algorithm/ranges_max.h __algorithm/ranges_max_element.h diff --git a/libcxx/include/__algorithm/ranges_lexicographical_compare.h b/libcxx/include/__algorithm/ranges_lexicographical_compare.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__algorithm/ranges_lexicographical_compare.h @@ -0,0 +1,98 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_LEXICOGRAPHICAL_COMPARE_H +#define _LIBCPP___ALGORITHM_RANGES_LEXICOGRAPHICAL_COMPARE_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __lexicographical_compare { +struct __fn { + + template + _LIBCPP_HIDE_FROM_ABI constexpr static + bool __lexicographical_compare_impl(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, + _Comp& __comp, + _Proj1& __proj1, + _Proj2& __proj2) { + while (__first2 != __last2) { + if (__first1 == __last1 + || std::invoke(__comp, std::invoke(__proj1, *__first1), std::invoke(__proj2, *__first2))) + return true; + if (std::invoke(__comp, std::invoke(__proj2, *__first2), std::invoke(__proj1, *__first1))) + return false; + ++__first1; + ++__first2; + } + return false; + } + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + class _Proj1 = identity, + class _Proj2 = identity, + indirect_strict_weak_order, projected<_Iter2, _Proj2>> _Comp = ranges::less> + _LIBCPP_HIDE_FROM_ABI constexpr + bool operator()(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + return __lexicographical_compare_impl(std::move(__first1), std::move(__last1), + std::move(__first2), std::move(__last2), + __comp, + __proj1, + __proj2); + } + + template , _Proj1>, + projected, _Proj2>> _Comp = ranges::less> + _LIBCPP_HIDE_FROM_ABI constexpr + bool operator()(_Range1&& __range1, _Range2&& __range2, _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { + return __lexicographical_compare_impl(ranges::begin(__range1), ranges::end(__range1), + ranges::begin(__range2), ranges::end(__range2), + __comp, + __proj1, + __proj2); + } + +}; +} // namespace __lexicographical_compare + +inline namespace __cpo { + inline constexpr auto lexicographical_compare = __lexicographical_compare::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + +#endif // _LIBCPP___ALGORITHM_RANGES_LEXICOGRAPHICAL_COMPARE_H diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -424,6 +424,22 @@ constexpr borrowed_iterator_t ranges::replace_if(R&& r, Pred pred, const T& new_value, Proj proj = {}); // since C++20 + template S1, input_iterator I2, sentinel_for S2, + class Proj1 = identity, class Proj2 = identity, + indirect_strict_weak_order, + projected> Comp = ranges::less> + constexpr bool + ranges::lexicographical_compare(I1 first1, S1 last1, I2 first2, S2 last2, + Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++20 + + template, Proj1>, + projected, Proj2>> Comp = ranges::less> + constexpr bool + ranges::lexicographical_compare(R1&& r1, R2&& r2, Comp comp = {}, + Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++20 + } constexpr bool // constexpr in C++20 @@ -1161,6 +1177,7 @@ #include <__algorithm/ranges_is_partitioned.h> #include <__algorithm/ranges_is_sorted.h> #include <__algorithm/ranges_is_sorted_until.h> +#include <__algorithm/ranges_lexicographical_compare.h> #include <__algorithm/ranges_lower_bound.h> #include <__algorithm/ranges_max.h> #include <__algorithm/ranges_max_element.h> diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -238,144 +238,145 @@ export * module __algorithm { - module adjacent_find { private header "__algorithm/adjacent_find.h" } - module all_of { private header "__algorithm/all_of.h" } - module any_of { private header "__algorithm/any_of.h" } - module binary_search { private header "__algorithm/binary_search.h" } - module clamp { private header "__algorithm/clamp.h" } - module comp { private header "__algorithm/comp.h" } - module comp_ref_type { private header "__algorithm/comp_ref_type.h" } - module copy { private header "__algorithm/copy.h" } - module copy_backward { private header "__algorithm/copy_backward.h" } - module copy_if { private header "__algorithm/copy_if.h" } - module copy_n { private header "__algorithm/copy_n.h" } - module count { private header "__algorithm/count.h" } - module count_if { private header "__algorithm/count_if.h" } - module equal { private header "__algorithm/equal.h" } - module equal_range { private header "__algorithm/equal_range.h" } - module fill { private header "__algorithm/fill.h" } - module fill_n { private header "__algorithm/fill_n.h" } - module find { private header "__algorithm/find.h" } - module find_end { private header "__algorithm/find_end.h" } - module find_first_of { private header "__algorithm/find_first_of.h" } - module find_if { private header "__algorithm/find_if.h" } - module find_if_not { private header "__algorithm/find_if_not.h" } - module for_each { private header "__algorithm/for_each.h" } - module for_each_n { private header "__algorithm/for_each_n.h" } - module generate { private header "__algorithm/generate.h" } - module generate_n { private header "__algorithm/generate_n.h" } - module half_positive { private header "__algorithm/half_positive.h" } - module in_found_result { private header "__algorithm/in_found_result.h" } - module in_fun_result { private header "__algorithm/in_fun_result.h" } - module in_in_out_result { private header "__algorithm/in_in_out_result.h" } - module in_in_result { private header "__algorithm/in_in_result.h" } - module in_out_out_result { private header "__algorithm/in_out_out_result.h" } - module in_out_result { private header "__algorithm/in_out_result.h" } - module includes { private header "__algorithm/includes.h" } - module inplace_merge { private header "__algorithm/inplace_merge.h" } - module is_heap { private header "__algorithm/is_heap.h" } - module is_heap_until { private header "__algorithm/is_heap_until.h" } - module is_partitioned { private header "__algorithm/is_partitioned.h" } - module is_permutation { private header "__algorithm/is_permutation.h" } - module is_sorted { private header "__algorithm/is_sorted.h" } - module is_sorted_until { private header "__algorithm/is_sorted_until.h" } - module iter_swap { private header "__algorithm/iter_swap.h" } - module iterator_operations { private header "__algorithm/iterator_operations.h" } - module lexicographical_compare { private header "__algorithm/lexicographical_compare.h" } - module lower_bound { private header "__algorithm/lower_bound.h" } - module make_heap { private header "__algorithm/make_heap.h" } - module max { private header "__algorithm/max.h" } - module max_element { private header "__algorithm/max_element.h" } - module merge { private header "__algorithm/merge.h" } - module min { private header "__algorithm/min.h" } - module min_element { private header "__algorithm/min_element.h" } - module min_max_result { private header "__algorithm/min_max_result.h" } - module minmax { private header "__algorithm/minmax.h" } - module minmax_element { private header "__algorithm/minmax_element.h" } - module mismatch { private header "__algorithm/mismatch.h" } - module move { private header "__algorithm/move.h" } - module move_backward { private header "__algorithm/move_backward.h" } - module next_permutation { private header "__algorithm/next_permutation.h" } - module none_of { private header "__algorithm/none_of.h" } - module nth_element { private header "__algorithm/nth_element.h" } - module partial_sort { private header "__algorithm/partial_sort.h" } - module partial_sort_copy { private header "__algorithm/partial_sort_copy.h" } - module partition { private header "__algorithm/partition.h" } - module partition_copy { private header "__algorithm/partition_copy.h" } - module partition_point { private header "__algorithm/partition_point.h" } - module pop_heap { private header "__algorithm/pop_heap.h" } - module prev_permutation { private header "__algorithm/prev_permutation.h" } - module push_heap { private header "__algorithm/push_heap.h" } - module ranges_adjacent_find { private header "__algorithm/ranges_adjacent_find.h" } - module ranges_all_of { private header "__algorithm/ranges_all_of.h" } - module ranges_any_of { private header "__algorithm/ranges_any_of.h" } - module ranges_binary_search { private header "__algorithm/ranges_binary_search.h" } - module ranges_copy { private header "__algorithm/ranges_copy.h" } - module ranges_copy_backward { private header "__algorithm/ranges_copy_backward.h" } - module ranges_copy_if { private header "__algorithm/ranges_copy_if.h" } - module ranges_copy_n { private header "__algorithm/ranges_copy_n.h" } - module ranges_count { private header "__algorithm/ranges_count.h" } - module ranges_count_if { private header "__algorithm/ranges_count_if.h" } - module ranges_equal { private header "__algorithm/ranges_equal.h" } - module ranges_fill { private header "__algorithm/ranges_fill.h" } - module ranges_fill_n { private header "__algorithm/ranges_fill_n.h" } - module ranges_find { private header "__algorithm/ranges_find.h" } - module ranges_find_first_of { private header "__algorithm/ranges_find_first_of.h" } - module ranges_find_if { private header "__algorithm/ranges_find_if.h" } - module ranges_find_if_not { private header "__algorithm/ranges_find_if_not.h" } - module ranges_for_each { private header "__algorithm/ranges_for_each.h" } - module ranges_for_each_n { private header "__algorithm/ranges_for_each_n.h" } - module ranges_is_partitioned { private header "__algorithm/ranges_is_partitioned.h" } - module ranges_is_sorted { private header "__algorithm/ranges_is_sorted.h" } - module ranges_is_sorted_until { private header "__algorithm/ranges_is_sorted_until.h" } - module ranges_lower_bound { private header "__algorithm/ranges_lower_bound.h" } - module ranges_max { private header "__algorithm/ranges_max.h" } - module ranges_max_element { private header "__algorithm/ranges_max_element.h" } - module ranges_min { private header "__algorithm/ranges_min.h" } - module ranges_min_element { private header "__algorithm/ranges_min_element.h" } - module ranges_minmax { private header "__algorithm/ranges_minmax.h" } - module ranges_minmax_element { private header "__algorithm/ranges_minmax_element.h" } - module ranges_mismatch { private header "__algorithm/ranges_mismatch.h" } - module ranges_none_of { private header "__algorithm/ranges_none_of.h" } - module ranges_replace { private header "__algorithm/ranges_replace.h" } - module ranges_replace_if { private header "__algorithm/ranges_replace_if.h" } - module ranges_reverse { private header "__algorithm/ranges_reverse.h" } - module ranges_swap_ranges { private header "__algorithm/ranges_swap_ranges.h" } - module ranges_transform { private header "__algorithm/ranges_transform.h" } - module ranges_upper_bound { private header "__algorithm/ranges_upper_bound.h" } - module remove { private header "__algorithm/remove.h" } - module remove_copy { private header "__algorithm/remove_copy.h" } - module remove_copy_if { private header "__algorithm/remove_copy_if.h" } - module remove_if { private header "__algorithm/remove_if.h" } - module replace { private header "__algorithm/replace.h" } - module replace_copy { private header "__algorithm/replace_copy.h" } - module replace_copy_if { private header "__algorithm/replace_copy_if.h" } - module replace_if { private header "__algorithm/replace_if.h" } - module reverse { private header "__algorithm/reverse.h" } - module reverse_copy { private header "__algorithm/reverse_copy.h" } - module rotate { private header "__algorithm/rotate.h" } - module rotate_copy { private header "__algorithm/rotate_copy.h" } - module sample { private header "__algorithm/sample.h" } - module search { private header "__algorithm/search.h" } - module search_n { private header "__algorithm/search_n.h" } - module set_difference { private header "__algorithm/set_difference.h" } - module set_intersection { private header "__algorithm/set_intersection.h" } - module set_symmetric_difference { private header "__algorithm/set_symmetric_difference.h" } - module set_union { private header "__algorithm/set_union.h" } - module shift_left { private header "__algorithm/shift_left.h" } - module shift_right { private header "__algorithm/shift_right.h" } - module shuffle { private header "__algorithm/shuffle.h" } - module sift_down { private header "__algorithm/sift_down.h" } - module sort { private header "__algorithm/sort.h" } - module sort_heap { private header "__algorithm/sort_heap.h" } - module stable_partition { private header "__algorithm/stable_partition.h" } - module stable_sort { private header "__algorithm/stable_sort.h" } - module swap_ranges { private header "__algorithm/swap_ranges.h" } - module transform { private header "__algorithm/transform.h" } - module unique { private header "__algorithm/unique.h" } - module unique_copy { private header "__algorithm/unique_copy.h" } - module unwrap_iter { private header "__algorithm/unwrap_iter.h" } - module upper_bound { private header "__algorithm/upper_bound.h" } + module adjacent_find { private header "__algorithm/adjacent_find.h" } + module all_of { private header "__algorithm/all_of.h" } + module any_of { private header "__algorithm/any_of.h" } + module binary_search { private header "__algorithm/binary_search.h" } + module clamp { private header "__algorithm/clamp.h" } + module comp { private header "__algorithm/comp.h" } + module comp_ref_type { private header "__algorithm/comp_ref_type.h" } + module copy { private header "__algorithm/copy.h" } + module copy_backward { private header "__algorithm/copy_backward.h" } + module copy_if { private header "__algorithm/copy_if.h" } + module copy_n { private header "__algorithm/copy_n.h" } + module count { private header "__algorithm/count.h" } + module count_if { private header "__algorithm/count_if.h" } + module equal { private header "__algorithm/equal.h" } + module equal_range { private header "__algorithm/equal_range.h" } + module fill { private header "__algorithm/fill.h" } + module fill_n { private header "__algorithm/fill_n.h" } + module find { private header "__algorithm/find.h" } + module find_end { private header "__algorithm/find_end.h" } + module find_first_of { private header "__algorithm/find_first_of.h" } + module find_if { private header "__algorithm/find_if.h" } + module find_if_not { private header "__algorithm/find_if_not.h" } + module for_each { private header "__algorithm/for_each.h" } + module for_each_n { private header "__algorithm/for_each_n.h" } + module generate { private header "__algorithm/generate.h" } + module generate_n { private header "__algorithm/generate_n.h" } + module half_positive { private header "__algorithm/half_positive.h" } + module in_found_result { private header "__algorithm/in_found_result.h" } + module in_fun_result { private header "__algorithm/in_fun_result.h" } + module in_in_out_result { private header "__algorithm/in_in_out_result.h" } + module in_in_result { private header "__algorithm/in_in_result.h" } + module in_out_out_result { private header "__algorithm/in_out_out_result.h" } + module in_out_result { private header "__algorithm/in_out_result.h" } + module includes { private header "__algorithm/includes.h" } + module inplace_merge { private header "__algorithm/inplace_merge.h" } + module is_heap { private header "__algorithm/is_heap.h" } + module is_heap_until { private header "__algorithm/is_heap_until.h" } + module is_partitioned { private header "__algorithm/is_partitioned.h" } + module is_permutation { private header "__algorithm/is_permutation.h" } + module is_sorted { private header "__algorithm/is_sorted.h" } + module is_sorted_until { private header "__algorithm/is_sorted_until.h" } + module iter_swap { private header "__algorithm/iter_swap.h" } + module iterator_operations { private header "__algorithm/iterator_operations.h" } + module lexicographical_compare { private header "__algorithm/lexicographical_compare.h" } + module lower_bound { private header "__algorithm/lower_bound.h" } + module make_heap { private header "__algorithm/make_heap.h" } + module max { private header "__algorithm/max.h" } + module max_element { private header "__algorithm/max_element.h" } + module merge { private header "__algorithm/merge.h" } + module min { private header "__algorithm/min.h" } + module min_element { private header "__algorithm/min_element.h" } + module min_max_result { private header "__algorithm/min_max_result.h" } + module minmax { private header "__algorithm/minmax.h" } + module minmax_element { private header "__algorithm/minmax_element.h" } + module mismatch { private header "__algorithm/mismatch.h" } + module move { private header "__algorithm/move.h" } + module move_backward { private header "__algorithm/move_backward.h" } + module next_permutation { private header "__algorithm/next_permutation.h" } + module none_of { private header "__algorithm/none_of.h" } + module nth_element { private header "__algorithm/nth_element.h" } + module partial_sort { private header "__algorithm/partial_sort.h" } + module partial_sort_copy { private header "__algorithm/partial_sort_copy.h" } + module partition { private header "__algorithm/partition.h" } + module partition_copy { private header "__algorithm/partition_copy.h" } + module partition_point { private header "__algorithm/partition_point.h" } + module pop_heap { private header "__algorithm/pop_heap.h" } + module prev_permutation { private header "__algorithm/prev_permutation.h" } + module push_heap { private header "__algorithm/push_heap.h" } + module ranges_adjacent_find { private header "__algorithm/ranges_adjacent_find.h" } + module ranges_all_of { private header "__algorithm/ranges_all_of.h" } + module ranges_any_of { private header "__algorithm/ranges_any_of.h" } + module ranges_binary_search { private header "__algorithm/ranges_binary_search.h" } + module ranges_copy { private header "__algorithm/ranges_copy.h" } + module ranges_copy_backward { private header "__algorithm/ranges_copy_backward.h" } + module ranges_copy_if { private header "__algorithm/ranges_copy_if.h" } + module ranges_copy_n { private header "__algorithm/ranges_copy_n.h" } + module ranges_count { private header "__algorithm/ranges_count.h" } + module ranges_count_if { private header "__algorithm/ranges_count_if.h" } + module ranges_equal { private header "__algorithm/ranges_equal.h" } + module ranges_fill { private header "__algorithm/ranges_fill.h" } + module ranges_fill_n { private header "__algorithm/ranges_fill_n.h" } + module ranges_find { private header "__algorithm/ranges_find.h" } + module ranges_find_first_of { private header "__algorithm/ranges_find_first_of.h" } + module ranges_find_if { private header "__algorithm/ranges_find_if.h" } + module ranges_find_if_not { private header "__algorithm/ranges_find_if_not.h" } + module ranges_for_each { private header "__algorithm/ranges_for_each.h" } + module ranges_for_each_n { private header "__algorithm/ranges_for_each_n.h" } + module ranges_is_partitioned { private header "__algorithm/ranges_is_partitioned.h" } + module ranges_is_sorted { private header "__algorithm/ranges_is_sorted.h" } + module ranges_is_sorted_until { private header "__algorithm/ranges_is_sorted_until.h" } + module ranges_lexicographical_compare { private header "__algorithm/ranges_lexicographical_compare.h" } + module ranges_lower_bound { private header "__algorithm/ranges_lower_bound.h" } + module ranges_max { private header "__algorithm/ranges_max.h" } + module ranges_max_element { private header "__algorithm/ranges_max_element.h" } + module ranges_min { private header "__algorithm/ranges_min.h" } + module ranges_min_element { private header "__algorithm/ranges_min_element.h" } + module ranges_minmax { private header "__algorithm/ranges_minmax.h" } + module ranges_minmax_element { private header "__algorithm/ranges_minmax_element.h" } + module ranges_mismatch { private header "__algorithm/ranges_mismatch.h" } + module ranges_none_of { private header "__algorithm/ranges_none_of.h" } + module ranges_replace { private header "__algorithm/ranges_replace.h" } + module ranges_replace_if { private header "__algorithm/ranges_replace_if.h" } + module ranges_reverse { private header "__algorithm/ranges_reverse.h" } + module ranges_swap_ranges { private header "__algorithm/ranges_swap_ranges.h" } + module ranges_transform { private header "__algorithm/ranges_transform.h" } + module ranges_upper_bound { private header "__algorithm/ranges_upper_bound.h" } + module remove { private header "__algorithm/remove.h" } + module remove_copy { private header "__algorithm/remove_copy.h" } + module remove_copy_if { private header "__algorithm/remove_copy_if.h" } + module remove_if { private header "__algorithm/remove_if.h" } + module replace { private header "__algorithm/replace.h" } + module replace_copy { private header "__algorithm/replace_copy.h" } + module replace_copy_if { private header "__algorithm/replace_copy_if.h" } + module replace_if { private header "__algorithm/replace_if.h" } + module reverse { private header "__algorithm/reverse.h" } + module reverse_copy { private header "__algorithm/reverse_copy.h" } + module rotate { private header "__algorithm/rotate.h" } + module rotate_copy { private header "__algorithm/rotate_copy.h" } + module sample { private header "__algorithm/sample.h" } + module search { private header "__algorithm/search.h" } + module search_n { private header "__algorithm/search_n.h" } + module set_difference { private header "__algorithm/set_difference.h" } + module set_intersection { private header "__algorithm/set_intersection.h" } + module set_symmetric_difference { private header "__algorithm/set_symmetric_difference.h" } + module set_union { private header "__algorithm/set_union.h" } + module shift_left { private header "__algorithm/shift_left.h" } + module shift_right { private header "__algorithm/shift_right.h" } + module shuffle { private header "__algorithm/shuffle.h" } + module sift_down { private header "__algorithm/sift_down.h" } + module sort { private header "__algorithm/sort.h" } + module sort_heap { private header "__algorithm/sort_heap.h" } + module stable_partition { private header "__algorithm/stable_partition.h" } + module stable_sort { private header "__algorithm/stable_sort.h" } + module swap_ranges { private header "__algorithm/swap_ranges.h" } + module transform { private header "__algorithm/transform.h" } + module unique { private header "__algorithm/unique.h" } + module unique_copy { private header "__algorithm/unique_copy.h" } + module unwrap_iter { private header "__algorithm/unwrap_iter.h" } + module upper_bound { private header "__algorithm/upper_bound.h" } } } module any { diff --git a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp --- a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp +++ b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp @@ -140,8 +140,8 @@ (void)std::ranges::is_sorted_until(a, Less(&copies)); assert(copies == 0); //if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(first, mid, last, Less(&copies)); assert(copies == 0); } //if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(a, mid, Less(&copies)); assert(copies == 0); } - //(void)std::ranges::lexicographical_compare(first, last, first2, last2, Less(&copies)); assert(copies == 0); - //(void)std::ranges::lexicographical_compare(a, b, Less(&copies)); assert(copies == 0); + (void)std::ranges::lexicographical_compare(first, last, first2, last2, Less(&copies)); assert(copies == 0); + (void)std::ranges::lexicographical_compare(a, b, Less(&copies)); assert(copies == 0); (void)std::ranges::lower_bound(first, last, value, Less(&copies)); assert(copies == 0); (void)std::ranges::lower_bound(a, value, Less(&copies)); assert(copies == 0); //(void)std::ranges::make_heap(first, last, Less(&copies)); assert(copies == 0); diff --git a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp --- a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp +++ b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp @@ -123,8 +123,8 @@ (void)std::ranges::is_sorted_until(a, Less(), Proj(&copies)); assert(copies == 0); //if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(first, mid, last, Less(), Proj(&copies)); assert(copies == 0); } //if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(a, mid, Less(), Proj(&copies)); assert(copies == 0); } - //(void)std::ranges::lexicographical_compare(first, last, first2, last2, Less(), Proj(&copies), Proj(&copies)); assert(copies == 0); - //(void)std::ranges::lexicographical_compare(a, b, Less(), Proj(&copies), Proj(&copies)); assert(copies == 0); + (void)std::ranges::lexicographical_compare(first, last, first2, last2, Less(), Proj(&copies), Proj(&copies)); assert(copies == 0); + (void)std::ranges::lexicographical_compare(a, b, Less(), Proj(&copies), Proj(&copies)); assert(copies == 0); //(void)std::ranges::lower_bound(first, last, value, Less(), Proj(&copies)); assert(copies == 0); //(void)std::ranges::lower_bound(a, value, Less(), Proj(&copies)); assert(copies == 0); //(void)std::ranges::make_heap(first, last, Less(), Proj(&copies)); assert(copies == 0); diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -126,6 +126,7 @@ #include <__algorithm/ranges_is_partitioned.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_partitioned.h'}} #include <__algorithm/ranges_is_sorted.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_sorted.h'}} #include <__algorithm/ranges_is_sorted_until.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_sorted_until.h'}} +#include <__algorithm/ranges_lexicographical_compare.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_lexicographical_compare.h'}} #include <__algorithm/ranges_lower_bound.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_lower_bound.h'}} #include <__algorithm/ranges_max.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_max.h'}} #include <__algorithm/ranges_max_element.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_max_element.h'}} diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/ranges.lexicographical_compare.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/ranges.lexicographical_compare.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/ranges.lexicographical_compare.pass.cpp @@ -0,0 +1,243 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// template S1, input_iterator I2, sentinel_for S2, +// class Proj1 = identity, class Proj2 = identity, +// indirect_strict_weak_order, +// projected> Comp = ranges::less> +// constexpr bool +// ranges::lexicographical_compare(I1 first1, S1 last1, I2 first2, S2 last2, +// Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}); +// template, Proj1>, +// projected, Proj2>> Comp = ranges::less> +// constexpr bool +// ranges::lexicographical_compare(R1&& r1, R2&& r2, Comp comp = {}, +// Proj1 proj1 = {}, Proj2 proj2 = {}); + +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "boolean_testable.h" +#include "test_iterators.h" + +template +concept HasLexicographicalCompareIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { + std::ranges::lexicographical_compare(first1, last1, first2, last2); +}; + +template > +concept HasLexicographicalCompareR = requires(Range1 range1, Range2 range2) { + std::ranges::lexicographical_compare(range1, range2); +}; + +static_assert(HasLexicographicalCompareIt); +static_assert(!HasLexicographicalCompareIt); +static_assert(!HasLexicographicalCompareIt); +static_assert(!HasLexicographicalCompareIt); +static_assert(!HasLexicographicalCompareIt); +static_assert(!HasLexicographicalCompareIt); +static_assert(!HasLexicographicalCompareIt); +static_assert(!HasLexicographicalCompareIt); +static_assert(!HasLexicographicalCompareIt); +static_assert(!HasLexicographicalCompareIt); +static_assert(!HasLexicographicalCompareIt); +static_assert(!HasLexicographicalCompareIt); // not indirect_strict_weak_order + +static_assert(HasLexicographicalCompareR>); +static_assert(!HasLexicographicalCompareR); +static_assert(!HasLexicographicalCompareR); +static_assert(!HasLexicographicalCompareR); +static_assert(!HasLexicographicalCompareR); +static_assert(!HasLexicographicalCompareR); +static_assert(!HasLexicographicalCompareR, InputRangeNotDerivedFrom>); +static_assert(!HasLexicographicalCompareR, InputRangeNotIndirectlyReadable>); +static_assert(!HasLexicographicalCompareR, InputRangeNotInputOrOutputIterator>); +static_assert(!HasLexicographicalCompareR, InputRangeNotSentinelSemiregular>); +static_assert(!HasLexicographicalCompareR, InputRangeNotSentinelEqualityComparableWith>); +static_assert(!HasLexicographicalCompareIt, UncheckedRange>); // not indirect_strict_weak_order + +template +struct Data { + std::array input1; + std::array input2; + bool expected; +}; + +template +constexpr void test(Data d) { + { + std::same_as decltype(auto) ret = + std::ranges::lexicographical_compare(Iter1(d.input1.data()), Sent1(Iter1(d.input1.data() + d.input1.size())), + Iter2(d.input2.data()), Sent2(Iter2(d.input2.data() + d.input2.size()))); + assert(ret == d.expected); + } + { + auto range1 = std::ranges::subrange(Iter1(d.input1.data()), Sent1(Iter1(d.input1.data() + d.input1.size()))); + auto range2 = std::ranges::subrange(Iter2(d.input2.data()), Sent2(Iter2(d.input2.data() + d.input2.size()))); + std::same_as decltype(auto) ret = + std::ranges::lexicographical_compare(range1, range2); + assert(ret == d.expected); + } +} + +template +constexpr void test_iterators() { + // simple test + test({.input1 = {1, 2}, .input2 = {1, 2, 3, 4}, .expected = true}); + // ranges are identical + test({.input1 = {1, 2, 3, 4}, .input2 = {1, 2, 3, 4}, .expected = false}); + // first range is empty + test({.input1 = {}, .input2 = {1, 2, 3, 4}, .expected = true}); + // second range is empty + test({.input1 = {1, 2, 3, 4}, .input2 = {}, .expected = false}); + // both ranges are empty + test({.input1 = {}, .input2 = {}, .expected = false}); + // the first range compares less; first range is smaller + test({.input1 = {1, 2, 3}, .input2 = {1, 2, 4, 5, 6}, .expected = true}); + // the second range compares less; first range is smaller + test({.input1 = {1, 2, 4}, .input2 = {1, 2, 3, 4, 5}, .expected = false}); + // the first range compares less; second range is smaller + test({.input1 = {1, 2, 3, 4, 5}, .input2 = {1, 2, 4}, .expected = true}); + // the second range compares less; second range is smaller + test({.input1 = {1, 2, 4, 5, 6}, .input2 = {1, 2, 3}, .expected = false}); +} + +template +constexpr void test_iterators2() { + test_iterators, sentinel_wrapper>>(); + test_iterators, sentinel_wrapper>>(); + test_iterators>(); + test_iterators>(); + test_iterators>(); + test_iterators>(); + test_iterators(); + test_iterators(); +} + +constexpr bool test() { + test_iterators2, sentinel_wrapper>>(); + test_iterators2, sentinel_wrapper>>(); + test_iterators2>(); + test_iterators2>(); + test_iterators2>(); + test_iterators2>(); + test_iterators2(); + test_iterators2(); + + { // check that custom projections and the comparator are used properly + { + int a[] = {3, 4, 5, 6}; + int b[] = {24, 33, 42, 51}; + + auto ret = std::ranges::lexicographical_compare(std::begin(a), std::end(a), + std::begin(b), std::end(b), + [](int lhs, int rhs) { return lhs == rhs + 5; }, + [](int v) { return v - 2; }, + [](int v) { return v / 3; }); + assert(!ret); + } + { + int a[] = {3, 4, 5, 6}; + int b[] = {24, 33, 42, 51}; + + auto ret = std::ranges::lexicographical_compare(a, b, + [](int lhs, int rhs) { return lhs == rhs + 5; }, + [](int v) { return v - 2; }, + [](int v) { return v / 3; }); + assert(!ret); + } + } + + { // check that std::invoke is used + struct S { + constexpr S(int i_) : i(i_) {} + constexpr bool compare(const S& j) const { return j.i < i; } + constexpr const S& identity() const { return *this; } + int i; + }; + { + S a[] = {1, 2, 3, 4}; + auto ret = std::ranges::lexicographical_compare(std::begin(a), std::end(a), + std::begin(a), std::end(a), + &S::compare, + &S::identity, + &S::identity); + assert(!ret); + } + { + S a[] = {1, 2, 3, 4}; + auto ret = std::ranges::lexicographical_compare(a, a, &S::compare, &S::identity, &S::identity); + assert(!ret); + } + } + + { // check that the implicit conversion to bool works + { + int a[] = {1, 2, 3, 4}; + auto ret = std::ranges::lexicographical_compare(std::begin(a), std::end(a), + std::begin(a), std::end(a), + [](int i, int j) { return BooleanTestable{i < j}; }); + assert(!ret); + } + { + int a[] = {1, 2, 3, 4}; + auto ret = std::ranges::lexicographical_compare(a, a, [](int i, int j) { return BooleanTestable{i < j}; }); + assert(!ret); + } + } + + { // check that the complexity requirements are met + { + int predCount = 0; + auto pred = [&](int i, int j) { ++predCount; return i < j; }; + auto proj1Count = 0; + auto proj1 = [&](int i) { ++proj1Count; return i; }; + auto proj2Count = 0; + auto proj2 = [&](int i) { ++proj2Count; return i; }; + int a[] = {1, 2, 3, 4, 5}; + auto ret = std::ranges::lexicographical_compare(std::begin(a), std::end(a), std::begin(a), std::end(a), pred, proj1, proj2); + assert(!ret); + assert(predCount == 10); + assert(proj1Count == 10); + assert(proj2Count == 10); + } + { + int predCount = 0; + auto pred = [&](int i, int j) { ++predCount; return i < j; }; + auto proj1Count = 0; + auto proj1 = [&](int i) { ++proj1Count; return i; }; + auto proj2Count = 0; + auto proj2 = [&](int i) { ++proj2Count; return i; }; + int a[] = {1, 2, 3, 4, 5}; + auto ret = std::ranges::lexicographical_compare(a, a, pred, proj1, proj2); + assert(!ret); + assert(predCount == 10); + assert(proj1Count == 10); + assert(proj2Count == 10); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp b/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp --- a/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp +++ b/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp @@ -93,7 +93,7 @@ //static_assert(test(std::ranges::is_permutation, a, a)); static_assert(test(std::ranges::is_sorted, a)); static_assert(test(std::ranges::is_sorted_until, a)); -//static_assert(test(std::ranges::lexicographical_compare, a, a)); +static_assert(test(std::ranges::lexicographical_compare, a, a)); static_assert(test(std::ranges::lower_bound, a, 42)); //static_assert(test(std::ranges::make_heap, a)); static_assert(test(std::ranges::max, a)); diff --git a/libcxx/test/support/boolean_testable.h b/libcxx/test/support/boolean_testable.h --- a/libcxx/test/support/boolean_testable.h +++ b/libcxx/test/support/boolean_testable.h @@ -9,6 +9,8 @@ #ifndef LIBCXX_TEST_SUPPORT_BOOLEAN_TESTABLE_H #define LIBCXX_TEST_SUPPORT_BOOLEAN_TESTABLE_H +#include "test_macros.h" + #if TEST_STD_VER > 17 class BooleanTestable {