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

Lift the invoke helper in Function.h

Summary: [Folly] Lift the `invoke` helper in `Function.h`.

Reviewed By: aary

Differential Revision: D6050569

fbshipit-source-id: da07901b8d058b0199d23db675c0fb9082fdf67d
parent 11b73c8f
......@@ -226,6 +226,7 @@
#include <folly/CppAttributes.h>
#include <folly/Portability.h>
#include <folly/Traits.h>
#include <folly/functional/Invoke.h>
namespace folly {
......@@ -405,19 +406,6 @@ bool execBig(Op o, Data* src, Data* dst) {
return true;
}
// Invoke helper
template <typename F, typename... Args>
inline constexpr auto invoke(F&& f, Args&&... args)
-> decltype(std::forward<F>(f)(std::forward<Args>(args)...)) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
template <typename M, typename C, typename... Args>
inline constexpr auto invoke(M(C::*d), Args&&... args)
-> decltype(std::mem_fn(d)(std::forward<Args>(args)...)) {
return std::mem_fn(d)(std::forward<Args>(args)...);
}
} // namespace function
} // namespace detail
......@@ -802,7 +790,7 @@ class FunctionRef<ReturnType(Args...)> final {
template <typename Fun>
static ReturnType call(void* object, Args&&... args) {
using Pointer = _t<std::add_pointer<Fun>>;
return static_cast<ReturnType>(detail::function::invoke(
return static_cast<ReturnType>(invoke(
static_cast<Fun&&>(*static_cast<Pointer>(object)),
static_cast<Args&&>(args)...));
}
......
......@@ -203,6 +203,7 @@ nobase_follyinclude_HEADERS = \
FormatTraits.h \
Format.h \
Format-inl.h \
functional/Invoke.h \
futures/Barrier.h \
futures/DrivableExecutor.h \
futures/Future-pre.h \
......
/*
* Copyright 2017-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <functional>
#include <type_traits>
#include <folly/Traits.h>
/**
* include or backport:
* * std::invoke
* * std::invoke_result
* * std::invoke_result_t
* * std::is_invocable
* * std::is_invocable_r
* * std::is_nothrow_invocable
* * std::is_nothrow_invocable_r
*/
#if __cpp_lib_invoke >= 201411 || _MSC_VER
namespace folly {
/* using override */ using std::invoke;
}
#else
namespace folly {
// mimic: std::invoke, C++17
template <typename F, typename... Args>
constexpr auto invoke(F&& f, Args&&... args) noexcept(
noexcept(std::forward<F>(f)(std::forward<Args>(args)...)))
-> decltype(std::forward<F>(f)(std::forward<Args>(args)...)) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
template <typename M, typename C, typename... Args>
constexpr auto invoke(M(C::*d), Args&&... args)
-> decltype(std::mem_fn(d)(std::forward<Args>(args)...)) {
return std::mem_fn(d)(std::forward<Args>(args)...);
}
} // namespace folly
#endif
#if __cpp_lib_is_invocable >= 201703 || _MSC_VER
namespace folly {
/* using override */ using std::invoke_result;
/* using override */ using std::invoke_result_t;
/* using override */ using std::is_invocable;
/* using override */ using std::is_invocable_r;
/* using override */ using std::is_nothrow_invocable;
/* using override */ using std::is_nothrow_invocable_r;
}
#else
namespace folly {
namespace detail {
template <typename F, typename... Args>
using invoke_result_ =
decltype(invoke(std::declval<F>(), std::declval<Args>()...));
template <typename F, typename... Args>
using invoke_nothrow_ = std::integral_constant<
bool,
noexcept(invoke(std::declval<F>(), std::declval<Args>()...))>;
// from: http://en.cppreference.com/w/cpp/types/result_of, CC-BY-SA
template <typename Void, typename F, typename... Args>
struct invoke_result {};
template <typename F, typename... Args>
struct invoke_result<void_t<invoke_result_<F, Args...>>, F, Args...> {
using type = invoke_result_<F, Args...>;
};
template <typename Void, typename F, typename... Args>
struct is_invocable : std::false_type {};
template <typename F, typename... Args>
struct is_invocable<void_t<invoke_result_<F, Args...>>, F, Args...>
: std::true_type {};
template <typename Void, typename R, typename F, typename... Args>
struct is_invocable_r : std::false_type {};
template <typename R, typename F, typename... Args>
struct is_invocable_r<void_t<invoke_result_<F, Args...>>, R, F, Args...>
: std::is_convertible<invoke_result_<F, Args...>, R> {};
template <typename Void, typename F, typename... Args>
struct is_nothrow_invocable : std::false_type {};
template <typename F, typename... Args>
struct is_nothrow_invocable<void_t<invoke_result_<F, Args...>>, F, Args...>
: invoke_nothrow_<F, Args...> {};
template <typename Void, typename R, typename F, typename... Args>
struct is_nothrow_invocable_r : std::false_type {};
template <typename R, typename F, typename... Args>
struct is_nothrow_invocable_r<void_t<invoke_result_<F, Args...>>, R, F, Args...>
: StrictConjunction<
std::is_convertible<invoke_result_<F, Args...>, R>,
invoke_nothrow_<F, Args...>> {};
} // namespace detail
// mimic: std::invoke_result, C++17
template <typename F, typename... Args>
struct invoke_result : detail::invoke_result<void, F, Args...> {};
// mimic: std::invoke_result_t, C++17
template <typename F, typename... Args>
using invoke_result_t = typename invoke_result<F, Args...>::type;
// mimic: std::is_invocable, C++17
template <typename F, typename... Args>
struct is_invocable : detail::is_invocable<void, F, Args...> {};
// mimic: std::is_invocable_r, C++17
template <typename R, typename F, typename... Args>
struct is_invocable_r : detail::is_invocable_r<void, R, F, Args...> {};
// mimic: std::is_nothrow_invocable, C++17
template <typename F, typename... Args>
struct is_nothrow_invocable : detail::is_nothrow_invocable<void, F, Args...> {};
// mimic: std::is_nothrow_invocable_r, C++17
template <typename R, typename F, typename... Args>
struct is_nothrow_invocable_r
: detail::is_nothrow_invocable_r<void, R, F, Args...> {};
} // namespace folly
#endif
/*
* Copyright 2017-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/functional/Invoke.h>
#include <folly/portability/GTest.h>
class InvokeTest : public testing::Test {};
namespace {
struct Fn {
char operator()(int, int) noexcept {
return 'a';
}
int volatile&& operator()(int, char const*) {
return std::move(x_);
}
float operator()(float, float) {
return 3.14;
}
int volatile x_ = 17;
};
} // namespace
TEST_F(InvokeTest, invoke) {
Fn fn;
EXPECT_TRUE(noexcept(folly::invoke(fn, 1, 2)));
EXPECT_FALSE(noexcept(folly::invoke(fn, 1, "2")));
EXPECT_EQ('a', folly::invoke(fn, 1, 2));
EXPECT_EQ(17, folly::invoke(fn, 1, "2"));
using FnA = char (Fn::*)(int, int);
using FnB = int volatile && (Fn::*)(int, char const*);
EXPECT_EQ('a', folly::invoke(static_cast<FnA>(&Fn::operator()), fn, 1, 2));
EXPECT_EQ(17, folly::invoke(static_cast<FnB>(&Fn::operator()), fn, 1, "2"));
}
TEST_F(InvokeTest, invoke_result) {
EXPECT_TRUE(
(std::is_same<char, folly::invoke_result_t<Fn, int, char>>::value));
EXPECT_TRUE(
(std::is_same<int volatile&&, folly::invoke_result_t<Fn, int, char*>>::
value));
}
TEST_F(InvokeTest, is_invocable) {
EXPECT_TRUE((folly::is_invocable<Fn, int, char>::value));
EXPECT_TRUE((folly::is_invocable<Fn, int, char*>::value));
EXPECT_FALSE((folly::is_invocable<Fn, int>::value));
}
TEST_F(InvokeTest, is_invocable_r) {
EXPECT_TRUE((folly::is_invocable_r<int, Fn, int, char>::value));
EXPECT_TRUE((folly::is_invocable_r<int, Fn, int, char*>::value));
EXPECT_FALSE((folly::is_invocable_r<int, Fn, int>::value));
}
TEST_F(InvokeTest, is_nothrow_invocable) {
EXPECT_TRUE((folly::is_nothrow_invocable<Fn, int, char>::value));
EXPECT_FALSE((folly::is_nothrow_invocable<Fn, int, char*>::value));
EXPECT_FALSE((folly::is_nothrow_invocable<Fn, int>::value));
}
TEST_F(InvokeTest, is_nothrow_invocable_r) {
EXPECT_TRUE((folly::is_nothrow_invocable_r<int, Fn, int, char>::value));
EXPECT_FALSE((folly::is_nothrow_invocable_r<int, Fn, int, char*>::value));
EXPECT_FALSE((folly::is_nothrow_invocable_r<int, Fn, int>::value));
}
......@@ -92,6 +92,8 @@ check_PROGRAMS += foreach_benchmark
hash_test_SOURCES = HashTest.cpp
hash_test_LDADD = libfollytestmain.la
invoke_test_SOURCES = ../functional/test/InvokeTest.cpp
invoke_test_LDADD = libfollytestmain.la
fbstring_test_using_jemalloc_SOURCES = FBStringTest.cpp
fbstring_test_using_jemalloc_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
......
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