Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support of lambdas to get_signature #36

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 82 additions & 134 deletions include/boost/python/signature.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,26 @@
// http://www.boost.org/LICENSE_1_0.txt)
//
///////////////////////////////////////////////////////////////////////////////
#if !defined(BOOST_PP_IS_ITERATING)

# ifndef SIGNATURE_JDG20020813_HPP
# define SIGNATURE_JDG20020813_HPP

# include <boost/python/detail/prefix.hpp>

# include <boost/mpl/if.hpp>
# include <boost/type_traits/is_convertible.hpp>

# include <boost/python/detail/preprocessor.hpp>
# include <boost/preprocessor/repeat.hpp>
# include <boost/preprocessor/enum.hpp>
# include <boost/preprocessor/enum_params.hpp>
# include <boost/preprocessor/empty.hpp>
# include <boost/preprocessor/arithmetic/sub.hpp>
# include <boost/preprocessor/iterate.hpp>
# include <boost/python/detail/type_list.hpp>

# include <boost/preprocessor/debug/line.hpp>
# include <boost/preprocessor/arithmetic/sub.hpp>
# include <boost/preprocessor/arithmetic/inc.hpp>
# include <boost/preprocessor/repetition/enum_trailing_params.hpp>

# define BOOST_PYTHON_LIST_INC(n) \
BOOST_PP_CAT(mpl::vector, BOOST_PP_INC(n))
# include <boost/type_traits/is_class.hpp>
# include <boost/type_traits/conditional.hpp>
# include <boost/type_traits/decay.hpp>
# include <boost/function_types/result_type.hpp>
# include <boost/function_types/parameter_types.hpp>
# include <boost/function_types/components.hpp>
# include <boost/function_types/is_function_pointer.hpp>
# include <boost/mpl/vector.hpp>
# include <boost/mpl/insert_range.hpp>
# include <boost/mpl/copy.hpp>
# include <boost/mpl/joint_view.hpp>
# include <boost/mpl/transform.hpp>
# include <boost/type_traits/remove_cv.hpp>

///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace python { namespace detail {
Expand Down Expand Up @@ -108,145 +102,99 @@ struct most_derived
//
// @group {

// 'default' calling convention

# define BOOST_PYTHON_FN_CC

# define BOOST_PP_ITERATION_PARAMS_1 \
(3, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/signature.hpp>))

# include BOOST_PP_ITERATE()

# undef BOOST_PYTHON_FN_CC

// __cdecl calling convention
template<typename T>
struct is_callable_detect {
private:
typedef char(&yes)[1];
typedef char(&no)[2];

# if defined(BOOST_PYTHON_ENABLE_CDECL)
struct Fallback { void operator()(); };
struct Derived : T, Fallback { };

# define BOOST_PYTHON_FN_CC __cdecl
# define BOOST_PYTHON_FN_CC_IS_CDECL
template<typename U, U> struct Check;

# define BOOST_PP_ITERATION_PARAMS_1 \
(3, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/signature.hpp>))
template<typename>
static yes test(...);

# include BOOST_PP_ITERATE()
template<typename C>
static no test(Check<void (Fallback::*)(), &C::operator()>*);

# undef BOOST_PYTHON_FN_CC
# undef BOOST_PYTHON_FN_CC_IS_CDECL
public:
static const bool value = sizeof(test<Derived>(0)) == sizeof(yes);
};

# endif // defined(BOOST_PYTHON_ENABLE_CDECL)
template<typename T>
struct is_callable
: conditional<
is_class<T>::value,
is_callable_detect<T>,
false_type
>::type
{ };

// __stdcall calling convention
template<class CallableT, class Target, class Enable = void>
struct get_signature_helper;

# if defined(BOOST_PYTHON_ENABLE_STDCALL)

# define BOOST_PYTHON_FN_CC __stdcall
template<class CallableT, class Target>
struct get_signature_helper<CallableT, Target, typename enable_if_c<is_function<CallableT>::value>::type>{
typedef typename function_types::components<CallableT>::types components;

# define BOOST_PP_ITERATION_PARAMS_1 \
(3, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/signature.hpp>))
inline static components signature(CallableT, Target * = 0){ return components(); }
};

# include BOOST_PP_ITERATE()

# undef BOOST_PYTHON_FN_CC
#if (__cplusplus > 199711L) && !defined(BOOST_NO_CXX11_LAMBDAS)
template<class CallableT, class Target>
struct get_signature_helper<CallableT, Target, typename enable_if_c<is_callable<CallableT>::value>::type>{
typedef decltype(&CallableT::operator()) operator_type;
typedef typename function_types::components<operator_type>::types components;

# endif // defined(BOOST_PYTHON_ENABLE_STDCALL)
inline static components signature(CallableT, Target * = 0){ return components(); }
};
#endif

// __fastcall calling convention
template<class CallableT, class Target>
struct get_signature_helper<CallableT, Target, typename enable_if_c<function_types::is_function_pointer<CallableT>::value>::type>{
typedef typename function_types::components<typename decay<CallableT>::type>::types components;

# if defined(BOOST_PYTHON_ENABLE_FASTCALL)
inline static components signature(CallableT, Target * = 0){ return components(); }
};

# define BOOST_PYTHON_FN_CC __fastcall
template<class CallableT, class Target>
struct get_signature_helper<CallableT, Target, typename enable_if_c<is_member_function_pointer<CallableT>::value>::type>{
typedef typename function_types::components<CallableT>::types base_components;
typedef typename mpl::at_c<base_components, 0>::type return_type;
typedef typename decay<typename
remove_cv<
typename mpl::at_c<base_components, 1>::type
>::type
>::type class_type;

# define BOOST_PP_ITERATION_PARAMS_1 \
(3, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/signature.hpp>))
typedef typename mpl::advance_c<typename mpl::begin<base_components>::type, 2>::type param_types_begin;
typedef typename mpl::end<base_components>::type param_types_end;
typedef mpl::iterator_range<param_types_begin, param_types_end> param_types;

# include BOOST_PP_ITERATE()
typedef typename mpl::if_c<is_same<Target, void>::value,
class_type,
typename most_derived<Target, class_type>::type
>::type target_type;

# undef BOOST_PYTHON_FN_CC
typedef mpl::vector<return_type, target_type&> result_and_class_type;
typedef mpl::joint_view<result_and_class_type, param_types> types_view;

# endif // defined(BOOST_PYTHON_ENABLE_FASTCALL)
typedef typename mpl::reverse_copy<types_view, mpl::front_inserter< mpl::vector0<> > >::type target_components;
typedef target_components components;

# undef BOOST_PYTHON_LIST_INC
inline static components signature(CallableT, Target * = 0){ return components();}
};

// }
template<class CallableT, class Target = void>
inline typename get_signature_helper<CallableT, Target>::components get_signature(CallableT c, Target *p = 0){
return get_signature_helper<CallableT, Target>::signature(boost::forward<CallableT>(c), p);
}

}}} // namespace boost::python::detail


# endif // SIGNATURE_JDG20020813_HPP

// For gcc 4.4 compatability, we must include the
// BOOST_PP_ITERATION_DEPTH test inside an #else clause.
#else // BOOST_PP_IS_ITERATING
#if BOOST_PP_ITERATION_DEPTH() == 1 // defined(BOOST_PP_IS_ITERATING)

# define N BOOST_PP_ITERATION()

// as 'get_signature(RT(*)(T0...TN), void* = 0)' is the same
// function as 'get_signature(RT(__cdecl *)(T0...TN), void* = 0)',
// we don't define it twice
# if !defined(BOOST_PYTHON_FN_CC_IS_CDECL)

template <
class RT BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class T)>
inline BOOST_PYTHON_LIST_INC(N)<
RT BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T)>
get_signature(RT(BOOST_PYTHON_FN_CC *)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)), void* = 0)
{
return BOOST_PYTHON_LIST_INC(N)<
RT BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T)
>();
}

# endif // !defined(BOOST_PYTHON_FN_CC_IS_CDECL)

# undef N

# define BOOST_PP_ITERATION_PARAMS_2 \
(3, (0, 3, <boost/python/signature.hpp>))
# include BOOST_PP_ITERATE()

#else

# define N BOOST_PP_RELATIVE_ITERATION(1)
# define Q BOOST_PYTHON_CV_QUALIFIER(BOOST_PP_ITERATION())

template <
class RT, class ClassT BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class T)>
inline BOOST_PYTHON_LIST_INC(BOOST_PP_INC(N))<
RT, ClassT& BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T)>
get_signature(RT(BOOST_PYTHON_FN_CC ClassT::*)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)) Q)
{
return BOOST_PYTHON_LIST_INC(BOOST_PP_INC(N))<
RT, ClassT& BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T)
>();
}

template <
class Target
, class RT
, class ClassT
BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class T)
>
inline BOOST_PYTHON_LIST_INC(BOOST_PP_INC(N))<
RT
, typename most_derived<Target, ClassT>::type&
BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T)
>
get_signature(
RT(BOOST_PYTHON_FN_CC ClassT::*)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)) Q
, Target*
)
{
return BOOST_PYTHON_LIST_INC(BOOST_PP_INC(N))<
RT
, BOOST_DEDUCED_TYPENAME most_derived<Target, ClassT>::type&
BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T)
>();
}

# undef Q
# undef N

#endif // BOOST_PP_ITERATION_DEPTH()
#endif // !defined(BOOST_PP_IS_ITERATING)
12 changes: 11 additions & 1 deletion test/class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,28 @@ using namespace boost::python;
struct X
{
int x;
X(int n) : x(n) { }
int foo;
X(int n) : x(n), foo(0){ }
};

int x_function(X& x)
{ return x.x;
}

int y_function(X& x)
{ return x.foo++;
}

BOOST_PYTHON_MODULE(class_ext)
{
class_<X>("X", init<int>());
def("x_function", x_function);
#if (__cplusplus > 199711L) && !defined(BOOST_NO_CXX11_LAMBDAS)
def("y_function", [&foo](int) -> int { return foo++; });
#else
def("y_function", y_function);

#endif
}

#include "module_tail.cpp"
4 changes: 4 additions & 0 deletions test/class.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
>>> x = X(42)
>>> x_function(x)
42
>>> y_function(x)
0
>>> y_function(x)
1

Demonstrate extraction in the presence of metaclass changes:

Expand Down