/****************************************************************************** * Icinga 2 * * Copyright (C) 2012-2018 Icinga Development Team (https://icinga.com/) * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software Foundation * * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ #ifndef FUNCTIONWRAPPER_H #define FUNCTIONWRAPPER_H #include "base/i2-base.hpp" #include "base/value.hpp" #include #include #include #include #include using namespace std::placeholders; 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 std::bind(function, _1); } 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 */