[libcxx] adds concepts `std::invocable` and `std::regular_invocable`

Implements parts of:
    - P0898R3 Standard Library Concepts
    - P1754 Rename concepts to standard_case for C++20, while we still can

Differential Revision: https://reviews.llvm.org/D96235
This commit is contained in:
Christopher Di Bella 2021-02-08 05:08:25 +00:00
parent c63de225fd
commit 17db24a7a8
5 changed files with 286 additions and 1 deletions

View File

@ -135,7 +135,9 @@ namespace std {
*/
#include <__config>
#include <functional>
#include <type_traits>
#include <utility>
#include <version>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@ -216,6 +218,16 @@ concept copy_constructible =
constructible_from<_Tp, const _Tp&> && convertible_to<const _Tp&, _Tp> &&
constructible_from<_Tp, const _Tp> && convertible_to<const _Tp, _Tp>;
// [concept.invocable]
template<class _Fn, class... _Args>
concept invocable = requires(_Fn&& __fn, _Args&&... __args) {
_VSTD::invoke(_VSTD::forward<_Fn>(__fn), _VSTD::forward<_Args>(__args)...); // not required to be equality preserving
};
// [concept.regular.invocable]
template<class _Fn, class... _Args>
concept regular_invocable = invocable<_Fn, _Args...>;
#endif //_LIBCPP_STD_VER > 17 && defined(__cpp_concepts) && __cpp_concepts >= 201811L
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// 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 CALLABLE_FUNCTIONS_H
#define CALLABLE_FUNCTIONS_H
namespace RegularInvocable {
struct A {
int I = 13;
constexpr int F() const noexcept { return 42; }
constexpr int G(int X) { return 2 * X + 1; }
constexpr int H(int J) && { return I * J; }
};
constexpr int F() noexcept { return 13; }
constexpr int G(int I) { return 2 * I + 1; }
} // namespace RegularInvocable
namespace Predicate {
struct L2rSorted {
template <class T>
constexpr bool operator()(T const& A, T const& B, T const& C) const noexcept {
return A <= B && B <= C;
}
};
struct NotAPredicate {
void operator()() const noexcept {}
};
} // namespace Predicate
namespace Relation {
int Greater(int X, int Y) noexcept { return X > Y; }
} // namespace Relation
#endif // CALLABLE_FUNCTIONS_H

View File

@ -0,0 +1,117 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// template<class T, class U>
// concept invocable;
#include <chrono>
#include <concepts>
#include <memory>
#include <random>
#include <type_traits>
#include "functions.h"
template <class F, class... Args>
requires std::invocable<F, Args...> constexpr void
ModelsInvocable(F, Args&&...) noexcept{};
template <class F, class... Args>
requires(!std::invocable<F, Args...>) constexpr
void NotInvocable(F, Args&&...) noexcept {}
static_assert(!std::invocable<void>);
static_assert(!std::invocable<void*>);
static_assert(!std::invocable<int>);
static_assert(!std::invocable<int&>);
static_assert(!std::invocable<int&&>);
int main(int, char**) {
{
using namespace RegularInvocable;
ModelsInvocable(F);
NotInvocable(F, 0);
ModelsInvocable(G, 2);
NotInvocable(G);
NotInvocable(G, 3, 0);
NotInvocable(&A::I);
NotInvocable(&A::F);
{
auto X = A{};
ModelsInvocable(&A::I, X);
ModelsInvocable(&A::F, X);
ModelsInvocable(&A::G, X, 0);
NotInvocable(&A::G, X);
NotInvocable(&A::G, 0);
NotInvocable(&A::H);
auto const& Y = X;
ModelsInvocable(&A::I, Y);
ModelsInvocable(&A::F, Y);
NotInvocable(&A::G, Y, 0);
NotInvocable(&A::H, Y, 0);
}
ModelsInvocable(&A::I, A{});
ModelsInvocable(&A::F, A{});
ModelsInvocable(&A::G, A{}, 0);
ModelsInvocable(&A::H, A{}, 0);
{
auto Up = std::make_unique<A>();
ModelsInvocable(&A::I, Up);
ModelsInvocable(&A::F, Up);
ModelsInvocable(&A::G, Up, 0);
NotInvocable(&A::H, Up, 0);
}
{
auto Sp = std::make_shared<A>();
ModelsInvocable(&A::I, Sp);
ModelsInvocable(&A::F, Sp);
ModelsInvocable(&A::G, Sp, 0);
NotInvocable(&A::H, Sp, 0);
}
}
{
using namespace Predicate;
{
ModelsInvocable(L2rSorted{}, 0, 1, 2);
NotInvocable(L2rSorted{});
NotInvocable(L2rSorted{}, 0);
NotInvocable(L2rSorted{}, 0, 1);
}
{
auto Up = std::make_unique<L2rSorted>();
ModelsInvocable(&L2rSorted::operator()<int>, Up, 0, 1, 2);
NotInvocable(&L2rSorted::operator()<int>, Up);
NotInvocable(&L2rSorted::operator()<int>, Up, 0);
NotInvocable(&L2rSorted::operator()<int>, Up, 0, 1);
}
{
auto Sp = std::make_shared<L2rSorted>();
ModelsInvocable(&L2rSorted::operator()<int>, Sp, 0, 1, 2);
NotInvocable(&L2rSorted::operator()<int>, Sp);
NotInvocable(&L2rSorted::operator()<int>, Sp, 0);
NotInvocable(&L2rSorted::operator()<int>, Sp, 0, 1);
}
}
{
auto G = std::mt19937_64(
std::chrono::high_resolution_clock().now().time_since_epoch().count());
auto D = std::uniform_int_distribution<>();
ModelsInvocable(D, G);
}
return 0;
}

View File

@ -0,0 +1,116 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// template<class T, class U>
// concept regular_invocable;
#include <concepts>
#include <memory>
#include <random>
#include <type_traits>
#include "functions.h"
template <class F, class... Args>
requires std::invocable<F, Args...> constexpr void
ModelsRegularInvocable(F, Args&&...) noexcept{};
template <class F, class... Args>
requires(!std::invocable<F, Args...>) constexpr
void NotRegularInvocable(F, Args&&...) noexcept {}
static_assert(!std::invocable<void>);
static_assert(!std::invocable<void*>);
static_assert(!std::invocable<int>);
static_assert(!std::invocable<int&>);
static_assert(!std::invocable<int&&>);
int main(int, char**) {
{
using namespace RegularInvocable;
ModelsRegularInvocable(F);
NotRegularInvocable(F, 0);
ModelsRegularInvocable(G, 2);
NotRegularInvocable(G);
NotRegularInvocable(G, 3, 0);
NotRegularInvocable(&A::I);
NotRegularInvocable(&A::F);
{
auto X = A{};
ModelsRegularInvocable(&A::I, X);
ModelsRegularInvocable(&A::F, X);
ModelsRegularInvocable(&A::G, X, 0);
NotRegularInvocable(&A::G, X);
NotRegularInvocable(&A::G, 0);
NotRegularInvocable(&A::H);
auto const& Y = X;
ModelsRegularInvocable(&A::I, Y);
ModelsRegularInvocable(&A::F, Y);
NotRegularInvocable(&A::G, Y, 0);
NotRegularInvocable(&A::H, Y, 0);
}
ModelsRegularInvocable(&A::I, A{});
ModelsRegularInvocable(&A::F, A{});
ModelsRegularInvocable(&A::G, A{}, 0);
ModelsRegularInvocable(&A::H, A{}, 0);
{
auto Up = std::make_unique<A>();
ModelsRegularInvocable(&A::I, Up);
ModelsRegularInvocable(&A::F, Up);
ModelsRegularInvocable(&A::G, Up, 0);
NotRegularInvocable(&A::H, Up, 0);
}
{
auto Sp = std::make_shared<A>();
ModelsRegularInvocable(&A::I, Sp);
ModelsRegularInvocable(&A::F, Sp);
ModelsRegularInvocable(&A::G, Sp, 0);
NotRegularInvocable(&A::H, Sp, 0);
}
}
{
using namespace Predicate;
{
ModelsRegularInvocable(L2rSorted{}, 0, 1, 2);
NotRegularInvocable(L2rSorted{});
NotRegularInvocable(L2rSorted{}, 0);
NotRegularInvocable(L2rSorted{}, 0, 1);
}
{
auto Up = std::make_unique<L2rSorted>();
ModelsRegularInvocable(&L2rSorted::operator()<int>, Up, 0, 1, 2);
NotRegularInvocable(&L2rSorted::operator()<int>, Up);
NotRegularInvocable(&L2rSorted::operator()<int>, Up, 0);
NotRegularInvocable(&L2rSorted::operator()<int>, Up, 0, 1);
}
{
auto Sp = std::make_shared<L2rSorted>();
ModelsRegularInvocable(&L2rSorted::operator()<int>, Sp, 0, 1, 2);
NotRegularInvocable(&L2rSorted::operator()<int>, Sp);
NotRegularInvocable(&L2rSorted::operator()<int>, Sp, 0);
NotRegularInvocable(&L2rSorted::operator()<int>, Sp, 0, 1);
}
}
// {
// RNG doesn't model regular_invocable, left here for documentation
// auto G = std::mt19937_64(std::random_device()());
// auto D = std::uniform_int_distribution<>();
// models_invocable(D, G);
// }
return 0;
}

View File

@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// template<class Derived, class Base>