// bslstl_function_invokerutil.h -*-C++-*- #ifndef INCLUDED_BSLSTL_FUNCTION_INVOKERUTIL #define INCLUDED_BSLSTL_FUNCTION_INVOKERUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide invoker adaptors for 'bsl::function' // //@CLASSES: // Function_InvokerUtil: Utility for returning an appropriate invoker function // Function_InvokerUtilNullCheck: Customization point to detect null invocable // //@MACROS // BSLSTL_FUNCTION_INVOKERUTIL_SUPPORT_IS_FUNC_INVOCABLE: defined if supported // //@SEE_ALSO: bslstl_function // //@DESCRIPTION: This component provides a struct, 'Function_InvokerUtil', // containing a function template, 'invokerForFunc', that returns a pointer to // a function that is used to invoke a callable object of a particular type. // The returned type is custom-generated for each specific target type. This // component is for private use only. // // The client of this component, 'bsl::function', is a complex class that is // templated in two ways: // //: 1 The class itself has a template parameter representing the prototype //: (argument and return types) of its call operator. E.g., type //: 'bsl::function<int(char*)>' has member 'int operator()(char*);'. //: //: 2 Several of its constructors take an argument of template parameter //: callable type and wrap it, using type erasure, so that the type of the //: wrapped target is not part of the type of the 'bsl::function'. // // Only the invocation mechanism needs both kinds of template parameters; other // parts of 'bsl::function' (e.g., 'bslstl::Function_Rep') concern themselves // with only the callable object type, not with the prototype of the call // operator. This component factors out most of that complexity so as to // minimise code size, especially when using the 'sim_cpp11_features.pl' script // to simulate C++11 variadic templates in C++03. // // The classes in this component are stateless and contain only static // functions. // ///Macros ///------ // If this component supports checking whether an object of an arbitrary // non-cvref-qualified type is invocable under a particular prototype, the // 'BSLSTL_FUNCTION_INVOKERUTIL_SUPPORT_IS_FUNC_INVOCABLE' macro is defined, // and it is not defined otherwise. // ///Return value of 'Function_InvokerUtil::invokerForFunc' ///------------------------------------------------------ // The function pointer, 'invoker_p', returned by // 'Function_InvokerUtil::invokerForFunc<RET(ARG0, ARG1, ...)>' takes an // argument of type 'Function_Rep *' and zero or more argument types 'ARG0', // 'ARG1', ..., as specified by the template argument. Calling // 'invoker_p(rep, arg0, arg1, ...)' gets the target, 'f' from 'rep' and // invokes it with the supplied arguments. Invocation of 'f' follows the // definition of *INVOKE* in section [func.require] of the C++ standard. These // rules are summarized in the following table: //.. // +----------------------------+-----------------------+ // | Type of target object, 'f' | Invocation expression | // +============================+=======================+ // | Pointer to function or | f(arg0, arg1, ...) | // | functor class | | // +----------------------------+-----------------------+ // | Pointer to member function | (arg0X.*f)(arg1, ...) | // +----------------------------+-----------------------+ // | pointer to data member | arg0X.*f | // +----------------------------+-----------------------+ //.. // The arguments to 'f' must be implicitly convertible from the corresponding // argument types 'ARG0', 'ARG1', ... and the return value of the call // expression must be implicitly convertible to 'RET', unless 'RET' is 'void'. // // In the case of a pointer to member function, 'R (T::*f)(...)', or pointer to // data member 'R T::*f', 'arg0X' is one of the following: // //: o 'arg0' if 'ARG0' is 'T' or derived from 'T'. //: o 'arg0.get()' if 'ARG0' is a specialization of 'reference_wrapper'. //: o '(*arg0)' if 'ARG0' is a pointer type or pointer-like type (e.g., a smart //: pointer). // // Note that, consistent with the C++ Standard definition of *INVOKE*, we // consider pointer-to-member-function and pointer-to-data-member types to be // "callable" even though, strictly speaking, they lack an 'operator()'. // ///Customization point 'Function_InvokerUtilNullCheck' ///--------------------------------------------------- // The class template, 'Function_InvokerUtilNullCheck<T>' provides a single, // 'static' member function 'isNull(const T& f)' that returns 'true' iff 'f' // represents a "null value". By default, // 'Function_InvokerUtilNullCheck<T>::isNull' returns 'true' iff 'T' is a // pointer or pointer-to-member type and has a null value. For non-pointer // types, the primary template always returns 'false'. However, other // components can provide specializations of 'Function_InvokerUtilNullCheck' // that add the notion of "nullness" to other invocable types. In particular, // 'bslstl_function.h' specializes this template for 'bsl::function' and // 'bdef_function.h' specializes this template for 'bdef_function'. In both // cases, a function object is considered null if it is empty, i.e., it does // not wrap an invocable object. Although it is theoretically possible to // specialize 'Function_InvokerUtilNullCheck' for types not related to // 'bsl::function', doing so would go outside of the behavior of the standard // 'std::function' type that 'bsl::function' is emulating. For this reason, // 'Function_InvokerUtilNullCheck' is tucked away in this private component for // use only through explicit collaboration. #include <bslscm_version.h> #include <bslalg_nothrowmovableutil.h> #include <bslmf_addrvaluereference.h> #include <bslmf_conditional.h> #include <bslmf_forwardingtype.h> #include <bslmf_integralconstant.h> #include <bslmf_invokeresult.h> #include <bslmf_ismemberpointer.h> #include <bslmf_isvoid.h> #include <bslmf_memberfunctionpointertraits.h> #include <bslmf_movableref.h> #include <bsls_compilerfeatures.h> #include <bsls_keyword.h> #include <bsls_libraryfeatures.h> #include <bsls_nullptr.h> #include <bslstl_function_rep.h> #include <bslstl_function_smallobjectoptimization.h> #include <utility> #if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // Include version that can be compiled with C++03 // Generated on Thu Oct 21 10:11:37 2021 // Command line: sim_cpp11_features.pl bslstl_function_invokerutil.h # define COMPILING_BSLSTL_FUNCTION_INVOKERUTIL_H # include <bslstl_function_invokerutil_cpp03.h> # undef COMPILING_BSLSTL_FUNCTION_INVOKERUTIL_H #else #ifndef BSLS_PLATFORM_CMP_SUN #define BSLSTL_FUNCTION_INVOKERUTIL_CAST_RESULT(RET, X) static_cast<RET>(X) #else #define BSLSTL_FUNCTION_INVOKERUTIL_CAST_RESULT(RET, X) (RET)(X) #endif #if defined(BSLMF_INVOKERESULT_SUPPORT_CPP17_SEMANTICS) \ && defined(BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE) \ && defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) \ && defined(BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY) #define BSLSTL_FUNCTION_INVOKERUTIL_SUPPORT_IS_FUNC_INVOCABLE #endif namespace BloombergLP { namespace bslstl { #ifdef BSLSTL_FUNCTION_INVOKERUTIL_SUPPORT_IS_FUNC_INVOCABLE template <class PROTOTYPE, class FUNC> struct Function_InvokerUtil_IsFuncInvocable; // forward declaration #endif // =========================== // struct Function_InvokerUtil // =========================== struct Function_InvokerUtil { // This struct is a namespace containing a single function template, // 'invokerForFunc', that returns a pointer to a function that is used to // invoke a callable object of a particular type. // TYPES enum { // Enumeration of the different types of callable objects. e_Null, e_FunctionPtr, e_MemFunctionPtr, e_MemDataPtr, e_InplaceFunctor, e_OutofplaceFunctor }; typedef Function_Rep::GenericInvoker GenericInvoker; // Generic function pointer. This type is as close as we can get to // 'void *' for function pointers. #ifdef BSLSTL_FUNCTION_INVOKERUTIL_SUPPORT_IS_FUNC_INVOCABLE template <class PROTOTYPE, class FUNC> struct IsFuncInvocable : Function_InvokerUtil_IsFuncInvocable<PROTOTYPE, FUNC> { // This 'struct' template implements a Boolean metafunction that // publicly inherits from 'bsl::true_type' if an object of the // specified 'FUNC' type is invocable under the specified 'PROTOTYPE', // and publicly inherits from 'bsl::false_type' otherwise. An object // of 'FUNC' type is invocable under the 'PROTOTYPE' if it is // Lvalue-Callable with the arguments of the 'PROTOTYPE' (as forwarded // by the facilities of 'bslmf_forwardingtype), and returns an object // of type explicitly convertible to the return type of the // 'PROTOTYPE'. If the return type of the 'PROTOTYPE' is 'void', then // any type is considered explicitly convertible to the return type of // the 'PROTOTYPE'. This 'struct' template requires 'PROTOTYPE" to be // an unqualified function type. // // Note that 'IsFuncInvocable' is qualitatively different than // 'std::is_invocable_r', in that it makes concessions for supporting // legacy behavior of 'bsl::function'. // 'std::is_invocable_r<RET, FUNC, ARGS...>' requires that the return // type of the invocation of 'FUNC' with 'ARGS...' be implicitly // convertible to 'RET', as opposed to explicitly convertible. // Further, the use of 'bslmf::ForwardingType' to forward arguments in // the invoker of a 'bsl::function' creates qualitatively different // behavior than the argument forwarding mechanism used by the standard // 'INVOKE' pseudo-expression. }; #endif // CLASS METHODS template <class PROTOTYPE> static GenericInvoker *invokerForFunc(const bsl::nullptr_t&); // Return a null pointer. Note that template argument 'PROTOTYPE' must // be supplied excplicitly, as there is no way to deduce it from the // function arguments. template <class PROTOTYPE, class FUNC> static GenericInvoker *invokerForFunc(const FUNC& f); // Return a pointer to the invoker for a callable object of (template // paramter) type 'FUNC'. If the specified 'f' object is a null // pointer or null pointer-to-member, return a null pointer. Note that // template argument 'PROTOTYPE' must be supplied excplicitly, as there // is no way to deduce it from the function arguments. }; // ============================================= // template struct Function_InvokerUtilNullCheck // ============================================= template <class FUNC> struct Function_InvokerUtilNullCheck { // Provides an 'isNull' static method that that returns whether or not its // argument is "null", i.e., it cannot be invoked. For must 'FUNC' types // 'isNull' always returns 'false' as every instance of 'FUNC' is // invocable. However, specializations of this class, especially for // pointer types, have 'isNull' functions that sometimes return 'true'. // This class is a customization point: types outside of this component can // (but rarely should) specialize this template. In particular, // 'bslstl_function' contains a specialization for 'bsl::function'. // CLASS METHODS static bool isNull(const FUNC&); // Return 'false'. }; template <class FUNC> struct Function_InvokerUtilNullCheck<FUNC *> { // Specialization of dispatcher for pointer objects. // CLASS METHODS static bool isNull(FUNC *f); // Return 'true' if the specified 'f' pointer is null; otherwise // 'false'. }; template <class CLASS, class MEMTYPE> struct Function_InvokerUtilNullCheck<MEMTYPE CLASS::*> { // Specialization of dispatcher for pointer-to-member objects. public: // CLASS METHODS static bool isNull(MEMTYPE CLASS::* f); // Return 'true' if the specified 'f' pointer to member is null; // otherwise 'false'. }; #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=13 // ==================================================== // template struct Function_InvokerUtil_IsFuncInvocable // ==================================================== #ifdef BSLSTL_FUNCTION_INVOKERUTIL_SUPPORT_IS_FUNC_INVOCABLE template <class VOID_TYPE, class RET, class FUNC, class... ARGS> struct Function_InvokerUtil_IsFuncInvocableImp; // forward declaration template <class RET, class FUNC, class... ARGS> struct Function_InvokerUtil_IsFuncInvocable<RET(ARGS...), FUNC> : Function_InvokerUtil_IsFuncInvocableImp<void, RET, FUNC, ARGS...> { // This 'struct' template implements a Boolean metafunction that publicly // inherits from 'bsl::true_type' if an object of the specified 'FUNC' type // is invocable with the specified 'RET' and 'ARGS...', and publicly // inherits from 'bsl::false_type' otherwise. An object of 'FUNC' type is // invocable with 'RET' and 'ARGS...' if it is Lvalue-Callable with // arguments having the types of the 'ARGS...', and returns an object of // type explicitly convertible to 'RET'. If 'RET' is 'void', then any type // is considered explicitly convertible to 'RET'. }; // ======================================================= // template struct Function_InvokerUtil_IsFuncInvocableImp // ======================================================= template <class ARG> struct Function_InvokerUtil_ForwardType; // forward declaration template <class FROM, class TO> struct Function_InvokerUtil_IsExplicitlyConvertible; // forward declaration template <class FUNC, class... ARGS> struct Function_InvokerUtil_ResultType; // forward declaration template <class VOID_TYPE, class RET, class FUNC, class... ARGS> struct Function_InvokerUtil_IsFuncInvocableImp : bsl::false_type { // This component-private 'struct' template provides the primary template // definition for the 'Function_InvokerUtil_IsFuncInvocableImp' Boolean // metafunction, which is an implementation detail of the // 'Function_InvokerUtil_IsFuncInvocable' Boolean metafunction. This // specialization is instantiated when 'std::invoke_result<T, FWD_ARGS...>' // does not provide a nested 'type' typedef, where 'T' is the result of // stripping a nothrow-movable wrapper from 'FUNC', if present, and adding // an lvalue reference, and where 'FWD_ARGS...' are the types that result // from forwarding objects of respective 'ARGS...' types. This 'struct' // template requires that the specified 'VOID_TYPE' type to be 'void'. }; template <class RET, class FUNC, class... ARGS> struct Function_InvokerUtil_IsFuncInvocableImp< typename bslmf::VoidType< typename Function_InvokerUtil_ResultType<FUNC, ARGS...>::type>::type, RET, FUNC, ARGS...> : bsl::conditional< bsl::is_void<RET>::value, bsl::true_type, Function_InvokerUtil_IsExplicitlyConvertible< typename Function_InvokerUtil_ResultType<FUNC, ARGS...>::type, RET> >::type { // This component-private 'struct' template provides a partial // specialization of 'Function_InvokerUtil_IsFuncInvocableImp' for 'FUNC' // types for which 'bsl::invoke_result<T, FWD_ARGS...>' provides a nested // 'type' typedef, where 'T' is the result of stripping a nothrow-movable // wrapper from 'FUNC', if present, and adding an lvalue reference, and // where 'FWD_ARGS...' are the types that result from forwarding objects // of respective 'ARGS...' types. // // Specifically, 'T' is // 'bslalg::NothrowMovableUtil::UnwrappedType<FUNC>::type&', and // 'FWD_ARGS...' are the types of respective // 'bslmf::ForwardingTypeUtil<ARGS...>::forwardToTarget(args...)' // expressions where 'args...' are lvalue expressions of respective // 'bslmf::ForwardingType<ARGS>::Type...' types. See the class-level // documentation of the primary 'Function_InvokerUtil::IsFuncInvocable' // declaration for more information about the behavior of this 'struct' // template. }; // =============================================== // template struct Function_InvokerUtil_ResultType // =============================================== template <class VOID_TYPE, class FUNC, class... ARGS> struct Function_InvokerUtil_ResultTypeImp; // forward declaration template <class FUNC, class... ARGS> struct Function_InvokerUtil_ResultType : Function_InvokerUtil_ResultTypeImp<void, FUNC, ARGS...> { // This component-private 'struct' template provides a metafunction that // conditionally defines a nested 'type' typedef if the standard // 'INVOKE(f, fwdArgs...)' pseudo-expression is well-formed, where 'f' is // an lvalue of 'bslalg::NothrowMoveableUtil::UnwrappedType<FUNC>' type, // and 'fwdArgs...' are defined to be the expressions // 'bslmf::ForwardingTypeUtil<ARGS>::forwardToTarget(args)...' where // 'args...' are lvalue expressions of the corresponding // 'bslmf::ForwardingType<ARGS>::Type...' types. If such an 'INVOKE' // expression is well-formed, this struct defines 'type' to be the result // type of the expression, and defines no such typedef otherwise. }; // ================================================== // template struct Function_InvokerUtil_ResultTypeImp // ================================================== template <class VOID_TYPE, class FUNC, class... ARGS> struct Function_InvokerUtil_ResultTypeImp { // This component-private 'struct' template provides the primary template // definition for the 'Function_InvokerUtil_ResultTypeImp' metafunction, // which is an implementation detail of the // 'Function_InvokerUtil_ResultType' metafunction. This specialization is // instantiated when the standard 'INVOKE(f, fwdArgs...)' pseudo-expression // is not well-formed, where 'f' is an lvalue of // 'bslalg::NothrowMoveableUtil::UnwrappedType<FUNC>' type, and // 'fwdArgs...' are defined to be the expressions // 'bslmf::ForwardingTypeUtil<ARGS>::forwardToTarget(args)...' where // 'args...' are lvalue expressions of the corresponding // 'bslmf::ForwardingType<ARGS>::Type...' types. }; template <class FUNC, class... ARGS> struct Function_InvokerUtil_ResultTypeImp< typename bslmf::VoidType< typename Function_InvokerUtil_ForwardType<ARGS>::Type...>::type, FUNC, ARGS...> : bsl::invoke_result< typename bsl::add_lvalue_reference<typename bslalg::NothrowMovableUtil:: UnwrappedType<FUNC>::type>::type, typename Function_InvokerUtil_ForwardType<ARGS>::Type...> { // This component-private 'struct' template provides a partial // specialization of 'Function_InvokerUtil_ResultTypeImp' for 'FUNC' and // 'ARGS...' types for which standard 'INVOKE(f, fwdArgs...)' // pseudo-expression is well-formed, where 'f' is an lvalue of // 'bslalg::NothrowMoveableUtil::UnwrappedType<FUNC>' type, and // 'fwdArgs...' are defined to be the expressions // 'bslmf::ForwardingTypeUtil<ARGS>::forwardToTarget(args)...' where // 'args...' are lvalue expressions of the corresponding // 'bslmf::ForwardingType<ARGS>::Type...' types. This 'struct' defines a // nested typedef 'type' that is the type of this expression. }; // ================================================ // template struct Function_InvokerUtil_ForwardType // ================================================ template <class VOID_TYPE, class ARG> struct Function_InvokerUtil_ForwardTypeImp; // forward declaration template <class ARG> struct Function_InvokerUtil_ForwardType : Function_InvokerUtil_ForwardTypeImp<void, ARG> { // This component-private 'struct' template provides a metafunction that // conditionally defines a nested 'type' typedef that is the type resulting // from forwarding an lvalue of the specified 'ARG' type using the // machinery from 'bslmf_forwardingtype'. If it is not possible to forward // an object of 'ARG' type (if, for example, 'ARG' is 'void') then this // 'struct' template does not define a 'type' typedef. // // Specifically, 'type' is defined to be the type of the expression // 'bslmf::ForwardingTypeUtil<ARG>::forwardingToTarget(arg)', where 'arg' // is an lvalue expression of 'bslmf::ForwardingType<ARG>::Type' type. // 'type' is not defined when this expression is not well-formed. }; // =================================================== // template struct Function_InvokerUtil_ForwardTypeImp // =================================================== template <class VOID_TYPE, class ARG> struct Function_InvokerUtil_ForwardTypeImp { // This component-private 'struct' template provides the primary template // definition for the 'Function_InvokerUtil_ForwardTypeImp' metafunction, // which is an implementation detail of the // 'Function_InvokerUtil_IsFuncInvocable' metafunction. This // specialization is instantiated when the expression // 'bslmf::ForwardingTypeUtil<ARG>::forwardToTarget(arg)' is not // well-formed, where 'arg' is an lvalue expression of // 'bslmf::ForwardingType<ARG>::Type' type. }; template <class ARG> struct Function_InvokerUtil_ForwardTypeImp< typename bslmf::VoidType<decltype( bslmf::ForwardingTypeUtil<ARG>::forwardToTarget( std::declval<typename bsl::add_lvalue_reference< typename bslmf::ForwardingType<ARG>::Type>::type>()))>::type, ARG> { // This component-private 'struct' template provides a partial // specialization of 'Function_InvokerUtil_ForwardTypeImp' for 'ARG' types // for which the expression // 'bslmf::ForwardingTypeUtil<ARG>::forwardToTarget(arg)' is well-formed, // where 'arg' is an lvalue expression of // 'bslmf::ForwardingType<ARG>::Type' type. This 'struct' template // defines a nested 'type' typedef that is the type of the expression. // This is the type resulting from forwarding an lvalue of the specified // 'ARG' type using the machinery from 'bslmf_forwardingtype'. // TYPES typedef decltype(bslmf::ForwardingTypeUtil<ARG>::forwardToTarget( std::declval<typename bsl::add_lvalue_reference< typename bslmf::ForwardingType<ARG>::Type>::type>())) Type; // 'Type' is an alias to the "forwarded" type of the specified 'ARG' // type. Specifically, it is the type of the expression // 'bslmf::ForwardingTypeUtil<ARG>::forwardingToTarget(arg)', where // 'arg' is an lvalue expression of 'bslmf::ForwardingType<ARG>::Type' // type. }; // ============================================================ // template struct Function_InvokerUtil_IsExplicitlyConvertible // ============================================================ template <class VOID_TYPE, class FROM, class TO> struct Function_InvokerUtil_IsExplicitlyConvertibleImp; // forward declaration template <class FROM, class TO> struct Function_InvokerUtil_IsExplicitlyConvertible : Function_InvokerUtil_IsExplicitlyConvertibleImp<void, FROM, TO> { // This component-private 'struct' template provides a Boolean metafunction // that publicly derives from 'bsl::true_type' if the specified 'FROM' type // can be explicitly converted to the specified 'TO' type, and derives from // 'bsl::false_type' otherwise. The type 'FROM' is explicitly convertible // to the type 'TO' if the expression // 'static_cast<TO>(std::declval<FROM>())' is well-formed. }; // =============================================================== // template struct Function_InvokerUtil_IsExplicitlyConvertibleImp // =============================================================== template <class VOID_TYPE, class FROM, class TO> struct Function_InvokerUtil_IsExplicitlyConvertibleImp : bsl::false_type { // This component-private 'struct' template provides the primary // specialization of the 'Function_InvokerUtil_IsExplicitlyConvertibleImp' // metafunction. This specialization is instantiated when the specified // 'FROM' type is not explicitly convertible to the specified 'TO' type, // and publicly ihherits from 'bsl::false_type'. This 'struct' template // requires the specified 'VOID_TYPE' type to be 'void'. }; template <class FROM, class TO> struct Function_InvokerUtil_IsExplicitlyConvertibleImp< typename bslmf::VoidType<decltype( static_cast<TO>(std::declval<FROM>()))>::type, FROM, TO> : bsl::true_type { // This component-private 'struct' template provides a partial // specialization of the 'Function_InvokerUtil_IsExplicitlyConvertibleImp' // metafunction. This specialization is instantiated when the specified // 'FROM' type is explicitly convertible to the specified 'TO' type, and // publicly inherits from 'bsl::true_type'. }; #endif // defined(BSLSTL_FUNCTION_INVOKERUTIL_SUPPORT_IS_FUNC_INVOCABLE) #endif // ============================================= // template struct Function_InvokerUtil_Dispatch // ============================================= template <int INVOCATION_TYPE, class PROTOTYPE, class FUNC> struct Function_InvokerUtil_Dispatch; // Specializations of this class contain a static 'invoke' method that can // invoke a callable object of type 'FUNC', converting each argument in // 'PROTOTYPE' (a function prototype) to the corresponding argument in the // invocation of the callable object and converting the return value of the // invocation to the return type of 'PROTOTYPE'. The 'INVOCATION_TYPE' // specifies the category of callable object: pointer to function, pointer // to member function, pointer to data member, inplace functor (i.e., one // that qualifies for the small-object optimization) and out-of-place // functor (i.e., one that is not stored in the small-object buffer). #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=13 // STATIC METHODS OF PRIVATE NESTED *Invoker CLASS TEMPLATES template <class FUNC, class RET, class... ARGS> struct Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_FunctionPtr, RET(ARGS...), FUNC> { // Specialization of dispatcher for pointer-to-function objects. // CLASS METHODS static RET invoke(const Function_Rep *rep, typename bslmf::ForwardingType<ARGS>::Type... args); // For the specified 'rep' and 'args', return // 'rep.target<FUNC>()(args...)'. }; template <class FUNC, class RET, class ARG0, class... ARGS> struct Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_MemFunctionPtr, RET(ARG0, ARGS...), FUNC> { // Specialization of dispatcher for pointer to member function objects. private: // PRIVATE CLASS METHODS static RET invokeImp(bsl::true_type /* isDirect */, FUNC f, typename bslmf::ForwardingType<ARG0>::Type obj, typename bslmf::ForwardingType<ARGS>::Type... args); // Use the specified 'obj' to invoke the specified 'f' pointer to // member function with the specified 'args' and return the result, // i.e., '(obj.*f)(args...)'. static RET invokeImp(bsl::false_type /* isDirect */, FUNC f, typename bslmf::ForwardingType<ARG0>::Type obj, typename bslmf::ForwardingType<ARGS>::Type... args); // Dereference the specified 'obj' and usit to invoke the specified 'f' // pointer to member function with the specified 'args' and return the // result, i.e., '((*obj).*f)(args...)'. public: // CLASS METHODS static RET invoke(const Function_Rep *rep, typename bslmf::ForwardingType<ARG0>::Type obj, typename bslmf::ForwardingType<ARGS>::Type... args); // Given pointer to member function, 'f', as the target of the // specified 'rep', use the specified 'obj' to invoke 'f' with the // specified 'args' and return the result, i.e., '(obj.*f)(args...)'. // If 'obj' is a pointer or smart-pointer, dereference 'obj' first, // i.e., call '((*obj).*f)(args...)'. }; template <class MEMBER_TYPE, class CLASS_TYPE, class RET, class ARG0> struct Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_MemDataPtr, RET(ARG0), MEMBER_TYPE CLASS_TYPE::*> { // Specialization of dispatcher for pointer to data member objects. private: // PRIVATE CLASS METHODS typedef MEMBER_TYPE CLASS_TYPE::* Func; static RET invokeImp(bsl::true_type /* isDirect */, Func f, typename bslmf::ForwardingType<ARG0>::Type obj); // Return the specified 'f' member of the specified 'obj', i.e., // 'obj.*f'. static RET invokeImp(bsl::false_type /* isDirect */, Func f, typename bslmf::ForwardingType<ARG0>::Type obj); // Return the specified 'f' member of the object obtained by // dereferencing the specified 'obj', i.e., '(*obj).f'. public: // CLASS METHODS static RET invoke(const Function_Rep *rep, typename bslmf::ForwardingType<ARG0>::Type obj); // Given pointer to data member, 'f', as the target of the specified // 'rep', return the specified 'f' member of the specified 'obj', i.e., // 'obj.*f'. If 'obj' is a pointer or smart-pointer, dereference 'obj' // first, i.e., return '(*obj).*f'. }; template <class FUNC, class RET, class... ARGS> struct Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_InplaceFunctor, RET(ARGS...), FUNC> { // Specialization of dispatcher functor class objects that are suitable for // the small-object optimization and are thus allocated inplace. // CLASS METHODS static RET invoke(const Function_Rep *rep, typename bslmf::ForwardingType<ARGS>::Type... args); // For the specified 'args' and 'rep', return // '(*rep.target<FUNC>())(args...)'. }; template <class FUNC, class RET, class... ARGS> struct Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_OutofplaceFunctor, RET(ARGS...), FUNC> { // Specialization of dispatcher functor class objects that are not suitable // for the small-object optimization and are thus allocated out of place. // CLASS METHODS static RET invoke(const Function_Rep *rep, typename bslmf::ForwardingType<ARGS>::Type... args); // For the specified 'args' and 'rep', return // '(*rep.target<FUNC>())(args...)'. }; #endif // =========================================================================== // TEMPLATE AND INLINE FUNCTION IMPLEMENTATIONS // =========================================================================== // --------------------------- // struct Function_InvokerUtil // --------------------------- template <class PROTOTYPE> inline bslstl::Function_InvokerUtil::GenericInvoker * bslstl::Function_InvokerUtil::invokerForFunc(const bsl::nullptr_t&) { return 0; } template <class PROTOTYPE, class FUNC> bslstl::Function_InvokerUtil::GenericInvoker * bslstl::Function_InvokerUtil::invokerForFunc(const FUNC& f) { typedef bslstl::Function_SmallObjectOptimization Soo; // Strip 'NothrowMovableWrapper' (if any) off of 'FUNC' type. typedef typename bslalg::NothrowMovableUtil::UnwrappedType<FUNC>::type UwFuncType; // Categorize the type of invocable corresponding to 'FUNC'. Note that the // parameter to 'Soo::Inplace' is 'FUNC', not 'UwFuncType'. That is // because 'Soo::Inplace' takes the wrapper into account when determining // whether the type should be inplace or not. static const int k_INVOCATION_TYPE = bslmf::IsFunctionPointer<UwFuncType>::value ? e_FunctionPtr : bslmf::IsMemberFunctionPointer<UwFuncType>::value ? e_MemFunctionPtr : bsl::is_member_pointer<UwFuncType>::value ? e_MemDataPtr : Soo::IsInplaceFunc<FUNC>::value ? e_InplaceFunctor : e_OutofplaceFunctor; // Instantiate the class for checking for null object typedef Function_InvokerUtilNullCheck<UwFuncType> NullCheckerClass; // Instantiate the class for dispatching the invoker typedef Function_InvokerUtil_Dispatch<k_INVOCATION_TYPE, PROTOTYPE, UwFuncType> DispatcherClass; // If a the object is "null", e.g., for a pointer, then return null. if (NullCheckerClass::isNull(bslalg::NothrowMovableUtil::unwrap(f))) { return 0; // RETURN } // Verify the assumption that all function pointers are the same size. BSLMF_ASSERT(sizeof(&DispatcherClass::invoke) == sizeof(Function_Rep::GenericInvoker *)); // Return a pointer to the actual invoker function return reinterpret_cast<Function_Rep::GenericInvoker *>( &DispatcherClass::invoke); } // --------------------------------------------- // struct template Function_InvokerUtilNullCheck // --------------------------------------------- // STATIC MEMBER FUNCTIONS template <class FUNC> inline bool Function_InvokerUtilNullCheck<FUNC>::isNull(const FUNC&) { return false; } template <class FUNC> inline bool Function_InvokerUtilNullCheck<FUNC *>::isNull(FUNC* f) { return 0 == f; } template <class CLASS, class MEMTYPE> inline bool Function_InvokerUtilNullCheck<MEMTYPE CLASS::*>::isNull(MEMTYPE CLASS::* f) { return 0 == f; } // --------------------------------------------- // struct template Function_InvokerUtil_Dispatch // --------------------------------------------- #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES template <class FUNC, class RET, class... ARGS> RET Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_FunctionPtr, RET(ARGS...), FUNC>:: invoke(const Function_Rep *rep, typename bslmf::ForwardingType<ARGS>::Type... args) { FUNC f = *rep->targetRaw<FUNC, true>(); // Note that 'FUNC' might be different than 'RET(*)(ARGS...)'. All that is // required is that it be Callable with 'ARGS...' and return something // convertible to 'RET'. // Cast to 'RET' is needed to avoid compilation error if 'RET' is 'void' // and 'f' returns non-void. return BSLSTL_FUNCTION_INVOKERUTIL_CAST_RESULT( RET, f(bslmf::ForwardingTypeUtil<ARGS>::forwardToTarget(args)...)); } template <class FUNC, class RET, class ARG0, class... ARGS> inline RET Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_MemFunctionPtr, RET(ARG0, ARGS...), FUNC>:: invokeImp(bsl::true_type /* isDirect */, FUNC f, typename bslmf::ForwardingType<ARG0>::Type obj, typename bslmf::ForwardingType<ARGS>::Type... args) { typedef typename bslmf::MovableRefUtil::RemoveReference<ARG0>::type& Arg0Ref; // In C++03, an rvalue is forwarded as a const lvalue. Fortunately, we can // recover the correct constness by casting 'obj' back to a reference to // the original type. return BSLSTL_FUNCTION_INVOKERUTIL_CAST_RESULT( RET, (const_cast<Arg0Ref>(obj).*f)( bslmf::ForwardingTypeUtil<ARGS>::forwardToTarget(args)...)); } template <class FUNC, class RET, class ARG0, class... ARGS> inline RET Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_MemFunctionPtr, RET(ARG0, ARGS...), FUNC>:: invokeImp(bsl::false_type /* isDirect */, FUNC f, typename bslmf::ForwardingType<ARG0>::Type obj, typename bslmf::ForwardingType<ARGS>::Type... args) { typedef typename bslmf::MovableRefUtil::RemoveReference<ARG0>::type& Arg0Ref; // In C++03, an rvalue is forwarded as a const lvalue. Fortunately, we can // recover the correct constness from by casting back to a reference to // the original type. return BSLSTL_FUNCTION_INVOKERUTIL_CAST_RESULT( RET, ((*const_cast<Arg0Ref>(obj)).*f)( bslmf::ForwardingTypeUtil<ARGS>::forwardToTarget(args)...)); } template <class FUNC, class RET, class ARG0, class... ARGS> RET Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_MemFunctionPtr, RET(ARG0, ARGS...), FUNC>:: invoke(const Function_Rep *rep, typename bslmf::ForwardingType<ARG0>::Type obj, typename bslmf::ForwardingType<ARGS>::Type... args) { typedef typename bslmf::MemberFunctionPointerTraits<FUNC>::ClassType ClassType; typedef typename bsl::is_convertible< typename bslmf::MovableRefUtil::RemoveReference<ARG0>::type *, ClassType * >::type IsDirect; // 'true_type' if 'ARG0' is a reference to 'ClassType' or class derived // from 'ClassType; otherwise, 'false_type'. FUNC f = *rep->targetRaw<FUNC, true>(); return BSLSTL_FUNCTION_INVOKERUTIL_CAST_RESULT(RET, invokeImp(IsDirect(), f, obj, args...)); } template <class MEMBER_TYPE, class CLASS_TYPE, class RET, class ARG0> inline RET Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_MemDataPtr, RET(ARG0), MEMBER_TYPE CLASS_TYPE::*>:: invokeImp(bsl::true_type /* isDirect */, Func f, typename bslmf::ForwardingType<ARG0>::Type obj) { typedef typename bslmf::MovableRefUtil::RemoveReference<ARG0>::type& Arg0Ref; // In C++03, an rvalue is forwarded as a const lvalue. Fortunately, we can // recover the correct constness by casting 'obj' back to a reference to // the original type. return BSLSTL_FUNCTION_INVOKERUTIL_CAST_RESULT( RET, (const_cast<Arg0Ref>(obj).*f)); } template <class MEMBER_TYPE, class CLASS_TYPE, class RET, class ARG0> inline RET Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_MemDataPtr, RET(ARG0), MEMBER_TYPE CLASS_TYPE::*>:: invokeImp(bsl::false_type /* isDirect */, Func f, typename bslmf::ForwardingType<ARG0>::Type obj) { typedef typename bslmf::MovableRefUtil::RemoveReference<ARG0>::type& Arg0Ref; // In C++03, an rvalue is forwarded as a const lvalue. Fortunately, we can // recover the correct constness from by casting back to a reference to // the original type. return BSLSTL_FUNCTION_INVOKERUTIL_CAST_RESULT( RET, ((*const_cast<Arg0Ref>(obj)).*f)); } template <class MEMBER_TYPE, class CLASS_TYPE, class RET, class ARG0> RET Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_MemDataPtr, RET(ARG0), MEMBER_TYPE CLASS_TYPE::*>:: invoke(const Function_Rep *rep, typename bslmf::ForwardingType<ARG0>::Type obj) { typedef typename bsl::is_convertible< typename bslmf::MovableRefUtil::RemoveReference<ARG0>::type *, const volatile CLASS_TYPE * >::type IsDirect; // 'true_type' if 'ARG0' is a reference to 'CLASS_TYPE' or class // derived from 'CLASS_TYPE; otherwise, 'false_type'. Note that this // differs from the corresponding check for pointers to member // functions because a pointer to data member for class type 'T' can // be used to access (as const) a member of a cv-qualified 'T'. Func f = *rep->targetRaw<Func, true>(); return BSLSTL_FUNCTION_INVOKERUTIL_CAST_RESULT( RET, invokeImp(IsDirect(), f, obj)); } template <class FUNC, class RET, class... ARGS> RET Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_InplaceFunctor, RET(ARGS...), FUNC>:: invoke(const Function_Rep *rep, typename bslmf::ForwardingType<ARGS>::Type... args) { FUNC& f = *rep->targetRaw<FUNC, true>(); // Cast to 'RET' is needed to avoid compilation error if 'RET' is void and // 'f' returns non-void. return BSLSTL_FUNCTION_INVOKERUTIL_CAST_RESULT( RET, f(bslmf::ForwardingTypeUtil<ARGS>::forwardToTarget(args)...)); } template <class FUNC, class RET, class... ARGS> RET Function_InvokerUtil_Dispatch<Function_InvokerUtil::e_OutofplaceFunctor, RET(ARGS...), FUNC>:: invoke(const Function_Rep *rep, typename bslmf::ForwardingType<ARGS>::Type... args) { FUNC& f = *rep->targetRaw<FUNC, false>(); // Cast to 'RET' is needed to avoid compilation error if 'RET' is void and // 'f' returns non-void. return BSLSTL_FUNCTION_INVOKERUTIL_CAST_RESULT( RET, f(bslmf::ForwardingTypeUtil<ARGS>::forwardToTarget(args)...)); } #endif } // close package namespace } // close enterprise namespace #endif // End C++11 code #endif // ! defined(INCLUDED_BSLSTL_FUNCTION_INVOKERUTIL) // ---------------------------------------------------------------------------- // Copyright 2020 Bloomberg Finance L.P. // // 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. // ----------------------------- END-OF-FILE ----------------------------------