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

Simpler free-invoke traits

Summary: [Folly] Simpler free-invoke traits. Only supports one namespace housing a base definition. For the typical case of `swap`, with a base definition in `namespace std`, this works.

Reviewed By: aary

Differential Revision: D8666221

fbshipit-source-id: abfd302e430ad7151c119e98a706201265d302d3
parent a65e66ab
...@@ -67,6 +67,8 @@ ...@@ -67,6 +67,8 @@
*/ */
#define FB_SINGLE_ARG(...) __VA_ARGS__ #define FB_SINGLE_ARG(...) __VA_ARGS__
#define FOLLY_PP_DETAIL_APPEND_VA_ARG(...) , ##__VA_ARGS__
/** /**
* Helper macro that just ignores its parameters. * Helper macro that just ignores its parameters.
*/ */
......
...@@ -167,6 +167,8 @@ struct is_nothrow_invocable_r ...@@ -167,6 +167,8 @@ struct is_nothrow_invocable_r
namespace folly { namespace folly {
namespace detail { namespace detail {
struct invoke_private_overload;
template <typename Invoke> template <typename Invoke>
struct free_invoke_proxy { struct free_invoke_proxy {
public: public:
...@@ -195,8 +197,6 @@ struct free_invoke_proxy { ...@@ -195,8 +197,6 @@ struct free_invoke_proxy {
} // namespace detail } // namespace detail
} // namespace folly } // namespace folly
#define FOLLY_INVOKE_DETAIL_USING_NAMESPACE(ns) using namespace ns;
/*** /***
* FOLLY_CREATE_FREE_INVOKE_TRAITS * FOLLY_CREATE_FREE_INVOKE_TRAITS
* *
...@@ -275,20 +275,28 @@ struct free_invoke_proxy { ...@@ -275,20 +275,28 @@ struct free_invoke_proxy {
* 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_INVOKE_TRAITS(classname, funcname, ...) \
namespace classname##__folly_detail_invoke_ns { \ namespace classname##__folly_detail_invoke_ns { \
FOLLY_PP_FOR_EACH(FOLLY_INVOKE_DETAIL_USING_NAMESPACE, __VA_ARGS__) \ namespace classname##__folly_detail_invoke_ns_inline { \
struct classname##__folly_detail_invoke { \ FOLLY_PUSH_WARNING \
template <typename... Args> \ FOLLY_CLANG_DISABLE_WARNING("-Wunused-function") \
constexpr auto operator()(Args&&... args) const \ void funcname(::folly::detail::invoke_private_overload&); \
noexcept(noexcept(funcname(static_cast<Args&&>(args)...))) \ FOLLY_POP_WARNING \
-> decltype(funcname(static_cast<Args&&>(args)...)) { \ } \
return funcname(static_cast<Args&&>(args)...); \ using FB_ARG_2_OR_1( \
} \ classname##__folly_detail_invoke_ns_inline \
}; \ FOLLY_PP_DETAIL_APPEND_VA_ARG(__VA_ARGS__))::funcname; \
} \ struct classname##__folly_detail_invoke { \
struct classname : ::folly::detail::free_invoke_proxy< \ template <typename... Args> \
classname##__folly_detail_invoke_ns:: \ constexpr auto operator()(Args&&... args) const \
noexcept(noexcept(funcname(static_cast<Args&&>(args)...))) \
-> decltype(funcname(static_cast<Args&&>(args)...)) { \
return funcname(static_cast<Args&&>(args)...); \
} \
}; \
} \
struct classname : ::folly::detail::free_invoke_proxy< \
classname##__folly_detail_invoke_ns:: \
classname##__folly_detail_invoke> {} classname##__folly_detail_invoke> {}
namespace folly { namespace folly {
......
...@@ -76,7 +76,16 @@ float go(z::Obj const&, int) { ...@@ -76,7 +76,16 @@ float go(z::Obj const&, int) {
return 9; return 9;
} }
FOLLY_CREATE_FREE_INVOKE_TRAITS(go_invoke_traits, go, z); namespace swappable {
struct Obj {
int x_;
};
void swap(Obj&, Obj&) noexcept {} // no-op
} // namespace swappable
FOLLY_CREATE_FREE_INVOKE_TRAITS(go_invoke_traits, go);
FOLLY_CREATE_FREE_INVOKE_TRAITS(swap_invoke_traits, swap, std);
FOLLY_CREATE_FREE_INVOKE_TRAITS(unused_invoke_traits, definitely_unused_name_);
} // namespace } // namespace
...@@ -132,15 +141,12 @@ TEST_F(InvokeTest, free_invoke) { ...@@ -132,15 +141,12 @@ TEST_F(InvokeTest, free_invoke) {
x::Obj x_; x::Obj x_;
y::Obj y_; y::Obj y_;
z::Obj z_;
EXPECT_TRUE(noexcept(traits::invoke(x_, 3))); EXPECT_TRUE(noexcept(traits::invoke(x_, 3)));
EXPECT_FALSE(noexcept(traits::invoke(y_, "hello"))); EXPECT_FALSE(noexcept(traits::invoke(y_, "hello")));
EXPECT_FALSE(noexcept(traits::invoke(z_, 7)));
EXPECT_EQ(3, traits::invoke(x_, 3)); EXPECT_EQ(3, traits::invoke(x_, 3));
EXPECT_EQ('a', traits::invoke(y_, "hello")); EXPECT_EQ('a', traits::invoke(y_, "hello"));
EXPECT_EQ(9, traits::invoke(z_, 7));
} }
TEST_F(InvokeTest, free_invoke_result) { TEST_F(InvokeTest, free_invoke_result) {
...@@ -149,8 +155,6 @@ TEST_F(InvokeTest, free_invoke_result) { ...@@ -149,8 +155,6 @@ TEST_F(InvokeTest, free_invoke_result) {
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((
std::is_same<char, traits::invoke_result_t<y::Obj, char const*>>::value)); std::is_same<char, traits::invoke_result_t<y::Obj, char const*>>::value));
EXPECT_TRUE(
(std::is_same<float, traits::invoke_result_t<z::Obj, int>>::value));
} }
TEST_F(InvokeTest, free_is_invocable) { TEST_F(InvokeTest, free_is_invocable) {
...@@ -158,7 +162,7 @@ TEST_F(InvokeTest, free_is_invocable) { ...@@ -158,7 +162,7 @@ TEST_F(InvokeTest, free_is_invocable) {
EXPECT_TRUE((traits::is_invocable<x::Obj, int>::value)); EXPECT_TRUE((traits::is_invocable<x::Obj, int>::value));
EXPECT_TRUE((traits::is_invocable<y::Obj, char const*>::value)); EXPECT_TRUE((traits::is_invocable<y::Obj, char const*>::value));
EXPECT_TRUE((traits::is_invocable<z::Obj, int>::value)); EXPECT_FALSE((traits::is_invocable<z::Obj, int>::value));
EXPECT_FALSE((traits::is_invocable<float>::value)); EXPECT_FALSE((traits::is_invocable<float>::value));
} }
...@@ -167,7 +171,7 @@ TEST_F(InvokeTest, free_is_invocable_r) { ...@@ -167,7 +171,7 @@ TEST_F(InvokeTest, free_is_invocable_r) {
EXPECT_TRUE((traits::is_invocable_r<int, x::Obj, int>::value)); EXPECT_TRUE((traits::is_invocable_r<int, x::Obj, int>::value));
EXPECT_TRUE((traits::is_invocable_r<char, y::Obj, char const*>::value)); EXPECT_TRUE((traits::is_invocable_r<char, y::Obj, char const*>::value));
EXPECT_TRUE((traits::is_invocable_r<float, z::Obj, int>::value)); EXPECT_FALSE((traits::is_invocable_r<float, z::Obj, int>::value));
EXPECT_FALSE((traits::is_invocable_r<from_any, float>::value)); EXPECT_FALSE((traits::is_invocable_r<from_any, float>::value));
} }
...@@ -190,6 +194,28 @@ TEST_F(InvokeTest, free_is_nothrow_invocable_r) { ...@@ -190,6 +194,28 @@ TEST_F(InvokeTest, free_is_nothrow_invocable_r) {
EXPECT_FALSE((traits::is_nothrow_invocable_r<from_any, float>::value)); EXPECT_FALSE((traits::is_nothrow_invocable_r<from_any, float>::value));
} }
TEST_F(InvokeTest, free_invoke_swap) {
using traits = swap_invoke_traits;
int a = 3;
int b = 4;
traits::invoke(a, b);
EXPECT_EQ(4, a);
EXPECT_EQ(3, b);
swappable::Obj x{3};
swappable::Obj y{4};
traits::invoke(x, y);
EXPECT_EQ(3, x.x_);
EXPECT_EQ(4, y.x_);
std::swap(x, y);
EXPECT_EQ(4, x.x_);
EXPECT_EQ(3, y.x_);
}
TEST_F(InvokeTest, member_invoke) { TEST_F(InvokeTest, member_invoke) {
using traits = test_invoke_traits; using traits = test_invoke_traits;
......
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