/* * Copyright (c) Meta Platforms, Inc. and 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 #include #include #define FOLLY_DETAIL_FORWARD_REF(a) static_cast(a) #define FOLLY_DETAIL_FORWARD_BODY(e) \ noexcept(noexcept(e))->decltype(e) { return e; } /** * 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 */ namespace folly { // invoke_fn // invoke // // mimic: std::invoke, C++17 struct invoke_fn { template FOLLY_ERASE constexpr auto operator()(F&& f, A&&... a) const noexcept(noexcept(static_cast(f)(static_cast(a)...))) -> decltype(static_cast(f)(static_cast(a)...)) { return static_cast(f)(static_cast(a)...); } template FOLLY_ERASE constexpr auto operator()(M C::*f, A&&... a) const noexcept(noexcept(std::mem_fn(f)(static_cast(a)...))) -> decltype(std::mem_fn(f)(static_cast(a)...)) { return std::mem_fn(f)(static_cast(a)...); } }; FOLLY_INLINE_VARIABLE constexpr invoke_fn invoke; } // namespace folly namespace folly { namespace invoke_detail { template struct traits { template using result = decltype( // FOLLY_DECLVAL(F &&)(FOLLY_DECLVAL(A &&)...)); template static constexpr bool nothrow = noexcept( // FOLLY_DECLVAL(F&&)(FOLLY_DECLVAL(A&&)...)); }; template struct traits_member_ptr { template using result = decltype( // std::mem_fn(FOLLY_DECLVAL(P))(FOLLY_DECLVAL(A &&)...)); template static constexpr bool nothrow = noexcept( // std::mem_fn(FOLLY_DECLVAL(P))(FOLLY_DECLVAL(A&&)...)); }; template struct traits : traits_member_ptr {}; template struct traits : traits_member_ptr {}; template struct traits : traits_member_ptr {}; template struct traits : traits_member_ptr {}; template struct traits : traits_member_ptr {}; template struct traits : traits_member_ptr {}; // adapted from: http://en.cppreference.com/w/cpp/types/result_of, CC-BY-SA template using invoke_result_t = typename traits::template result; template struct invoke_result {}; template struct invoke_result>, F, A...> { using type = invoke_result_t; }; template FOLLY_INLINE_VARIABLE constexpr bool is_invocable_v = false; template FOLLY_INLINE_VARIABLE constexpr bool is_invocable_v>, F, A...> = true; template FOLLY_INLINE_VARIABLE constexpr bool is_invocable_r_v = false; template FOLLY_INLINE_VARIABLE constexpr bool is_invocable_r_v>, R, F, A...> = std::is_convertible, R>::value; template FOLLY_INLINE_VARIABLE constexpr bool is_nothrow_invocable_v = false; template FOLLY_INLINE_VARIABLE constexpr bool is_nothrow_invocable_v>, F, A...> = traits::template nothrow; template FOLLY_INLINE_VARIABLE constexpr bool is_nothrow_invocable_r_v = false; template FOLLY_INLINE_VARIABLE constexpr bool is_nothrow_invocable_r_v>, R, F, A...> = std::is_convertible, R>::value&& traits::template nothrow; } // namespace invoke_detail // mimic: std::invoke_result, C++17 template using invoke_result = invoke_detail::invoke_result; // mimic: std::invoke_result_t, C++17 using invoke_detail::invoke_result_t; // mimic: std::is_invocable_v, C++17 template FOLLY_INLINE_VARIABLE constexpr bool is_invocable_v = invoke_detail::is_invocable_v; // mimic: std::is_invocable, C++17 template struct is_invocable : bool_constant> {}; // mimic: std::is_invocable_r_v, C++17 template FOLLY_INLINE_VARIABLE constexpr bool is_invocable_r_v = invoke_detail::is_invocable_r_v; // mimic: std::is_invocable_r, C++17 template struct is_invocable_r : bool_constant> {}; // mimic: std::is_nothrow_invocable_v, C++17 template FOLLY_INLINE_VARIABLE constexpr bool is_nothrow_invocable_v = invoke_detail::is_nothrow_invocable_v; // mimic: std::is_nothrow_invocable, C++17 template struct is_nothrow_invocable : bool_constant> {}; // mimic: std::is_nothrow_invocable_r_v, C++17 template FOLLY_INLINE_VARIABLE constexpr bool is_nothrow_invocable_r_v = invoke_detail::is_nothrow_invocable_r_v; // mimic: std::is_nothrow_invocable_r, C++17 template struct is_nothrow_invocable_r : bool_constant> {}; } // namespace folly 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 I invoke{}; }; template using invoke_traits_base = invoke_traits_base_, I>; } // 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 = I; // If invoke_type is constexpr default-constructible: // // inline static constexpr invoke_type invoke{}; template using invoke_result = invoke_detail::invoke_result; template using invoke_result_t = invoke_detail::invoke_result_t; template FOLLY_INLINE_VARIABLE static constexpr bool is_invocable_v = invoke_detail::is_invocable_v; template struct is_invocable // : bool_constant> {}; template FOLLY_INLINE_VARIABLE static constexpr bool is_invocable_r_v = invoke_detail::is_invocable_r_v; template struct is_invocable_r // : bool_constant> {}; template FOLLY_INLINE_VARIABLE static constexpr bool is_nothrow_invocable_v = invoke_detail::is_nothrow_invocable_v; template struct is_nothrow_invocable // : bool_constant> {}; template FOLLY_INLINE_VARIABLE static constexpr bool is_nothrow_invocable_r_v = invoke_detail::is_nothrow_invocable_r_v; template struct is_nothrow_invocable_r // : bool_constant< invoke_detail::is_nothrow_invocable_r_v> {}; }; } // 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_MAYBE_UNUSED 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_FREE_INVOKER_SUITE * * Used to create an invoker type and associated variable bound to a specific * free-invocable name. The invoker variable is named like the free-invocable * name and the invoker type is named with a suffix of _fn. * * See FOLLY_CREATE_FREE_INVOKER. */ #define FOLLY_CREATE_FREE_INVOKER_SUITE(funcname, ...) \ FOLLY_CREATE_FREE_INVOKER(funcname##_fn, funcname, __VA_ARGS__); \ FOLLY_MAYBE_UNUSED FOLLY_INLINE_VARIABLE constexpr funcname##_fn funcname {} /*** * FOLLY_CREATE_QUAL_INVOKER * * Used to create an invoker type bound to a specific free-invocable qualified * name. It is permitted that the qualification be empty and that the name be * unqualified in practice. This differs from FOLLY_CREATE_FREE_INVOKER in that * it is required that the name be in scope and that it is not possible to * provide a list of namespaces in which to look up the name.. */ #define FOLLY_CREATE_QUAL_INVOKER(classname, funcpath) \ struct classname { \ template \ FOLLY_MAYBE_UNUSED FOLLY_ERASE_HACK_GCC constexpr auto operator()( \ A&&... a) const \ FOLLY_DETAIL_FORWARD_BODY(funcpath(static_cast(a)...)) \ } /*** * FOLLY_CREATE_QUAL_INVOKER_SUITE * * Used to create an invoker type and associated variable bound to a specific * free-invocable qualified name. * * See FOLLY_CREATE_QUAL_INVOKER. */ #define FOLLY_CREATE_QUAL_INVOKER_SUITE(name, funcpath) \ FOLLY_CREATE_QUAL_INVOKER(name##_fn, funcpath); \ FOLLY_MAYBE_UNUSED FOLLY_INLINE_VARIABLE constexpr name##_fn name {} /*** * FOLLY_INVOKE_QUAL * * An invoker expression resulting in an invocable which, when invoked, invokes * the free-invocable qualified name with the given arguments. */ #define FOLLY_INVOKE_QUAL(funcpath) \ [](auto&&... __folly_param_a) \ FOLLY_CXX17_CONSTEXPR FOLLY_DETAIL_FORWARD_BODY( \ funcpath(FOLLY_DETAIL_FORWARD_REF(__folly_param_a)...)) /*** * 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_MAYBE_UNUSED 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_MEMBER_INVOKER_SUITE * * Used to create an invoker type and associated variable bound to a specific * member-invocable name. The invoker variable is named like the member- * invocable name and the invoker type is named with a suffix of _fn. * * See FOLLY_CREATE_MEMBER_INVOKER. */ #define FOLLY_CREATE_MEMBER_INVOKER_SUITE(membername) \ FOLLY_CREATE_MEMBER_INVOKER(membername##_fn, membername); \ FOLLY_MAYBE_UNUSED FOLLY_INLINE_VARIABLE constexpr membername##_fn \ membername {} /*** * FOLLY_INVOKE_MEMBER * * An invoker expression resulting in an invocable which, when invoked, invokes * the member on the object with the given arguments. * * Example: * * FOLLY_INVOKE_MEMBER(find)(map, key) * * Equivalent to: * * map.find(key) * * But also equivalent to: * * std::invoke(FOLLY_INVOKE_MEMBER(find), map, key) * * As an implementation detail, the resulting callable is a lambda. This has * two observable consequences. * * Since C++17 only, lambda invocations may be marked constexpr. * * Since C++20 only, lambda definitions may appear in an unevaluated context, * namely, in an operand to decltype, noexcept, sizeof, or typeid. */ #define FOLLY_INVOKE_MEMBER(membername) \ [](auto&& __folly_param_o, auto&&... __folly_param_a) \ FOLLY_CXX17_CONSTEXPR FOLLY_DETAIL_FORWARD_BODY( \ FOLLY_DETAIL_FORWARD_REF(__folly_param_o) \ .membername(FOLLY_DETAIL_FORWARD_REF(__folly_param_a)...)) /*** * 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_MAYBE_UNUSED FOLLY_ERASE constexpr auto operator()(Args&&... args) \ const noexcept(noexcept(U::membername(static_cast(args)...))) \ -> decltype(U::membername(static_cast(args)...)) { \ return U::membername(static_cast(args)...); \ } \ } /*** * FOLLY_CREATE_STATIC_MEMBER_INVOKER_SUITE * * Used to create an invoker type template and associated variable template * bound to a specific static-member-invocable name. The invoker variable * template is named like the static-member-invocable name and the invoker type * template is named with a suffix of _fn. * * See FOLLY_CREATE_STATIC_MEMBER_INVOKER. */ #define FOLLY_CREATE_STATIC_MEMBER_INVOKER_SUITE(membername) \ FOLLY_CREATE_STATIC_MEMBER_INVOKER(membername##_fn, membername); \ template \ FOLLY_MAYBE_UNUSED FOLLY_INLINE_VARIABLE constexpr membername##_fn \ membername {} namespace folly { namespace detail_tag_invoke_fn { void tag_invoke(); struct tag_invoke_fn { template constexpr auto operator()(Tag tag, Args&&... args) const noexcept(noexcept( tag_invoke(static_cast(tag), static_cast(args)...))) -> decltype(tag_invoke( static_cast(tag), static_cast(args)...)) { return tag_invoke(static_cast(tag), static_cast(args)...); } }; // Manually implement the traits here rather than defining them in terms of // the corresponding std::invoke_result/is_invocable/is_nothrow_invocable // traits to improve compile-times. We don't need all of the generality of // the std:: traits and the tag_invoke traits can be used heavily in CPO-based // code so optimising them for compile times can make a big difference. // Use the immediately-invoked function-pointer trick here to avoid // instantiating the std::declval() template. template using tag_invoke_result_t = decltype(tag_invoke( static_cast(nullptr)(), static_cast(nullptr)()...)); template auto try_tag_invoke(int) noexcept( noexcept(tag_invoke(FOLLY_DECLVAL(Tag&&), FOLLY_DECLVAL(Args&&)...))) -> decltype( static_cast( tag_invoke(FOLLY_DECLVAL(Tag &&), FOLLY_DECLVAL(Args&&)...)), std::true_type{}); template std::false_type try_tag_invoke(...) noexcept(false); template