From 37b45d2baf5188f7be7e2883eff723760bf43e14 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 4 Apr 2010 05:19:57 +0000 Subject: [PATCH] merging current boost/python and libs/python from trunk into release branch [SVN r61033] --- build/Jamfile.v2 | 20 +++ doc/v2/configuration.html | 27 +++ doc/v2/object.html | 12 +- include/boost/python/detail/destroy.hpp | 2 +- include/boost/python/object/make_instance.hpp | 3 +- .../boost/python/object/pointer_holder.hpp | 11 +- include/boost/python/object_core.hpp | 11 +- include/boost/python/signature.hpp | 83 ++++++++- src/exec.cpp | 20 +-- src/object/function.cpp | 6 +- src/object/pickle_support.cpp | 8 +- test/Jamfile.v2 | 3 + test/calling_conventions.cpp | 158 +++++++++++++++++ test/calling_conventions.py | 81 +++++++++ test/calling_conventions_mf.cpp | 159 ++++++++++++++++++ test/calling_conventions_mf.py | 84 +++++++++ test/destroy_test.cpp | 4 + 17 files changed, 659 insertions(+), 33 deletions(-) create mode 100644 test/calling_conventions.cpp create mode 100644 test/calling_conventions.py create mode 100644 test/calling_conventions_mf.cpp create mode 100644 test/calling_conventions_mf.py diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 803f8bc5..cc8a8be2 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -3,6 +3,7 @@ # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) import os ; +import indirect ; import modules ; import feature ; @@ -41,8 +42,27 @@ py3-version = [ find-py3-version ] ; project boost/python : source-location ../src + : requirements + -@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + @$(__name__).tag ; +rule tag ( name : type ? : property-set ) +{ + local result = $(name) ; + if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB + { + if $(name) = boost_python && $(PYTHON_ID) + { + result = $(result)-$(PYTHON_ID) ; + } + } + + # forward to the boost tagging rule + return [ indirect.call $(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + $(result) : $(type) : $(property-set) ] ; +} + rule cond ( test ? : yes * : no * ) { if $(test) { return $(yes) ; } else { return $(no) ; } } rule unless ( test ? : yes * : no * ) { if ! $(test) { return $(yes) ; } else { return $(no) ; } } diff --git a/doc/v2/configuration.html b/doc/v2/configuration.html index 0415ca2b..1be862ed 100644 --- a/doc/v2/configuration.html +++ b/doc/v2/configuration.html @@ -106,6 +106,33 @@ function from being treated as an exported symbol on platforms which support that distinction in-code + + + BOOST_PYTHON_ENABLE_CDECL + + not defined + + If defined, allows functions using the __cdecl + calling convention to be wrapped. + + + + BOOST_PYTHON_ENABLE_STDCALL + + not defined + + If defined, allows functions using the __stdcall + calling convention to be wrapped. + + + + BOOST_PYTHON_ENABLE_FASTCALL + + not defined + + If defined, allows functions using the __fastcall + calling convention to be wrapped. +

Library Defined Implementation diff --git a/doc/v2/object.html b/doc/v2/object.html index 6fa48fa5..8df8ef5f 100644 --- a/doc/v2/object.html +++ b/doc/v2/object.html @@ -835,6 +835,8 @@ namespace boost { namespace python { namespace api object& operator=(object const&); PyObject* ptr() const; + + bool is_none() const; }; }}} @@ -895,6 +897,14 @@ PyObject* ptr() const;
Returns: a pointer to the internally-held Python object.
+ +
+bool is_none() const;
+
+ +
+
Returns: result of (ptr() == Py_None)
+

Class template proxy

@@ -1101,7 +1111,7 @@ object sum_items(object seq)

Revised - 27 May, 2008 + 15 March, 2010

diff --git a/include/boost/python/detail/destroy.hpp b/include/boost/python/detail/destroy.hpp index 7df31d4c..0172dca2 100644 --- a/include/boost/python/detail/destroy.hpp +++ b/include/boost/python/detail/destroy.hpp @@ -30,7 +30,7 @@ struct value_destroyer< template static void execute(T const volatile* p) { - p->T::~T(); + p->~T(); } }; diff --git a/include/boost/python/object/make_instance.hpp b/include/boost/python/object/make_instance.hpp index 8f355fe2..1ffded12 100644 --- a/include/boost/python/object/make_instance.hpp +++ b/include/boost/python/object/make_instance.hpp @@ -10,6 +10,7 @@ # include # include # include +# include namespace boost { namespace python { namespace objects { @@ -21,7 +22,7 @@ struct make_instance_impl template static inline PyObject* execute(Arg& x) { - BOOST_STATIC_ASSERT(is_class::value); + BOOST_MPL_ASSERT((mpl::or_, is_union >)); PyTypeObject* type = Derived::get_class_object(x); diff --git a/include/boost/python/object/pointer_holder.hpp b/include/boost/python/object/pointer_holder.hpp index 2dc6dda9..4627e34a 100644 --- a/include/boost/python/object/pointer_holder.hpp +++ b/include/boost/python/object/pointer_holder.hpp @@ -35,6 +35,8 @@ # include +# include + namespace boost { namespace python { template class wrapper; @@ -122,26 +124,29 @@ inline pointer_holder_back_reference::pointer_holder_back_referen template void* pointer_holder::holds(type_info dst_t, bool null_ptr_only) { + typedef typename boost::remove_const< Value >::type non_const_value; + if (dst_t == python::type_id() && !(null_ptr_only && get_pointer(this->m_p)) ) return &this->m_p; - Value* p + Value* p0 # if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) = static_cast( get_pointer(this->m_p) ) # else = get_pointer(this->m_p) # endif ; - + non_const_value* p = const_cast( p0 ); + if (p == 0) return 0; if (void* wrapped = holds_wrapped(dst_t, p, p)) return wrapped; - type_info src_t = python::type_id(); + type_info src_t = python::type_id(); return src_t == dst_t ? p : find_dynamic_type(p, src_t, dst_t); } diff --git a/include/boost/python/object_core.hpp b/include/boost/python/object_core.hpp index 5857422f..4d81e2ea 100644 --- a/include/boost/python/object_core.hpp +++ b/include/boost/python/object_core.hpp @@ -5,6 +5,8 @@ #ifndef OBJECT_CORE_DWA2002615_HPP # define OBJECT_CORE_DWA2002615_HPP +# define BOOST_PYTHON_OBJECT_HAS_IS_NONE // added 2010-03-15 by rwgk + # include # include @@ -239,7 +241,9 @@ namespace api // Underlying object access -- returns a borrowed reference inline PyObject* ptr() const; - + + inline bool is_none() const; + private: PyObject* m_ptr; }; @@ -539,6 +543,11 @@ inline PyObject* api::object_base::ptr() const return m_ptr; } +inline bool api::object_base::is_none() const +{ + return (m_ptr == Py_None); +} + // // Converter specialization implementations // diff --git a/include/boost/python/signature.hpp b/include/boost/python/signature.hpp index 1bb2b226..f1143e3a 100644 --- a/include/boost/python/signature.hpp +++ b/include/boost/python/signature.hpp @@ -52,16 +52,23 @@ struct most_derived // // template // inline mpl::vector -// get_signature(RT(*)(T0...TN), void* = 0) +// get_signature(RT(BOOST_PYTHON_FN_CC *)(T0...TN), void* = 0) // { // return mpl::list(); // } // +// where BOOST_PYTHON_FN_CC is a calling convention keyword, can be +// +// empty, for default calling convention +// __cdecl (if BOOST_PYTHON_ENABLE_CDECL is defined) +// __stdcall (if BOOST_PYTHON_ENABLE_STDCALL is defined) +// __fastcall (if BOOST_PYTHON_ENABLE_FASTCALL is defined) +// // And, for an appropriate assortment of cv-qualifications:: // // template // inline mpl::vector -// get_signature(RT(ClassT::*)(T0...TN) cv)) +// get_signature(RT(BOOST_PYTHON_FN_CC ClassT::*)(T0...TN) cv)) // { // return mpl::list(); // } @@ -72,7 +79,7 @@ struct most_derived // , typename most_derived::type& // , T0...TN // > -// get_signature(RT(ClassT::*)(T0...TN) cv), Target*) +// get_signature(RT(BOOST_PYTHON_FN_CC ClassT::*)(T0...TN) cv), Target*) // { // return mpl::list(); // } @@ -87,7 +94,8 @@ struct most_derived // // These functions extract the return type, class (for member // functions) and arguments of the input signature and stuff them in -// an mpl type sequence. Note that cv-qualification is dropped from +// an mpl type sequence (the calling convention is dropped). +// Note that cv-qualification is dropped from // the "hidden this" argument of member functions; that is a // necessary sacrifice to ensure that an lvalue from_python converter // is used. A pointer is not used so that None will be rejected for @@ -100,10 +108,64 @@ struct most_derived // // @group { +// 'default' calling convention + +# define BOOST_PYTHON_FN_CC + # define BOOST_PP_ITERATION_PARAMS_1 \ (3, (0, BOOST_PYTHON_MAX_ARITY, )) # include BOOST_PP_ITERATE() + +# undef BOOST_PYTHON_FN_CC + +// __cdecl calling convention + +# if defined(BOOST_PYTHON_ENABLE_CDECL) + +# define BOOST_PYTHON_FN_CC __cdecl +# define BOOST_PYTHON_FN_CC_IS_CDECL + +# define BOOST_PP_ITERATION_PARAMS_1 \ + (3, (0, BOOST_PYTHON_MAX_ARITY, )) + +# include BOOST_PP_ITERATE() + +# undef BOOST_PYTHON_FN_CC +# undef BOOST_PYTHON_FN_CC_IS_CDECL + +# endif // defined(BOOST_PYTHON_ENABLE_CDECL) + +// __stdcall calling convention + +# if defined(BOOST_PYTHON_ENABLE_STDCALL) + +# define BOOST_PYTHON_FN_CC __stdcall + +# define BOOST_PP_ITERATION_PARAMS_1 \ + (3, (0, BOOST_PYTHON_MAX_ARITY, )) + +# include BOOST_PP_ITERATE() + +# undef BOOST_PYTHON_FN_CC + +# endif // defined(BOOST_PYTHON_ENABLE_STDCALL) + +// __fastcall calling convention + +# if defined(BOOST_PYTHON_ENABLE_FASTCALL) + +# define BOOST_PYTHON_FN_CC __fastcall + +# define BOOST_PP_ITERATION_PARAMS_1 \ + (3, (0, BOOST_PYTHON_MAX_ARITY, )) + +# include BOOST_PP_ITERATE() + +# undef BOOST_PYTHON_FN_CC + +# endif // defined(BOOST_PYTHON_ENABLE_FASTCALL) + # undef BOOST_PYTHON_LIST_INC // } @@ -120,17 +182,24 @@ struct most_derived # 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_PP_ENUM_PARAMS_Z(1, N, T)), void* = 0) +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 \ @@ -146,7 +215,7 @@ 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(ClassT::*)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)) Q) +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) @@ -165,7 +234,7 @@ inline BOOST_PYTHON_LIST_INC(BOOST_PP_INC(N))< BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T) > get_signature( - RT(ClassT::*)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)) Q + RT(BOOST_PYTHON_FN_CC ClassT::*)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)) Q , Target* ) { diff --git a/src/exec.cpp b/src/exec.cpp index e772dcd7..9fe1b23b 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -17,15 +17,14 @@ namespace python object BOOST_PYTHON_DECL eval(str string, object global, object local) { // Set suitable default values for global and local dicts. - object none; - if (global.ptr() == none.ptr()) + if (global.is_none()) { if (PyObject *g = PyEval_GetGlobals()) global = object(detail::borrowed_reference(g)); else global = dict(); } - if (local.ptr() == none.ptr()) local = global; + if (local.is_none()) local = global; // should be 'char const *' but older python versions don't use 'const' yet. char *s = python::extract(string); PyObject* result = PyRun_String(s, Py_eval_input, global.ptr(), local.ptr()); @@ -36,15 +35,14 @@ object BOOST_PYTHON_DECL eval(str string, object global, object local) object BOOST_PYTHON_DECL exec(str string, object global, object local) { // Set suitable default values for global and local dicts. - object none; - if (global.ptr() == none.ptr()) + if (global.is_none()) { if (PyObject *g = PyEval_GetGlobals()) global = object(detail::borrowed_reference(g)); else global = dict(); } - if (local.ptr() == none.ptr()) local = global; + if (local.is_none()) local = global; // should be 'char const *' but older python versions don't use 'const' yet. char *s = python::extract(string); PyObject* result = PyRun_String(s, Py_file_input, global.ptr(), local.ptr()); @@ -55,15 +53,14 @@ object BOOST_PYTHON_DECL exec(str string, object global, object local) object BOOST_PYTHON_DECL exec_statement(str string, object global, object local) { // Set suitable default values for global and local dicts. - object none; - if (global.ptr() == none.ptr()) + if (global.is_none()) { if (PyObject *g = PyEval_GetGlobals()) global = object(detail::borrowed_reference(g)); else global = dict(); } - if (local.ptr() == none.ptr()) local = global; + if (local.is_none()) local = global; // should be 'char const *' but older python versions don't use 'const' yet. char *s = python::extract(string); PyObject* result = PyRun_String(s, Py_single_input, global.ptr(), local.ptr()); @@ -77,15 +74,14 @@ object BOOST_PYTHON_DECL exec_statement(str string, object global, object local) object BOOST_PYTHON_DECL exec_file(str filename, object global, object local) { // Set suitable default values for global and local dicts. - object none; - if (global.ptr() == none.ptr()) + if (global.is_none()) { if (PyObject *g = PyEval_GetGlobals()) global = object(detail::borrowed_reference(g)); else global = dict(); } - if (local.ptr() == none.ptr()) local = global; + if (local.is_none()) local = global; // should be 'char const *' but older python versions don't use 'const' yet. char *f = python::extract(filename); #if PY_VERSION_HEX >= 0x03000000 diff --git a/src/object/function.cpp b/src/object/function.cpp index 0054966e..98c7c966 100644 --- a/src/object/function.cpp +++ b/src/object/function.cpp @@ -144,7 +144,7 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const if (n_keyword_actual > 0 // Keyword arguments were supplied || n_actual < min_arity) // or default keyword values are needed { - if (f->m_arg_names.ptr() == Py_None) + if (f->m_arg_names.is_none()) { // this overload doesn't accept keywords inner_args = handle<>(); @@ -487,7 +487,7 @@ void function::add_to_namespace( } // A function is named the first time it is added to a namespace. - if (new_func->name().ptr() == Py_None) + if (new_func->name().is_none()) new_func->m_name = name; handle<> name_space_name( @@ -653,7 +653,7 @@ extern "C" static PyObject* function_get_name(PyObject* op, void*) { function* f = downcast(op); - if (f->name().ptr() == Py_None) + if (f->name().is_none()) #if PY_VERSION_HEX >= 0x03000000 return PyUnicode_InternFromString(""); #else diff --git a/src/object/pickle_support.cpp b/src/object/pickle_support.cpp index f70eb17f..428c07b6 100644 --- a/src/object/pickle_support.cpp +++ b/src/object/pickle_support.cpp @@ -38,21 +38,21 @@ namespace { } object getinitargs = getattr(instance_obj, "__getinitargs__", none); tuple initargs; - if (getinitargs.ptr() != none.ptr()) { + if (!getinitargs.is_none()) { initargs = tuple(getinitargs()); } result.append(initargs); object getstate = getattr(instance_obj, "__getstate__", none); object instance_dict = getattr(instance_obj, "__dict__", none); long len_instance_dict = 0; - if (instance_dict.ptr() != none.ptr()) { + if (!instance_dict.is_none()) { len_instance_dict = len(instance_dict); } - if (getstate.ptr() != none.ptr()) { + if (!getstate.is_none()) { if (len_instance_dict > 0) { object getstate_manages_dict = getattr( instance_obj, "__getstate_manages_dict__", none); - if (getstate_manages_dict.ptr() == none.ptr()) { + if (getstate_manages_dict.is_none()) { PyErr_SetString(PyExc_RuntimeError, "Incomplete pickle support" " (__getstate_manages_dict__ not set)"); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 764dfa41..1a5683b0 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -184,6 +184,9 @@ bpl-test crossmod_opaque # bpl-test bienstman5 ; # } +[ bpl-test calling_conventions ] +[ bpl-test calling_conventions_mf ] + # --- unit tests of library components --- [ compile indirect_traits_test.cpp ] diff --git a/test/calling_conventions.cpp b/test/calling_conventions.cpp new file mode 100644 index 00000000..54f49aeb --- /dev/null +++ b/test/calling_conventions.cpp @@ -0,0 +1,158 @@ +// +// adapted from bind_stdcall_test.cpp - test for bind.hpp + __stdcall (free functions) +// The purpose of this simple test is to determine if a function can be +// called from Python with the various existing calling conventions +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#if !defined(TEST_INCLUDE_RECURSION) + +#define TEST_INCLUDE_RECURSION + +//------------------------------------------------------------------------------ +// this section is the main body of the test extension module + +#define BOOST_PYTHON_ENABLE_CDECL +#define BOOST_PYTHON_ENABLE_STDCALL +#define BOOST_PYTHON_ENABLE_FASTCALL +#include +#include +#include +using namespace boost::python; + +// first define test functions for every calling convention + +#define TEST_DECLARE_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_DECLARE_FUNCTIONS + +// then create a module wrapping the defined functions for every calling convention + +BOOST_PYTHON_MODULE( calling_conventions_ext ) +{ + +#define TEST_WRAP_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_WRAP_FUNCTIONS + +} + +#else // !defined(TEST_INCLUDE_RECURSION) + +//------------------------------------------------------------------------------ +// this section defines the functions to be wrapped + +# if defined(TEST_DECLARE_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + +namespace BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION) { + + long TESTED_CALLING_CONVENTION f_0() + { + return 17041L; + } + + long TESTED_CALLING_CONVENTION f_1(long a) + { + return a; + } + + long TESTED_CALLING_CONVENTION f_2(long a, long b) + { + return a + 10 * b; + } + + long TESTED_CALLING_CONVENTION f_3(long a, long b, long c) + { + return a + 10 * b + 100 * c; + } + + long TESTED_CALLING_CONVENTION f_4(long a, long b, long c, long d) + { + return a + 10 * b + 100 * c + 1000 * d; + } + + long TESTED_CALLING_CONVENTION f_5(long a, long b, long c, long d, long e) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e; + } + + long TESTED_CALLING_CONVENTION f_6(long a, long b, long c, long d, long e, long f) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f; + } + + long TESTED_CALLING_CONVENTION f_7(long a, long b, long c, long d, long e, long f, long g) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f + 1000000 * g; + } + + long TESTED_CALLING_CONVENTION f_8(long a, long b, long c, long d, long e, long f, long g, long h) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f + 1000000 * g + 10000000 * h; + } + + long TESTED_CALLING_CONVENTION f_9(long a, long b, long c, long d, long e, long f, long g, long h, long i) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f + 1000000 * g + 10000000 * h + 100000000 * i; + } + +} // namespace test##TESTED_CALLING_CONVENTION + +# endif // defined(TEST_DECLARE_FUNCTIONS) + +//------------------------------------------------------------------------------ +// this section wraps the functions + +# if defined(TEST_WRAP_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + + def("f_0" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_0); + def("f_1" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_1); + def("f_2" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_2); + def("f_3" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_3); + def("f_4" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_4); + def("f_5" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_5); + def("f_6" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_6); + def("f_7" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_7); + def("f_8" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_8); + def("f_9" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_9); + +# endif // defined(TEST_WRAP_FUNCTIONS) + +#endif // !defined(TEST_INCLUDE_RECURSION) diff --git a/test/calling_conventions.py b/test/calling_conventions.py new file mode 100644 index 00000000..ce74a843 --- /dev/null +++ b/test/calling_conventions.py @@ -0,0 +1,81 @@ +# Copyright Nicolas Lelong, 2010. Distributed under the Boost +# Software License, Version 1.0 (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from calling_conventions_ext import * +>>> f_0__cdecl() +17041 +>>> f_1__cdecl(1) +1 +>>> f_2__cdecl(1, 2) +21 +>>> f_3__cdecl(1, 2, 3) +321 +>>> f_4__cdecl(1, 2, 3, 4) +4321 +>>> f_5__cdecl(1, 2, 3, 4, 5) +54321 +>>> f_6__cdecl(1, 2, 3, 4, 5, 6) +654321 +>>> f_7__cdecl(1, 2, 3, 4, 5, 6, 7) +7654321 +>>> f_8__cdecl(1, 2, 3, 4, 5, 6, 7, 8) +87654321 +>>> f_9__cdecl(1, 2, 3, 4, 5, 6, 7, 8, 9) +987654321 +>>> f_0__stdcall() +17041 +>>> f_1__stdcall(1) +1 +>>> f_2__stdcall(1, 2) +21 +>>> f_3__stdcall(1, 2, 3) +321 +>>> f_4__stdcall(1, 2, 3, 4) +4321 +>>> f_5__stdcall(1, 2, 3, 4, 5) +54321 +>>> f_6__stdcall(1, 2, 3, 4, 5, 6) +654321 +>>> f_7__stdcall(1, 2, 3, 4, 5, 6, 7) +7654321 +>>> f_8__stdcall(1, 2, 3, 4, 5, 6, 7, 8) +87654321 +>>> f_9__stdcall(1, 2, 3, 4, 5, 6, 7, 8, 9) +987654321 +>>> f_0__fastcall() +17041 +>>> f_1__fastcall(1) +1 +>>> f_2__fastcall(1, 2) +21 +>>> f_3__fastcall(1, 2, 3) +321 +>>> f_4__fastcall(1, 2, 3, 4) +4321 +>>> f_5__fastcall(1, 2, 3, 4, 5) +54321 +>>> f_6__fastcall(1, 2, 3, 4, 5, 6) +654321 +>>> f_7__fastcall(1, 2, 3, 4, 5, 6, 7) +7654321 +>>> f_8__fastcall(1, 2, 3, 4, 5, 6, 7, 8) +87654321 +>>> f_9__fastcall(1, 2, 3, 4, 5, 6, 7, 8, 9) +987654321 +""" + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/test/calling_conventions_mf.cpp b/test/calling_conventions_mf.cpp new file mode 100644 index 00000000..80ccc406 --- /dev/null +++ b/test/calling_conventions_mf.cpp @@ -0,0 +1,159 @@ +// +// adapted from bind_stdcall_mf_test.cpp - test for bind.hpp + __stdcall (free functions) +// The purpose of this simple test is to determine if a function can be +// called from Python with the various existing calling conventions +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#if !defined(TEST_INCLUDE_RECURSION) + +#define TEST_INCLUDE_RECURSION + +//------------------------------------------------------------------------------ +// this section is the main body of the test extension module + +#define BOOST_PYTHON_ENABLE_CDECL +#define BOOST_PYTHON_ENABLE_STDCALL +#define BOOST_PYTHON_ENABLE_FASTCALL +#include +#include +#include +using namespace boost::python; + +// first define test functions for every calling convention + +#define TEST_DECLARE_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_DECLARE_FUNCTIONS + +// then create a module wrapping the defined functions for every calling convention + +BOOST_PYTHON_MODULE( calling_conventions_mf_ext ) +{ + +#define TEST_WRAP_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_WRAP_FUNCTIONS + +} + +#else // !defined(TEST_INCLUDE_RECURSION) + +//------------------------------------------------------------------------------ +// this section defines the functions to be wrapped + +# if defined(TEST_DECLARE_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + +namespace BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION) { + +struct X +{ + mutable unsigned int hash; + + X(): hash(0) {} + + void TESTED_CALLING_CONVENTION f0() { f1(17); } + void TESTED_CALLING_CONVENTION g0() const { g1(17); } + + void TESTED_CALLING_CONVENTION f1(int a1) { hash = (hash * 17041 + a1) % 32768; } + void TESTED_CALLING_CONVENTION g1(int a1) const { hash = (hash * 17041 + a1 * 2) % 32768; } + + void TESTED_CALLING_CONVENTION f2(int a1, int a2) { f1(a1); f1(a2); } + void TESTED_CALLING_CONVENTION g2(int a1, int a2) const { g1(a1); g1(a2); } + + void TESTED_CALLING_CONVENTION f3(int a1, int a2, int a3) { f2(a1, a2); f1(a3); } + void TESTED_CALLING_CONVENTION g3(int a1, int a2, int a3) const { g2(a1, a2); g1(a3); } + + void TESTED_CALLING_CONVENTION f4(int a1, int a2, int a3, int a4) { f3(a1, a2, a3); f1(a4); } + void TESTED_CALLING_CONVENTION g4(int a1, int a2, int a3, int a4) const { g3(a1, a2, a3); g1(a4); } + + void TESTED_CALLING_CONVENTION f5(int a1, int a2, int a3, int a4, int a5) { f4(a1, a2, a3, a4); f1(a5); } + void TESTED_CALLING_CONVENTION g5(int a1, int a2, int a3, int a4, int a5) const { g4(a1, a2, a3, a4); g1(a5); } + + void TESTED_CALLING_CONVENTION f6(int a1, int a2, int a3, int a4, int a5, int a6) { f5(a1, a2, a3, a4, a5); f1(a6); } + void TESTED_CALLING_CONVENTION g6(int a1, int a2, int a3, int a4, int a5, int a6) const { g5(a1, a2, a3, a4, a5); g1(a6); } + + void TESTED_CALLING_CONVENTION f7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) { f6(a1, a2, a3, a4, a5, a6); f1(a7); } + void TESTED_CALLING_CONVENTION g7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) const { g6(a1, a2, a3, a4, a5, a6); g1(a7); } + + void TESTED_CALLING_CONVENTION f8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { f7(a1, a2, a3, a4, a5, a6, a7); f1(a8); } + void TESTED_CALLING_CONVENTION g8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) const { g7(a1, a2, a3, a4, a5, a6, a7); g1(a8); } +}; + +} // namespace BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION) + +# endif // defined(TEST_DECLARE_FUNCTIONS) + +//------------------------------------------------------------------------------ +// this section wraps the functions + +# if defined(TEST_WRAP_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + +{ + + typedef BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::X X; + + class_("X" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION)) + .def("f0", &X::f0) + .def("g0", &X::g0) + .def("f1", &X::f1) + .def("g1", &X::g1) + .def("f2", &X::f2) + .def("g2", &X::g2) + .def("f3", &X::f3) + .def("g3", &X::g3) + .def("f4", &X::f4) + .def("g4", &X::g4) + .def("f5", &X::f5) + .def("g5", &X::g5) + .def("f6", &X::f6) + .def("g6", &X::g6) + .def("f7", &X::f7) + .def("g7", &X::g7) + .def("f8", &X::f8) + .def("g8", &X::g8) + .def_readonly("hash", &X::hash) + ; + +} + +# endif // defined(TEST_WRAP_FUNCTIONS) + +#endif // !defined(TEST_INCLUDE_RECURSION) diff --git a/test/calling_conventions_mf.py b/test/calling_conventions_mf.py new file mode 100644 index 00000000..1ec9c2b6 --- /dev/null +++ b/test/calling_conventions_mf.py @@ -0,0 +1,84 @@ +# Copyright Nicolas Lelong, 2010. Distributed under the Boost +# Software License, Version 1.0 (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from calling_conventions_mf_ext import * +>>> x = X__cdecl() +>>> x.f0() +>>> x.g0() +>>> x.f1(1) +>>> x.g1(1) +>>> x.f2(1, 2) +>>> x.g2(1, 2) +>>> x.f3(1, 2, 3) +>>> x.g3(1, 2, 3) +>>> x.f4(1, 2, 3, 4) +>>> x.g4(1, 2, 3, 4) +>>> x.f5(1, 2, 3, 4, 5) +>>> x.g5(1, 2, 3, 4, 5) +>>> x.f6(1, 2, 3, 4, 5, 6) +>>> x.g6(1, 2, 3, 4, 5, 6) +>>> x.f7(1, 2, 3, 4, 5, 6, 7) +>>> x.g7(1, 2, 3, 4, 5, 6, 7) +>>> x.f8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.g8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.hash +2155 +>>> x = X__stdcall() +>>> x.f0() +>>> x.g0() +>>> x.f1(1) +>>> x.g1(1) +>>> x.f2(1, 2) +>>> x.g2(1, 2) +>>> x.f3(1, 2, 3) +>>> x.g3(1, 2, 3) +>>> x.f4(1, 2, 3, 4) +>>> x.g4(1, 2, 3, 4) +>>> x.f5(1, 2, 3, 4, 5) +>>> x.g5(1, 2, 3, 4, 5) +>>> x.f6(1, 2, 3, 4, 5, 6) +>>> x.g6(1, 2, 3, 4, 5, 6) +>>> x.f7(1, 2, 3, 4, 5, 6, 7) +>>> x.g7(1, 2, 3, 4, 5, 6, 7) +>>> x.f8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.g8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.hash +2155 +>>> x = X__fastcall() +>>> x.f0() +>>> x.g0() +>>> x.f1(1) +>>> x.g1(1) +>>> x.f2(1, 2) +>>> x.g2(1, 2) +>>> x.f3(1, 2, 3) +>>> x.g3(1, 2, 3) +>>> x.f4(1, 2, 3, 4) +>>> x.g4(1, 2, 3, 4) +>>> x.f5(1, 2, 3, 4, 5) +>>> x.g5(1, 2, 3, 4, 5) +>>> x.f6(1, 2, 3, 4, 5, 6) +>>> x.g6(1, 2, 3, 4, 5, 6) +>>> x.f7(1, 2, 3, 4, 5, 6, 7) +>>> x.g7(1, 2, 3, 4, 5, 6, 7) +>>> x.f8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.g8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.hash +2155 +""" + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/test/destroy_test.cpp b/test/destroy_test.cpp index 254bfc26..cae95ae9 100644 --- a/test/destroy_test.cpp +++ b/test/destroy_test.cpp @@ -22,6 +22,10 @@ struct foo *kills++ = n; } int n; + + // This used to cause compiler errors with MSVC 9.0. + foo& operator~(); + foo& T(); }; void assert_destructions(int n)