diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv --- a/libcxx/docs/Status/RangesPaper.csv +++ b/libcxx/docs/Status/RangesPaper.csv @@ -63,7 +63,7 @@ | indirectly_copyable_storable",[iterator.concepts],Zoe Carver,In progress [common.alg.req]: pt. 2,indirectly_swappable,"| [iterator.concepts] | [iterator.cust.swap]",Zoe Carver,✅ -[common.alg.req]: pt. 3,indirectly_comparable,[projected],Louis Dionne,Not started +[common.alg.req]: pt. 3,indirectly_comparable,[projected],Nikolas Klauser,✅ [common.alg.req]: pt. 4,"| permutable | mergeable | sortable",[iterator.concepts],Unassigned,Not started diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -215,6 +215,7 @@ __iterator/erase_if_container.h __iterator/front_insert_iterator.h __iterator/incrementable_traits.h + __iterator/indirectly_comparable.h __iterator/insert_iterator.h __iterator/istream_iterator.h __iterator/istreambuf_iterator.h diff --git a/libcxx/include/__iterator/indirectly_comparable.h b/libcxx/include/__iterator/indirectly_comparable.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__iterator/indirectly_comparable.h @@ -0,0 +1,30 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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___ITERATOR_INDIRECTLY_COMPARABLE_H +#define _LIBCPP___ITERATOR_INDIRECTLY_COMPARABLE_H + +#include <__config> +#include <__functional/identity.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#ifndef _LIBCPP_HAS_NO_RANGES + +template +concept indirectly_comparable = + indirect_binary_predicate<_Rp, projected<_I1, _P1>, projected<_I2, _P2>>; + +#endif // _LIBCPP_HAS_NO_RANGES + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_INDIRECTLY_COMPARABLE_H diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -140,6 +140,11 @@ template concept indirectly_swappable = see below; // since C++20 +template + concept indirectly_comparable = + indirect_binary_predicate, projected>; // since C++20 + template S> requires (!same_as && copyable) class common_iterator; // since C++20 @@ -593,6 +598,7 @@ #include <__iterator/erase_if_container.h> #include <__iterator/front_insert_iterator.h> #include <__iterator/incrementable_traits.h> +#include <__iterator/indirectly_comparable.h> #include <__iterator/insert_iterator.h> #include <__iterator/istreambuf_iterator.h> #include <__iterator/istream_iterator.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -594,6 +594,7 @@ module erase_if_container { private header "__iterator/erase_if_container.h" } module front_insert_iterator { private header "__iterator/front_insert_iterator.h" } module incrementable_traits { private header "__iterator/incrementable_traits.h" } + module indirectly_comparable { private header "__iterator/indirectly_comparable.h" } module insert_iterator { private header "__iterator/insert_iterator.h" } module istream_iterator { private header "__iterator/istream_iterator.h" } module istreambuf_iterator { private header "__iterator/istreambuf_iterator.h" } diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/iterator/indirectly_comparable.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/iterator/indirectly_comparable.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/iterator/indirectly_comparable.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__iterator/indirectly_comparable.h'}} +#include <__iterator/indirectly_comparable.h> diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_comparable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_comparable.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_comparable.compile.pass.cpp @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts + +// template +// concept indirectly_­comparable; + +#include +#include +#include + +struct Deref { + int operator()(int*) const; +}; + +static_assert(!std::indirectly_comparable>); // not dereferenceable +static_assert(!std::indirectly_comparable); // not a predicate +static_assert( std::indirectly_comparable>); +static_assert(!std::indirectly_comparable>); +static_assert( std::indirectly_comparable, Deref>); +static_assert(!std::indirectly_comparable, Deref, Deref>); +static_assert(!std::indirectly_comparable, std::identity, Deref>); +static_assert( std::indirectly_comparable, std::identity, Deref>); + +template + requires std::indirectly_comparable + && true // This true is an additional atomic constraint as a tie breaker +constexpr bool subsumes(F) { return true; } + +template + requires std::indirect_binary_predicate, std::projected> +void subsumes(F); + +template + requires std::indirect_binary_predicate, std::projected> + && true // This true is an additional atomic constraint as a tie breaker +constexpr bool is_subsumed(F) { return true; } + +template + requires std::indirectly_comparable +void is_subsumed(F); + +static_assert(subsumes(std::less())); +static_assert(is_subsumed(std::less()));