1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#ifndef FUNCTIONWRAPPER_H
#define FUNCTIONWRAPPER_H
#include "base/i2-base.hpp"
#include "base/value.hpp"
#include <boost/function_types/function_type.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/function_arity.hpp>
#include <vector>
namespace icinga
{
template<typename FuncType>
typename std::enable_if<
std::is_class<FuncType>::value &&
std::is_same<typename boost::function_types::result_type<decltype(&FuncType::operator())>::type, Value>::value &&
boost::function_types::function_arity<decltype(&FuncType::operator())>::value == 2,
std::function<Value (const std::vector<Value>&)>>::type
WrapFunction(FuncType function)
{
static_assert(std::is_same<typename boost::mpl::at_c<typename boost::function_types::parameter_types<decltype(&FuncType::operator())>, 1>::type, const std::vector<Value>&>::value, "Argument type must be const std::vector<Value>");
return function;
}
inline std::function<Value (const std::vector<Value>&)> WrapFunction(void (*function)(const std::vector<Value>&))
{
return [function](const std::vector<Value>& arguments) {
function(arguments);
return Empty;
};
}
template<typename Return>
std::function<Value (const std::vector<Value>&)> WrapFunction(Return (*function)(const std::vector<Value>&))
{
return [function](const std::vector<Value>& values) -> Value { return function(values); };
}
template <std::size_t... Indices>
struct indices {
using next = indices<Indices..., sizeof...(Indices)>;
};
template <std::size_t N>
struct build_indices {
using type = typename build_indices<N-1>::type::next;
};
template <>
struct build_indices<0> {
using type = indices<>;
};
template <std::size_t N>
using BuildIndices = typename build_indices<N>::type;
struct UnpackCaller
{
private:
template <typename FuncType, size_t... I>
auto Invoke(FuncType f, const std::vector<Value>& args, indices<I...>) -> decltype(f(args[I]...))
{
return f(args[I]...);
}
public:
template <typename FuncType, int Arity>
auto operator() (FuncType f, const std::vector<Value>& args) -> decltype(Invoke(f, args, BuildIndices<Arity>{}))
{
return Invoke(f, args, BuildIndices<Arity>{});
}
};
template<typename FuncType, int Arity, typename ReturnType>
struct FunctionWrapper
{
static Value Invoke(FuncType function, const std::vector<Value>& arguments)
{
return UnpackCaller().operator()<FuncType, Arity>(function, arguments);
}
};
template<typename FuncType, int Arity>
struct FunctionWrapper<FuncType, Arity, void>
{
static Value Invoke(FuncType function, const std::vector<Value>& arguments)
{
UnpackCaller().operator()<FuncType, Arity>(function, arguments);
return Empty;
}
};
template<typename FuncType>
typename std::enable_if<
std::is_function<typename std::remove_pointer<FuncType>::type>::value && !std::is_same<FuncType, Value(*)(const std::vector<Value>&)>::value,
std::function<Value (const std::vector<Value>&)>>::type
WrapFunction(FuncType function)
{
return [function](const std::vector<Value>& arguments) {
constexpr size_t arity = boost::function_types::function_arity<typename std::remove_pointer<FuncType>::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()<FuncType, arity>(*static_cast<FuncType *>(nullptr), std::vector<Value>()));
return FunctionWrapper<FuncType, arity, ReturnType>::Invoke(function, arguments);
};
}
template<typename FuncType>
typename std::enable_if<
std::is_class<FuncType>::value &&
!(std::is_same<typename boost::function_types::result_type<decltype(&FuncType::operator())>::type, Value>::value &&
boost::function_types::function_arity<decltype(&FuncType::operator())>::value == 2),
std::function<Value (const std::vector<Value>&)>>::type
WrapFunction(FuncType function)
{
static_assert(!std::is_same<typename boost::mpl::at_c<typename boost::function_types::parameter_types<decltype(&FuncType::operator())>, 1>::type, const std::vector<Value>&>::value, "Argument type must be const std::vector<Value>");
using FuncTypeInvoker = decltype(&FuncType::operator());
return [function](const std::vector<Value>& arguments) {
constexpr size_t arity = boost::function_types::function_arity<FuncTypeInvoker>::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()<FuncType, arity>(*static_cast<FuncType *>(nullptr), std::vector<Value>()));
return FunctionWrapper<FuncType, arity, ReturnType>::Invoke(function, arguments);
};
}
}
#endif /* FUNCTIONWRAPPER_H */
|