From: Yedidya Feldblum Date: Wed, 18 Oct 2017 06:36:06 +0000 (-0700) Subject: Lift the invoke helper in Function.h X-Git-Tag: v2017.10.23.00~29 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=commitdiff_plain;h=86617507c88ebb628b8d292903edacd40e77ab13 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 --- diff --git a/folly/Function.h b/folly/Function.h index a73a8b7a..8cff8d8b 100644 --- a/folly/Function.h +++ b/folly/Function.h @@ -226,6 +226,7 @@ #include #include #include +#include namespace folly { @@ -405,19 +406,6 @@ bool execBig(Op o, Data* src, Data* dst) { return true; } -// Invoke helper -template -inline constexpr auto invoke(F&& f, Args&&... args) - -> decltype(std::forward(f)(std::forward(args)...)) { - return std::forward(f)(std::forward(args)...); -} - -template -inline constexpr auto invoke(M(C::*d), Args&&... args) - -> decltype(std::mem_fn(d)(std::forward(args)...)) { - return std::mem_fn(d)(std::forward(args)...); -} - } // namespace function } // namespace detail @@ -802,7 +790,7 @@ class FunctionRef final { template static ReturnType call(void* object, Args&&... args) { using Pointer = _t>; - return static_cast(detail::function::invoke( + return static_cast(invoke( static_cast(*static_cast(object)), static_cast(args)...)); } diff --git a/folly/Makefile.am b/folly/Makefile.am index 2e172ead..94b417c2 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -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 \ diff --git a/folly/functional/Invoke.h b/folly/functional/Invoke.h new file mode 100644 index 00000000..5e17a6b6 --- /dev/null +++ b/folly/functional/Invoke.h @@ -0,0 +1,161 @@ +/* + * 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 +#include + +#include + +/** + * 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 +constexpr auto invoke(F&& f, Args&&... args) noexcept( + noexcept(std::forward(f)(std::forward(args)...))) + -> decltype(std::forward(f)(std::forward(args)...)) { + return std::forward(f)(std::forward(args)...); +} +template +constexpr auto invoke(M(C::*d), Args&&... args) + -> decltype(std::mem_fn(d)(std::forward(args)...)) { + return std::mem_fn(d)(std::forward(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 +using invoke_result_ = + decltype(invoke(std::declval(), std::declval()...)); + +template +using invoke_nothrow_ = std::integral_constant< + bool, + noexcept(invoke(std::declval(), std::declval()...))>; + +// from: http://en.cppreference.com/w/cpp/types/result_of, CC-BY-SA + +template +struct invoke_result {}; + +template +struct invoke_result>, F, Args...> { + using type = invoke_result_; +}; + +template +struct is_invocable : std::false_type {}; + +template +struct is_invocable>, F, Args...> + : std::true_type {}; + +template +struct is_invocable_r : std::false_type {}; + +template +struct is_invocable_r>, R, F, Args...> + : std::is_convertible, R> {}; + +template +struct is_nothrow_invocable : std::false_type {}; + +template +struct is_nothrow_invocable>, F, Args...> + : invoke_nothrow_ {}; + +template +struct is_nothrow_invocable_r : std::false_type {}; + +template +struct is_nothrow_invocable_r>, R, F, Args...> + : StrictConjunction< + std::is_convertible, R>, + invoke_nothrow_> {}; + +} // namespace detail + +// mimic: std::invoke_result, C++17 +template +struct invoke_result : detail::invoke_result {}; + +// mimic: std::invoke_result_t, C++17 +template +using invoke_result_t = typename invoke_result::type; + +// mimic: std::is_invocable, C++17 +template +struct is_invocable : detail::is_invocable {}; + +// mimic: std::is_invocable_r, C++17 +template +struct is_invocable_r : detail::is_invocable_r {}; + +// mimic: std::is_nothrow_invocable, C++17 +template +struct is_nothrow_invocable : detail::is_nothrow_invocable {}; + +// mimic: std::is_nothrow_invocable_r, C++17 +template +struct is_nothrow_invocable_r + : detail::is_nothrow_invocable_r {}; + +} // namespace folly + +#endif diff --git a/folly/functional/test/InvokeTest.cpp b/folly/functional/test/InvokeTest.cpp new file mode 100644 index 00000000..721073d5 --- /dev/null +++ b/folly/functional/test/InvokeTest.cpp @@ -0,0 +1,83 @@ +/* + * 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 + +#include + +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(&Fn::operator()), fn, 1, 2)); + EXPECT_EQ(17, folly::invoke(static_cast(&Fn::operator()), fn, 1, "2")); +} + +TEST_F(InvokeTest, invoke_result) { + EXPECT_TRUE( + (std::is_same>::value)); + EXPECT_TRUE( + (std::is_same>:: + value)); +} + +TEST_F(InvokeTest, is_invocable) { + EXPECT_TRUE((folly::is_invocable::value)); + EXPECT_TRUE((folly::is_invocable::value)); + EXPECT_FALSE((folly::is_invocable::value)); +} + +TEST_F(InvokeTest, is_invocable_r) { + EXPECT_TRUE((folly::is_invocable_r::value)); + EXPECT_TRUE((folly::is_invocable_r::value)); + EXPECT_FALSE((folly::is_invocable_r::value)); +} + +TEST_F(InvokeTest, is_nothrow_invocable) { + EXPECT_TRUE((folly::is_nothrow_invocable::value)); + EXPECT_FALSE((folly::is_nothrow_invocable::value)); + EXPECT_FALSE((folly::is_nothrow_invocable::value)); +} + +TEST_F(InvokeTest, is_nothrow_invocable_r) { + EXPECT_TRUE((folly::is_nothrow_invocable_r::value)); + EXPECT_FALSE((folly::is_nothrow_invocable_r::value)); + EXPECT_FALSE((folly::is_nothrow_invocable_r::value)); +} diff --git a/folly/test/Makefile.am b/folly/test/Makefile.am index f0ca1460..eeada6eb 100644 --- a/folly/test/Makefile.am +++ b/folly/test/Makefile.am @@ -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