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