2019-02-25 14:48:22 +01:00
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2013-03-25 20:47:02 +01:00
2017-11-29 11:53:45 +01:00
# ifndef FUNCTIONWRAPPER_H
# define FUNCTIONWRAPPER_H
2013-03-25 20:47:02 +01:00
2014-05-25 16:23:35 +02:00
# include "base/i2-base.hpp"
# include "base/value.hpp"
2017-12-19 08:42:24 +01:00
# include <boost/function_types/function_type.hpp>
# include <boost/function_types/parameter_types.hpp>
# include <boost/function_types/result_type.hpp>
2017-12-13 11:35:38 +01:00
# include <boost/function_types/function_arity.hpp>
2018-01-04 18:24:45 +01:00
# include <vector>
2017-11-21 11:52:55 +01:00
using namespace std : : placeholders ;
2013-03-25 20:47:02 +01:00
namespace icinga
{
2017-12-19 08:42:24 +01:00
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 & &
2018-01-01 09:13:47 +01:00
boost : : function_types : : function_arity < decltype ( & FuncType : : operator ( ) ) > : : value = = 2 ,
2017-12-19 08:42:24 +01:00
std : : function < Value ( const std : : vector < Value > & ) > > : : type
WrapFunction ( FuncType function )
2013-03-25 20:47:02 +01:00
{
2018-01-01 09:13:47 +01:00
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> " ) ;
2017-11-29 11:53:45 +01:00
return function ;
2013-03-25 20:47:02 +01:00
}
2017-11-29 11:53:45 +01:00
inline std : : function < Value ( const std : : vector < Value > & ) > WrapFunction ( void ( * function ) ( const std : : vector < Value > & ) )
2013-03-25 20:47:02 +01:00
{
2017-11-29 11:53:45 +01:00
return [ function ] ( const std : : vector < Value > & arguments ) {
function ( arguments ) ;
return Empty ;
} ;
2013-03-25 20:47:02 +01:00
}
2017-12-19 08:42:24 +01:00
2017-11-29 11:53:45 +01:00
template < typename Return >
std : : function < Value ( const std : : vector < Value > & ) > WrapFunction ( Return ( * function ) ( const std : : vector < Value > & ) )
2013-03-25 20:47:02 +01:00
{
2017-12-19 08:42:24 +01:00
return std : : bind ( function , _1 ) ;
2013-03-25 20:47:02 +01:00
}
2017-11-29 11:53:45 +01:00
template < std : : size_t . . . Indices >
struct indices {
using next = indices < Indices . . . , sizeof . . . ( Indices ) > ;
} ;
2013-03-25 20:47:02 +01:00
2017-11-29 11:53:45 +01:00
template < std : : size_t N >
struct build_indices {
using type = typename build_indices < N - 1 > : : type : : next ;
} ;
2013-03-25 20:47:02 +01:00
2017-11-29 11:53:45 +01:00
template < >
struct build_indices < 0 > {
using type = indices < > ;
} ;
2013-03-25 20:47:02 +01:00
2017-11-29 11:53:45 +01:00
template < std : : size_t N >
using BuildIndices = typename build_indices < N > : : type ;
2013-03-25 20:47:02 +01:00
2017-12-19 08:42:24 +01:00
struct UnpackCaller
2013-03-25 20:47:02 +01:00
{
2017-11-29 11:53:45 +01:00
private :
template < typename FuncType , size_t . . . I >
2017-12-19 08:42:24 +01:00
auto Invoke ( FuncType f , const std : : vector < Value > & args , indices < I . . . > ) - > decltype ( f ( args [ I ] . . . ) )
2017-11-29 11:53:45 +01:00
{
return f ( args [ I ] . . . ) ;
}
2013-03-25 20:47:02 +01:00
2017-11-29 11:53:45 +01:00
public :
2017-12-19 08:42:24 +01:00
template < typename FuncType , int Arity >
2017-12-19 15:50:05 +01:00
auto operator ( ) ( FuncType f , const std : : vector < Value > & args ) - > decltype ( Invoke ( f , args , BuildIndices < Arity > { } ) )
2017-11-29 11:53:45 +01:00
{
2017-12-19 08:42:24 +01:00
return Invoke ( f , args , BuildIndices < Arity > { } ) ;
2017-11-29 11:53:45 +01:00
}
} ;
2013-03-25 20:47:02 +01:00
2017-12-19 08:42:24 +01:00
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 ) ;
}
} ;
2013-03-25 20:47:02 +01:00
2017-12-19 08:42:24 +01:00
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 ;
}
} ;
2013-03-25 20:47:02 +01:00
2017-11-29 11:53:45 +01:00
template < typename FuncType >
2017-12-19 08:42:24 +01:00
typename std : : enable_if <
2017-12-19 15:50:05 +01:00
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
2017-12-19 08:42:24 +01:00
WrapFunction ( FuncType function )
2013-03-25 20:47:02 +01:00
{
2017-11-29 11:53:45 +01:00
return [ function ] ( const std : : vector < Value > & arguments ) {
2017-12-19 08:42:24 +01:00
constexpr size_t arity = boost : : function_types : : function_arity < typename std : : remove_pointer < FuncType > : : type > : : value ;
2013-03-25 20:47:02 +01:00
2017-12-19 08:42:24 +01:00
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. " ) ) ;
}
2013-03-25 20:47:02 +01:00
2017-12-19 08:42:24 +01:00
using ReturnType = decltype ( UnpackCaller ( ) . operator ( ) < FuncType , arity > ( * static_cast < FuncType * > ( nullptr ) , std : : vector < Value > ( ) ) ) ;
return FunctionWrapper < FuncType , arity , ReturnType > : : Invoke ( function , arguments ) ;
2017-11-29 11:53:45 +01:00
} ;
2013-03-25 20:47:02 +01:00
}
2017-11-29 11:53:45 +01:00
template < typename FuncType >
2017-12-19 08:42:24 +01:00
typename std : : enable_if <
std : : is_class < FuncType > : : value & &
! ( std : : is_same < typename boost : : function_types : : result_type < decltype ( & FuncType : : operator ( ) ) > : : type , Value > : : value & &
2018-01-01 09:13:47 +01:00
boost : : function_types : : function_arity < decltype ( & FuncType : : operator ( ) ) > : : value = = 2 ) ,
2017-12-19 08:42:24 +01:00
std : : function < Value ( const std : : vector < Value > & ) > > : : type
WrapFunction ( FuncType function )
2013-03-25 20:47:02 +01:00
{
2018-01-01 09:13:47 +01:00
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> " ) ;
2017-12-19 08:42:24 +01:00
using FuncTypeInvoker = decltype ( & FuncType : : operator ( ) ) ;
2017-11-29 11:53:45 +01:00
return [ function ] ( const std : : vector < Value > & arguments ) {
2017-12-19 08:42:24 +01:00
constexpr size_t arity = boost : : function_types : : function_arity < FuncTypeInvoker > : : value - 1 ;
2013-03-25 20:47:02 +01:00
2017-11-29 11:53:45 +01:00
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. " ) ) ;
}
2013-10-19 00:19:16 +02:00
2017-12-19 08:42:24 +01:00
using ReturnType = decltype ( UnpackCaller ( ) . operator ( ) < FuncType , arity > ( * static_cast < FuncType * > ( nullptr ) , std : : vector < Value > ( ) ) ) ;
return FunctionWrapper < FuncType , arity , ReturnType > : : Invoke ( function , arguments ) ;
2017-11-29 11:53:45 +01:00
} ;
2014-04-01 09:33:54 +02:00
}
2013-03-25 20:47:02 +01:00
}
2017-11-29 11:53:45 +01:00
# endif /* FUNCTIONWRAPPER_H */