diff --git a/lib/base/functionwrapper.hpp b/lib/base/functionwrapper.hpp index a8cbce913..2ee22d9b2 100644 --- a/lib/base/functionwrapper.hpp +++ b/lib/base/functionwrapper.hpp @@ -23,6 +23,9 @@ #include "base/i2-base.hpp" #include "base/value.hpp" #include +#include +#include +#include #include #include @@ -31,7 +34,14 @@ using namespace std::placeholders; namespace icinga { -inline std::function&)> WrapFunction(const std::function&)>& function) +template +typename std::enable_if< + std::is_class::value && + std::is_same::type, Value>::value && + std::is_same, 1>::type, const std::vector&>::value && + boost::function_types::function_arity::value == 2, + std::function&)>>::type +WrapFunction(FuncType function) { return function; } @@ -43,12 +53,11 @@ inline std::function&)> WrapFunction(void (*func return Empty; }; } + template std::function&)> WrapFunction(Return (*function)(const std::vector&)) { - return [function](const std::vector& arguments) { - return static_cast(function(arguments)); - }; + return std::bind(function, _1); } template @@ -69,52 +78,51 @@ struct build_indices<0> { template using BuildIndices = typename build_indices::type; -struct unpack_caller +struct UnpackCaller { private: template - auto call(FuncType f, const std::vector& args, indices) -> decltype(f(args[I]...)) + auto Invoke(FuncType f, const std::vector& args, indices) -> decltype(f(args[I]...)) { return f(args[I]...); } public: - template - auto operator () (FuncType f, const std::vector& args) - -> decltype(call(f, args, BuildIndices::type>::value>{})) + template + auto operator() (FuncType f, const std::vector& args) + -> decltype(Invoke(f, args, BuildIndices{})) { - return call(f, args, BuildIndices::type>::value>{}); + return Invoke(f, args, BuildIndices{}); } }; -enum class enabler_t {}; - -template -using EnableIf = typename std::enable_if::type; - -template -std::function&)> WrapFunction(FuncType function, - EnableIf())), void>::value>* = 0) +template +struct FunctionWrapper { - return [function](const std::vector& arguments) { - constexpr int arity = boost::function_types::function_arity::type>::value; + static Value Invoke(FuncType function, const std::vector& arguments) + { + return UnpackCaller().operator()(function, arguments); + } +}; - if (arguments.size() < arity) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); - else if (arguments.size() > arity) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); - - unpack_caller()(function, arguments); +template +struct FunctionWrapper +{ + static Value Invoke(FuncType function, const std::vector& arguments) + { + UnpackCaller().operator()(function, arguments); return Empty; - }; -} + } +}; template -std::function&)> WrapFunction(FuncType function, - EnableIf())), void>::value>* = 0) +typename std::enable_if< + std::is_function::type>::value && !std::is_same&)>::value, + std::function&)>>::type +WrapFunction(FuncType function) { return [function](const std::vector& arguments) { - constexpr int arity = boost::function_types::function_arity::type>::value; + constexpr size_t arity = boost::function_types::function_arity::type>::value; if (arity > 0) { if (arguments.size() < arity) @@ -123,7 +131,36 @@ std::function&)> WrapFunction(FuncType function, BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); } - return unpack_caller()(function, arguments); + using ReturnType = decltype(UnpackCaller().operator()(*static_cast(nullptr), std::vector())); + + return FunctionWrapper::Invoke(function, arguments); + }; +} + +template +typename std::enable_if< + std::is_class::value && + !(std::is_same::type, Value>::value && + std::is_same, 1>::type, const std::vector&>::value && + boost::function_types::function_arity::value == 2), + std::function&)>>::type +WrapFunction(FuncType function) +{ + using FuncTypeInvoker = decltype(&FuncType::operator()); + + return [function](const std::vector& arguments) { + constexpr size_t arity = boost::function_types::function_arity::value - 1; + + if (arity > 0) { + if (arguments.size() < arity) + BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function.")); + else if (arguments.size() > arity) + BOOST_THROW_EXCEPTION(std::invalid_argument("Too many arguments for function.")); + } + + using ReturnType = decltype(UnpackCaller().operator()(*static_cast(nullptr), std::vector())); + + return FunctionWrapper::Invoke(function, arguments); }; } diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp index 97c5d6358..323ba51ee 100644 --- a/lib/config/vmops.hpp +++ b/lib/config/vmops.hpp @@ -113,7 +113,7 @@ public: { auto evaluatedClosedVars = EvaluateClosedVars(frame, closedVars); - auto wrapper = [argNames, evaluatedClosedVars, expression](const std::vector& arguments) { + auto wrapper = [argNames, evaluatedClosedVars, expression](const std::vector& arguments) -> Value { if (arguments.size() < argNames.size()) BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function")); diff --git a/lib/icinga/macroprocessor.cpp b/lib/icinga/macroprocessor.cpp index e3d81202f..9789313f7 100644 --- a/lib/icinga/macroprocessor.cpp +++ b/lib/icinga/macroprocessor.cpp @@ -180,30 +180,6 @@ bool MacroProcessor::ResolveMacro(const String& macro, const ResolverList& resol return false; } -Value MacroProcessor::InternalResolveMacrosShim(const std::vector& args, const ResolverList& resolvers, - const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, - bool useResolvedMacros, int recursionLevel) -{ - if (args.size() < 1) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function")); - - String missingMacro; - - return MacroProcessor::InternalResolveMacros(args[0], resolvers, cr, &missingMacro, escapeFn, - resolvedMacros, useResolvedMacros, recursionLevel); -} - -Value MacroProcessor::InternalResolveArgumentsShim(const std::vector& args, const ResolverList& resolvers, - const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, - bool useResolvedMacros, int recursionLevel) -{ - if (args.size() < 2) - BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function")); - - return MacroProcessor::ResolveArguments(args[0], args[1], resolvers, cr, - resolvedMacros, useResolvedMacros, recursionLevel); -} - Value MacroProcessor::EvaluateFunction(const Function::Ptr& func, const ResolverList& resolvers, const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel) @@ -214,12 +190,27 @@ Value MacroProcessor::EvaluateFunction(const Function::Ptr& func, const Resolver resolvers_this->Set(resolver.first, resolver.second); } - resolvers_this->Set("macro", new Function("macro (temporary)", std::bind(&MacroProcessor::InternalResolveMacrosShim, - _1, std::cref(resolvers), cr, MacroProcessor::EscapeCallback(), resolvedMacros, useResolvedMacros, - recursionLevel + 1), { "str" })); - resolvers_this->Set("resolve_arguments", new Function("resolve_arguments (temporary)", std::bind(&MacroProcessor::InternalResolveArgumentsShim, - _1, std::cref(resolvers), cr, resolvedMacros, useResolvedMacros, - recursionLevel + 1))); + auto internalResolveMacrosShim = [resolvers, cr, resolvedMacros, useResolvedMacros, recursionLevel](const std::vector& args) { + if (args.size() < 1) + BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function")); + + String missingMacro; + + return MacroProcessor::InternalResolveMacros(args[0], resolvers, cr, &missingMacro, MacroProcessor::EscapeCallback(), + resolvedMacros, useResolvedMacros, recursionLevel); + }; + + resolvers_this->Set("macro", new Function("macro (temporary)", internalResolveMacrosShim, { "str" })); + + auto internalResolveArgumentsShim = [resolvers, cr, resolvedMacros, useResolvedMacros, recursionLevel](const std::vector& args) { + if (args.size() < 2) + BOOST_THROW_EXCEPTION(std::invalid_argument("Too few arguments for function")); + + return MacroProcessor::ResolveArguments(args[0], args[1], resolvers, cr, + resolvedMacros, useResolvedMacros, recursionLevel + 1); + }; + + resolvers_this->Set("resolve_arguments", new Function("resolve_arguments (temporary)", internalResolveArgumentsShim, { "command", "args" })); return func->InvokeThis(resolvers_this); } diff --git a/lib/icinga/macroprocessor.hpp b/lib/icinga/macroprocessor.hpp index 1b2c015da..8924162ae 100644 --- a/lib/icinga/macroprocessor.hpp +++ b/lib/icinga/macroprocessor.hpp @@ -63,12 +63,6 @@ private: String *missingMacro, const EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel = 0); - static Value InternalResolveMacrosShim(const std::vector& args, const ResolverList& resolvers, - const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn, - const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel); - static Value InternalResolveArgumentsShim(const std::vector& args, const ResolverList& resolvers, - const CheckResult::Ptr& cr, const Dictionary::Ptr& resolvedMacros, - bool useResolvedMacros, int recursionLevel); static Value EvaluateFunction(const Function::Ptr& func, const ResolverList& resolvers, const CheckResult::Ptr& cr, const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros, int recursionLevel);