diff --git a/libcxx/docs/OneRangesProposalStatus.csv b/libcxx/docs/OneRangesProposalStatus.csv --- a/libcxx/docs/OneRangesProposalStatus.csv +++ b/libcxx/docs/OneRangesProposalStatus.csv @@ -17,8 +17,8 @@ input_iterator: `D100271 `_ forward_iterator: `D100275 `_ bidirectional_iterator: `D100278 `_", -[indirectcallable.indirectinvocable],"indirectly_unary_invocable, indirectly_regular_unary_invocable, indirectly_unary_predicate, indirectly_binary_predicate, indirectly_equivalence_relation, and indirectly_strict_weak_order.","[concepts], [readable.traits]: iter_value_t, [iterator.traits]",,, -[projected],,[iterator.concepts],,, +[indirectcallable.indirectinvocable],"indirectly_unary_invocable, indirectly_regular_unary_invocable, indirectly_unary_predicate, indirectly_binary_predicate, indirectly_equivalence_relation, and indirectly_strict_weak_order.","[concepts], [readable.traits]: iter_value_t, [iterator.traits]",,,In progress +[projected],,[iterator.concepts],,,✅ [common.alg.req]: pt. 1,"indirectly_movable, indirectly_movable_storable, indirectly_copyable, and indirectly_copyable_storable.",[iterator.concepts],,, [common.alg.req]: pt. 2,indirectly_swappable,"[iterator.concepts], [iterator.cust.swap]",,, [common.alg.req]: pt. 3,indirectly_comparable,[projected],,, diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -13,6 +13,7 @@ __hash_table __iterator/concepts.h __iterator/incrementable_traits.h + __iterator/indirect_callable.h __iterator/iter_move.h __iterator/iterator_traits.h __iterator/readable_traits.h diff --git a/libcxx/include/__iterator/concepts.h b/libcxx/include/__iterator/concepts.h --- a/libcxx/include/__iterator/concepts.h +++ b/libcxx/include/__iterator/concepts.h @@ -16,6 +16,7 @@ #include <__iterator/incrementable_traits.h> #include <__iterator/iterator_traits.h> #include <__iterator/readable_traits.h> +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -47,6 +48,9 @@ template concept indirectly_readable = __indirectly_readable_impl >; +template +using iter_common_reference_t = common_reference_t, iter_value_t<_Tp>&>; + // [iterator.concept.writable] template concept indirectly_writable = diff --git a/libcxx/include/__iterator/indirect_callable.h b/libcxx/include/__iterator/indirect_callable.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__iterator/indirect_callable.h @@ -0,0 +1,78 @@ +// -*- 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_INDIRECT_CALLABLE_H +#define _LIBCPP___ITERATOR_INDIRECT_CALLABLE_H + +#include <__config> +#include +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// clang-format off + +#if !defined(_LIBCPP_HAS_NO_RANGES) + +// [indirectcallable.indirectinvocable], indirect callables +template +concept indirectly_unary_invocable = + indirectly_readable && + copy_constructible && + invocable&> && + invocable > && + invocable > && + common_reference_with< + invoke_result_t&>, + invoke_result_t >>; + +template +concept indirectly_regular_unary_invocable = + indirectly_readable && + copy_constructible && + regular_invocable&> && + regular_invocable > && + regular_invocable > && + common_reference_with< + invoke_result_t&>, + invoke_result_t >>; + +template +requires (indirectly_readable && ...) && invocable...> +using indirect_result_t = invoke_result_t...>; + +// [projected], projected +template Proj> +struct projected { + using value_type = remove_cvref_t >; + indirect_result_t operator*() const; // not defined +}; + +template +struct incrementable_traits > { + using difference_type = iter_difference_t; +}; + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +// clang-format on + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_INDIRECT_CALLABLE_H diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -46,7 +46,11 @@ // [iterator.concepts], iterator concepts // [iterator.concept.readable], concept indirectly_readable template - concept indirectly_readable = see below; // since C++20 + concept indirectly_readable = see below; // since C++20 + +template + using iter_common_reference_t = + common_reference_t, iter_value_t&>; // since C++20 // [iterator.concept.writable], concept indirectly_writable template @@ -68,6 +72,25 @@ template concept sentinel_for = see below; // since C++20 +// [indirectcallable] +// [indirectcallable.indirectinvocable] +template + concept indirectly_unary_invocable = see below; // since C++20 + +template + concept indirectly_regular_unary_invocable = see below; // since C++20 + +template + requires (indirectly_readable && ...) && invocable...> + using indirect_result_t = invoke_result_t...>; // since C++20 + +// [projected], projected +template Proj> + struct projected; // since C++20 + +template Proj> + struct incrementable_traits>; // since C++20 + template struct iterator @@ -456,6 +479,7 @@ #include #include <__iterator/concepts.h> #include <__iterator/incrementable_traits.h> +#include <__iterator/indirect_callable.h> #include <__iterator/iter_move.h> #include <__iterator/iterator_traits.h> #include <__iterator/readable_traits.h> diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectcallable.indirectinvocable/indirect_result_t.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectcallable.indirectinvocable/indirect_result_t.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectcallable.indirectinvocable/indirect_result_t.compile.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: gcc-10 +// XFAIL: msvc && clang + +// indirect_result_t + +#include + +#include + +static_assert(std::same_as, int>); +static_assert(std::same_as, double>); + +struct S {}; +static_assert(std::same_as, S>); +static_assert(std::same_as, long&>); +static_assert(std::same_as, S&&>); +static_assert(std::same_as, int S::*>); + +template +constexpr bool no_indirect_result = !requires { + typename std::indirect_result_t; +}; + +static_assert(no_indirect_result); // `int` isn't `indirectly_readable` +static_assert(no_indirect_result); // `int` isn't `invocable` diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectcallable.indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectcallable.indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectcallable.indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: gcc-10 +// XFAIL: msvc && clang + +// template +// concept indirectly_unary_invocable; + +#include + +#include + +#include "indirectly_invocable.h" + +template +[[nodiscard]] consteval bool check_indirectly_unary_invocable() { + constexpr auto result = std::indirectly_unary_invocable; + static_assert(std::indirectly_unary_invocable == result); + return result; +} + +static_assert(check_indirectly_unary_invocable, indirectly_readable>()); +static_assert(check_indirectly_unary_invocable()); +static_assert(check_indirectly_unary_invocable()); +static_assert(check_indirectly_unary_invocable()); +static_assert(check_indirectly_unary_invocable()); +static_assert(check_indirectly_unary_invocable()); +static_assert(check_indirectly_unary_invocable()); +static_assert(check_indirectly_unary_invocable()); + +static_assert(!check_indirectly_unary_invocable()); // not move constructible +static_assert(!check_indirectly_unary_invocable()); +static_assert(!check_indirectly_unary_invocable()); +static_assert(!check_indirectly_unary_invocable()); +static_assert(!check_indirectly_unary_invocable()); +static_assert(!check_indirectly_unary_invocable()); +static_assert(!check_indirectly_unary_invocable()); + +static_assert( + !check_indirectly_unary_invocable, indirectly_readable>()); +static_assert( + !check_indirectly_unary_invocable, indirectly_readable>()); +static_assert( + !check_indirectly_unary_invocable, indirectly_readable>()); +static_assert( + !check_indirectly_unary_invocable, indirectly_readable>()); +static_assert(!check_indirectly_unary_invocable, + indirectly_readable>()); +static_assert(!check_indirectly_unary_invocable, + indirectly_readable>()); +static_assert(!check_indirectly_unary_invocable, + indirectly_readable>()); +static_assert(!check_indirectly_unary_invocable, indirectly_readable>()); diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectcallable.indirectinvocable/indirectly_unary_invocable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectcallable.indirectinvocable/indirectly_unary_invocable.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectcallable.indirectinvocable/indirectly_unary_invocable.compile.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: gcc-10 +// XFAIL: msvc && clang + +// template +// concept indirectly_regular_unary_invocable; + +#include + +#include + +#include "indirectly_invocable.h" + +template +[[nodiscard]] consteval bool check_indirectly_regular_unary_invocable() { + constexpr auto result = std::indirectly_regular_unary_invocable; + static_assert(std::indirectly_regular_unary_invocable == result); + return result; +} + +static_assert( + check_indirectly_regular_unary_invocable, indirectly_readable>()); +static_assert(check_indirectly_regular_unary_invocable()); +static_assert(check_indirectly_regular_unary_invocable()); +static_assert(check_indirectly_regular_unary_invocable()); +static_assert(check_indirectly_regular_unary_invocable()); +static_assert(check_indirectly_regular_unary_invocable()); +static_assert(check_indirectly_regular_unary_invocable()); +static_assert(check_indirectly_regular_unary_invocable()); + +static_assert(!check_indirectly_regular_unary_invocable()); // not move constructible +static_assert(!check_indirectly_regular_unary_invocable()); +static_assert(!check_indirectly_regular_unary_invocable()); +static_assert(!check_indirectly_regular_unary_invocable()); +static_assert(!check_indirectly_regular_unary_invocable()); +static_assert(!check_indirectly_regular_unary_invocable()); +static_assert(!check_indirectly_regular_unary_invocable()); + +static_assert(!check_indirectly_regular_unary_invocable, + indirectly_readable>()); +static_assert(!check_indirectly_regular_unary_invocable, + indirectly_readable>()); +static_assert(!check_indirectly_regular_unary_invocable, + indirectly_readable>()); +static_assert(!check_indirectly_regular_unary_invocable, + indirectly_readable>()); +static_assert(!check_indirectly_regular_unary_invocable, + indirectly_readable>()); +static_assert(!check_indirectly_regular_unary_invocable, + indirectly_readable>()); +static_assert(!check_indirectly_regular_unary_invocable< + rvalue_invocable_from_iter_common_reference, indirectly_readable>()); +static_assert( + !check_indirectly_regular_unary_invocable, indirectly_readable>()); diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectcallable.indirectinvocable/subsumption.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectcallable.indirectinvocable/subsumption.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectcallable.indirectinvocable/subsumption.compile.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: gcc-10 +// XFAIL: msvc && clang + +// template +// concept indirectly_unary_invocable; + +// template +// concept indirectly_regular_unary_invocable; + +#include + +// clang-format off + +template +requires std::indirectly_readable && + std::copy_constructible && + std::invocable&> && + std::invocable > && + std::invocable > && + std::common_reference_with< + std::invoke_result_t&>, + std::invoke_result_t >> +[[nodiscard]] consteval bool check_indirectly_unary_invocable() { + return false; +} + +template F> +requires true +[[nodiscard]] consteval bool check_indirectly_unary_invocable() { + return true; +} + +// clang-format on + +struct S {}; + +static_assert(check_indirectly_unary_invocable()); + +// clang-format off + +template +requires std::indirectly_readable && + std::copy_constructible && + std::regular_invocable&> && + std::regular_invocable > && + std::regular_invocable > && + std::common_reference_with< + std::invoke_result_t&>, + std::invoke_result_t >> +[[nodiscard]] consteval bool check_regular_indirectly_unary_invocable() { + return false; +} + +template F> +requires true +[[nodiscard]] consteval bool check_indirectly_regular_unary_invocable() { + return true; +} + +// clang-format on + +static_assert(check_indirectly_regular_unary_invocable()); diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/projected/projected.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/projected/projected.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/projected/projected.compile.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: gcc-10 +// XFAIL: msvc && clang + +// projected + +#include + +#include +#include + +#include "test_iterators.h" + +using projected_int_ptr = std::projected; +static_assert(std::same_as); +static_assert(std::same_as()), int const&>); +static_assert(std::same_as, std::ptrdiff_t>); + +struct S {}; + +using projected_input_iterator = std::projected, int S::*>; +static_assert(std::same_as); +static_assert(std::same_as()), int&>); +static_assert(std::same_as, std::ptrdiff_t>); + +using projected_forward_iterator = std::projected, int (S::*)()>; +static_assert(std::same_as); +static_assert(std::same_as()), int>); +static_assert(std::same_as, std::ptrdiff_t>); + +using projected_bidirectional_iterator = std::projected, S* (S::*)() const>; +static_assert(std::same_as); +static_assert(std::same_as()), S*>); +static_assert(std::same_as, std::ptrdiff_t>); + +using projected_random_access_iterator = std::projected, S && (S::*)() volatile>; +static_assert(std::same_as); +static_assert(std::same_as()), S&&>); +static_assert(std::same_as, std::ptrdiff_t>); + +using projected_contiguous_iterator = std::projected, S& (S::*)() const volatile>; +static_assert(std::same_as); +static_assert(std::same_as()), S&>); +static_assert(std::same_as, std::ptrdiff_t>); + +template +constexpr bool not_projectable = !requires { + typename std::projected; +}; + +static_assert(not_projectable); // `int` isn't `indirectly_readable` +static_assert(not_projectable); // `S` isn't `weakly_incrementable` +static_assert(not_projectable); // `void(int)` doesn't satisfy `indirectly_regular_unary_invcable` diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/iter_common_reference_t.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/iter_common_reference_t.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/iter_common_reference_t.compile.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: gcc-10 +// XFAIL: msvc && clang + +// iter_common_reference_t + +#include + +#include + +struct value_reference_same { + using value_type = int; + int operator*() const; +}; +static_assert(std::same_as, int>); + +struct value_reference_same_without_qualifiers { + using value_type = double; + double& operator*() const; +}; +static_assert(std::same_as, double&>); + +struct S { + explicit(false) S(int); +}; + +namespace std { +template