diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -17,10 +17,12 @@ __iterator/advance.h __iterator/concepts.h __iterator/incrementable_traits.h + __iterator/indirect_concepts.h __iterator/iter_move.h __iterator/iterator_traits.h __iterator/next.h __iterator/prev.h + __iterator/projected.h __iterator/readable_traits.h __libcpp_version __locale 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 @@ -17,6 +17,7 @@ #include <__iterator/readable_traits.h> #include <__memory/pointer_traits.h> #include +#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -48,6 +49,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_concepts.h b/libcxx/include/__iterator/indirect_concepts.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__iterator/indirect_concepts.h @@ -0,0 +1,99 @@ +// -*- 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_CONCEPTS_H +#define _LIBCPP___ITERATOR_INDIRECT_CONCEPTS_H + +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if !defined(_LIBCPP_HAS_NO_RANGES) + +template +concept indirectly_unary_invocable = + indirectly_readable<_It> && + copy_constructible<_Fp> && + invocable<_Fp&, iter_value_t<_It>&> && + invocable<_Fp&, iter_reference_t<_It>> && + invocable<_Fp&, iter_common_reference_t<_It>> && + common_reference_with< + invoke_result_t<_Fp&, iter_value_t<_It>&>, + invoke_result_t<_Fp&, iter_reference_t<_It>>>; + +template +concept indirectly_regular_unary_invocable = + indirectly_readable<_It> && + copy_constructible<_Fp> && + regular_invocable<_Fp&, iter_value_t<_It>&> && + regular_invocable<_Fp&, iter_reference_t<_It>> && + regular_invocable<_Fp&, iter_common_reference_t<_It>> && + common_reference_with< + invoke_result_t<_Fp&, iter_value_t<_It>&>, + invoke_result_t<_Fp&, iter_reference_t<_It>>>; + +template +concept indirect_unary_predicate = + indirectly_readable<_It> && + copy_constructible<_Fp> && + predicate<_Fp&, iter_value_t<_It>&> && + predicate<_Fp&, iter_reference_t<_It>> && + predicate<_Fp&, iter_common_reference_t<_It>>; + +template +concept indirect_binary_predicate = + indirectly_readable<_It1> && indirectly_readable<_It2> && + copy_constructible<_Fp> && + predicate<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> && + predicate<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> && + predicate<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> && + predicate<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> && + predicate<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>; + +template +concept indirect_equivalence_relation = + indirectly_readable<_It1> && indirectly_readable<_It2> && + copy_constructible<_Fp> && + equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> && + equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> && + equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> && + equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> && + equivalence_relation<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>; + +template +concept indirect_strict_weak_order = + indirectly_readable<_It1> && indirectly_readable<_It2> && + copy_constructible<_Fp> && + strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> && + strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> && + strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> && + strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> && + strict_weak_order<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>; + +template + requires (indirectly_readable<_Its> && ...) && invocable<_Fp, iter_reference_t<_Its>...> +using indirect_result_t = invoke_result_t<_Fp, iter_reference_t<_Its>...>; + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_INDIRECT_CONCEPTS_H diff --git a/libcxx/include/__iterator/projected.h b/libcxx/include/__iterator/projected.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__iterator/projected.h @@ -0,0 +1,46 @@ +// -*- 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_PROJECTED_H +#define _LIBCPP___ITERATOR_PROJECTED_H + +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/indirect_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 + +#if !defined(_LIBCPP_HAS_NO_RANGES) + +template _Proj> +struct projected { + using value_type = remove_cvref_t>; + indirect_result_t<_Proj&, _It> operator*() const; // not defined +}; + +template +struct incrementable_traits> { + using difference_type = iter_difference_t<_It>; +}; + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_PROJECTED_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 @@ -91,6 +95,36 @@ template concept random_access_iterator = 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 + concept indirect_unary_predicate = see below; // since C++20 + +template + concept indirect_binary_predicate = see below; // since C++20 + +template + concept indirect_equivalence_relation = see below; // since C++20 + +template + concept indirect_strict_weak_order = see below; // since C++20 + +template + using indirect_result_t = see below; // since C++20 + +// [projected], projected +template Proj> + struct projected; // since C++20 + +template Proj> + struct incrementable_traits>; // since C++20 + template struct iterator // deprecated in C++17 @@ -486,10 +520,12 @@ #include <__iterator/advance.h> #include <__iterator/concepts.h> #include <__iterator/incrementable_traits.h> +#include <__iterator/indirect_concepts.h> #include <__iterator/iter_move.h> #include <__iterator/iterator_traits.h> #include <__iterator/next.h> #include <__iterator/prev.h> +#include <__iterator/projected.h> #include <__iterator/readable_traits.h> #include <__memory/addressof.h> #include <__memory/pointer_traits.h> diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// concept indirect_binary_predicate; + +#include +#include + +#include "indirectly_readable.h" + +using It1 = IndirectlyReadable; +using It2 = IndirectlyReadable; + +template +struct GoodPredicate { + bool operator()(std::iter_value_t&, std::iter_value_t&) const; + bool operator()(std::iter_value_t&, std::iter_reference_t) const; + bool operator()(std::iter_reference_t, std::iter_value_t&) const; + bool operator()(std::iter_reference_t, std::iter_reference_t) const; + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const; +}; + +// Should work when all constraints are satisfied +static_assert(std::indirect_binary_predicate, It1, It2>); +static_assert(std::indirect_binary_predicate); +[[maybe_unused]] auto lambda = [](int i, int j) { return i < j; }; +static_assert(std::indirect_binary_predicate); + +// Should fail when either of the iterators is not indirectly_readable +struct NotIndirectlyReadable { }; +static_assert(!std::indirect_binary_predicate, It1, NotIndirectlyReadable>); +static_assert(!std::indirect_binary_predicate, NotIndirectlyReadable, It2>); + +// Should fail when the predicate is not copy constructible +struct BadPredicate1 { + BadPredicate1(BadPredicate1 const&) = delete; + template bool operator()(T const&, U const&) const; +}; +static_assert(!std::indirect_binary_predicate); + +// Should fail when the predicate can't be called with (iter_value_t&, iter_value_t&) +struct BadPredicate2 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_value_t&, std::iter_value_t&) const = delete; +}; +static_assert(!std::indirect_binary_predicate); + +// Should fail when the predicate can't be called with (iter_value_t&, iter_reference_t) +struct BadPredicate3 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_value_t&, std::iter_reference_t) const = delete; +}; +static_assert(!std::indirect_binary_predicate); + +// Should fail when the predicate can't be called with (iter_reference_t, iter_value_t&) +struct BadPredicate4 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_reference_t, std::iter_value_t&) const = delete; +}; +static_assert(!std::indirect_binary_predicate); + +// Should fail when the predicate can't be called with (iter_reference_t, iter_reference_t) +struct BadPredicate5 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_reference_t, std::iter_reference_t) const = delete; +}; +static_assert(!std::indirect_binary_predicate); + +// Should fail when the predicate can't be called with (iter_common_reference_t, iter_common_reference_t) +struct BadPredicate6 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const = delete; +}; +static_assert(!std::indirect_binary_predicate); diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp @@ -0,0 +1,99 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// concept indirect_equivalence_relation; + +#include +#include + +#include "indirectly_readable.h" + +using It1 = IndirectlyReadable; +using It2 = IndirectlyReadable; + +template +struct GoodRelation { + bool operator()(std::iter_value_t&, std::iter_value_t&) const; + bool operator()(std::iter_value_t&, std::iter_value_t&) const; + bool operator()(std::iter_value_t&, std::iter_value_t&) const; + bool operator()(std::iter_value_t&, std::iter_value_t&) const; + + bool operator()(std::iter_value_t&, std::iter_reference_t) const; + bool operator()(std::iter_reference_t, std::iter_value_t&) const; + bool operator()(std::iter_reference_t, std::iter_reference_t) const; + + bool operator()(std::iter_reference_t, std::iter_value_t&) const; + bool operator()(std::iter_value_t&, std::iter_reference_t) const; + bool operator()(std::iter_reference_t, std::iter_reference_t) const; + + bool operator()(std::iter_reference_t, std::iter_reference_t) const; + bool operator()(std::iter_reference_t, std::iter_reference_t) const; + + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const; + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const; + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const; + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const; +}; + +// Should work when all constraints are satisfied +static_assert(std::indirect_equivalence_relation, It1, It2>); +static_assert(std::indirect_equivalence_relation); +[[maybe_unused]] auto lambda = [](int i, long j) { return i == j; }; +static_assert(std::indirect_equivalence_relation); + +// Should fail when either of the iterators is not indirectly_readable +struct NotIndirectlyReadable { }; +static_assert(!std::indirect_equivalence_relation, It1, NotIndirectlyReadable>); +static_assert(!std::indirect_equivalence_relation, NotIndirectlyReadable, It2>); + +// Should fail when the function is not copy constructible +struct BadRelation1 { + BadRelation1(BadRelation1 const&) = delete; + template bool operator()(T const&, U const&) const; +}; +static_assert(!std::indirect_equivalence_relation); + +// Should fail when the function can't be called with (iter_value_t&, iter_value_t&) +struct BadRelation2 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_value_t&, std::iter_value_t&) const = delete; +}; +static_assert(!std::indirect_equivalence_relation); + +// Should fail when the function can't be called with (iter_value_t&, iter_reference_t) +struct BadRelation3 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_value_t&, std::iter_reference_t) const = delete; +}; +static_assert(!std::indirect_equivalence_relation); + +// Should fail when the function can't be called with (iter_reference_t, iter_value_t&) +struct BadRelation4 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_reference_t, std::iter_value_t&) const = delete; +}; +static_assert(!std::indirect_equivalence_relation); + +// Should fail when the function can't be called with (iter_reference_t, iter_reference_t) +struct BadRelation5 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_reference_t, std::iter_reference_t) const = delete; +}; +static_assert(!std::indirect_equivalence_relation); + +// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t) +struct BadRelation6 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const = delete; +}; +static_assert(!std::indirect_equivalence_relation); diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_result_t.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_result_t.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_result_t.compile.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// 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 has_indirect_result = requires { + typename std::indirect_result_t; +}; + +static_assert(!has_indirect_result); // int isn't indirectly_readable +static_assert(!has_indirect_result); // int isn't invocable diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp @@ -0,0 +1,99 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// concept indirect_strict_weak_order; + +#include +#include + +#include "indirectly_readable.h" + +using It1 = IndirectlyReadable; +using It2 = IndirectlyReadable; + +template +struct GoodOrder { + bool operator()(std::iter_value_t&, std::iter_value_t&) const; + bool operator()(std::iter_value_t&, std::iter_value_t&) const; + bool operator()(std::iter_value_t&, std::iter_value_t&) const; + bool operator()(std::iter_value_t&, std::iter_value_t&) const; + + bool operator()(std::iter_value_t&, std::iter_reference_t) const; + bool operator()(std::iter_reference_t, std::iter_value_t&) const; + bool operator()(std::iter_reference_t, std::iter_reference_t) const; + + bool operator()(std::iter_reference_t, std::iter_value_t&) const; + bool operator()(std::iter_value_t&, std::iter_reference_t) const; + bool operator()(std::iter_reference_t, std::iter_reference_t) const; + + bool operator()(std::iter_reference_t, std::iter_reference_t) const; + bool operator()(std::iter_reference_t, std::iter_reference_t) const; + + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const; + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const; + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const; + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const; +}; + +// Should work when all constraints are satisfied +static_assert(std::indirect_strict_weak_order, It1, It2>); +static_assert(std::indirect_strict_weak_order); +[[maybe_unused]] auto lambda = [](int i, long j) { return i < j; }; +static_assert(std::indirect_strict_weak_order); + +// Should fail when either of the iterators is not indirectly_readable +struct NotIndirectlyReadable { }; +static_assert(!std::indirect_strict_weak_order, It1, NotIndirectlyReadable>); +static_assert(!std::indirect_strict_weak_order, NotIndirectlyReadable, It2>); + +// Should fail when the function is not copy constructible +struct BadOrder1 { + BadOrder1(BadOrder1 const&) = delete; + template bool operator()(T const&, U const&) const; +}; +static_assert(!std::indirect_strict_weak_order); + +// Should fail when the function can't be called with (iter_value_t&, iter_value_t&) +struct BadOrder2 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_value_t&, std::iter_value_t&) const = delete; +}; +static_assert(!std::indirect_strict_weak_order); + +// Should fail when the function can't be called with (iter_value_t&, iter_reference_t) +struct BadOrder3 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_value_t&, std::iter_reference_t) const = delete; +}; +static_assert(!std::indirect_strict_weak_order); + +// Should fail when the function can't be called with (iter_reference_t, iter_value_t&) +struct BadOrder4 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_reference_t, std::iter_value_t&) const = delete; +}; +static_assert(!std::indirect_strict_weak_order); + +// Should fail when the function can't be called with (iter_reference_t, iter_reference_t) +struct BadOrder5 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_reference_t, std::iter_reference_t) const = delete; +}; +static_assert(!std::indirect_strict_weak_order); + +// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t) +struct BadOrder6 { + template bool operator()(T const&, U const&) const; + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const = delete; +}; +static_assert(!std::indirect_strict_weak_order); diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// concept indirect_unary_predicate; + +#include +#include + +#include "indirectly_readable.h" + +using It = IndirectlyReadable; + +template +struct GoodPredicate { + bool operator()(std::iter_reference_t) const; + bool operator()(std::iter_value_t&) const; + bool operator()(std::iter_common_reference_t) const; +}; + +// Should work when all constraints are satisfied +static_assert(std::indirect_unary_predicate, It>); +static_assert(std::indirect_unary_predicate); +[[maybe_unused]] auto lambda = [](int i) { return i % 2 == 0; }; +static_assert(std::indirect_unary_predicate); + +// Should fail when the iterator is not indirectly_readable +struct NotIndirectlyReadable { }; +static_assert(!std::indirect_unary_predicate, NotIndirectlyReadable>); + +// Should fail when the predicate is not copy constructible +struct BadPredicate1 { + BadPredicate1(BadPredicate1 const&) = delete; + template bool operator()(T const&) const; +}; +static_assert(!std::indirect_unary_predicate); + +// Should fail when the predicate can't be called with std::iter_value_t& +struct BadPredicate2 { + template bool operator()(T const&) const; + bool operator()(std::iter_value_t&) const = delete; +}; +static_assert(!std::indirect_unary_predicate); + +// Should fail when the predicate can't be called with std::iter_reference_t +struct BadPredicate3 { + template bool operator()(T const&) const; + bool operator()(std::iter_reference_t) const = delete; +}; +static_assert(!std::indirect_unary_predicate); + +// Should fail when the predicate can't be called with std::iter_common_reference_t +struct BadPredicate4 { + template bool operator()(T const&) const; + bool operator()(std::iter_common_reference_t) const = delete; +}; +static_assert(!std::indirect_unary_predicate); diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// concept indirectly_regular_unary_invocable; + +#include +#include + +#include "indirectly_readable.h" + +using It = IndirectlyReadable; +using R1 = T1; +using R2 = T2; + +template +struct GoodInvocable { + R1 operator()(std::iter_value_t&) const; + R2 operator()(std::iter_reference_t) const; + R2 operator()(std::iter_common_reference_t) const; +}; + +// Should work when all constraints are satisfied +static_assert(std::indirectly_regular_unary_invocable, It>); + +// Should fail when the iterator is not indirectly_readable +struct NotIndirectlyReadable { }; +static_assert(!std::indirectly_regular_unary_invocable, NotIndirectlyReadable>); + +// Should fail when the invocable is not copy constructible +struct BadInvocable1 { + BadInvocable1(BadInvocable1 const&) = delete; + template R1 operator()(T const&) const; +}; +static_assert(!std::indirectly_regular_unary_invocable); + +// Should fail when the invocable can't be called with (iter_value_t&) +struct BadInvocable2 { + template R1 operator()(T const&) const; + R1 operator()(std::iter_value_t&) const = delete; +}; +static_assert(!std::indirectly_regular_unary_invocable); + +// Should fail when the invocable can't be called with (iter_reference_t) +struct BadInvocable3 { + template R1 operator()(T const&) const; + R1 operator()(std::iter_reference_t) const = delete; +}; +static_assert(!std::indirectly_regular_unary_invocable); + +// Should fail when the invocable can't be called with (iter_common_reference_t) +struct BadInvocable4 { + template R1 operator()(T const&) const; + R1 operator()(std::iter_common_reference_t) const = delete; +}; +static_assert(!std::indirectly_regular_unary_invocable); + +// Should fail when the invocable doesn't have a common reference between its return types +struct BadInvocable5 { + R1 operator()(std::iter_value_t&) const; + struct Unrelated { }; + Unrelated operator()(std::iter_reference_t) const; + R1 operator()(std::iter_common_reference_t) const; +}; +static_assert(!std::indirectly_regular_unary_invocable); + +// Various tests with callables +struct S; +static_assert(std::indirectly_regular_unary_invocable); +static_assert(std::indirectly_regular_unary_invocable); +static_assert(std::indirectly_regular_unary_invocable); +static_assert(std::indirectly_regular_unary_invocable); +static_assert(std::indirectly_regular_unary_invocable); +static_assert(std::indirectly_regular_unary_invocable); + +static_assert(!std::indirectly_regular_unary_invocable); // not move constructible +static_assert(!std::indirectly_regular_unary_invocable); +static_assert(!std::indirectly_regular_unary_invocable); +static_assert(!std::indirectly_regular_unary_invocable); +static_assert(!std::indirectly_regular_unary_invocable); diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// concept indirectly_unary_invocable; + +#include +#include + +#include "indirectly_readable.h" + +using It = IndirectlyReadable; +using R1 = T1; +using R2 = T2; + +template +struct GoodInvocable { + R1 operator()(std::iter_value_t&) const; + R2 operator()(std::iter_reference_t) const; + R2 operator()(std::iter_common_reference_t) const; +}; + +// Should work when all constraints are satisfied +static_assert(std::indirectly_unary_invocable, It>); + +// Should fail when the iterator is not indirectly_readable +struct NotIndirectlyReadable { }; +static_assert(!std::indirectly_unary_invocable, NotIndirectlyReadable>); + +// Should fail when the invocable is not copy constructible +struct BadInvocable1 { + BadInvocable1(BadInvocable1 const&) = delete; + template R1 operator()(T const&) const; +}; +static_assert(!std::indirectly_unary_invocable); + +// Should fail when the invocable can't be called with (iter_value_t&) +struct BadInvocable2 { + template R1 operator()(T const&) const; + R1 operator()(std::iter_value_t&) const = delete; +}; +static_assert(!std::indirectly_unary_invocable); + +// Should fail when the invocable can't be called with (iter_reference_t) +struct BadInvocable3 { + template R1 operator()(T const&) const; + R1 operator()(std::iter_reference_t) const = delete; +}; +static_assert(!std::indirectly_unary_invocable); + +// Should fail when the invocable can't be called with (iter_common_reference_t) +struct BadInvocable4 { + template R1 operator()(T const&) const; + R1 operator()(std::iter_common_reference_t) const = delete; +}; +static_assert(!std::indirectly_unary_invocable); + +// Should fail when the invocable doesn't have a common reference between its return types +struct BadInvocable5 { + R1 operator()(std::iter_value_t&) const; + struct Unrelated { }; + Unrelated operator()(std::iter_reference_t) const; + R1 operator()(std::iter_common_reference_t) const; +}; +static_assert(!std::indirectly_unary_invocable); + +// Various tests with callables +struct S; +static_assert(std::indirectly_unary_invocable); +static_assert(std::indirectly_unary_invocable); +static_assert(std::indirectly_unary_invocable); +static_assert(std::indirectly_unary_invocable); +static_assert(std::indirectly_unary_invocable); +static_assert(std::indirectly_unary_invocable); + +static_assert(!std::indirectly_unary_invocable); // not move constructible +static_assert(!std::indirectly_unary_invocable); +static_assert(!std::indirectly_unary_invocable); +static_assert(!std::indirectly_unary_invocable); +static_assert(!std::indirectly_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,66 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// projected + +#include + +#include +#include + +#include "test_iterators.h" + +using IntPtr = 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 Cpp17InputIterator = std::projected, int S::*>; +static_assert(std::same_as); +static_assert(std::same_as()), int&>); +static_assert(std::same_as, std::ptrdiff_t>); + +using Cpp20InputIterator = std::projected, int S::*>; +static_assert(std::same_as); +static_assert(std::same_as()), int&>); +static_assert(std::same_as, std::ptrdiff_t>); + +using ForwardIterator = std::projected, int (S::*)()>; +static_assert(std::same_as); +static_assert(std::same_as()), int>); +static_assert(std::same_as, std::ptrdiff_t>); + +using BidirectionalIterator = 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 RandomAccessIterator = std::projected, S && (S::*)()>; +static_assert(std::same_as); +static_assert(std::same_as()), S&&>); +static_assert(std::same_as, std::ptrdiff_t>); + +using ContiguousIterator = std::projected, S& (S::*)() const>; +static_assert(std::same_as); +static_assert(std::same_as()), S&>); +static_assert(std::same_as, std::ptrdiff_t>); + +template +constexpr bool projectable = requires { + typename std::projected; +}; + +static_assert(!projectable); // int isn't indirectly_readable +static_assert(!projectable); // S isn't weakly_incrementable +static_assert(!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,60 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// iter_common_reference_t + +#include + +#include + +struct X { }; + +// value_type and dereferencing are the same +struct T1 { + using value_type = X; + X operator*() const; +}; +static_assert(std::same_as, X>); + +// value_type and dereferencing are the same (modulo qualifiers) +struct T2 { + using value_type = X; + X& operator*() const; +}; +static_assert(std::same_as, X&>); + +// There's a custom common reference between value_type and the type of dereferencing +struct A { }; +struct B { }; +struct Common { Common(A); Common(B); }; +template