[libc++] Add all indirect callable concepts and projected

Differential Revision: https://reviews.llvm.org/D101277
This commit is contained in:
Louis Dionne 2021-04-28 15:02:08 -04:00
parent 2b9b9652ce
commit 58b29a4efc
15 changed files with 911 additions and 1 deletions

View File

@ -17,10 +17,12 @@ set(files
__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

View File

@ -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 @@ concept __indirectly_readable_impl =
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 =

View File

@ -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

View File

@ -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

View File

@ -46,7 +46,11 @@ using iter_rvalue_reference_t = decltype(ranges::iter_move(declval<T&>())); // s
// [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>
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 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
#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>

View File

@ -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>);

View File

@ -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>);

View File

@ -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

View File

@ -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>);

View File

@ -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>);

View File

@ -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*>);

View File

@ -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*>);

View File

@ -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

View File

@ -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>);

View File

@ -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