/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #ifndef FUNCTIONWRAPPER_H #define FUNCTIONWRAPPER_H #include "base/i2-base.hpp" #include "base/value.hpp" #include #include #include #include #include namespace icinga { template typename std::enable_if< std::is_class::value && std::is_same::type, Value>::value && boost::function_types::function_arity::value == 2, std::function&)>>::type WrapFunction(FuncType function) { static_assert(std::is_same, 1>::type, const std::vector&>::value, "Argument type must be const std::vector"); return function; } inline std::function&)> WrapFunction(void (*function)(const std::vector&)) { return [function](const std::vector& arguments) { function(arguments); return Empty; }; } template std::function&)> WrapFunction(Return (*function)(const std::vector&)) { return [function](const std::vector& values) -> Value { return function(values); }; } template struct indices { using next = indices; }; template struct build_indices { using type = typename build_indices::type::next; }; template <> struct build_indices<0> { using type = indices<>; }; template using BuildIndices = typename build_indices::type; struct UnpackCaller { private: template 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(Invoke(f, args, BuildIndices{})) { return Invoke(f, args, BuildIndices{}); } }; template struct FunctionWrapper { static Value Invoke(FuncType function, const std::vector& arguments) { return UnpackCaller().operator()(function, arguments); } }; template struct FunctionWrapper { static Value Invoke(FuncType function, const std::vector& arguments) { UnpackCaller().operator()(function, arguments); return Empty; } }; template 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 size_t arity = boost::function_types::function_arity::type>::value; 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); }; } template typename std::enable_if< std::is_class::value && !(std::is_same::type, Value>::value && boost::function_types::function_arity::value == 2), std::function&)>>::type WrapFunction(FuncType function) { static_assert(!std::is_same, 1>::type, const std::vector&>::value, "Argument type must be const std::vector"); 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); }; } } #endif /* FUNCTIONWRAPPER_H */