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 <concepts> +#include <type_traits> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -48,6 +49,9 @@ template<class _In> concept indirectly_readable = __indirectly_readable_impl<remove_cvref_t<_In> >; +template<indirectly_readable _Tp> +using iter_common_reference_t = common_reference_t<iter_reference_t<_Tp>, iter_value_t<_Tp>&>; + // [iterator.concept.writable] template<class _Out, class _Tp> 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 <concepts> +#include <type_traits> + +#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<class _Fp, class _It> +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<class _Fp, class _It> +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<class _Fp, class _It> +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<class _Fp, class _It1, class _It2> +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<class _Fp, class _It1, class _It2 = _It1> +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<class _Fp, class _It1, class _It2 = _It1> +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<class _Fp, class... _Its> + 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 <type_traits> + +#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<indirectly_readable _It, indirectly_regular_unary_invocable<_It> _Proj> +struct projected { + using value_type = remove_cvref_t<indirect_result_t<_Proj&, _It>>; + indirect_result_t<_Proj&, _It> operator*() const; // not defined +}; + +template<weakly_incrementable _It, class _Proj> +struct incrementable_traits<projected<_It, _Proj>> { + 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<class In> - concept indirectly_readable = see below; // since C++20 + concept indirectly_readable = see below; // since C++20 + +template<indirectly_readable T> + using iter_common_reference_t = + common_reference_t<iter_reference_t<T>, iter_value_t<T>&>; // since C++20 // [iterator.concept.writable], concept indirectly_writable template<class Out, class T> @@ -91,6 +95,36 @@ template<class I> concept random_access_iterator = see below; // since C++20 +// [indirectcallable] +// [indirectcallable.indirectinvocable] +template<class F, class I> + concept indirectly_unary_invocable = see below; // since C++20 + +template<class F, class I> + concept indirectly_regular_unary_invocable = see below; // since C++20 + +template<class F, class I> + concept indirect_unary_predicate = see below; // since C++20 + +template<class F, class I1, class I2> + concept indirect_binary_predicate = see below; // since C++20 + +template<class F, class I1, class I2 = I1> + concept indirect_equivalence_relation = see below; // since C++20 + +template<class F, class I1, class I2 = I1> + concept indirect_strict_weak_order = see below; // since C++20 + +template<class F, class... Is> + using indirect_result_t = see below; // since C++20 + +// [projected], projected +template<indirectly_readable I, indirectly_regular_unary_invocable<I> Proj> + struct projected; // since C++20 + +template<weakly_incrementable I, indirectly_regular_unary_invocable<I> Proj> + struct incrementable_traits<projected<I, Proj>>; // since C++20 + template<class Category, class T, class Distance = ptrdiff_t, class Pointer = T*, class Reference = T&> 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<class F, class I1, class I2> +// concept indirect_binary_predicate; + +#include <iterator> +#include <type_traits> + +#include "indirectly_readable.h" + +using It1 = IndirectlyReadable<struct Token1>; +using It2 = IndirectlyReadable<struct Token2>; + +template <class I1, class I2> +struct GoodPredicate { + bool operator()(std::iter_value_t<I1>&, std::iter_value_t<I2>&) const; + bool operator()(std::iter_value_t<I1>&, std::iter_reference_t<I2>) const; + bool operator()(std::iter_reference_t<I1>, std::iter_value_t<I2>&) const; + bool operator()(std::iter_reference_t<I1>, std::iter_reference_t<I2>) const; + bool operator()(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I2>) const; +}; + +// Should work when all constraints are satisfied +static_assert(std::indirect_binary_predicate<GoodPredicate<It1, It2>, It1, It2>); +static_assert(std::indirect_binary_predicate<bool(*)(int, float), int*, float*>); +[[maybe_unused]] auto lambda = [](int i, int j) { return i < j; }; +static_assert(std::indirect_binary_predicate<decltype(lambda), int*, int*>); + +// Should fail when either of the iterators is not indirectly_readable +struct NotIndirectlyReadable { }; +static_assert(!std::indirect_binary_predicate<GoodPredicate<It1, NotIndirectlyReadable>, It1, NotIndirectlyReadable>); +static_assert(!std::indirect_binary_predicate<GoodPredicate<NotIndirectlyReadable, It2>, NotIndirectlyReadable, It2>); + +// Should fail when the predicate is not copy constructible +struct BadPredicate1 { + BadPredicate1(BadPredicate1 const&) = delete; + template <class T, class U> bool operator()(T const&, U const&) const; +}; +static_assert(!std::indirect_binary_predicate<BadPredicate1, It1, It2>); + +// Should fail when the predicate can't be called with (iter_value_t&, iter_value_t&) +struct BadPredicate2 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_value_t<It1>&, std::iter_value_t<It2>&) const = delete; +}; +static_assert(!std::indirect_binary_predicate<BadPredicate2, It1, It2>); + +// Should fail when the predicate can't be called with (iter_value_t&, iter_reference_t) +struct BadPredicate3 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_value_t<It1>&, std::iter_reference_t<It2>) const = delete; +}; +static_assert(!std::indirect_binary_predicate<BadPredicate3, It1, It2>); + +// Should fail when the predicate can't be called with (iter_reference_t, iter_value_t&) +struct BadPredicate4 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_reference_t<It1>, std::iter_value_t<It2>&) const = delete; +}; +static_assert(!std::indirect_binary_predicate<BadPredicate4, It1, It2>); + +// Should fail when the predicate can't be called with (iter_reference_t, iter_reference_t) +struct BadPredicate5 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_reference_t<It1>, std::iter_reference_t<It2>) const = delete; +}; +static_assert(!std::indirect_binary_predicate<BadPredicate5, It1, It2>); + +// Should fail when the predicate can't be called with (iter_common_reference_t, iter_common_reference_t) +struct BadPredicate6 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete; +}; +static_assert(!std::indirect_binary_predicate<BadPredicate6, It1, It2>); 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<class F, class I1, class I2 = I1> +// concept indirect_equivalence_relation; + +#include <iterator> +#include <concepts> + +#include "indirectly_readable.h" + +using It1 = IndirectlyReadable<struct Token1>; +using It2 = IndirectlyReadable<struct Token2>; + +template <class I1, class I2> +struct GoodRelation { + bool operator()(std::iter_value_t<I1>&, std::iter_value_t<I1>&) const; + bool operator()(std::iter_value_t<I2>&, std::iter_value_t<I2>&) const; + bool operator()(std::iter_value_t<I1>&, std::iter_value_t<I2>&) const; + bool operator()(std::iter_value_t<I2>&, std::iter_value_t<I1>&) const; + + bool operator()(std::iter_value_t<I1>&, std::iter_reference_t<I2>) const; + bool operator()(std::iter_reference_t<I2>, std::iter_value_t<I1>&) const; + bool operator()(std::iter_reference_t<I2>, std::iter_reference_t<I2>) const; + + bool operator()(std::iter_reference_t<I1>, std::iter_value_t<I2>&) const; + bool operator()(std::iter_value_t<I2>&, std::iter_reference_t<I1>) const; + bool operator()(std::iter_reference_t<I1>, std::iter_reference_t<I1>) const; + + bool operator()(std::iter_reference_t<I1>, std::iter_reference_t<I2>) const; + bool operator()(std::iter_reference_t<I2>, std::iter_reference_t<I1>) const; + + bool operator()(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I1>) const; + bool operator()(std::iter_common_reference_t<I2>, std::iter_common_reference_t<I2>) const; + bool operator()(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I2>) const; + bool operator()(std::iter_common_reference_t<I2>, std::iter_common_reference_t<I1>) const; +}; + +// Should work when all constraints are satisfied +static_assert(std::indirect_equivalence_relation<GoodRelation<It1, It2>, It1, It2>); +static_assert(std::indirect_equivalence_relation<bool(*)(int, long), int*, long*>); +[[maybe_unused]] auto lambda = [](int i, long j) { return i == j; }; +static_assert(std::indirect_equivalence_relation<decltype(lambda), int*, long*>); + +// Should fail when either of the iterators is not indirectly_readable +struct NotIndirectlyReadable { }; +static_assert(!std::indirect_equivalence_relation<GoodRelation<It1, NotIndirectlyReadable>, It1, NotIndirectlyReadable>); +static_assert(!std::indirect_equivalence_relation<GoodRelation<NotIndirectlyReadable, It2>, NotIndirectlyReadable, It2>); + +// Should fail when the function is not copy constructible +struct BadRelation1 { + BadRelation1(BadRelation1 const&) = delete; + template <class T, class U> bool operator()(T const&, U const&) const; +}; +static_assert(!std::indirect_equivalence_relation<BadRelation1, It1, It2>); + +// Should fail when the function can't be called with (iter_value_t&, iter_value_t&) +struct BadRelation2 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_value_t<It1>&, std::iter_value_t<It2>&) const = delete; +}; +static_assert(!std::indirect_equivalence_relation<BadRelation2, It1, It2>); + +// Should fail when the function can't be called with (iter_value_t&, iter_reference_t) +struct BadRelation3 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_value_t<It1>&, std::iter_reference_t<It2>) const = delete; +}; +static_assert(!std::indirect_equivalence_relation<BadRelation3, It1, It2>); + +// Should fail when the function can't be called with (iter_reference_t, iter_value_t&) +struct BadRelation4 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_reference_t<It1>, std::iter_value_t<It2>&) const = delete; +}; +static_assert(!std::indirect_equivalence_relation<BadRelation4, It1, It2>); + +// Should fail when the function can't be called with (iter_reference_t, iter_reference_t) +struct BadRelation5 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_reference_t<It1>, std::iter_reference_t<It2>) const = delete; +}; +static_assert(!std::indirect_equivalence_relation<BadRelation5, It1, It2>); + +// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t) +struct BadRelation6 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete; +}; +static_assert(!std::indirect_equivalence_relation<BadRelation6, It1, It2>); 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 <iterator> +#include <concepts> + +static_assert(std::same_as<std::indirect_result_t<int (*)(int), int*>, int>); +static_assert(std::same_as<std::indirect_result_t<double (*)(int const&, float), int const*, float*>, double>); + +struct S { }; +static_assert(std::same_as<std::indirect_result_t<S (&)(int), int*>, S>); +static_assert(std::same_as<std::indirect_result_t<long S::*, S*>, long&>); +static_assert(std::same_as<std::indirect_result_t<S && (S::*)(), S*>, S&&>); +static_assert(std::same_as<std::indirect_result_t<int S::* (S::*)(int) const, S*, int*>, int S::*>); + +template <class F, class... Is> +constexpr bool has_indirect_result = requires { + typename std::indirect_result_t<F, Is...>; +}; + +static_assert(!has_indirect_result<int (*)(int), int>); // int isn't indirectly_readable +static_assert(!has_indirect_result<int, int*>); // 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<class F, class I1, class I2 = I1> +// concept indirect_strict_weak_order; + +#include <iterator> +#include <concepts> + +#include "indirectly_readable.h" + +using It1 = IndirectlyReadable<struct Token1>; +using It2 = IndirectlyReadable<struct Token2>; + +template <class I1, class I2> +struct GoodOrder { + bool operator()(std::iter_value_t<I1>&, std::iter_value_t<I1>&) const; + bool operator()(std::iter_value_t<I2>&, std::iter_value_t<I2>&) const; + bool operator()(std::iter_value_t<I1>&, std::iter_value_t<I2>&) const; + bool operator()(std::iter_value_t<I2>&, std::iter_value_t<I1>&) const; + + bool operator()(std::iter_value_t<I1>&, std::iter_reference_t<I2>) const; + bool operator()(std::iter_reference_t<I2>, std::iter_value_t<I1>&) const; + bool operator()(std::iter_reference_t<I2>, std::iter_reference_t<I2>) const; + + bool operator()(std::iter_reference_t<I1>, std::iter_value_t<I2>&) const; + bool operator()(std::iter_value_t<I2>&, std::iter_reference_t<I1>) const; + bool operator()(std::iter_reference_t<I1>, std::iter_reference_t<I1>) const; + + bool operator()(std::iter_reference_t<I1>, std::iter_reference_t<I2>) const; + bool operator()(std::iter_reference_t<I2>, std::iter_reference_t<I1>) const; + + bool operator()(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I1>) const; + bool operator()(std::iter_common_reference_t<I2>, std::iter_common_reference_t<I2>) const; + bool operator()(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I2>) const; + bool operator()(std::iter_common_reference_t<I2>, std::iter_common_reference_t<I1>) const; +}; + +// Should work when all constraints are satisfied +static_assert(std::indirect_strict_weak_order<GoodOrder<It1, It2>, It1, It2>); +static_assert(std::indirect_strict_weak_order<bool(*)(int, long), int*, long*>); +[[maybe_unused]] auto lambda = [](int i, long j) { return i < j; }; +static_assert(std::indirect_strict_weak_order<decltype(lambda), int*, long*>); + +// Should fail when either of the iterators is not indirectly_readable +struct NotIndirectlyReadable { }; +static_assert(!std::indirect_strict_weak_order<GoodOrder<It1, NotIndirectlyReadable>, It1, NotIndirectlyReadable>); +static_assert(!std::indirect_strict_weak_order<GoodOrder<NotIndirectlyReadable, It2>, NotIndirectlyReadable, It2>); + +// Should fail when the function is not copy constructible +struct BadOrder1 { + BadOrder1(BadOrder1 const&) = delete; + template <class T, class U> bool operator()(T const&, U const&) const; +}; +static_assert(!std::indirect_strict_weak_order<BadOrder1, It1, It2>); + +// Should fail when the function can't be called with (iter_value_t&, iter_value_t&) +struct BadOrder2 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_value_t<It1>&, std::iter_value_t<It2>&) const = delete; +}; +static_assert(!std::indirect_strict_weak_order<BadOrder2, It1, It2>); + +// Should fail when the function can't be called with (iter_value_t&, iter_reference_t) +struct BadOrder3 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_value_t<It1>&, std::iter_reference_t<It2>) const = delete; +}; +static_assert(!std::indirect_strict_weak_order<BadOrder3, It1, It2>); + +// Should fail when the function can't be called with (iter_reference_t, iter_value_t&) +struct BadOrder4 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_reference_t<It1>, std::iter_value_t<It2>&) const = delete; +}; +static_assert(!std::indirect_strict_weak_order<BadOrder4, It1, It2>); + +// Should fail when the function can't be called with (iter_reference_t, iter_reference_t) +struct BadOrder5 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_reference_t<It1>, std::iter_reference_t<It2>) const = delete; +}; +static_assert(!std::indirect_strict_weak_order<BadOrder5, It1, It2>); + +// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t) +struct BadOrder6 { + template <class T, class U> bool operator()(T const&, U const&) const; + bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete; +}; +static_assert(!std::indirect_strict_weak_order<BadOrder6, It1, It2>); 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<class F, class I> +// concept indirect_unary_predicate; + +#include <iterator> +#include <type_traits> + +#include "indirectly_readable.h" + +using It = IndirectlyReadable<struct Token>; + +template <class I> +struct GoodPredicate { + bool operator()(std::iter_reference_t<I>) const; + bool operator()(std::iter_value_t<I>&) const; + bool operator()(std::iter_common_reference_t<I>) const; +}; + +// Should work when all constraints are satisfied +static_assert(std::indirect_unary_predicate<GoodPredicate<It>, It>); +static_assert(std::indirect_unary_predicate<bool(*)(int), int*>); +[[maybe_unused]] auto lambda = [](int i) { return i % 2 == 0; }; +static_assert(std::indirect_unary_predicate<decltype(lambda), int*>); + +// Should fail when the iterator is not indirectly_readable +struct NotIndirectlyReadable { }; +static_assert(!std::indirect_unary_predicate<GoodPredicate<NotIndirectlyReadable>, NotIndirectlyReadable>); + +// Should fail when the predicate is not copy constructible +struct BadPredicate1 { + BadPredicate1(BadPredicate1 const&) = delete; + template <class T> bool operator()(T const&) const; +}; +static_assert(!std::indirect_unary_predicate<BadPredicate1, It>); + +// Should fail when the predicate can't be called with std::iter_value_t<It>& +struct BadPredicate2 { + template <class T> bool operator()(T const&) const; + bool operator()(std::iter_value_t<It>&) const = delete; +}; +static_assert(!std::indirect_unary_predicate<BadPredicate2, It>); + +// Should fail when the predicate can't be called with std::iter_reference_t<It> +struct BadPredicate3 { + template <class T> bool operator()(T const&) const; + bool operator()(std::iter_reference_t<It>) const = delete; +}; +static_assert(!std::indirect_unary_predicate<BadPredicate3, It>); + +// Should fail when the predicate can't be called with std::iter_common_reference_t<It> +struct BadPredicate4 { + template <class T> bool operator()(T const&) const; + bool operator()(std::iter_common_reference_t<It>) const = delete; +}; +static_assert(!std::indirect_unary_predicate<BadPredicate4, It>); 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<class F, class I> +// concept indirectly_regular_unary_invocable; + +#include <iterator> +#include <concepts> + +#include "indirectly_readable.h" + +using It = IndirectlyReadable<struct Token>; +using R1 = T1<struct ReturnToken>; +using R2 = T2<struct ReturnToken>; + +template <class I> +struct GoodInvocable { + R1 operator()(std::iter_value_t<I>&) const; + R2 operator()(std::iter_reference_t<I>) const; + R2 operator()(std::iter_common_reference_t<I>) const; +}; + +// Should work when all constraints are satisfied +static_assert(std::indirectly_regular_unary_invocable<GoodInvocable<It>, It>); + +// Should fail when the iterator is not indirectly_readable +struct NotIndirectlyReadable { }; +static_assert(!std::indirectly_regular_unary_invocable<GoodInvocable<NotIndirectlyReadable>, NotIndirectlyReadable>); + +// Should fail when the invocable is not copy constructible +struct BadInvocable1 { + BadInvocable1(BadInvocable1 const&) = delete; + template <class T> R1 operator()(T const&) const; +}; +static_assert(!std::indirectly_regular_unary_invocable<BadInvocable1, It>); + +// Should fail when the invocable can't be called with (iter_value_t&) +struct BadInvocable2 { + template <class T> R1 operator()(T const&) const; + R1 operator()(std::iter_value_t<It>&) const = delete; +}; +static_assert(!std::indirectly_regular_unary_invocable<BadInvocable2, It>); + +// Should fail when the invocable can't be called with (iter_reference_t) +struct BadInvocable3 { + template <class T> R1 operator()(T const&) const; + R1 operator()(std::iter_reference_t<It>) const = delete; +}; +static_assert(!std::indirectly_regular_unary_invocable<BadInvocable3, It>); + +// Should fail when the invocable can't be called with (iter_common_reference_t) +struct BadInvocable4 { + template <class T> R1 operator()(T const&) const; + R1 operator()(std::iter_common_reference_t<It>) const = delete; +}; +static_assert(!std::indirectly_regular_unary_invocable<BadInvocable4, It>); + +// Should fail when the invocable doesn't have a common reference between its return types +struct BadInvocable5 { + R1 operator()(std::iter_value_t<It>&) const; + struct Unrelated { }; + Unrelated operator()(std::iter_reference_t<It>) const; + R1 operator()(std::iter_common_reference_t<It>) const; +}; +static_assert(!std::indirectly_regular_unary_invocable<BadInvocable5, It>); + +// Various tests with callables +struct S; +static_assert(std::indirectly_regular_unary_invocable<int (*)(int), int*>); +static_assert(std::indirectly_regular_unary_invocable<int (&)(int), int*>); +static_assert(std::indirectly_regular_unary_invocable<int S::*, S*>); +static_assert(std::indirectly_regular_unary_invocable<int (S::*)(), S*>); +static_assert(std::indirectly_regular_unary_invocable<int (S::*)() const, S*>); +static_assert(std::indirectly_regular_unary_invocable<void(*)(int), int*>); + +static_assert(!std::indirectly_regular_unary_invocable<int(int), int*>); // not move constructible +static_assert(!std::indirectly_regular_unary_invocable<int (*)(int*, int*), int*>); +static_assert(!std::indirectly_regular_unary_invocable<int (&)(int*, int*), int*>); +static_assert(!std::indirectly_regular_unary_invocable<int (S::*)(int*), S*>); +static_assert(!std::indirectly_regular_unary_invocable<int (S::*)(int*) const, S*>); 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<class F, class I> +// concept indirectly_unary_invocable; + +#include <iterator> +#include <concepts> + +#include "indirectly_readable.h" + +using It = IndirectlyReadable<struct Token>; +using R1 = T1<struct ReturnToken>; +using R2 = T2<struct ReturnToken>; + +template <class I> +struct GoodInvocable { + R1 operator()(std::iter_value_t<I>&) const; + R2 operator()(std::iter_reference_t<I>) const; + R2 operator()(std::iter_common_reference_t<I>) const; +}; + +// Should work when all constraints are satisfied +static_assert(std::indirectly_unary_invocable<GoodInvocable<It>, It>); + +// Should fail when the iterator is not indirectly_readable +struct NotIndirectlyReadable { }; +static_assert(!std::indirectly_unary_invocable<GoodInvocable<NotIndirectlyReadable>, NotIndirectlyReadable>); + +// Should fail when the invocable is not copy constructible +struct BadInvocable1 { + BadInvocable1(BadInvocable1 const&) = delete; + template <class T> R1 operator()(T const&) const; +}; +static_assert(!std::indirectly_unary_invocable<BadInvocable1, It>); + +// Should fail when the invocable can't be called with (iter_value_t&) +struct BadInvocable2 { + template <class T> R1 operator()(T const&) const; + R1 operator()(std::iter_value_t<It>&) const = delete; +}; +static_assert(!std::indirectly_unary_invocable<BadInvocable2, It>); + +// Should fail when the invocable can't be called with (iter_reference_t) +struct BadInvocable3 { + template <class T> R1 operator()(T const&) const; + R1 operator()(std::iter_reference_t<It>) const = delete; +}; +static_assert(!std::indirectly_unary_invocable<BadInvocable3, It>); + +// Should fail when the invocable can't be called with (iter_common_reference_t) +struct BadInvocable4 { + template <class T> R1 operator()(T const&) const; + R1 operator()(std::iter_common_reference_t<It>) const = delete; +}; +static_assert(!std::indirectly_unary_invocable<BadInvocable4, It>); + +// Should fail when the invocable doesn't have a common reference between its return types +struct BadInvocable5 { + R1 operator()(std::iter_value_t<It>&) const; + struct Unrelated { }; + Unrelated operator()(std::iter_reference_t<It>) const; + R1 operator()(std::iter_common_reference_t<It>) const; +}; +static_assert(!std::indirectly_unary_invocable<BadInvocable5, It>); + +// Various tests with callables +struct S; +static_assert(std::indirectly_unary_invocable<int (*)(int), int*>); +static_assert(std::indirectly_unary_invocable<int (&)(int), int*>); +static_assert(std::indirectly_unary_invocable<int S::*, S*>); +static_assert(std::indirectly_unary_invocable<int (S::*)(), S*>); +static_assert(std::indirectly_unary_invocable<int (S::*)() const, S*>); +static_assert(std::indirectly_unary_invocable<void(*)(int), int*>); + +static_assert(!std::indirectly_unary_invocable<int(int), int*>); // not move constructible +static_assert(!std::indirectly_unary_invocable<int (*)(int*, int*), int*>); +static_assert(!std::indirectly_unary_invocable<int (&)(int*, int*), int*>); +static_assert(!std::indirectly_unary_invocable<int (S::*)(int*), S*>); +static_assert(!std::indirectly_unary_invocable<int (S::*)(int*) const, S*>); 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 <iterator> + +#include <concepts> +#include <functional> + +#include "test_iterators.h" + +using IntPtr = std::projected<int const*, std::identity>; +static_assert(std::same_as<IntPtr::value_type, int>); +static_assert(std::same_as<decltype(*std::declval<IntPtr>()), int const&>); +static_assert(std::same_as<std::iter_difference_t<IntPtr>, std::ptrdiff_t>); + +struct S { }; + +using Cpp17InputIterator = std::projected<cpp17_input_iterator<S*>, int S::*>; +static_assert(std::same_as<Cpp17InputIterator::value_type, int>); +static_assert(std::same_as<decltype(*std::declval<Cpp17InputIterator>()), int&>); +static_assert(std::same_as<std::iter_difference_t<Cpp17InputIterator>, std::ptrdiff_t>); + +using Cpp20InputIterator = std::projected<cpp20_input_iterator<S*>, int S::*>; +static_assert(std::same_as<Cpp20InputIterator::value_type, int>); +static_assert(std::same_as<decltype(*std::declval<Cpp20InputIterator>()), int&>); +static_assert(std::same_as<std::iter_difference_t<Cpp20InputIterator>, std::ptrdiff_t>); + +using ForwardIterator = std::projected<forward_iterator<S*>, int (S::*)()>; +static_assert(std::same_as<ForwardIterator::value_type, int>); +static_assert(std::same_as<decltype(*std::declval<ForwardIterator>()), int>); +static_assert(std::same_as<std::iter_difference_t<ForwardIterator>, std::ptrdiff_t>); + +using BidirectionalIterator = std::projected<bidirectional_iterator<S*>, S* (S::*)() const>; +static_assert(std::same_as<BidirectionalIterator::value_type, S*>); +static_assert(std::same_as<decltype(*std::declval<BidirectionalIterator>()), S*>); +static_assert(std::same_as<std::iter_difference_t<BidirectionalIterator>, std::ptrdiff_t>); + +using RandomAccessIterator = std::projected<random_access_iterator<S*>, S && (S::*)()>; +static_assert(std::same_as<RandomAccessIterator::value_type, S>); +static_assert(std::same_as<decltype(*std::declval<RandomAccessIterator>()), S&&>); +static_assert(std::same_as<std::iter_difference_t<RandomAccessIterator>, std::ptrdiff_t>); + +using ContiguousIterator = std::projected<contiguous_iterator<S*>, S& (S::*)() const>; +static_assert(std::same_as<ContiguousIterator::value_type, S>); +static_assert(std::same_as<decltype(*std::declval<ContiguousIterator>()), S&>); +static_assert(std::same_as<std::iter_difference_t<ContiguousIterator>, std::ptrdiff_t>); + +template <class I, class F> +constexpr bool projectable = requires { + typename std::projected<I, F>; +}; + +static_assert(!projectable<int, void (*)(int)>); // int isn't indirectly_readable +static_assert(!projectable<S, void (*)(int)>); // S isn't weakly_incrementable +static_assert(!projectable<int*, void(int)>); // 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 <iterator> + +#include <concepts> + +struct X { }; + +// value_type and dereferencing are the same +struct T1 { + using value_type = X; + X operator*() const; +}; +static_assert(std::same_as<std::iter_common_reference_t<T1>, X>); + +// value_type and dereferencing are the same (modulo qualifiers) +struct T2 { + using value_type = X; + X& operator*() const; +}; +static_assert(std::same_as<std::iter_common_reference_t<T2>, 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 <template <class> class TQual, template <class> class QQual> +struct std::basic_common_reference<A, B, TQual, QQual> { + using type = Common; +}; +template <template <class> class TQual, template <class> class QQual> +struct std::basic_common_reference<B, A, TQual, QQual> + : std::basic_common_reference<A, B, TQual, QQual> +{ }; + +struct T3 { + using value_type = A; + B&& operator*() const; +}; +static_assert(std::same_as<std::iter_common_reference_t<T3>, Common>); + +// Make sure we're SFINAE-friendly +template <class T> +constexpr bool has_common_reference = requires { + typename std::iter_common_reference_t<T>; +}; +struct NotIndirectlyReadable { }; +static_assert(!has_common_reference<NotIndirectlyReadable>); diff --git a/libcxx/test/support/indirectly_readable.h b/libcxx/test/support/indirectly_readable.h new file mode 100644 --- /dev/null +++ b/libcxx/test/support/indirectly_readable.h @@ -0,0 +1,38 @@ +// -*- 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 LIBCXX_TEST_SUPPORT_INDIRECTLY_READABLE_H +#define LIBCXX_TEST_SUPPORT_INDIRECTLY_READABLE_H + +#include <type_traits> + +template <class Token> +struct Common { }; + +template <class Token> +struct T1 : Common<Token> { }; + +template <class Token> +struct T2 : Common<Token> { }; + +template <template <class> class T1Qual, template <class> class T2Qual, class Token> +struct std::basic_common_reference<T1<Token>, T2<Token>, T1Qual, T2Qual> { + using type = Common<Token>; +}; +template <template <class> class T2Qual, template <class> class T1Qual, class Token> +struct std::basic_common_reference<T2<Token>, T1<Token>, T2Qual, T1Qual> + : std::basic_common_reference<T1<Token>, T2<Token>, T1Qual, T2Qual> +{ }; + +template <class Token> +struct IndirectlyReadable { + using value_type = T1<Token>; + T2<Token>& operator*() const; +}; + +#endif // LIBCXX_TEST_SUPPORT_INDIRECTLY_READABLE_H