// This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2018, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #ifndef CHAISCRIPT_FUNCTION_CALL_HPP_ #define CHAISCRIPT_FUNCTION_CALL_HPP_ #include #include #include #include "boxed_cast.hpp" #include "function_call_detail.hpp" #include "proxy_functions.hpp" namespace chaiscript { class Boxed_Value; class Type_Conversions_State; namespace detail { template struct Cast_Helper; } // namespace detail } // namespace chaiscript namespace chaiscript { namespace dispatch { namespace detail { template constexpr auto arity(Ret (*)(Param...)) noexcept { return sizeof...(Param); } } // namespace detail /// Build a function caller that knows how to dispatch on a set of functions /// example: /// std::function f = /// build_function_caller(dispatchkit.get_function("print")); /// \returns A std::function object for dispatching /// \param[in] funcs the set of functions to dispatch on. template std::function functor(const std::vector &funcs, const Type_Conversions_State *t_conversions) { const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(), [](const Const_Proxy_Function &f) { return f->get_arity() == -1 || size_t(f->get_arity()) == detail::arity(static_cast(nullptr)); }); if (!has_arity_match) { throw exception::bad_boxed_cast(user_type(), typeid(std::function)); } FunctionType *p = nullptr; return detail::build_function_caller_helper(p, funcs, t_conversions); } /// Build a function caller for a particular Proxy_Function object /// useful in the case that a function is being pass out from scripting back /// into code /// example: /// void my_function(Proxy_Function f) /// { /// std::function local_f = /// build_function_caller(f); /// } /// \returns A std::function object for dispatching /// \param[in] func A function to execute. template std::function functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions) { return functor(std::vector({std::move(func)}), t_conversions); } /// Helper for automatically unboxing a Boxed_Value that contains a function object /// and creating a typesafe C++ function caller from it. template std::function functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions) { return functor(boxed_cast(bv, t_conversions), t_conversions); } } // namespace dispatch namespace detail { /// Cast helper to handle automatic casting to const std::function & template struct Cast_Helper &> { static std::function cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { if (ob.get_type_info().bare_equal(user_type())) { return dispatch::functor(ob, t_conversions); } else { return Cast_Helper_Inner &>::cast(ob, t_conversions); } } }; /// Cast helper to handle automatic casting to std::function template struct Cast_Helper> { static std::function cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { if (ob.get_type_info().bare_equal(user_type())) { return dispatch::functor(ob, t_conversions); } else { return Cast_Helper_Inner>::cast(ob, t_conversions); } } }; /// Cast helper to handle automatic casting to const std::function template struct Cast_Helper> { static std::function cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) { if (ob.get_type_info().bare_equal(user_type())) { return dispatch::functor(ob, t_conversions); } else { return Cast_Helper_Inner>::cast(ob, t_conversions); } } }; } // namespace detail } // namespace chaiscript #endif