Commit 808c845b authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

FOLLY_CREATE_FREE_INVOKER, FOLLY_CREATE_MEMBER_INVOKER

Summary:
[Folly] `FOLLY_CREATE_FREE_INVOKER` and `FOLLY_CREATE_MEMBER_INVOKER` to replace `FOLLY_CREATE_FREE_INVOKE_TRAITS` and `FOLLY_CREATE_MEMBER_INVOKE_TRAITS`.

New approach: just emit an invoker object. For the traits, just use the normal traits instead of rewriting them, or use `invoke_traits` to get an invoke-traits type specialized to the invoker.

Reviewed By: vitaut

Differential Revision: D18079121

fbshipit-source-id: 8258c36b8ba6ee62a8ecc104cd1b6281d313960f
parent 3de8f357
...@@ -41,10 +41,10 @@ namespace folly { ...@@ -41,10 +41,10 @@ namespace folly {
namespace detail { namespace detail {
namespace member { namespace member {
FOLLY_CREATE_MEMBER_INVOKE_TRAITS(lock, lock); FOLLY_CREATE_MEMBER_INVOKER(lock, lock);
FOLLY_CREATE_MEMBER_INVOKE_TRAITS(try_lock_for, try_lock_for); FOLLY_CREATE_MEMBER_INVOKER(try_lock_for, try_lock_for);
FOLLY_CREATE_MEMBER_INVOKE_TRAITS(lock_shared, lock_shared); FOLLY_CREATE_MEMBER_INVOKER(lock_shared, lock_shared);
FOLLY_CREATE_MEMBER_INVOKE_TRAITS(lock_upgrade, lock_upgrade); FOLLY_CREATE_MEMBER_INVOKER(lock_upgrade, lock_upgrade);
} // namespace member } // namespace member
/** /**
...@@ -86,7 +86,7 @@ class LockInterfaceDispatcher { ...@@ -86,7 +86,7 @@ class LockInterfaceDispatcher {
private: private:
// assert that the mutex type has basic lock and unlock functions // assert that the mutex type has basic lock and unlock functions
static_assert( static_assert(
member::lock::is_invocable<Mutex>::value, folly::is_invocable<member::lock, Mutex>::value,
"The mutex type must support lock and unlock functions"); "The mutex type must support lock and unlock functions");
using duration = std::chrono::milliseconds; using duration = std::chrono::milliseconds;
...@@ -94,11 +94,11 @@ class LockInterfaceDispatcher { ...@@ -94,11 +94,11 @@ class LockInterfaceDispatcher {
public: public:
static constexpr bool has_lock_unique = true; static constexpr bool has_lock_unique = true;
static constexpr bool has_lock_timed = static constexpr bool has_lock_timed =
member::try_lock_for::is_invocable<Mutex, duration>::value; folly::is_invocable<member::try_lock_for, Mutex, duration>::value;
static constexpr bool has_lock_shared = static constexpr bool has_lock_shared =
member::lock_shared::is_invocable<Mutex>::value; folly::is_invocable<member::lock_shared, Mutex>::value;
static constexpr bool has_lock_upgrade = static constexpr bool has_lock_upgrade =
member::lock_upgrade::is_invocable<Mutex>::value; folly::is_invocable<member::lock_upgrade, Mutex>::value;
}; };
/** /**
......
...@@ -667,12 +667,12 @@ struct AllocatorHasTrivialDeallocate<CxxAllocatorAdaptor<T, Alloc>> ...@@ -667,12 +667,12 @@ struct AllocatorHasTrivialDeallocate<CxxAllocatorAdaptor<T, Alloc>>
namespace detail { namespace detail {
// note that construct and destroy here are methods, not short names for // note that construct and destroy here are methods, not short names for
// the constructor and destructor // the constructor and destructor
FOLLY_CREATE_MEMBER_INVOKE_TRAITS(AllocatorConstruct_, construct); FOLLY_CREATE_MEMBER_INVOKER(AllocatorConstruct_, construct);
FOLLY_CREATE_MEMBER_INVOKE_TRAITS(AllocatorDestroy_, destroy); FOLLY_CREATE_MEMBER_INVOKER(AllocatorDestroy_, destroy);
template <typename Void, typename Alloc, typename... Args> template <typename Void, typename Alloc, typename... Args>
struct AllocatorCustomizesConstruct_ struct AllocatorCustomizesConstruct_
: AllocatorConstruct_::template is_invocable<Alloc, Args...> {}; : folly::is_invocable<AllocatorConstruct_, Alloc, Args...> {};
template <typename Alloc, typename... Args> template <typename Alloc, typename... Args>
struct AllocatorCustomizesConstruct_< struct AllocatorCustomizesConstruct_<
...@@ -682,7 +682,7 @@ struct AllocatorCustomizesConstruct_< ...@@ -682,7 +682,7 @@ struct AllocatorCustomizesConstruct_<
template <typename Void, typename Alloc, typename... Args> template <typename Void, typename Alloc, typename... Args>
struct AllocatorCustomizesDestroy_ struct AllocatorCustomizesDestroy_
: AllocatorDestroy_::template is_invocable<Alloc, Args...> {}; : folly::is_invocable<AllocatorDestroy_, Alloc, Args...> {};
template <typename Alloc, typename... Args> template <typename Alloc, typename... Args>
struct AllocatorCustomizesDestroy_< struct AllocatorCustomizesDestroy_<
......
...@@ -296,41 +296,16 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> { ...@@ -296,41 +296,16 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> {
BOOST_PP_TUPLE_TO_LIST((__VA_ARGS__)))) BOOST_PP_TUPLE_TO_LIST((__VA_ARGS__))))
/*** /***
* FOLLY_CREATE_FREE_INVOKE_TRAITS * FOLLY_CREATE_FREE_INVOKER
* *
* Used to create traits container, bound to a specific free-invocable name, * Used to create an invoker type bound to a specific free-invocable name.
* with the following member traits types and aliases:
*
* * invoke_result
* * invoke_result_t
* * is_invocable
* * is_invocable_v
* * is_invocable_r
* * is_invocable_r_v
* * is_nothrow_invocable
* * is_nothrow_invocable_v
* * is_nothrow_invocable_r
* * is_nothrow_invocable_r_v
*
* The container also has a static member function:
*
* * invoke
*
* And a member type alias:
*
* * invoke_type
*
* These members have behavior matching the behavior of C++17's corresponding
* invocation traits types, aliases, and functions, but substituting canonical
* invocation with member invocation.
* *
* Example: * Example:
* *
* FOLLY_CREATE_FREE_INVOKE_TRAITS(foo_invoke_traits, foo); * FOLLY_CREATE_FREE_INVOKER(foo_invoker, foo);
* *
* The traits container type `foo_invoke_traits` is generated in the current * The type `foo_invoker` is generated in the current namespace and may be used
* namespace and has the listed member types and aliases. They may be used as * as follows:
* follows:
* *
* namespace Deep { * namespace Deep {
* struct CanFoo {}; * struct CanFoo {};
...@@ -338,7 +313,7 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> { ...@@ -338,7 +313,7 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> {
* int foo(CanFoo&&, Car&&) noexcept { return 2; } * int foo(CanFoo&&, Car&&) noexcept { return 2; }
* } * }
* *
* using traits = foo_invoke_traits; * using traits = folly::invoke_traits<foo_invoker>;
* *
* traits::invoke(Deep::CanFoo{}, Car{}) // 2 * traits::invoke(Deep::CanFoo{}, Car{}) // 2
* *
...@@ -365,7 +340,7 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> { ...@@ -365,7 +340,7 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> {
* and alternate definitions in the namespaces of its arguments, the primary * and alternate definitions in the namespaces of its arguments, the primary
* definitions may automatically be found as follows: * definitions may automatically be found as follows:
* *
* FOLLY_CREATE_FREE_INVOKE_TRAITS(swap_invoke_traits, swap, std); * FOLLY_CREATE_FREE_INVOKER(swap_invoker, swap, std);
* *
* In this case, `swap_invoke_traits::invoke(int&, int&)` will use the primary * In this case, `swap_invoke_traits::invoke(int&, int&)` will use the primary
* definition found in `namespace std` relative to the current namespace, which * definition found in `namespace std` relative to the current namespace, which
...@@ -376,12 +351,12 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> { ...@@ -376,12 +351,12 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> {
* void swap(HasData&, HasData&) { throw 7; } * void swap(HasData&, HasData&) { throw 7; }
* } * }
* *
* using traits = swap_invoke_traits; * using traits = invoke_traits<swap_invoker>;
* *
* HasData a, b; * HasData a, b;
* traits::invoke(a, b); // throw 7 * traits::invoke(a, b); // throw 7
*/ */
#define FOLLY_CREATE_FREE_INVOKE_TRAITS(classname, funcname, ...) \ #define FOLLY_CREATE_FREE_INVOKER(classname, funcname, ...) \
namespace classname##__folly_detail_invoke_ns { \ namespace classname##__folly_detail_invoke_ns { \
FOLLY_MAYBE_UNUSED void funcname( \ FOLLY_MAYBE_UNUSED void funcname( \
::folly::detail::invoke_private_overload&); \ ::folly::detail::invoke_private_overload&); \
...@@ -396,52 +371,26 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> { ...@@ -396,52 +371,26 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> {
}; \ }; \
} \ } \
struct classname \ struct classname \
: ::folly::invoke_traits< \ : classname##__folly_detail_invoke_ns::__folly_detail_invoke_obj {}
classname##__folly_detail_invoke_ns::__folly_detail_invoke_obj> {}
/*** /***
* FOLLY_CREATE_MEMBER_INVOKE_TRAITS * FOLLY_CREATE_MEMBER_INVOKER
*
* Used to create traits container, bound to a specific member-invocable name,
* with the following member traits types and aliases:
* *
* * invoke_result * Used to create an invoker type bound to a specific member-invocable name.
* * invoke_result_t
* * is_invocable
* * is_invocable_v
* * is_invocable_r
* * is_invocable_r_v
* * is_nothrow_invocable
* * is_nothrow_invocable_v
* * is_nothrow_invocable_r
* * is_nothrow_invocable_r_v
*
* The container also has a static member function:
*
* * invoke
*
* And a member type alias:
*
* * invoke_type
*
* These members have behavior matching the behavior of C++17's corresponding
* invocation traits types, aliases, and functions, but substituting canonical
* invocation with member invocation.
* *
* Example: * Example:
* *
* FOLLY_CREATE_MEMBER_INVOKE_TRAITS(foo_invoke_traits, foo); * FOLLY_CREATE_MEMBER_INVOKER(foo_invoker, foo);
* *
* The traits container type `foo_invoke_traits` is generated in the current * The type `foo_invoker` is generated in the current namespace and may be used
* namespace and has the listed member types and aliases. They may be used as * as follows:
* follows:
* *
* struct CanFoo { * struct CanFoo {
* int foo(Bar&) { return 1; } * int foo(Bar&) { return 1; }
* int foo(Car&&) noexcept { return 2; } * int foo(Car&&) noexcept { return 2; }
* }; * };
* *
* using traits = foo_invoke_traits; * using traits = folly::invoke_traits<foo_invoker>;
* *
* traits::invoke(CanFoo{}, Car{}) // 2 * traits::invoke(CanFoo{}, Car{}) // 2
* *
...@@ -464,8 +413,8 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> { ...@@ -464,8 +413,8 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> {
* traits::is_nothrow_invocable_v<int, CanFoo, Car&&> // true * traits::is_nothrow_invocable_v<int, CanFoo, Car&&> // true
* traits::is_nothrow_invocable_v<char*, CanFoo, Car&&> // false * traits::is_nothrow_invocable_v<char*, CanFoo, Car&&> // false
*/ */
#define FOLLY_CREATE_MEMBER_INVOKE_TRAITS(classname, membername) \ #define FOLLY_CREATE_MEMBER_INVOKER(classname, membername) \
struct classname##__folly_detail_member_invoke { \ struct classname { \
template <typename O, typename... Args> \ template <typename O, typename... Args> \
constexpr auto operator()(O&& o, Args&&... args) const noexcept(noexcept( \ constexpr auto operator()(O&& o, Args&&... args) const noexcept(noexcept( \
static_cast<O&&>(o).membername(static_cast<Args&&>(args)...))) \ static_cast<O&&>(o).membername(static_cast<Args&&>(args)...))) \
...@@ -473,6 +422,4 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> { ...@@ -473,6 +422,4 @@ struct invoke_traits : detail::invoke_traits_base<Invoke> {
static_cast<O&&>(o).membername(static_cast<Args&&>(args)...)) { \ static_cast<O&&>(o).membername(static_cast<Args&&>(args)...)) { \
return static_cast<O&&>(o).membername(static_cast<Args&&>(args)...); \ return static_cast<O&&>(o).membername(static_cast<Args&&>(args)...); \
} \ } \
}; \ }
struct classname \
: ::folly::invoke_traits<classname##__folly_detail_member_invoke> {}
...@@ -41,7 +41,7 @@ struct Fn { ...@@ -41,7 +41,7 @@ struct Fn {
int volatile x_ = 17; int volatile x_ = 17;
}; };
FOLLY_CREATE_MEMBER_INVOKE_TRAITS(test_invoke_traits, test); FOLLY_CREATE_MEMBER_INVOKER(test_invoker, test);
struct Obj { struct Obj {
char test(int, int) noexcept { char test(int, int) noexcept {
...@@ -90,9 +90,9 @@ namespace unswappable { ...@@ -90,9 +90,9 @@ namespace unswappable {
FOLLY_MAYBE_UNUSED AltSwappableRet swap(AltSwappable&, AltSwappable&); FOLLY_MAYBE_UNUSED AltSwappableRet swap(AltSwappable&, AltSwappable&);
} // namespace unswappable } // namespace unswappable
FOLLY_CREATE_FREE_INVOKE_TRAITS(go_invoke_traits, go); FOLLY_CREATE_FREE_INVOKER(go_invoker, go);
FOLLY_CREATE_FREE_INVOKE_TRAITS(swap_invoke_traits, swap, std, unswappable); FOLLY_CREATE_FREE_INVOKER(swap_invoker, swap, std, unswappable);
FOLLY_CREATE_FREE_INVOKE_TRAITS(unused_invoke_traits, definitely_unused_name_); FOLLY_CREATE_FREE_INVOKER(unused_invoker, definitely_unused_name_);
} // namespace } // namespace
...@@ -144,7 +144,7 @@ TEST_F(InvokeTest, is_nothrow_invocable_r) { ...@@ -144,7 +144,7 @@ TEST_F(InvokeTest, is_nothrow_invocable_r) {
} }
TEST_F(InvokeTest, free_invoke) { TEST_F(InvokeTest, free_invoke) {
using traits = go_invoke_traits; using traits = folly::invoke_traits<go_invoker>;
x::Obj x_; x::Obj x_;
y::Obj y_; y::Obj y_;
...@@ -157,7 +157,7 @@ TEST_F(InvokeTest, free_invoke) { ...@@ -157,7 +157,7 @@ TEST_F(InvokeTest, free_invoke) {
} }
TEST_F(InvokeTest, free_invoke_result) { TEST_F(InvokeTest, free_invoke_result) {
using traits = go_invoke_traits; using traits = folly::invoke_traits<go_invoker>;
EXPECT_TRUE((std::is_same<int, traits::invoke_result_t<x::Obj, int>>::value)); EXPECT_TRUE((std::is_same<int, traits::invoke_result_t<x::Obj, int>>::value));
EXPECT_TRUE(( EXPECT_TRUE((
...@@ -165,7 +165,7 @@ TEST_F(InvokeTest, free_invoke_result) { ...@@ -165,7 +165,7 @@ TEST_F(InvokeTest, free_invoke_result) {
} }
TEST_F(InvokeTest, free_is_invocable) { TEST_F(InvokeTest, free_is_invocable) {
using traits = go_invoke_traits; using traits = folly::invoke_traits<go_invoker>;
EXPECT_TRUE((traits::is_invocable_v<x::Obj, int>)); EXPECT_TRUE((traits::is_invocable_v<x::Obj, int>));
EXPECT_TRUE((traits::is_invocable_v<y::Obj, char const*>)); EXPECT_TRUE((traits::is_invocable_v<y::Obj, char const*>));
...@@ -174,7 +174,7 @@ TEST_F(InvokeTest, free_is_invocable) { ...@@ -174,7 +174,7 @@ TEST_F(InvokeTest, free_is_invocable) {
} }
TEST_F(InvokeTest, free_is_invocable_r) { TEST_F(InvokeTest, free_is_invocable_r) {
using traits = go_invoke_traits; using traits = folly::invoke_traits<go_invoker>;
EXPECT_TRUE((traits::is_invocable_r_v<int, x::Obj, int>)); EXPECT_TRUE((traits::is_invocable_r_v<int, x::Obj, int>));
EXPECT_TRUE((traits::is_invocable_r_v<char, y::Obj, char const*>)); EXPECT_TRUE((traits::is_invocable_r_v<char, y::Obj, char const*>));
...@@ -183,7 +183,7 @@ TEST_F(InvokeTest, free_is_invocable_r) { ...@@ -183,7 +183,7 @@ TEST_F(InvokeTest, free_is_invocable_r) {
} }
TEST_F(InvokeTest, free_is_nothrow_invocable) { TEST_F(InvokeTest, free_is_nothrow_invocable) {
using traits = go_invoke_traits; using traits = folly::invoke_traits<go_invoker>;
EXPECT_TRUE((traits::is_nothrow_invocable_v<x::Obj, int>)); EXPECT_TRUE((traits::is_nothrow_invocable_v<x::Obj, int>));
EXPECT_FALSE((traits::is_nothrow_invocable_v<y::Obj, char const*>)); EXPECT_FALSE((traits::is_nothrow_invocable_v<y::Obj, char const*>));
...@@ -192,7 +192,7 @@ TEST_F(InvokeTest, free_is_nothrow_invocable) { ...@@ -192,7 +192,7 @@ TEST_F(InvokeTest, free_is_nothrow_invocable) {
} }
TEST_F(InvokeTest, free_is_nothrow_invocable_r) { TEST_F(InvokeTest, free_is_nothrow_invocable_r) {
using traits = go_invoke_traits; using traits = folly::invoke_traits<go_invoker>;
EXPECT_TRUE((traits::is_nothrow_invocable_r_v<int, x::Obj, int>)); EXPECT_TRUE((traits::is_nothrow_invocable_r_v<int, x::Obj, int>));
EXPECT_FALSE((traits::is_nothrow_invocable_r_v<char, y::Obj, char const*>)); EXPECT_FALSE((traits::is_nothrow_invocable_r_v<char, y::Obj, char const*>));
...@@ -201,7 +201,7 @@ TEST_F(InvokeTest, free_is_nothrow_invocable_r) { ...@@ -201,7 +201,7 @@ TEST_F(InvokeTest, free_is_nothrow_invocable_r) {
} }
TEST_F(InvokeTest, free_invoke_swap) { TEST_F(InvokeTest, free_invoke_swap) {
using traits = swap_invoke_traits; using traits = folly::invoke_traits<swap_invoker>;
int a = 3; int a = 3;
int b = 4; int b = 4;
...@@ -226,7 +226,7 @@ TEST_F(InvokeTest, free_invoke_swap) { ...@@ -226,7 +226,7 @@ TEST_F(InvokeTest, free_invoke_swap) {
} }
TEST_F(InvokeTest, member_invoke) { TEST_F(InvokeTest, member_invoke) {
using traits = test_invoke_traits; using traits = folly::invoke_traits<test_invoker>;
Obj fn; Obj fn;
...@@ -238,7 +238,7 @@ TEST_F(InvokeTest, member_invoke) { ...@@ -238,7 +238,7 @@ TEST_F(InvokeTest, member_invoke) {
} }
TEST_F(InvokeTest, member_invoke_result) { TEST_F(InvokeTest, member_invoke_result) {
using traits = test_invoke_traits; using traits = folly::invoke_traits<test_invoker>;
EXPECT_TRUE( EXPECT_TRUE(
(std::is_same<char, traits::invoke_result_t<Obj, int, char>>::value)); (std::is_same<char, traits::invoke_result_t<Obj, int, char>>::value));
...@@ -248,7 +248,7 @@ TEST_F(InvokeTest, member_invoke_result) { ...@@ -248,7 +248,7 @@ TEST_F(InvokeTest, member_invoke_result) {
} }
TEST_F(InvokeTest, member_is_invocable) { TEST_F(InvokeTest, member_is_invocable) {
using traits = test_invoke_traits; using traits = folly::invoke_traits<test_invoker>;
EXPECT_TRUE((traits::is_invocable_v<Obj, int, char>)); EXPECT_TRUE((traits::is_invocable_v<Obj, int, char>));
EXPECT_TRUE((traits::is_invocable_v<Obj, int, char*>)); EXPECT_TRUE((traits::is_invocable_v<Obj, int, char*>));
...@@ -256,7 +256,7 @@ TEST_F(InvokeTest, member_is_invocable) { ...@@ -256,7 +256,7 @@ TEST_F(InvokeTest, member_is_invocable) {
} }
TEST_F(InvokeTest, member_is_invocable_r) { TEST_F(InvokeTest, member_is_invocable_r) {
using traits = test_invoke_traits; using traits = folly::invoke_traits<test_invoker>;
EXPECT_TRUE((traits::is_invocable_r_v<int, Obj, int, char>)); EXPECT_TRUE((traits::is_invocable_r_v<int, Obj, int, char>));
EXPECT_TRUE((traits::is_invocable_r_v<int, Obj, int, char*>)); EXPECT_TRUE((traits::is_invocable_r_v<int, Obj, int, char*>));
...@@ -264,7 +264,7 @@ TEST_F(InvokeTest, member_is_invocable_r) { ...@@ -264,7 +264,7 @@ TEST_F(InvokeTest, member_is_invocable_r) {
} }
TEST_F(InvokeTest, member_is_nothrow_invocable) { TEST_F(InvokeTest, member_is_nothrow_invocable) {
using traits = test_invoke_traits; using traits = folly::invoke_traits<test_invoker>;
EXPECT_TRUE((traits::is_nothrow_invocable_v<Obj, int, char>)); EXPECT_TRUE((traits::is_nothrow_invocable_v<Obj, int, char>));
EXPECT_FALSE((traits::is_nothrow_invocable_v<Obj, int, char*>)); EXPECT_FALSE((traits::is_nothrow_invocable_v<Obj, int, char*>));
...@@ -272,7 +272,7 @@ TEST_F(InvokeTest, member_is_nothrow_invocable) { ...@@ -272,7 +272,7 @@ TEST_F(InvokeTest, member_is_nothrow_invocable) {
} }
TEST_F(InvokeTest, member_is_nothrow_invocable_r) { TEST_F(InvokeTest, member_is_nothrow_invocable_r) {
using traits = test_invoke_traits; using traits = folly::invoke_traits<test_invoker>;
EXPECT_TRUE((traits::is_nothrow_invocable_r_v<int, Obj, int, char>)); EXPECT_TRUE((traits::is_nothrow_invocable_r_v<int, Obj, int, char>));
EXPECT_FALSE((traits::is_nothrow_invocable_r_v<int, Obj, int, char*>)); EXPECT_FALSE((traits::is_nothrow_invocable_r_v<int, Obj, int, char*>));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment