/* * Copyright (c) Facebook, Inc. and its affiliates. * * 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 #include #include #include #include #include #include /** * include or backport: * * std::invoke * * std::invoke_result * * std::invoke_result_t * * std::is_invocable * * std::is_invocable_v * * std::is_invocable_r * * std::is_invocable_r_v * * std::is_nothrow_invocable * * std::is_nothrow_invocable_v * * std::is_nothrow_invocable_r * * std::is_nothrow_invocable_r_v */ #if __cpp_lib_invoke >= 201411 || _MSC_VER namespace folly { /* using override */ using std::invoke; } #else namespace folly { // mimic: std::invoke, C++17 template FOLLY_ERASE constexpr auto invoke(F&& f, Args&&... args) noexcept( noexcept(static_cast(f)(static_cast(args)...))) -> decltype(static_cast(f)(static_cast(args)...)) { return static_cast(f)(static_cast(args)...); } template FOLLY_ERASE constexpr auto invoke(M(C::*d), Args&&... args) -> decltype(std::mem_fn(d)(static_cast(args)...)) { return std::mem_fn(d)(static_cast(args)...); } } // namespace folly #endif // Only available in >= MSVC 2017 15.3 in C++17 #if __cpp_lib_is_invocable >= 201703 || \ (_MSC_VER >= 1911 && _MSVC_LANG > 201402) 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_invocable_r_v; /* using override */ using std::is_invocable_v; /* using override */ using std::is_nothrow_invocable; /* using override */ using std::is_nothrow_invocable_r; /* using override */ using std::is_nothrow_invocable_r_v; /* using override */ using std::is_nothrow_invocable_v; } // namespace folly #else namespace folly { namespace invoke_detail { template using invoke_result_ = decltype(invoke(std::declval(), std::declval()...)); template struct invoke_nothrow_ : bool_constant(), 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 invoke_detail // mimic: std::invoke_result, C++17 template struct invoke_result : invoke_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 : invoke_detail::is_invocable {}; // mimic: std::is_invocable_v, C++17 template FOLLY_INLINE_VARIABLE constexpr bool is_invocable_v = is_invocable::value; // mimic: std::is_invocable_r, C++17 template struct is_invocable_r : invoke_detail::is_invocable_r {}; // mimic: std::is_invocable_r_v, C++17 template FOLLY_INLINE_VARIABLE constexpr bool is_invocable_r_v = is_invocable_r::value; // mimic: std::is_nothrow_invocable, C++17 template struct is_nothrow_invocable : invoke_detail::is_nothrow_invocable {}; // mimic: std::is_nothrow_invocable_v, C++17 template FOLLY_INLINE_VARIABLE constexpr bool is_nothrow_invocable_v = is_nothrow_invocable::value; // mimic: std::is_nothrow_invocable_r, C++17 template struct is_nothrow_invocable_r : invoke_detail::is_nothrow_invocable_r {}; // mimic: std::is_nothrow_invocable_r_v, C++17 template FOLLY_INLINE_VARIABLE constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r::value; } // namespace folly #endif namespace folly { namespace detail { struct invoke_private_overload; template struct invoke_traits_base_ {}; template struct invoke_traits_base_ {}; template struct invoke_traits_base_ { FOLLY_INLINE_VARIABLE static constexpr Invoke invoke{}; }; template using invoke_traits_base = invoke_traits_base_, Invoke>; } // namespace detail // invoke_traits // // A traits container struct with the following member types, type aliases, and // variables: // // * 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 // // These members have behavior matching the behavior of C++17's corresponding // invocation traits types, type aliases, and variables, but using invoke_type // as the invocable argument passed to the usual nivocation traits. // // The traits container struct also has a member type alias: // // * invoke_type // // And an invocable variable as a default-constructed instance of invoke_type, // if the latter is constexpr default-constructible: // // * invoke template struct invoke_traits : detail::invoke_traits_base { public: using invoke_type = Invoke; // If invoke_type is constexpr default-constructible: // // inline static constexpr invoke_type invoke{}; template struct invoke_result : folly::invoke_result {}; template using invoke_result_t = folly::invoke_result_t; template struct is_invocable : folly::is_invocable {}; template FOLLY_INLINE_VARIABLE static constexpr bool is_invocable_v = is_invocable::value; template struct is_invocable_r : folly::is_invocable_r {}; template FOLLY_INLINE_VARIABLE static constexpr bool is_invocable_r_v = is_invocable_r::value; template struct is_nothrow_invocable : folly::is_nothrow_invocable {}; template FOLLY_INLINE_VARIABLE static constexpr bool is_nothrow_invocable_v = is_nothrow_invocable::value; template struct is_nothrow_invocable_r : folly::is_nothrow_invocable_r {}; template FOLLY_INLINE_VARIABLE static constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r::value; }; } // namespace folly #define FOLLY_DETAIL_CREATE_FREE_INVOKE_TRAITS_USING_1(_, funcname, ns) \ using ns::funcname; #define FOLLY_DETAIL_CREATE_FREE_INVOKE_TRAITS_USING(_, funcname, ...) \ BOOST_PP_EXPR_IIF( \ BOOST_PP_NOT(BOOST_PP_IS_EMPTY(__VA_ARGS__)), \ BOOST_PP_LIST_FOR_EACH( \ FOLLY_DETAIL_CREATE_FREE_INVOKE_TRAITS_USING_1, \ funcname, \ BOOST_PP_TUPLE_TO_LIST((__VA_ARGS__)))) /*** * FOLLY_CREATE_FREE_INVOKER * * Used to create an invoker type bound to a specific free-invocable name. * * Example: * * FOLLY_CREATE_FREE_INVOKER(foo_invoker, foo); * * The type `foo_invoker` is generated in the current namespace and may be used * as follows: * * namespace Deep { * struct CanFoo {}; * int foo(CanFoo const&, Bar&) { return 1; } * int foo(CanFoo&&, Car&&) noexcept { return 2; } * } * * using traits = folly::invoke_traits; * * traits::invoke(Deep::CanFoo{}, Car{}) // 2 * * traits::invoke_result // has member * traits::invoke_result_t // int * traits::invoke_result // empty * traits::invoke_result_t // error * * traits::is_invocable_v // true * traits::is_invocable_v // false * * traits::is_invocable_r_v // true * traits::is_invocable_r_v // false * * traits::is_nothrow_invocable_v // false * traits::is_nothrow_invocable_v // true * * traits::is_nothrow_invocable_v // false * traits::is_nothrow_invocable_v // false * traits::is_nothrow_invocable_v // true * traits::is_nothrow_invocable_v // false * * When a name has one or more primary definition in a fixed set of namespaces * and alternate definitions in the namespaces of its arguments, the primary * definitions may automatically be found as follows: * * FOLLY_CREATE_FREE_INVOKER(swap_invoker, swap, std); * * In this case, `swap_invoke_traits::invoke(int&, int&)` will use the primary * definition found in `namespace std` relative to the current namespace, which * may be equivalent to `namespace ::std`. In contrast: * * namespace Deep { * struct HasData {}; * void swap(HasData&, HasData&) { throw 7; } * } * * using traits = invoke_traits; * * HasData a, b; * traits::invoke(a, b); // throw 7 */ #define FOLLY_CREATE_FREE_INVOKER(classname, funcname, ...) \ namespace classname##__folly_detail_invoke_ns { \ FOLLY_MAYBE_UNUSED void funcname( \ ::folly::detail::invoke_private_overload&); \ FOLLY_DETAIL_CREATE_FREE_INVOKE_TRAITS_USING(_, funcname, __VA_ARGS__) \ struct __folly_detail_invoke_obj { \ template \ FOLLY_ERASE_HACK_GCC constexpr auto operator()(Args&&... args) const \ noexcept(noexcept(funcname(static_cast(args)...))) \ -> decltype(funcname(static_cast(args)...)) { \ return funcname(static_cast(args)...); \ } \ }; \ } \ struct classname \ : classname##__folly_detail_invoke_ns::__folly_detail_invoke_obj {} /*** * FOLLY_CREATE_MEMBER_INVOKER * * Used to create an invoker type bound to a specific member-invocable name. * * Example: * * FOLLY_CREATE_MEMBER_INVOKER(foo_invoker, foo); * * The type `foo_invoker` is generated in the current namespace and may be used * as follows: * * struct CanFoo { * int foo(Bar&) { return 1; } * int foo(Car&&) noexcept { return 2; } * }; * * using traits = folly::invoke_traits; * * traits::invoke(CanFoo{}, Car{}) // 2 * * traits::invoke_result // has member * traits::invoke_result_t // int * traits::invoke_result // empty * traits::invoke_result_t // error * * traits::is_invocable_v // true * traits::is_invocable_v // false * * traits::is_invocable_r_v // true * traits::is_invocable_r_v // false * * traits::is_nothrow_invocable_v // false * traits::is_nothrow_invocable_v // true * * traits::is_nothrow_invocable_v // false * traits::is_nothrow_invocable_v // false * traits::is_nothrow_invocable_v // true * traits::is_nothrow_invocable_v // false */ #define FOLLY_CREATE_MEMBER_INVOKER(classname, membername) \ struct classname { \ template \ FOLLY_ERASE_HACK_GCC constexpr auto operator()(O&& o, Args&&... args) \ const noexcept(noexcept( \ static_cast(o).membername(static_cast(args)...))) \ -> decltype(static_cast(o).membername( \ static_cast(args)...)) { \ return static_cast(o).membername(static_cast(args)...); \ } \ } /*** * FOLLY_CREATE_STATIC_MEMBER_INVOKER * * Used to create an invoker type template bound to a specific static-member- * invocable name. * * Example: * * FOLLY_CREATE_STATIC_MEMBER_INVOKER(foo_invoker, foo); * * The type template `foo_invoker` is generated in the current namespace and * may be used as follows: * * struct CanFoo { * static int foo(Bar&) { return 1; } * static int foo(Car&&) noexcept { return 2; } * }; * * using traits = folly::invoke_traits>; * * traits::invoke(Car{}) // 2 * * traits::invoke_result // has member * traits::invoke_result_t // int * traits::invoke_result // empty * traits::invoke_result_t // error * * traits::is_invocable_v // true * traits::is_invocable_v // false * * traits::is_invocable_r_v // true * traits::is_invocable_r_v // false * * traits::is_nothrow_invocable_v // false * traits::is_nothrow_invocable_v // true * * traits::is_nothrow_invocable_v // false * traits::is_nothrow_invocable_v // false * traits::is_nothrow_invocable_v // true * traits::is_nothrow_invocable_v // false */ #define FOLLY_CREATE_STATIC_MEMBER_INVOKER(classname, membername) \ template \ struct classname { \ template \ FOLLY_ERASE constexpr auto operator()(Args&&... args) const \ noexcept(noexcept(T::membername(static_cast(args)...))) \ -> decltype(T::membername(static_cast(args)...)) { \ return T::membername(static_cast(args)...); \ } \ }