From 1f78c7408592a4ce634bc7268c5a910b6e0c6b05 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 24 Dec 2001 19:27:39 +0000 Subject: [PATCH] fixes [SVN r12146] --- Jamfile | 39 + build/Jamfile | 22 +- doc/new-conversions.html | 326 +++++++ doc/new-conversions.txt | 111 +++ example/simple_vector.cpp | 2 +- include/boost/python/call.hpp | 210 +++++ include/boost/python/classes.hpp | 6 +- include/boost/python/conversions.hpp | 53 +- include/boost/python/convert.hpp | 84 ++ include/boost/python/converter/body.hpp | 68 ++ include/boost/python/converter/class.hpp | 56 ++ include/boost/python/converter/handle.hpp | 91 ++ .../boost/python/converter/registration.hpp | 83 ++ include/boost/python/converter/registry.hpp | 74 ++ include/boost/python/converter/source.hpp | 80 ++ .../boost/python/converter/source_holder.hpp | 24 + include/boost/python/converter/target.hpp | 173 ++++ include/boost/python/converter/type_id.hpp | 200 +++++ include/boost/python/converter/unwrap.hpp | 192 ++++ include/boost/python/converter/unwrapper.hpp | 53 ++ .../boost/python/converter/unwrapper_base.hpp | 25 + include/boost/python/converter/wrap.hpp | 145 +++ include/boost/python/converter/wrapper.hpp | 69 ++ include/boost/python/cross_module.hpp | 110 +-- .../boost/python/detail/arg_tuple_size.hpp | 233 +++++ include/boost/python/detail/base_object.hpp | 6 +- include/boost/python/detail/call_object.hpp | 66 ++ include/boost/python/detail/caller.hpp | 27 + include/boost/python/detail/config.hpp | 18 +- .../python/detail/python_library_include.hpp | 1 + include/boost/python/detail/returning.hpp | 846 ++++++++++++++++++ include/boost/python/detail/types.hpp | 4 - include/boost/python/detail/void_adaptor.hpp | 2 +- include/boost/python/detail/wrap_python.hpp | 46 +- include/boost/python/errors.hpp | 42 +- include/boost/python/export.hpp | 20 + include/boost/python/make_function.hpp | 40 + include/boost/python/module.hpp | 12 + include/boost/python/module_builder.hpp | 39 +- include/boost/python/object/class.hpp | 103 +++ .../boost/python/object/class_unwrapper.hpp | 40 + include/boost/python/object/construct.hpp | 24 + include/boost/python/object/forward.hpp | 33 + include/boost/python/object/function.hpp | 36 + include/boost/python/object/make_holder.hpp | 124 +++ include/boost/python/object/value_holder.hpp | 80 ++ include/boost/python/objects.hpp | 223 +++-- include/boost/python/operators.hpp | 2 +- src/classes.cpp | 4 +- src/conversions.cpp | 99 +- src/converter/body.cpp | 18 + src/converter/handle.cpp | 35 + src/converter/registry.cpp | 177 ++++ src/converter/type_id.cpp | 67 ++ src/converter/unwrap.cpp | 35 + src/converter/unwrapper.cpp | 24 + src/converter/wrapper.cpp | 30 + src/cross_module.cpp | 117 +-- src/errors.cpp | 68 ++ src/extension_class.cpp | 25 +- src/gen_call.py | 82 ++ src/gen_returning.py | 191 ++++ src/module_builder.cpp | 16 +- src/object/class.cpp | 165 ++++ src/object/function.cpp | 95 ++ src/objects.cpp | 126 +-- src/types.cpp | 126 +-- test/complicated.hpp | 39 + test/m1.cpp | 281 ++++++ test/m2.cpp | 197 ++++ test/module_tail.cpp | 39 + test/newtest.py | 95 ++ test/simple_type.hpp | 14 + 73 files changed, 5947 insertions(+), 581 deletions(-) create mode 100644 Jamfile create mode 100644 doc/new-conversions.html create mode 100644 doc/new-conversions.txt create mode 100644 include/boost/python/call.hpp create mode 100644 include/boost/python/convert.hpp create mode 100644 include/boost/python/converter/body.hpp create mode 100644 include/boost/python/converter/class.hpp create mode 100644 include/boost/python/converter/handle.hpp create mode 100644 include/boost/python/converter/registration.hpp create mode 100644 include/boost/python/converter/registry.hpp create mode 100644 include/boost/python/converter/source.hpp create mode 100644 include/boost/python/converter/source_holder.hpp create mode 100644 include/boost/python/converter/target.hpp create mode 100644 include/boost/python/converter/type_id.hpp create mode 100644 include/boost/python/converter/unwrap.hpp create mode 100644 include/boost/python/converter/unwrapper.hpp create mode 100644 include/boost/python/converter/unwrapper_base.hpp create mode 100644 include/boost/python/converter/wrap.hpp create mode 100644 include/boost/python/converter/wrapper.hpp create mode 100644 include/boost/python/detail/arg_tuple_size.hpp create mode 100644 include/boost/python/detail/call_object.hpp create mode 100644 include/boost/python/detail/caller.hpp create mode 100644 include/boost/python/detail/returning.hpp create mode 100644 include/boost/python/export.hpp create mode 100644 include/boost/python/make_function.hpp create mode 100644 include/boost/python/module.hpp create mode 100644 include/boost/python/object/class.hpp create mode 100644 include/boost/python/object/class_unwrapper.hpp create mode 100644 include/boost/python/object/construct.hpp create mode 100644 include/boost/python/object/forward.hpp create mode 100644 include/boost/python/object/function.hpp create mode 100644 include/boost/python/object/make_holder.hpp create mode 100644 include/boost/python/object/value_holder.hpp create mode 100644 src/converter/body.cpp create mode 100644 src/converter/handle.cpp create mode 100644 src/converter/registry.cpp create mode 100644 src/converter/type_id.cpp create mode 100644 src/converter/unwrap.cpp create mode 100644 src/converter/unwrapper.cpp create mode 100644 src/converter/wrapper.cpp create mode 100644 src/errors.cpp create mode 100644 src/gen_call.py create mode 100644 src/gen_returning.py create mode 100644 src/object/class.cpp create mode 100644 src/object/function.cpp create mode 100644 test/complicated.hpp create mode 100644 test/m1.cpp create mode 100644 test/m2.cpp create mode 100644 test/module_tail.cpp create mode 100644 test/newtest.py create mode 100644 test/simple_type.hpp diff --git a/Jamfile b/Jamfile new file mode 100644 index 00000000..18372684 --- /dev/null +++ b/Jamfile @@ -0,0 +1,39 @@ +subproject libs/python ; + +# bring in the rules for python +SEARCH on python.jam = $(BOOST_BUILD_PATH) ; +include python.jam ; + +PYTHON_PROPERTIES + += <*>"-inline deferred" + <*>$(BOOST_ROOT)/boost/compatibility/cpp_c_headers + BOOST_PYTHON_DYNAMIC_LIB + ; + + +dll bpl + : + src/converter/body.cpp + src/converter/handle.cpp + src/converter/registry.cpp + src/converter/wrapper.cpp + src/converter/unwrap.cpp + src/converter/unwrapper.cpp + src/converter/type_id.cpp + src/object/class.cpp + src/object/function.cpp + src/errors.cpp + : + $(PYTHON_PROPERTIES) + BOOST_PYTHON_SOURCE + ; + +extension m1 : test/m1.cpp bpl # BOOST_PYTHON_TRACE + : + : debug-python ; + +extension m2 : test/m2.cpp bpl # BOOST_PYTHON_TRACE + : + : debug-python ; + +boost-python-runtest try : test/newtest.py m1 m2 : : debug-python ; \ No newline at end of file diff --git a/build/Jamfile b/build/Jamfile index 78d1e84a..7fd8c285 100644 --- a/build/Jamfile +++ b/build/Jamfile @@ -61,6 +61,8 @@ subproject libs/python/build ; SEARCH on python.jam = $(BOOST_BUILD_PATH) ; include python.jam ; +local PYTHON_PROPERTIES = $(PYTHON_PROPERTIES) BOOST_PYTHON_DYNAMIC_LIB ; + ####################### local rule bpl-test ( test-name : sources + ) { @@ -75,21 +77,27 @@ local rule bpl-test ( test-name : sources + ) # Base names of the source files for libboost_python local CPP_SOURCES = - types classes conversions extension_class functions - init_function module_builder objects cross_module ; + types classes conversions extension_class functions + init_function module_builder objects cross_module errors + ; -lib libboost_python : ../src/$(CPP_SOURCES).cpp +lib libboost_python_static : ../src/$(CPP_SOURCES).cpp # requirements : $(BOOST_PYTHON_INCLUDES) true + BOOST_PYTHON_STATIC_LIB=1 $(PYTHON_PROPERTIES) ; -dll libboost_python$(SUFDLL[1]) : ../src/$(CPP_SOURCES).cpp +dll libboost_python + # $(SUFDLL[1]) + : ../src/$(CPP_SOURCES).cpp # requirements - : $(BOOST_PYTHON_INCLUDES) + : $(BOOST_PYTHON_INCLUDES) true - BOOST_RE_BUILD_DLL=1 - $(PYTHON_PROPERTIES) ; + dynamic + BOOST_PYTHON_HAS_DLL_RUNTIME=1 + $(PYTHON_PROPERTIES) + ; ############# comprehensive module and test ########### bpl-test boost_python_test diff --git a/doc/new-conversions.html b/doc/new-conversions.html new file mode 100644 index 00000000..cd8a5b19 --- /dev/null +++ b/doc/new-conversions.html @@ -0,0 +1,326 @@ + + + + +A New Type Conversion Mechanism for Boost.Python + + + + +

+ +

A New Type Conversion Mechanism for Boost.Python

+ +

By David Abrahams. + +

Introduction

+ +This document describes a redesign of the mechanism for automatically +converting objects between C++ and Python. The current implementation +uses two functions for any type T: + +
+U from_python(PyObject*, type<T>);
+void to_python(V);
+
+ +where U is convertible to T and T is convertible to V. These functions +are at the heart of C++/Python interoperability in Boost.Python, so +why would we want to change them? There are many reasons: + +

Bugs

+

Firstly, the current mechanism relies on a common C++ compiler +bug. This is not just embarrassing: as compilers get to be more +conformant, the library stops working. The issue, in detail, is the +use of inline friend functions in templates to generate +conversions. It is a very powerful, and legal technique as long as +it's used correctly: + +

+template <class Derived>
+struct add_some_functions
+{
+     friend return-type some_function1(..., Derived cv-*-&-opt, ...);
+     friend return-type some_function2(..., Derived cv-*-&-opt, ...);
+};
+
+template <class T>
+struct some_template : add_some_functions<some_template<T> >
+{
+};
+
+ +The add_some_functions template generates free functions +which operate on Derived, or on related types. Strictly +speaking the related types are not just cv-qualified Derived +values, pointers and/or references. Section 3.4.2 in the standard +describes exactly which types you must use as parameters to these +functions if you want the functions to be found +(there is also a less-technical description in section 11.5.1 of +C++PL3 [1]). Suffice it to say that +with the current design, the from_python and +to_python functions are not supposed to be callable under any +conditions! + +

Compilation and Linking Time

+ +The conversion functions generated for each wrapped class using the +above technique are not function templates, but regular functions. The +upshot is that they must all be generated regardless of whether +they are actually used. Generating all of those functions can slow +down module compilation, and resolving the references can slow down +linking. + +

Efficiency

+ +The conversion functions are primarily used in (member) function +wrappers to convert the arguments and return values. Being functions, +converters have no interface which allows us to ask "will the +conversion succeed?" without calling the function. Since the +return value of the function must be the object to be passed as an +argument, Boost.Python currently uses C++ exception-handling to detect +an unsuccessful conversion. It's not a particularly good use of +exception-handling, since the failure is not handled very far from +where it occurred. More importantly, it means that C++ exceptions are +thrown during overload resolution as we seek an overload that matches +the arguments passed. Depending on the implementation, this approach +can result in significant slowdowns. + +

It is also unclear that the current library generates a minimal +amount of code for any type conversion. Many of the conversion +functions are nontrivial, and partly because of compiler limitations, +they are declared inline. Also, we could have done a better +job separating the type-specific conversion code from the code which +is type-independent. + +

Cross-module Support

+ +The current strategy requires every module to contain the definition +of conversions it uses. In general, a new module can never supply +conversion code which is used by another module. Ralf Grosse-Kunstleve +designed a clever system which imports conversions directly from one +library into another using some explicit declarations, but it has some +disadvantages also: + +
    +
  1. The system Ullrich Koethe designed for implicit conversion between +wrapped classes related through inheritance does not currently work if +the classes are defined in separate modules. + +
  2. The writer of the importing module is required to know the name of +the module supplying the imported conversions. + +
  3. There can be only one way to extract any given C++ type from a +Python object in a given module. +
+ +The first item might be addressed by moving Boost.Python into a shared +library, but the other two cannot. Ralf turned the limitation in item +two into a feature: the required module is loaded implicitly when a +conversion it defines is invoked. We will probably want to provide +that functionality anyway, but it's not clear that we should require +the declaration of all such conversions. The final item is a more +serious limitation. If, for example, new numeric types are defined in +separate modules, and these types can all be converted to +doubles, we have to choose just one conversion method. + +

Ease-of-use

+ +One persistent source of confusion for users of Boost.Python has been +the fact that conversions for a class are not be visible at +compile-time until the declaration of that class has been seen. When +the user tries to expose a (member) function operating on or returning +an instance of the class in question, compilation fails...even though +the user goes on to expose the class in the same translation unit! + +

+The new system lifts all compile-time checks for the existence of +particular type conversions and replaces them with runtime checks, in +true Pythonic style. While this might seem cavalier, the compile-time +checks are actually not much use in the current system if many classes +are wrapped in separate modules, since the checks are based only on +the user's declaration that the conversions exist. + +

The New Design

+ +

Motivation

+ +The new design was heavily influenced by a desire to generate as +little code as possible in extension modules. Some of Boost.Python's +clients are enormous projects where link time is proportional to the +amount of object code, and there are many Python extension modules. As +such, we try to keep type-specific conversion code out of modules +other than the one the converters are defined in, and rely as much as +possible on centralized control through a shared library. + +

The Basics

+ +The library contains a registry which maps runtime type +identifiers (actually an extension of std::type_info which +preserves references and constness) to entries containing type +converters. An entry can contain only one converter from C++ to Python +(wrapper), but many converters from Python to C++ +(unwrappers). What should happen if +multiple modules try to register wrappers for the same type?. Wrappers +and unwrappers are known as body objects, and are accessed +by the user and the library (in its function-wrapping code) through +corresponding handle (wrap<T> and +unwrap<T>) objects. The handle objects are +extremely lightweight, and delegate all of their operations to +the corresponding body. + +

+When a handle object is constructed, it accesses the +registry to find a corresponding body that can convert the +handle's constructor argument. Actually the registry record for any +type +Tused in a module is looked up only once and stored in a +static registration<T> object for efficiency. For +example, if the handle is an unwrap<Foo&> object, +the entry for Foo& is looked up in the +registry, and each unwrapper it contains is queried +to determine if it can convert the +PyObject* with which the unwrap was constructed. If +a body object which can perform the conversion is found, a pointer to +it is stored in the handle. A body object may at any point store +additional data in the handle to speed up the conversion process. + +

+Now that the handle has been constructed, the user can ask it whether +the conversion can be performed. All handles can be tested as though +they were convertible to bool; a true value +indicates success. If the user forges ahead and tries to do the +conversion without checking when no conversion is possible, an +exception will be thrown as usual. The conversion itself is performed +by the body object. + +

Handling complex conversions

+ +

Some conversions may require a dynamic allocation. For example, +when a Python tuple is converted to a std::vector<double> +const&, we need some storage into which to construct the +vector so that a reference to it can be formed. Furthermore, multiple +conversions of the same type may need to be "active" +simultaneously, so we can't keep a single copy of the storage +anywhere. We could keep the storage in the body object, and +have the body clone itself in case the storage is used, but in that +case the storage in the body which lives in the registry is never +used. If the storage was actually an object of the target type (the +safest way in C++), we'd have to find a way to construct one for the +body in the registry, since it may not have a default constructor. + +

+The most obvious way out of this quagmire is to allocate the object using a +new-expression, and store a pointer to it in the handle. Since +the body object knows everything about the data it needs to +allocate (if any), it is also given responsibility for destroying that +data. When the handle is destroyed it asks the body +object to tear down any data it may have stored there. In many ways, +you can think of the body as a "dynamically-determined +vtable" for the handle. + +

Eliminating Redundancy

+ +If you look at the current Boost.Python code, you'll see that there +are an enormous number of conversion functions generated for each +wrapped class. For a given class T, functions are generated +to extract the following types from_python: + +
+T*
+T const*
+T const* const&
+T* const&
+T&
+T const&
+T
+std::auto_ptr<T>&
+std::auto_ptr<T>
+std::auto_ptr<T> const&
+boost::shared_ptr<T>&
+boost::shared_ptr<T>
+boost::shared_ptr<T> const&
+
+ +Most of these are implemented in terms of just a few conversions, and +if you're lucky, they will be inlined and cause no extra +overhead. In the new system, however, a significant amount of data +will be associated with each type that needs to be converted. We +certainly don't want to register a separate unwrapper object for all +of the above types. + +

Fortunately, much of the redundancy can be eliminated. For example, +if we generate an unwrapper for T&, we don't need an +unwrapper for T const& or T. Accordingly, the user's +request to wrap/unwrap a given type is translated at compile-time into +a request which helps to eliminate redundancy. The rules used to +unwrap a type are: + +

    +
  1. Treat built-in types specially: when unwrapping a value or + constant reference to one of these, use a value for the target + type. It will bind to a const reference if neccessary, and more + importantly, avoids having to dynamically allocate room for + an lvalue of types which can be cheaply copied. +
  2. + Reduce everything else to a reference to an un-cv-qualified type + where possible. Since cv-qualification is lost on Python + anyway, there's no point in trying to convert to a + const&. What about conversions + to values like the tuple->vector example above? It seems to me + that we don't want to make a vector<double>& + (non-const) converter available for that case. We may need to + rethink this slightly. +
+ +

To handle the problem described above in item 2, we modify the +procedure slightly. To unwrap any non-scalar T, we seek an +unwrapper for add_reference<T>::type. Unwrappers for +T const& always return T&, and are +registered under both T & and +T const&. + +

For compilers not supporting partial specialization, unwrappers for +T const& must return T const& +(since constness can't be stripped), but a separate unwrapper object +need to be registered for T & and +T const& anyway, for the same reasons. + +We may want to make it possible to compile as +though partial specialization were unavailable even on compilers where +it is available, in case modules could be compiled by different +compilers with compatible ABIs (e.g. Intel C++ and MSVC6). + +

Efficient Argument Conversion

+ +Since type conversions are primarily used in function wrappers, an +optimization is provided for the case where a group of conversions are +used together. Each handle class has a corresponding +"_more" class which does the same job, but has a +trivial destructor. Instead of asking each "_more" +handle to destroy its own body, it is linked into an endogenous list +managed by the first (ordinary) handle. The wrap and +unwrap destructors are responsible for traversing that list +and asking each body class to tear down its +handle. This mechanism is also used to determine if all of +the argument/return-value conversions can succeed with a single +function call in the function wrapping code. We +might need to handle return values in a separate step for Python +callbacks, since the availablility of a conversion won't be known +until the result object is retrieved. + +
+
+

References

+ +

[1]B. Stroustrup, The C++ Programming Language +Special Edition Addison-Wesley, ISBN 0-201-70073-5. + +


+

Revised 19 December 2001

+

© Copyright David Abrahams, 2001

+ + + + diff --git a/doc/new-conversions.txt b/doc/new-conversions.txt new file mode 100644 index 00000000..1540e199 --- /dev/null +++ b/doc/new-conversions.txt @@ -0,0 +1,111 @@ +This hierarchy contains converter handle classes. + + + +-------------+ + | noncopyable | + +-------------+ + ^ + | A common base class used so that + +--------+--------+ conversions can be linked into a + | conversion_base | chain for efficient argument + +-----------------+ conversion + ^ + | + +---------+-----------+ + | | ++-----------+----+ +------+-------+ only used for +| unwrap_more | | wrap_more | chaining, and don't manage any ++----------------+ +--------------+ resources. + ^ ^ + | | + +-----+-----+ +-------+-+ These converters are what users + | unwrap | | wrap | actually touch, but they do so + +-----------+ +---------+ through a type generator which + minimizes the number of converters + that must be generated, so they + + +Each unwrap, unwrap_more, wrap, wrap_more converter holds +a reference to an appropriate converter object + +This hierarchy contains converter body classes + + Exposes use/release which + are needed in case the converter + +-----------+ in the registry needs to be + | converter | cloned. That occurs when a + +-----------+ unwrap target type is not + ^ contained within the Python object. + | + +------------------+-----+ + | | + +--------+-------+ Exposes | + | unwrapper_base | convertible() | + +----------------+ | + ^ | + | | + +--------+----+ +-----+-----+ + | unwrapper| | wrapper| + +-------------+ +-----------+ + Exposes T convert(PyObject*) Exposes PyObject* convert(T) + + +unwrap: + + constructed with a PyObject*, whose reference count is + incremented. + + find the registry entry for the target type + + look in the collection of converters for one which claims to be + able to convert the PyObject to the target type. + + stick a pointer to the unwrapper in the unwrap object + + when unwrap is queried for convertibility, it checks to see + if it has a pointer to an unwrapper. + + on conversion, the unwrapper is asked to allocate an + implementation if the unwrap object isn't already holding + one. The unwrap object "takes ownership" of the unwrapper's + implementation. No memory allocation will actually take place + unless this is a value conversion. + + on destruction, the unwrapper is asked to free any implementation + held by the unwrap object. No memory deallocation actually + takes place unless this is a value conversion + + on destruction, the reference count on the held PyObject is + decremented. + + We need to make sure that by default, you can't instantiate + callback<> for reference and pointer return types: although the + unwrappers may exist, they may convert by-value, which would cause + the referent to be destroyed upon return. + +wrap: + + find the registry entry for the source type + + see if there is a converter. If found, stick a pointer to it in + the wrap object. + + when queried for convertibility, it checks to see if it has a + pointer to a converter. + + on conversion, a reference to the target PyObject is held by the + converter. Generally, the PyObject will have been created by the + converter, but in certain cases it may be a pre-existing object, + whose reference count will have been incremented. + + when a wrap x is used to return from a C++ function, + x.release() is returned so that x no longer holds a reference to + the PyObject when destroyed. + + Otherwise, on destruction, any PyObject still held has its + reference-count decremented. + + +When a converter is created by the user, the appropriate element must +be added to the registry; when it is destroyed, it must be removed +from the registry. diff --git a/example/simple_vector.cpp b/example/simple_vector.cpp index 8c7ee0ce..e0f9e85e 100644 --- a/example/simple_vector.cpp +++ b/example/simple_vector.cpp @@ -91,7 +91,7 @@ BOOST_PYTHON_MODULE_INIT(simple_vector) vector_double(this_module, "vector_double"); vector_double.def(python::constructor<>()); - vector_double.def(python::constructor()); + vector_double.def(python::constructor()); vector_double.def(python::constructor()); vector_double.def(&std::vector::size, "__len__"); vector_double.def(getitem, "__getitem__"); diff --git a/include/boost/python/call.hpp b/include/boost/python/call.hpp new file mode 100644 index 00000000..bdda879d --- /dev/null +++ b/include/boost/python/call.hpp @@ -0,0 +1,210 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +// +// This work was funded in part by Lawrence Berkeley National Labs +// +// This file generated for 5-argument member functions and 6-argument free +// functions by gen_call.py + +#ifndef CALL_DWA20011214_HPP +# define CALL_DWA20011214_HPP + +# include + +namespace boost { namespace python { + +template +PyObject* call(R (*f)(), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (*f)(A0), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (*f)(A0, A1), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (*f)(A0, A1, A2), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (*f)(A0, A1, A2, A3), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (*f)(A0, A1, A2, A3, A4), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (*f)(A0, A1, A2, A3, A4, A5), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +// Member functions +template +PyObject* call(R (A0::*f)(), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2, A3), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2, A3, A4), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2, A3, A4, A5), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)() const, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1) const, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2) const, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2, A3) const, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2, A3, A4) const, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2, A3, A4, A5) const, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)() volatile, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1) volatile, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2) volatile, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2, A3) volatile, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2, A3, A4) volatile, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2, A3, A4, A5) volatile, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)() const volatile, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1) const volatile, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2) const volatile, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2, A3) const volatile, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2, A3, A4) const volatile, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +template +PyObject* call(R (A0::*f)(A1, A2, A3, A4, A5) const volatile, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + + +}} // namespace boost::python + +#endif // CALL_DWA20011214_HPP + diff --git a/include/boost/python/classes.hpp b/include/boost/python/classes.hpp index f88f1000..548a57db 100644 --- a/include/boost/python/classes.hpp +++ b/include/boost/python/classes.hpp @@ -20,7 +20,7 @@ namespace boost { namespace python { // A simple type which acts something like a built-in Python class obj. -class instance +class BOOST_PYTHON_DECL instance : public boost::python::detail::python_object { public: @@ -105,7 +105,7 @@ class instance template class meta_class; namespace detail { - class class_base : public type_object_base + class BOOST_PYTHON_DECL class_base : public type_object_base { public: class_base(PyTypeObject* meta_class_obj, string name, tuple bases, const dictionary& name_space); @@ -344,7 +344,7 @@ int class_t::instance_mapping_ass_subscript(PyObject* obj, PyObject* key, PyO return 0; } -void adjust_slice_indices(PyObject* obj, int& start, int& finish); +void BOOST_PYTHON_DECL adjust_slice_indices(PyObject* obj, int& start, int& finish); template PyObject* class_t::instance_sequence_slice(PyObject* obj, int start, int finish) const diff --git a/include/boost/python/conversions.hpp b/include/boost/python/conversions.hpp index c1a7d390..aa07547f 100644 --- a/include/boost/python/conversions.hpp +++ b/include/boost/python/conversions.hpp @@ -122,61 +122,68 @@ BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // Converters // PyObject* to_python(long); -long from_python(PyObject* p, boost::python::type); +BOOST_PYTHON_DECL long from_python(PyObject* p, boost::python::type); long from_python(PyObject* p, boost::python::type); -PyObject* to_python(unsigned long); -unsigned long from_python(PyObject* p, boost::python::type); +BOOST_PYTHON_DECL PyObject* to_python(unsigned long); +BOOST_PYTHON_DECL unsigned long from_python(PyObject* p, boost::python::type); unsigned long from_python(PyObject* p, boost::python::type); PyObject* to_python(int); -int from_python(PyObject*, boost::python::type); +BOOST_PYTHON_DECL int from_python(PyObject*, boost::python::type); int from_python(PyObject*, boost::python::type); -PyObject* to_python(unsigned int); -unsigned int from_python(PyObject*, boost::python::type); +BOOST_PYTHON_DECL PyObject* to_python(unsigned int); +BOOST_PYTHON_DECL unsigned int from_python(PyObject*, boost::python::type); unsigned int from_python(PyObject*, boost::python::type); PyObject* to_python(short); -short from_python(PyObject*, boost::python::type); +BOOST_PYTHON_DECL short from_python(PyObject*, boost::python::type); short from_python(PyObject*, boost::python::type); -PyObject* to_python(unsigned short); -unsigned short from_python(PyObject*, boost::python::type); +BOOST_PYTHON_DECL PyObject* to_python(unsigned short); +BOOST_PYTHON_DECL unsigned short from_python(PyObject*, boost::python::type); unsigned short from_python(PyObject*, boost::python::type); -PyObject* to_python(char); -char from_python(PyObject*, boost::python::type); +BOOST_PYTHON_DECL PyObject* to_python(char); +BOOST_PYTHON_DECL char from_python(PyObject*, boost::python::type); char from_python(PyObject*, boost::python::type); -PyObject* to_python(signed char); -signed char from_python(PyObject*, boost::python::type); +BOOST_PYTHON_DECL PyObject* to_python(signed char); +BOOST_PYTHON_DECL signed char from_python(PyObject*, boost::python::type); signed char from_python(PyObject*, boost::python::type); -PyObject* to_python(unsigned char); -unsigned char from_python(PyObject*, boost::python::type); +BOOST_PYTHON_DECL PyObject* to_python(unsigned char); +BOOST_PYTHON_DECL unsigned char from_python(PyObject*, boost::python::type); unsigned char from_python(PyObject*, boost::python::type); +# ifndef BOOST_MSVC6_OR_EARLIER PyObject* to_python(float); float from_python(PyObject*, boost::python::type); -float from_python(PyObject*, boost::python::type); - PyObject* to_python(double); double from_python(PyObject*, boost::python::type); +# else +BOOST_PYTHON_DECL PyObject* to_python(float); +BOOST_PYTHON_DECL float from_python(PyObject*, boost::python::type); +BOOST_PYTHON_DECL PyObject* to_python(double); +BOOST_PYTHON_DECL double from_python(PyObject*, boost::python::type); +# endif +float from_python(PyObject*, boost::python::type); + double from_python(PyObject*, boost::python::type); PyObject* to_python(bool); -bool from_python(PyObject*, boost::python::type); +BOOST_PYTHON_DECL bool from_python(PyObject*, boost::python::type); bool from_python(PyObject*, boost::python::type); -PyObject* to_python(void); -void from_python(PyObject*, boost::python::type); +BOOST_PYTHON_DECL PyObject* to_python(void); +BOOST_PYTHON_DECL void from_python(PyObject*, boost::python::type); PyObject* to_python(const char* s); -const char* from_python(PyObject*, boost::python::type); +BOOST_PYTHON_DECL const char* from_python(PyObject*, boost::python::type); -PyObject* to_python(const std::string& s); -std::string from_python(PyObject*, boost::python::type); +BOOST_PYTHON_DECL PyObject* to_python(const std::string& s); +BOOST_PYTHON_DECL std::string from_python(PyObject*, boost::python::type); std::string from_python(PyObject*, boost::python::type); inline PyObject* to_python(const std::complex& x) diff --git a/include/boost/python/convert.hpp b/include/boost/python/convert.hpp new file mode 100644 index 00000000..5614bd3b --- /dev/null +++ b/include/boost/python/convert.hpp @@ -0,0 +1,84 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef CONVERT_DWA20011129_HPP +# define CONVERT_DWA20011129_HPP + +# include +# include +# include +# include + +namespace boost { namespace python { + +namespace detail +{ + template + struct converter_gen + { + typedef T value_type; + typedef typename converter::source::type source_t; + typedef converter::wrap_ wrap_t; + typedef converter::wrap_more_ wrap_more_t; + + typedef typename converter::target::type target_t; + typedef converter::unwrap_ unwrap_t; + typedef converter::unwrap_more_ unwrap_more_t; + }; +} + +template +struct wrap : detail::converter_gen::wrap_t +{ + typedef typename detail::converter_gen::wrap_t base_t; + typedef typename detail::converter_gen::source_t source_t; +}; + +template +struct wrap_more : detail::converter_gen::wrap_more_t +{ + typedef typename detail::converter_gen::wrap_more_t base_t; + typedef typename detail::converter_gen::source_t source_t; + wrap_more(converter::handle& prev); +}; + +template +struct unwrap : detail::converter_gen::unwrap_t +{ + typedef typename detail::converter_gen::unwrap_t base_t; + unwrap(PyObject*); +}; + +template +struct unwrap_more : detail::converter_gen::unwrap_more_t +{ + typedef typename detail::converter_gen::unwrap_more_t base_t; + unwrap_more(PyObject*, converter::handle& prev); +}; + +// +// implementations +// +template +inline wrap_more::wrap_more(converter::handle& prev) + : base_t(prev) +{ +} + +template +inline unwrap::unwrap(PyObject* source) + : base_t(source) +{ +} + +template +inline unwrap_more::unwrap_more(PyObject* source, converter::handle& prev) + : base_t(source, prev) +{ +} + +}} // namespace boost::python + +#endif // CONVERT_DWA20011129_HPP diff --git a/include/boost/python/converter/body.hpp b/include/boost/python/converter/body.hpp new file mode 100644 index 00000000..c8d932a0 --- /dev/null +++ b/include/boost/python/converter/body.hpp @@ -0,0 +1,68 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef BODY_DWA2001127_HPP +# define BODY_DWA2001127_HPP +# include +# include +# include + +namespace boost { namespace python { namespace converter { + +struct BOOST_PYTHON_EXPORT handle; + +namespace registry +{ + class entry; +} + +struct BOOST_PYTHON_EXPORT body +{ + public: + body(type_id_t key); + virtual ~body() {} + + // default implementation is a no-op + virtual void destroy_handle(handle*) const; + + type_id_t key() const; + + protected: + // true iff the registry is still alive + bool can_unregister() const; + + private: + // called when the registry is destroyed, to prevent it from being + // unregistered. + void do_not_unregister(); + friend class registry::entry; + + private: + type_id_t m_key; + bool m_can_unregister; +}; + +// +// implementations +// +inline body::body(type_id_t key) + : m_key(key) + , m_can_unregister(true) +{ +} + +inline type_id_t body::key() const +{ + return m_key; +} + +inline bool body::can_unregister() const +{ + return m_can_unregister; +} + +}}} // namespace boost::python::converter + +#endif // BODY_DWA2001127_HPP diff --git a/include/boost/python/converter/class.hpp b/include/boost/python/converter/class.hpp new file mode 100644 index 00000000..305ec448 --- /dev/null +++ b/include/boost/python/converter/class.hpp @@ -0,0 +1,56 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef CLASS_DWA20011215_HPP +# define CLASS_DWA20011215_HPP + +# include +# include + +namespace boost { namespace python { namespace converter { + +struct class_unwrapper_base +{ + class_unwrapper_base(type_id_t sought_type); + void* +}; + +template +struct class_unwrapper +{ + struct ref_unwrapper : unwrapper + { + bool convertible(PyObject* p) const + { + return p->ob_type == &SimpleType; + } + + simple const& convert(PyObject* p, void*&) const + { + return static_cast(p)->x; + } + + }; + +# ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + struct const_ref_unwrapper : unwrapper + { + bool convertible(PyObject* p) const + { + return p->ob_type == &SimpleType; + } + + simple const& convert(PyObject* p, void*&) const + { + return static_cast(p)->x; + } + + }; +# endif +}; + +}}} // namespace boost::python::converter + +#endif // CLASS_DWA20011215_HPP diff --git a/include/boost/python/converter/handle.hpp b/include/boost/python/converter/handle.hpp new file mode 100644 index 00000000..16a50b38 --- /dev/null +++ b/include/boost/python/converter/handle.hpp @@ -0,0 +1,91 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef HANDLE_DWA20011130_HPP +# define HANDLE_DWA20011130_HPP +# include +# include +# include +# include + +namespace boost { namespace python { namespace converter { + +struct BOOST_PYTHON_EXPORT body; + +// The common base class for unwrap_ and wrap_ handle objects. They +// share a common base so that handles can be linked into a chain +// within a function wrapper which is managed by a single object. +struct BOOST_PYTHON_EXPORT handle : boost::noncopyable +{ + public: // member functions + + // All constructors take a body* passed from the derived class. + // + // Constructors taking a handle links this into a chain of + // handles, for more efficient management in function wrappers + handle(body* body); + handle(body* body, handle& prev); + + // returns true iff all handles in the chain can convert their + // arguments + bool convertible() const; + + // safe_bool idiom from Peter Dimov: provides handles to/from + // bool without enabling handles to integer types/void*. + private: + struct dummy { inline void nonnull() {} }; + typedef void (dummy::*safe_bool)(); + public: + inline operator safe_bool() const; + inline safe_bool operator!() const; + + protected: // member functions for derived classes + // Get the body we hold + inline body* get_body() const; + + // Release all bodies in the chain, in reverse order of + // initialization. Only actually called for the head of the chain. + void destroy(); + + private: + // Holds implementation + body* m_body; + + // handle for next argument, if any. + handle* m_next; +}; + +// +// implementations +// +inline handle::handle(body* body, handle& prev) + : m_body(body), m_next(0) +{ + prev.m_next = this; +} + +inline handle::handle(body* body) + : m_body(body), m_next(0) +{ +} + +inline handle::operator handle::safe_bool() const +{ + return convertible() ? &dummy::nonnull : 0; +} + +inline handle::safe_bool handle::operator!() const +{ + return convertible() ? 0 : &dummy::nonnull; +} + +inline body* handle::get_body() const +{ + return m_body; +} + +}}} // namespace boost::python::converter + +#endif // HANDLE_DWA20011130_HPP diff --git a/include/boost/python/converter/registration.hpp b/include/boost/python/converter/registration.hpp new file mode 100644 index 00000000..0d85d1d7 --- /dev/null +++ b/include/boost/python/converter/registration.hpp @@ -0,0 +1,83 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef REGISTRATION_DWA20011130_HPP +# define REGISTRATION_DWA20011130_HPP +# include +# include +# include +# include +# ifdef BOOST_PYTHON_TRACE +# include +# endif + +namespace boost { namespace python { namespace converter { + +struct BOOST_PYTHON_EXPORT wrapper_base; +struct BOOST_PYTHON_EXPORT unwrapper_base; + +// This class is really sort of a "templated namespace". It manages a +// static data member which refers to the registry entry for T. This +// reference is acquired once to reduce the burden of multiple +// dictionary lookups at runtime. +template +struct registration +{ + public: // member functions + // Return a converter which can convert the given Python object to + // T, or 0 if no such converter exists + static unwrapper_base* unwrapper(PyObject*); + + // Return a converter which can convert T to a Python object, or 0 + // if no such converter exists + static wrapper_base* wrapper(); + + private: // helper functions + static registry::entry* entry(); + static registry::entry* find_entry(); + + private: // data members + static registry::entry* m_registry_entry; +}; + +// because this is static POD data it will be initialized to zero +template +registry::entry* registration::m_registry_entry; + +template +registry::entry* registration::find_entry() +{ + return registry::find(type_id()); +} + +template +inline registry::entry* registration::entry() +{ + if (!m_registry_entry) + m_registry_entry = find_entry(); + return m_registry_entry; +} + +template +unwrapper_base* registration::unwrapper(PyObject* p) +{ +# ifdef BOOST_PYTHON_TRACE + std::cout << "retrieving unwrapper for " << type_id() << std::endl; +# endif + return entry()->unwrapper(p); +} + +template +wrapper_base* registration::wrapper() +{ +# ifdef BOOST_PYTHON_TRACE + std::cout << "retrieving wrapper for " << type_id() << std::endl; +# endif + return entry()->wrapper(); +} + +}}} // namespace boost::python::converter + +#endif // REGISTRATION_DWA20011130_HPP diff --git a/include/boost/python/converter/registry.hpp b/include/boost/python/converter/registry.hpp new file mode 100644 index 00000000..30eeba8d --- /dev/null +++ b/include/boost/python/converter/registry.hpp @@ -0,0 +1,74 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef REGISTRY_DWA20011127_HPP +# define REGISTRY_DWA20011127_HPP +# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace converter { + +struct BOOST_PYTHON_EXPORT wrapper_base; +struct BOOST_PYTHON_EXPORT unwrapper_base; + +// This namespace acts as a sort of singleton +namespace registry +{ + // These are the elements stored in the registry + class BOOST_PYTHON_EXPORT entry + { + public: // member functions + entry(); + ~entry(); + + // Return a converter appropriate for converting the given + // Python object from_python to the C++ type with which this + // converter is associated in the registry, or 0 if no such + // converter exists. + unwrapper_base* unwrapper(PyObject*) const; + + // Return a converter appropriate for converting a C++ object + // whose type this entry is associated with in the registry to a + // Python object, or 0 if no such converter exists. + wrapper_base* wrapper() const; + + // Conversion classes use these functions to register + // themselves. + void insert(wrapper_base&); + void remove(wrapper_base&); + + void insert(unwrapper_base&); + void remove(unwrapper_base&); + + private: // types + typedef std::list unwrappers; + + private: // helper functions + unwrappers::iterator find(unwrapper_base const&); + + private: // data members + + // The collection of from_python converters for the associated + // C++ type. + unwrappers m_unwrappers; + + // The unique to_python converter for the associated C++ type. + converter::wrapper_base* m_wrapper; + }; + + BOOST_PYTHON_EXPORT entry* find(type_id_t); + + BOOST_PYTHON_EXPORT void insert(wrapper_base& x); + BOOST_PYTHON_EXPORT void insert(unwrapper_base& x); + BOOST_PYTHON_EXPORT void remove(wrapper_base& x); + BOOST_PYTHON_EXPORT void remove(unwrapper_base& x); +} + +}}} // namespace boost::python::converter + +#endif // REGISTRY_DWA20011127_HPP diff --git a/include/boost/python/converter/source.hpp b/include/boost/python/converter/source.hpp new file mode 100644 index 00000000..9af1cf49 --- /dev/null +++ b/include/boost/python/converter/source.hpp @@ -0,0 +1,80 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef SOURCE_DWA20011119_HPP +# define SOURCE_DWA20011119_HPP +# include +# include +# include + +namespace boost { namespace python { namespace converter { + +// source -- +// +// This type generator (see +// ../../../more/generic_programming.html#type_generator) is used +// to select the argument type to use when converting T to a PyObject* + +template struct source; + +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +// Since for some strange reason temporaries can't be bound to const +// volatile references (8.5.3/5 in the C++ standard), we cannot use a +// const volatile reference as the standard for values and references. +template +struct source +{ + typedef T const& type; +}; + +// This will handle the following: +// T const volatile& -> T const volatile& +// T volatile& -> T const volatile& +// T const& -> T const& +// T& -> T const& +template +struct source +{ + typedef T const& type; +}; + +template +struct source +{ + typedef T const* type; +}; + +template +struct source +{ + typedef T const* type; +}; + +// Deal with references to pointers +template +struct source +{ + typedef T const* type; +}; + +template +struct source +{ + typedef T const* type; +}; +# else +template +struct source +{ + typedef typename add_reference< + typename add_const::type + >::type type; +}; +# endif + +}}} // namespace boost::python::converter + +#endif // SOURCE_DWA20011119_HPP diff --git a/include/boost/python/converter/source_holder.hpp b/include/boost/python/converter/source_holder.hpp new file mode 100644 index 00000000..f2c774f9 --- /dev/null +++ b/include/boost/python/converter/source_holder.hpp @@ -0,0 +1,24 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef SOURCE_HOLDER_DWA20011215_HPP +# define SOURCE_HOLDER_DWA20011215_HPP + +namespace boost { namespace python { namespace converter { + +struct source_holder_base +{ +}; + +template +struct source_holder : source_holder_base +{ + source_holder(T x) : value(x) {} + T value; +}; + +}}} // namespace boost::python::converter + +#endif // SOURCE_HOLDER_DWA20011215_HPP diff --git a/include/boost/python/converter/target.hpp b/include/boost/python/converter/target.hpp new file mode 100644 index 00000000..6effb996 --- /dev/null +++ b/include/boost/python/converter/target.hpp @@ -0,0 +1,173 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#ifndef TARGET_DWA20011119_HPP +# define TARGET_DWA20011119_HPP +# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace converter { + +// target -- +// +// This type generator (see +// ../../../more/generic_programming.html#type_generator) is used +// to select the return type of the appropriate converter for +// unwrapping a given type. + +// Strategy: +// +// 1. reduce everything to a common, un-cv-qualified reference +// type where possible. This will save on registering many different +// converter types. +// +// 2. Treat built-in types specially: when unwrapping a value or +// constant reference to one of these, use a value for the target +// type. It will bind to a const reference if neccessary, and more +// importantly, avoids having to dynamically allocate room for +// an lvalue of types which can be cheaply copied. +// +// In the tables below, "cv" stands for the set of all possible +// cv-qualifications. + +// Target Source +// int int +// int const& int +// int& int& +// int volatile& int volatile& +// int const volatile& int const volatile& + +// On compilers supporting partial specialization: +// +// Target Source +// T T& +// T cv& T& +// T cv* T* +// T cv*const& T* +// T cv*& T*& <- should this be legal? +// T cv*volatile& T*& <- should this be legal? +// T cv*const volatile& T*& <- should this be legal? + +// On others: +// +// Target Source +// T T& +// T cv& T cv& +// T cv* T cv* +// T cv*cv& T cv*cv& + +// As you can see, in order to handle the same range of types without +// partial specialization, more converters need to be registered. + +template +struct target +{ + // Some pointer types are handled in a more sophisticated way on + // compilers supporting partial specialization. + BOOST_STATIC_CONSTANT(bool, use_identity = (::boost::is_scalar::value)); + + typedef typename mpl::select_type< + use_identity + , T + , typename add_reference::type>::type + >::type type; +}; + +// When partial specialization is not present, we'll simply need to +// register many more converters. +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +template +struct target +{ + typedef typename remove_cv::type& type; +}; + +template +struct target +{ + typedef typename remove_cv::type* type; +}; + +// Handle T*-cv for completeness. Function arguments in a signature +// are never actually cv-qualified, but who knows how these converters +// might be used, or whether compiler bugs lurk which make it seem +// otherwise? +template +struct target +{ + typedef typename remove_cv::type* type; +}; + +template +struct target +{ + typedef typename remove_cv::type* type; +}; + +template +struct target +{ + typedef typename remove_cv::type* type; +}; + +// non-const references to pointers should be handled by the +// specialization for T&, above. +template +struct target +{ + typedef typename remove_cv::type* type; +}; +# endif + +// Fortunately, we can handle T const& where T is an arithmetic type +// by explicit specialization. These specializations will cause value +// and const& arguments to be converted to values, rather than to +// references. +# define BOOST_PYTHON_UNWRAP_VALUE(T) \ +template <> \ +struct target \ +{ \ + typedef T type; \ +}; \ +template <> \ +struct target \ +{ \ + typedef T type; \ +}; \ +template <> \ +struct target \ +{ \ + typedef T type; \ +}; \ +template <> \ +struct target \ +{ \ + typedef T type; \ +}; \ +template <> \ +struct target \ +{ \ + typedef T type; \ +} + +BOOST_PYTHON_UNWRAP_VALUE(char); +BOOST_PYTHON_UNWRAP_VALUE(unsigned char); +BOOST_PYTHON_UNWRAP_VALUE(signed char); +BOOST_PYTHON_UNWRAP_VALUE(unsigned int); +BOOST_PYTHON_UNWRAP_VALUE(signed int); +BOOST_PYTHON_UNWRAP_VALUE(unsigned short); +BOOST_PYTHON_UNWRAP_VALUE(signed short); +BOOST_PYTHON_UNWRAP_VALUE(unsigned long); +BOOST_PYTHON_UNWRAP_VALUE(signed long); +BOOST_PYTHON_UNWRAP_VALUE(char const*); + +}}} // namespace boost::python::converter + +#endif // TARGET_DWA20011119_HPP diff --git a/include/boost/python/converter/type_id.hpp b/include/boost/python/converter/type_id.hpp new file mode 100644 index 00000000..ddc04266 --- /dev/null +++ b/include/boost/python/converter/type_id.hpp @@ -0,0 +1,200 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef TYPE_ID_DWA20011127_HPP +# define TYPE_ID_DWA20011127_HPP +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + + +namespace boost { namespace python { namespace converter { + +// a portable mechanism for identifying types at runtime across modules. + +namespace detail +{ + template class dummy; +} + +// for this compiler at least, cross-shared-library type_info +// comparisons don't work, so use typeid(x).name() instead. It's not +// yet clear what the best default strategy is. +# if defined(__GNUC__) && __GNUC__ >= 3 +# define BOOST_PYTHON_TYPE_ID_NAME +# endif + +# if 1 +struct type_id_t : totally_ordered +{ + enum decoration { const_ = 0x1, volatile_ = 0x2, reference = 0x4 }; + +# ifdef BOOST_PYTHON_TYPE_ID_NAME +typedef char const* base_id_t; +# else +typedef std::type_info const* base_id_t; +# endif + + type_id_t(base_id_t, decoration decoration); + + bool operator<(type_id_t const& rhs) const; + bool operator==(type_id_t const& rhs) const; + friend BOOST_PYTHON_EXPORT std::ostream& operator<<(std::ostream&, type_id_t const&); + + private: + decoration m_decoration; + base_id_t m_base_type; +}; + +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +struct is_reference_to_const +{ + BOOST_STATIC_CONSTANT(bool, value = false); +}; + +template +struct is_reference_to_const +{ + BOOST_STATIC_CONSTANT(bool, value = true); +}; + +template +struct is_reference_to_volatile +{ + BOOST_STATIC_CONSTANT(bool, value = false); +}; + +template +struct is_reference_to_volatile +{ + BOOST_STATIC_CONSTANT(bool, value = true); +}; +# else +template +struct is_const_help +{ + typedef typename mpl::select_type< + is_const::value + , type_traits::yes_type + , type_traits::no_type + >::type type; +}; + +template +struct is_volatile_help +{ + typedef typename mpl::select_type< + is_volatile::value + , type_traits::yes_type + , type_traits::no_type + >::type type; +}; + +template +typename is_const_help::type reference_to_const_helper(V&); + +type_traits::no_type +reference_to_const_helper(...); + +template +struct is_reference_to_const +{ + static T t; + BOOST_STATIC_CONSTANT( + bool, value + = sizeof(reference_to_const_helper(t)) == sizeof(type_traits::yes_type)); +}; + +template +typename is_volatile_help::type reference_to_volatile_helper(V&); +type_traits::no_type reference_to_volatile_helper(...); + +template +struct is_reference_to_volatile +{ + static T t; + BOOST_STATIC_CONSTANT( + bool, value + = sizeof(reference_to_volatile_helper(t)) == sizeof(type_traits::yes_type)); +}; +# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +template +inline type_id_t type_id(detail::dummy* = 0) +{ + return type_id_t( +# ifdef BOOST_PYTHON_TYPE_ID_NAME + typeid(T).name() +# else + &typeid(T) +# endif + , type_id_t::decoration( + (is_const::value || is_reference_to_const::value + ? type_id_t::const_ : 0) + | (is_volatile::value || is_reference_to_volatile::value + ? type_id_t::volatile_ : 0) + | (is_reference::value ? type_id_t::reference : 0) + ) + ); +} + +inline type_id_t::type_id_t(base_id_t base_t, decoration decoration) + : m_decoration(decoration) + , m_base_type(base_t) +{ +} + +inline bool type_id_t::operator<(type_id_t const& rhs) const +{ + return m_decoration < rhs.m_decoration + || m_decoration == rhs.m_decoration +# ifdef BOOST_PYTHON_TYPE_ID_NAME + && std::strcmp(m_base_type, rhs.m_base_type) < 0; +# else + && m_base_type->before(*rhs.m_base_type); +# endif +} + +inline bool type_id_t::operator==(type_id_t const& rhs) const +{ + return m_decoration == rhs.m_decoration +# ifdef BOOST_PYTHON_TYPE_ID_NAME + && !std::strcmp(m_base_type, rhs.m_base_type); +# else + && *m_base_type == *rhs.m_base_type; +# endif +} + +# else +// This is the type which is used to identify a type +typedef char const* type_id_t; + +// This is a workaround for a silly MSVC bug +// Converts a compile-time type to its corresponding runtime identifier. +template +type_id_t type_id(detail::dummy* = 0) +{ + return typeid(T).name(); +} +# endif + +struct BOOST_PYTHON_EXPORT type_id_before +{ + bool operator()(type_id_t const& x, type_id_t const& y) const; +}; + +BOOST_PYTHON_EXPORT std::ostream& operator<<(std::ostream&, type_id_t const&); + +}}} // namespace boost::python::converter + +#endif // TYPE_ID_DWA20011127_HPP diff --git a/include/boost/python/converter/unwrap.hpp b/include/boost/python/converter/unwrap.hpp new file mode 100644 index 00000000..6dda61fb --- /dev/null +++ b/include/boost/python/converter/unwrap.hpp @@ -0,0 +1,192 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef UNWRAP_BASE_DWA20011130_HPP +# define UNWRAP_BASE_DWA20011130_HPP + +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace converter { + +template struct unwrapper; +struct BOOST_PYTHON_EXPORT body; + +struct BOOST_PYTHON_EXPORT unwrap_base : handle +{ + public: // member functions + inline unwrap_base(PyObject* source, body*, handle& prev); + inline unwrap_base(PyObject* source, body*); + inline PyObject* source() const; + + private: // data members + PyObject* m_source; +}; + +// These converters will be used by the function wrappers. They don't +// manage any resources, but are instead linked into a chain which is +// managed by an instance of unwrap_ or wrap_. +template +struct unwrap_more_ : unwrap_base +{ + public: // member functions + // Construction + unwrap_more_(PyObject* source, handle& prev); + + // invoke the conversion or throw an exception if unsuccessful + T operator*(); + + protected: // constructor + // this constructor is only for the use of unwrap_ + unwrap_more_(PyObject* source); + + private: // helper functions + // Return the unwrapper which will convert the given Python object + // to T, or 0 if no such converter exists + static unwrapper_base* lookup(PyObject*); + + private: + // unspecified storage which may be allocated by the unwrapper to + // do value conversions. + mutable void* m_storage; + friend class unwrapper; +}; + +// specialization for PyObject* +template <> +struct unwrap_more_ + : unwrap_base +{ + public: // member functions + // Construction + unwrap_more_(PyObject* source, handle& prev) + : unwrap_base(source, m_unwrapper, prev) + { + } + + + // invoke the conversion or throw an exception if unsuccessful + PyObject* operator*() + { + return source(); + } + + bool convertible(PyObject*) const + { + return true; + } + + protected: // constructor + // this constructor is only for the use of unwrap_ + unwrap_more_(PyObject* source) + : unwrap_base(source, m_unwrapper) + + { + } + private: + static BOOST_PYTHON_EXPORT unwrapper_base* m_unwrapper; +}; + +template +struct unwrap_ : unwrap_more_ +{ + unwrap_(PyObject* source); + ~unwrap_(); +}; + +// +// implementations +// +inline unwrap_base::unwrap_base(PyObject* source, body* body, handle& prev) + : handle(body, prev) + , m_source(source) +{ +} + +inline unwrap_base::unwrap_base(PyObject* source, body* body) + : handle(body) + , m_source(source) +{ +} + +inline PyObject* unwrap_base::source() const +{ + return m_source; +} + +template +inline unwrapper_base* unwrap_more_::lookup(PyObject* source) +{ + // Find the converters registered for T and get a unwrapper + // appropriate for the source object + return registration::unwrapper(source); +} + +template +unwrap_more_::unwrap_more_(PyObject* source, handle& prev) + : unwrap_base(source, lookup(source), prev) + , m_storage(0) +{ +} + +template +unwrap_more_::unwrap_more_(PyObject* source) + : unwrap_base(source, lookup(source)) + , m_storage(0) +{ +} + +# if 0 +template <> +inline unwrap_more_::unwrap_more_(PyObject* source, handle& prev) + : unwrap_base(source, m_unwrapper, prev) +{ +} + +template <> +inline unwrap_more_::unwrap_more_(PyObject* source) + : unwrap_base(source, m_unwrapper) + +{ +} + +template <> +inline PyObject* unwrap_more_::operator*() +{ + return source(); +} + +template <> +inline bool unwrap_more_::convertible(PyObject*) const +{ + return true; +} +# endif +template +inline unwrap_::unwrap_(PyObject* source) + : unwrap_more_(source) +{ +} + +template +T unwrap_more_::operator*() +{ + return static_cast*>( + get_body())->do_conversion(this); +} + +template +unwrap_::~unwrap_() +{ + destroy(); +} + +}}} // namespace boost::python::converter + +#endif // UNWRAP_BASE_DWA20011130_HPP diff --git a/include/boost/python/converter/unwrapper.hpp b/include/boost/python/converter/unwrapper.hpp new file mode 100644 index 00000000..a30ff522 --- /dev/null +++ b/include/boost/python/converter/unwrapper.hpp @@ -0,0 +1,53 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef UNWRAPPER_DWA2001127_HPP +# define UNWRAPPER_DWA2001127_HPP + +# include +# include +# include + +namespace boost { namespace python { namespace converter { + +template struct unwrap_more_; + +// Abstract base for all unwrappers of Ts +template +struct unwrapper : unwrapper_base +{ + public: + unwrapper(); + + T do_conversion(unwrap_more_ const* handle) const; + + private: + virtual T convert(PyObject*, void*&) const = 0; + + private: // body required interface implementation + void destroy_handle(handle*) const {} +}; + +// +// implementations +// +template +unwrapper::unwrapper() + : unwrapper_base(type_id()) +{ +} + +// We could think about making this virtual in an effort to get its +// code generated in the module where the unwrapper is defined, but +// it's not clear that it's a good tradeoff. +template +T unwrapper::do_conversion(unwrap_more_ const* handle) const +{ + return convert(handle->source(), handle->m_storage); +} + +}}} // namespace boost::python::converter + +#endif // UNWRAPPER_DWA2001127_HPP diff --git a/include/boost/python/converter/unwrapper_base.hpp b/include/boost/python/converter/unwrapper_base.hpp new file mode 100644 index 00000000..54e2e54c --- /dev/null +++ b/include/boost/python/converter/unwrapper_base.hpp @@ -0,0 +1,25 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef UNWRAPPER_BASE_DWA20011215_HPP +# define UNWRAPPER_BASE_DWA20011215_HPP +# include +# include +# include +# include + +namespace boost { namespace python { namespace converter { + +struct BOOST_PYTHON_EXPORT unwrapper_base : body +{ + public: + unwrapper_base(type_id_t); // registers + ~unwrapper_base(); // unregisters + virtual bool convertible(PyObject*) const = 0; +}; + +}}} // namespace boost::python::converter + +#endif // UNWRAPPER_BASE_DWA20011215_HPP diff --git a/include/boost/python/converter/wrap.hpp b/include/boost/python/converter/wrap.hpp new file mode 100644 index 00000000..91c9de86 --- /dev/null +++ b/include/boost/python/converter/wrap.hpp @@ -0,0 +1,145 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef WRAP_DWA2001127_HPP +# define WRAP_DWA2001127_HPP +# include +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace converter { + +struct BOOST_PYTHON_EXPORT wrapper_base; + +template struct wrapper; + +struct wrap_base : handle +{ + public: // member functions + wrap_base(body*, handle& prev); + wrap_base(body*); + PyObject* release(); + + public: // accessor, really only for wrappers + PyObject*& target() const; + + protected: + void hold_result(PyObject*) const; + + private: + mutable PyObject* m_target; +}; + +template +struct wrap_more_ : wrap_base +{ + protected: + typedef T source_t; + + public: // member functions + wrap_more_(handle& prev); + + PyObject* operator()(source_t) const; + + protected: // constructor for wrap_, below + wrap_more_(); + + private: // helper functions + static wrapper_base* lookup(); + + private: + friend class wrapper; +}; + +template +struct wrap_ : wrap_more_ +{ + typedef typename wrap_more_::source_t source_t; + public: // member functions + wrap_(); + ~wrap_(); +}; + +// +// implementations +// + +inline wrap_base::wrap_base(body* body, handle& prev) + : handle(body, prev), + m_target(0) +{ +} + +inline wrap_base::wrap_base(body* body) + : handle(body), + m_target(0) +{ +} + +inline PyObject*& wrap_base::target() const +{ + return m_target; +} + +inline void wrap_base::hold_result(PyObject* p) const +{ + assert(m_target == 0); + m_target = p; +} + +inline PyObject* wrap_base::release() +{ + PyObject* result = m_target; + m_target = 0; + return result; +} + +template +inline wrapper_base* wrap_more_::lookup() +{ + // Find the converters registered for T and get a wrapper + // appropriate for the source object + return registration::wrapper(); +} + +template +inline wrap_more_::wrap_more_(handle& prev) + : wrap_base(lookup(), prev) +{ + +} + +template +PyObject* wrap_more_::operator()(source_t x) const +{ + return static_cast*>( + get_body())->do_conversion(*this, source_holder(x)); +} + +template +wrap_more_::wrap_more_() + : wrap_base(lookup()) +{ +} + +template +wrap_::wrap_() + : wrap_more_() +{ +} + +template +wrap_::~wrap_() +{ + destroy(); +} + +}}} // namespace boost::python::converter + +#endif // WRAP_DWA2001127_HPP diff --git a/include/boost/python/converter/wrapper.hpp b/include/boost/python/converter/wrapper.hpp new file mode 100644 index 00000000..ada5e8cb --- /dev/null +++ b/include/boost/python/converter/wrapper.hpp @@ -0,0 +1,69 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef WRAPPER_DWA2001127_HPP +# define WRAPPER_DWA2001127_HPP +# include +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace converter { + +struct source_holder_base; +struct wrap_base; +template struct wrap_more_; + +struct BOOST_PYTHON_EXPORT wrapper_base : body +{ + public: + wrapper_base(type_id_t); // registers + ~wrapper_base(); // unregisters + + virtual PyObject* do_conversion(wrap_base const&, source_holder_base const&) const = 0; +}; + +template +struct wrapper : wrapper_base +{ + public: + wrapper(); + + PyObject* do_conversion(wrap_base const&, source_holder_base const&) const; + + // This does the actual conversion + virtual PyObject* convert(T source) const = 0; +}; + +// +// implementations +// + +template +wrapper::wrapper() + : wrapper_base(type_id()) +{ +} + + +template +PyObject* wrapper::do_conversion(wrap_base const& handle_, source_holder_base const& data_) const +{ + // Casting pointers instead of references suppresses a CWPro7 bug. + wrap_more_ const& handle = *static_cast const*>(&handle_); + source_holder const& data = *static_cast const*>(&data_); + if (handle.target() == 0) + { + handle.hold_result(convert(data.value)); + } + return handle.target(); +} + +}}} // namespace boost::python::converter + +#endif // WRAPPER_DWA2001127_HPP diff --git a/include/boost/python/cross_module.hpp b/include/boost/python/cross_module.hpp index dd1c47d2..f5ca315d 100644 --- a/include/boost/python/cross_module.hpp +++ b/include/boost/python/cross_module.hpp @@ -18,26 +18,28 @@ # include namespace boost { namespace python { - struct import_error : error_already_set {}; - struct export_error : error_already_set {}; -}} + struct BOOST_PYTHON_DECL import_error: error_already_set {}; + struct BOOST_PYTHON_DECL export_error : error_already_set {}; -namespace boost { namespace python { namespace detail { +namespace detail +{ // Concept: throw exception if api_major is changed // show warning on stderr if api_minor is changed -const int export_converters_api_major = 4; -const int export_converters_api_minor = 1; -extern const char* converters_attribute_name; -void* import_converter_object(const std::string& module_name, - const std::string& py_class_name, - const std::string& attribute_name); -void check_export_converters_api(const int importing_major, - const int importing_minor, - const int imported_major, - const int imported_minor); + const int export_converters_api_major = 4; + const int export_converters_api_minor = 1; + extern BOOST_PYTHON_DECL const char* converters_attribute_name; + BOOST_PYTHON_DECL void* import_converter_object(const std::string& module_name, + const std::string& py_class_name, + const std::string& attribute_name); + BOOST_PYTHON_DECL void check_export_converters_api(const int importing_major, + const int importing_minor, + const int imported_major, + const int imported_minor); -}}} +} + +}} // namespace boost::python // forward declaration namespace boost { namespace python { namespace detail { @@ -232,56 +234,56 @@ struct export_converter_object : export_converter_object_noncopyable } }; -namespace detail { +namespace detail +{ /* This class template is instantiated by import_converters. Its purpose is to import the converter_object via the Python API. The actual import is only done once. The pointer to the imported converter object is kept in the static data member imported_converters. - */ -template -class import_extension_class - : public python_import_extension_class_converters -{ - public: - inline import_extension_class(const char* module, const char* py_class) { - m_module = module; - m_py_class = py_class; - } +*/ + template + class import_extension_class + : public python_import_extension_class_converters + { + public: + inline import_extension_class(const char* module, const char* py_class) { + m_module = module; + m_py_class = py_class; + } - static boost::python::export_converter_object_base* get_converters(); + static boost::python::export_converter_object_base* get_converters(); - private: - static std::string m_module; - static std::string m_py_class; - static boost::python::export_converter_object_base* imported_converters; -}; + private: + static std::string m_module; + static std::string m_py_class; + static boost::python::export_converter_object_base* imported_converters; + }; -template std::string import_extension_class::m_module; -template std::string import_extension_class::m_py_class; -template -boost::python::export_converter_object_base* -import_extension_class::imported_converters = 0; + template std::string import_extension_class::m_module; + template std::string import_extension_class::m_py_class; + template + boost::python::export_converter_object_base* + import_extension_class::imported_converters = 0; -template -boost::python::export_converter_object_base* -import_extension_class::get_converters() { - if (imported_converters == 0) { - void* cobject - = import_converter_object(m_module, m_py_class, - converters_attribute_name); - imported_converters - = static_cast*>(cobject); - check_export_converters_api( - export_converters_api_major, - export_converters_api_minor, - imported_converters->get_api_major(), - imported_converters->get_api_minor()); + template + boost::python::export_converter_object_base* + import_extension_class::get_converters() { + if (imported_converters == 0) { + void* cobject + = import_converter_object(m_module, m_py_class, + converters_attribute_name); + imported_converters + = static_cast*>(cobject); + check_export_converters_api( + export_converters_api_major, + export_converters_api_minor, + imported_converters->get_api_major(), + imported_converters->get_api_minor()); + } + return imported_converters; } - return imported_converters; -} - }}} // namespace boost::python::detail namespace boost { namespace python { diff --git a/include/boost/python/detail/arg_tuple_size.hpp b/include/boost/python/detail/arg_tuple_size.hpp new file mode 100644 index 00000000..e6b6ccc1 --- /dev/null +++ b/include/boost/python/detail/arg_tuple_size.hpp @@ -0,0 +1,233 @@ +// (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and +// distribute this software is granted provided this copyright notice appears +// in all copies. This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// This work was funded in part by Lawrence Berkeley National Labs +// +// This file generated for 5-argument member functions and 6-argument free +// functions by gen_arg_tuple_size.python + +#ifndef ARG_TUPLE_SIZE_DWA20011201_HPP +# define ARG_TUPLE_SIZE_DWA20011201_HPP + +namespace boost { namespace python { namespace detail { + +// Computes (at compile-time) the number of elements that a Python +// argument tuple must have in order to be passed to a wrapped C++ +// (member) function of the given type. +template struct arg_tuple_size; + +# if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(__BORLANDC__) + +template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = 0); +}; + +template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = 1); +}; + +template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = 2); +}; + +template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = 3); +}; + +template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = 4); +}; + +template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = 5); +}; + +template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = 6); +}; + + +template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = 1); +}; + +template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = 2); +}; + +template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = 3); +}; + +template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = 4); +}; + +template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = 5); +}; + +template +struct arg_tuple_size +{ + BOOST_STATIC_CONSTANT(std::size_t, value = 6); +}; + +# else + +// We will use the "sizeof() trick" to work around the lack of +// partial specialization in MSVC6 and its broken-ness in borland. +// See http://opensource.adobe.com or +// http://groups.yahoo.com/group/boost/message/5441 for +// more examples + +// This little package is used to transmit the number of arguments +// from the helper functions below to the sizeof() expression below. +// Because we can never have an array of fewer than 1 element, we +// add 1 to n and then subtract 1 from the result of sizeof() below. +template +struct char_array +{ + char elements[n+1]; +}; + +// The following helper functions are never actually called, since +// they are only used within a sizeof() expression, but the type of +// their return value is used to discriminate between various free +// and member function pointers at compile-time. + +template +char_array<0> arg_tuple_size_helper(R (*)()); + +template +char_array<1> arg_tuple_size_helper(R (*)(A1)); + +template +char_array<2> arg_tuple_size_helper(R (*)(A1, A2)); + +template +char_array<3> arg_tuple_size_helper(R (*)(A1, A2, A3)); + +template +char_array<4> arg_tuple_size_helper(R (*)(A1, A2, A3, A4)); + +template +char_array<5> arg_tuple_size_helper(R (*)(A1, A2, A3, A4, A5)); + +template +char_array<6> arg_tuple_size_helper(R (*)(A1, A2, A3, A4, A5, A6)); + +template +char_array<1> arg_tuple_size_helper(R (A0::*)()); + +template +char_array<2> arg_tuple_size_helper(R (A0::*)(A1)); + +template +char_array<3> arg_tuple_size_helper(R (A0::*)(A1, A2)); + +template +char_array<4> arg_tuple_size_helper(R (A0::*)(A1, A2, A3)); + +template +char_array<5> arg_tuple_size_helper(R (A0::*)(A1, A2, A3, A4)); + +template +char_array<6> arg_tuple_size_helper(R (A0::*)(A1, A2, A3, A4, A5)); + + +template +char_array<1> arg_tuple_size_helper(R (A0::*)() const); + +template +char_array<2> arg_tuple_size_helper(R (A0::*)(A1) const); + +template +char_array<3> arg_tuple_size_helper(R (A0::*)(A1, A2) const); + +template +char_array<4> arg_tuple_size_helper(R (A0::*)(A1, A2, A3) const); + +template +char_array<5> arg_tuple_size_helper(R (A0::*)(A1, A2, A3, A4) const); + +template +char_array<6> arg_tuple_size_helper(R (A0::*)(A1, A2, A3, A4, A5) const); + + +template +char_array<1> arg_tuple_size_helper(R (A0::*)() volatile); + +template +char_array<2> arg_tuple_size_helper(R (A0::*)(A1) volatile); + +template +char_array<3> arg_tuple_size_helper(R (A0::*)(A1, A2) volatile); + +template +char_array<4> arg_tuple_size_helper(R (A0::*)(A1, A2, A3) volatile); + +template +char_array<5> arg_tuple_size_helper(R (A0::*)(A1, A2, A3, A4) volatile); + +template +char_array<6> arg_tuple_size_helper(R (A0::*)(A1, A2, A3, A4, A5) volatile); + + +template +char_array<1> arg_tuple_size_helper(R (A0::*)() const volatile); + +template +char_array<2> arg_tuple_size_helper(R (A0::*)(A1) const volatile); + +template +char_array<3> arg_tuple_size_helper(R (A0::*)(A1, A2) const volatile); + +template +char_array<4> arg_tuple_size_helper(R (A0::*)(A1, A2, A3) const volatile); + +template +char_array<5> arg_tuple_size_helper(R (A0::*)(A1, A2, A3, A4) const volatile); + +template +char_array<6> arg_tuple_size_helper(R (A0::*)(A1, A2, A3, A4, A5) const volatile); + + +template +struct arg_tuple_size +{ + // The sizeof() magic happens here + BOOST_STATIC_CONSTANT(std::size_t, value + = sizeof(arg_tuple_size_helper(F(0)).elements) - 1); +}; +# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +}}} // namespace boost::python::detail + +#endif // ARG_TUPLE_SIZE_DWA20011201_HPP + diff --git a/include/boost/python/detail/base_object.hpp b/include/boost/python/detail/base_object.hpp index 19715876..d92b3972 100644 --- a/include/boost/python/detail/base_object.hpp +++ b/include/boost/python/detail/base_object.hpp @@ -13,7 +13,6 @@ # define BASE_OBJECT_DWA051600_H_ # include -# include // really just for type<> # include # include @@ -45,10 +44,7 @@ template base_object::base_object(PyTypeObject* type_obj) { base_python_type* bp = this; -#if !defined(_MSC_VER) || defined(__STLPORT) - std:: -#endif - memset(bp, 0, sizeof(base_python_type)); + BOOST_CSTD_::memset(bp, 0, sizeof(base_python_type)); Py_INCREF(type_obj); PyObject_INIT(bp, type_obj); } diff --git a/include/boost/python/detail/call_object.hpp b/include/boost/python/detail/call_object.hpp new file mode 100644 index 00000000..5595e5c0 --- /dev/null +++ b/include/boost/python/detail/call_object.hpp @@ -0,0 +1,66 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef CALL_OBJECT_DWA20011222_HPP +# define CALL_OBJECT_DWA20011222_HPP +# include +# include +# include + +namespace boost { namespace python { + +namespace detail +{ + // A function object adaptor which turns a function returning R into + // an "equivalent" function returning void, but taking an R& in + // which the adapted function's result is stored. + template + struct return_by_reference + { + typedef void return_type; + + return_by_reference(R& result, F f) + : m_result(result) + , m_f(f) + { + } + + void operator()() const + { + m_result = m_f(); + } + + R& m_result; + F m_f; + }; + + // An object generator for the above adaptors + template + return_by_reference bind_return(R& result, F f) + { + return return_by_reference(result, f); + } + + // Given a function object f with signature + // + // R f(PyTypeObject*,PyObject*) + // + // calls f inside of handle_exception_impl, placing f's result in + // ret. Returns true iff an exception is thrown by f, leaving ret + // unmodified. + template + bool call_object(R& ret, PyObject* obj, F f) + { + return handle_exception( + detail::bind_return( + ret + , boost::bind( + f, static_cast(obj->ob_type), obj))); + } +} // namespace detail + +}} // namespace boost::python + +#endif // CALL_OBJECT_DWA20011222_HPP diff --git a/include/boost/python/detail/caller.hpp b/include/boost/python/detail/caller.hpp new file mode 100644 index 00000000..95c6dc7a --- /dev/null +++ b/include/boost/python/detail/caller.hpp @@ -0,0 +1,27 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef CALLER_DWA20011214_HPP +# define CALLER_DWA20011214_HPP + +# include +# include + +namespace boost { namespace python { namespace detail { + +struct caller +{ + typedef PyObject* result_type; + + template + PyObject* operator()(F f, PyObject* args, PyObject* keywords) + { + return call(f, args, keywords); + } +}; + +}}} // namespace boost::python::detail + +#endif // CALLER_DWA20011214_HPP diff --git a/include/boost/python/detail/config.hpp b/include/boost/python/detail/config.hpp index 0fc1093a..498fa07a 100644 --- a/include/boost/python/detail/config.hpp +++ b/include/boost/python/detail/config.hpp @@ -59,9 +59,9 @@ # ifndef BOOST_PYTHON_MODULE_INIT # if defined(_WIN32) || defined(__CYGWIN__) -# define BOOST_PYTHON_MODULE_INIT(name) void init_module_##name(); extern "C" __declspec(dllexport) void init##name() { boost::python::handle_exception(init_module_##name); } void init_module_##name() +# define BOOST_PYTHON_MODULE_INIT(name) void init_module_##name(); extern "C" __declspec(dllexport) void init##name() { boost::python::handle_exception(&init_module_##name); } void init_module_##name() # else -# define BOOST_PYTHON_MODULE_INIT(name) void init_module_##name(); extern "C" void init##name() { boost::python::handle_exception(init_module_##name); } void init_module_##name() +# define BOOST_PYTHON_MODULE_INIT(name) void init_module_##name(); extern "C" void init##name() { boost::python::handle_exception(&init_module_##name); } void init_module_##name() # endif # endif @@ -72,23 +72,23 @@ ****************************************************************************/ // backwards compatibility: -#ifdef BOOST_RE_STATIC_LIB +#ifdef BOOST_PYTHON_STATIC_LIB # define BOOST_PYTHON_STATIC_LINK #endif -#if defined(BOOST_MSVC) && defined(_DLL) +#if defined(BOOST_MSVC) && defined(_DLL) && !defined(BOOST_PYTHON_HAS_DLL_RUNTIME) # define BOOST_PYTHON_HAS_DLL_RUNTIME #endif -#if defined(__BORLANDC__) && defined(_RTLDLL) +#if defined(__BORLANDC__) && defined(_RTLDLL) && !defined(BOOST_PYTHON_HAS_DLL_RUNTIME) # define BOOST_PYTHON_HAS_DLL_RUNTIME #endif -#if defined(__ICL) && defined(_DLL) +#if defined(__ICL) && defined(_DLL) && !defined(BOOST_PYTHON_HAS_DLL_RUNTIME) # define BOOST_PYTHON_HAS_DLL_RUNTIME #endif -#if defined(BOOST_PYTHON_HAS_DLL_RUNTIME) && !defined(BOOST_PYTHON_STATIC_LINK) +#if defined(BOOST_PYTHON_DYNAMIC_LIB) && defined(_WIN32) // && !defined(BOOST_PYTHON_STATIC_LINK) # if defined(BOOST_PYTHON_SOURCE) # define BOOST_PYTHON_DECL __declspec(dllexport) # define BOOST_PYTHON_BUILD_DLL @@ -102,7 +102,7 @@ #endif #if (defined(BOOST_MSVC) || defined(__BORLANDC__)) && !defined(BOOST_PYTHON_NO_LIB) && !defined(BOOST_PYTHON_SOURCE) -# include +// # include #endif // Borland C++ Fix/error check: @@ -117,7 +117,7 @@ # endif # endif # ifndef _RTLDLL - // this is harmless for a staic link: + // this is harmless for a static link: # define _RWSTD_COMPILE_INSTANTIATE # endif # endif diff --git a/include/boost/python/detail/python_library_include.hpp b/include/boost/python/detail/python_library_include.hpp index 903f02be..d2b78c6e 100644 --- a/include/boost/python/detail/python_library_include.hpp +++ b/include/boost/python/detail/python_library_include.hpp @@ -1,3 +1,4 @@ +#error obsolete /* * * Copyright (c) 1998-2000 diff --git a/include/boost/python/detail/returning.hpp b/include/boost/python/detail/returning.hpp new file mode 100644 index 00000000..28f1846e --- /dev/null +++ b/include/boost/python/detail/returning.hpp @@ -0,0 +1,846 @@ +// (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and +// distribute this software is granted provided this copyright notice appears +// in all copies. This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// This work was funded in part by Lawrence Berkeley National Labs +// +// This file generated for 5-argument member functions and 6-argument free +// functions by gen_returning.py + +#ifndef RETURNING_DWA20011201_HPP +# define RETURNING_DWA20011201_HPP + +//# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace detail { + +// Calling C++ from Python +template +struct returning +{ + template + static PyObject* call(R (A0::*pmf)(), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + + // find the result converter + wrap_more r(c0); + if (!c0) return 0; + return r( ((*c0).*pmf)() ); + }; + template + static PyObject* call(R (A0::*pmf)(A1), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + + // find the result converter + wrap_more r(c1); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + + // find the result converter + wrap_more r(c2); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + + // find the result converter + wrap_more r(c3); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2, *c3) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + + // find the result converter + wrap_more r(c4); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2, *c3, *c4) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4, A5), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + unwrap_more c5(PyTuple_GET_ITEM(args, 5), c4); + + // find the result converter + wrap_more r(c5); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2, *c3, *c4, *c5) ); + }; + + template + static PyObject* call(R (A0::*pmf)() const, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + + // find the result converter + wrap_more r(c0); + if (!c0) return 0; + return r( ((*c0).*pmf)() ); + }; + template + static PyObject* call(R (A0::*pmf)(A1) const, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + + // find the result converter + wrap_more r(c1); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2) const, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + + // find the result converter + wrap_more r(c2); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3) const, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + + // find the result converter + wrap_more r(c3); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2, *c3) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4) const, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + + // find the result converter + wrap_more r(c4); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2, *c3, *c4) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4, A5) const, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + unwrap_more c5(PyTuple_GET_ITEM(args, 5), c4); + + // find the result converter + wrap_more r(c5); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2, *c3, *c4, *c5) ); + }; + + template + static PyObject* call(R (A0::*pmf)() volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + + // find the result converter + wrap_more r(c0); + if (!c0) return 0; + return r( ((*c0).*pmf)() ); + }; + template + static PyObject* call(R (A0::*pmf)(A1) volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + + // find the result converter + wrap_more r(c1); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2) volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + + // find the result converter + wrap_more r(c2); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3) volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + + // find the result converter + wrap_more r(c3); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2, *c3) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4) volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + + // find the result converter + wrap_more r(c4); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2, *c3, *c4) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4, A5) volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + unwrap_more c5(PyTuple_GET_ITEM(args, 5), c4); + + // find the result converter + wrap_more r(c5); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2, *c3, *c4, *c5) ); + }; + + +// missing const volatile type traits +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + template + static PyObject* call(R (A0::*pmf)() const volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + + // find the result converter + wrap_more r(c0); + if (!c0) return 0; + return r( ((*c0).*pmf)() ); + }; + template + static PyObject* call(R (A0::*pmf)(A1) const volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + + // find the result converter + wrap_more r(c1); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2) const volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + + // find the result converter + wrap_more r(c2); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3) const volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + + // find the result converter + wrap_more r(c3); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2, *c3) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4) const volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + + // find the result converter + wrap_more r(c4); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2, *c3, *c4) ); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4, A5) const volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + unwrap_more c5(PyTuple_GET_ITEM(args, 5), c4); + + // find the result converter + wrap_more r(c5); + if (!c0) return 0; + return r( ((*c0).*pmf)(*c1, *c2, *c3, *c4, *c5) ); + }; + +# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + + static PyObject* call(R (*pf)(), PyObject*, PyObject* /* keywords */ ) + { + // find the result converter + wrap r; + return r( (*pf)() ); + }; + template + static PyObject* call(R (*pf)(A0), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + + // find the result converter + wrap_more r(c0); + if (!c0) return 0; + return r( (*pf)(*c0) ); + }; + template + static PyObject* call(R (*pf)(A0, A1), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + + // find the result converter + wrap_more r(c1); + if (!c0) return 0; + return r( (*pf)(*c0, *c1) ); + }; + template + static PyObject* call(R (*pf)(A0, A1, A2), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + + // find the result converter + wrap_more r(c2); + if (!c0) return 0; + return r( (*pf)(*c0, *c1, *c2) ); + }; + template + static PyObject* call(R (*pf)(A0, A1, A2, A3), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + + // find the result converter + wrap_more r(c3); + if (!c0) return 0; + return r( (*pf)(*c0, *c1, *c2, *c3) ); + }; + template + static PyObject* call(R (*pf)(A0, A1, A2, A3, A4), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + + // find the result converter + wrap_more r(c4); + if (!c0) return 0; + return r( (*pf)(*c0, *c1, *c2, *c3, *c4) ); + }; + template + static PyObject* call(R (*pf)(A0, A1, A2, A3, A4, A5), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + unwrap_more c5(PyTuple_GET_ITEM(args, 5), c4); + + // find the result converter + wrap_more r(c5); + if (!c0) return 0; + return r( (*pf)(*c0, *c1, *c2, *c3, *c4, *c5) ); + }; +}; + +template <> +struct returning +{ + typedef void R; + template + static PyObject* call(R (A0::*pmf)(), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + + if (!c0) return 0; + ((*c0).*pmf)(); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + + if (!c0) return 0; + ((*c0).*pmf)(*c1); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2, *c3); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2, *c3, *c4); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4, A5), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + unwrap_more c5(PyTuple_GET_ITEM(args, 5), c4); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2, *c3, *c4, *c5); + return detail::none(); + }; + + template + static PyObject* call(R (A0::*pmf)() const, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + + if (!c0) return 0; + ((*c0).*pmf)(); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1) const, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + + if (!c0) return 0; + ((*c0).*pmf)(*c1); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2) const, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3) const, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2, *c3); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4) const, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2, *c3, *c4); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4, A5) const, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + unwrap_more c5(PyTuple_GET_ITEM(args, 5), c4); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2, *c3, *c4, *c5); + return detail::none(); + }; + + template + static PyObject* call(R (A0::*pmf)() volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + + if (!c0) return 0; + ((*c0).*pmf)(); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1) volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + + if (!c0) return 0; + ((*c0).*pmf)(*c1); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2) volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3) volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2, *c3); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4) volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2, *c3, *c4); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4, A5) volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + unwrap_more c5(PyTuple_GET_ITEM(args, 5), c4); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2, *c3, *c4, *c5); + return detail::none(); + }; + + +// missing const volatile type traits +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + template + static PyObject* call(R (A0::*pmf)() const volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + + if (!c0) return 0; + ((*c0).*pmf)(); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1) const volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + + if (!c0) return 0; + ((*c0).*pmf)(*c1); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2) const volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3) const volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2, *c3); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4) const volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2, *c3, *c4); + return detail::none(); + }; + template + static PyObject* call(R (A0::*pmf)(A1, A2, A3, A4, A5) const volatile, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + unwrap_more c5(PyTuple_GET_ITEM(args, 5), c4); + + if (!c0) return 0; + ((*c0).*pmf)(*c1, *c2, *c3, *c4, *c5); + return detail::none(); + }; + +# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + + static PyObject* call(R (*pf)(), PyObject*, PyObject* /* keywords */ ) + { + (*pf)(); + return detail::none(); + }; + template + static PyObject* call(R (*pf)(A0), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + + if (!c0) return 0; + (*pf)(*c0); + return detail::none(); + }; + template + static PyObject* call(R (*pf)(A0, A1), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + + if (!c0) return 0; + (*pf)(*c0, *c1); + return detail::none(); + }; + template + static PyObject* call(R (*pf)(A0, A1, A2), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + + if (!c0) return 0; + (*pf)(*c0, *c1, *c2); + return detail::none(); + }; + template + static PyObject* call(R (*pf)(A0, A1, A2, A3), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + + if (!c0) return 0; + (*pf)(*c0, *c1, *c2, *c3); + return detail::none(); + }; + template + static PyObject* call(R (*pf)(A0, A1, A2, A3, A4), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + + if (!c0) return 0; + (*pf)(*c0, *c1, *c2, *c3, *c4); + return detail::none(); + }; + template + static PyObject* call(R (*pf)(A0, A1, A2, A3, A4, A5), PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); + unwrap_more c1(PyTuple_GET_ITEM(args, 1), c0); + unwrap_more c2(PyTuple_GET_ITEM(args, 2), c1); + unwrap_more c3(PyTuple_GET_ITEM(args, 3), c2); + unwrap_more c4(PyTuple_GET_ITEM(args, 4), c3); + unwrap_more c5(PyTuple_GET_ITEM(args, 5), c4); + + if (!c0) return 0; + (*pf)(*c0, *c1, *c2, *c3, *c4, *c5); + return detail::none(); + }; +}; + +}}} // namespace boost::python::detail + +#endif // RETURNING_DWA20011201_HPP + diff --git a/include/boost/python/detail/types.hpp b/include/boost/python/detail/types.hpp index f4e62f88..2e69d24e 100644 --- a/include/boost/python/detail/types.hpp +++ b/include/boost/python/detail/types.hpp @@ -31,12 +31,8 @@ namespace boost { namespace python { -class string; - namespace detail { -class instance_holder_base; - class BOOST_PYTHON_DECL type_object_base : public python_type { public: diff --git a/include/boost/python/detail/void_adaptor.hpp b/include/boost/python/detail/void_adaptor.hpp index 3d60e4bf..3b4b2124 100644 --- a/include/boost/python/detail/void_adaptor.hpp +++ b/include/boost/python/detail/void_adaptor.hpp @@ -8,7 +8,7 @@ namespace boost { namespace python { namespace detail { - BOOST_PYTHON_DECL extern PyObject arbitrary_object; + extern BOOST_PYTHON_DECL PyObject arbitrary_object; template struct void_adaptor diff --git a/include/boost/python/detail/wrap_python.hpp b/include/boost/python/detail/wrap_python.hpp index 34a9c2b5..d0ad5dd2 100644 --- a/include/boost/python/detail/wrap_python.hpp +++ b/include/boost/python/detail/wrap_python.hpp @@ -34,36 +34,36 @@ // Some things we need in order to get Python.h to work with compilers other // than MSVC on Win32 // -#if defined(_WIN32) +#if defined(_WIN32) || defined(__CYGWIN__) # if defined(__GNUC__) && defined(__CYGWIN__) # if PY_MAJOR_VERSION < 2 || PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION <= 2 typedef int pid_t; # define WORD_BIT 32 # define hypot _hypot # include +# if PY_MAJOR_VERSION < 2 +# define HAVE_CLOCK +# define HAVE_STRFTIME +# define HAVE_STRERROR +# endif +# define NT_THREADS +# define WITH_THREAD +# ifndef NETSCAPE_PI +# define USE_SOCKET +# endif + +# ifdef USE_DL_IMPORT +# define DL_IMPORT(RTYPE) __declspec(dllimport) RTYPE +# endif + +# ifdef USE_DL_EXPORT +# define DL_IMPORT(RTYPE) __declspec(dllexport) RTYPE +# define DL_EXPORT(RTYPE) __declspec(dllexport) RTYPE +# endif + +# define HAVE_LONG_LONG 1 +# define LONG_LONG long long # endif -# if !defined(PY_MAJOR_VERSION) || PY_MAJOR_VERSION < 2 -# define HAVE_CLOCK -# define HAVE_STRFTIME -# define HAVE_STRERROR -# endif -# define NT_THREADS -# define WITH_THREAD -# ifndef NETSCAPE_PI -# define USE_SOCKET -# endif - -# ifdef USE_DL_IMPORT -# define DL_IMPORT(RTYPE) __declspec(dllimport) RTYPE -# endif - -# ifdef USE_DL_EXPORT -# define DL_IMPORT(RTYPE) __declspec(dllexport) RTYPE -# define DL_EXPORT(RTYPE) __declspec(dllexport) RTYPE -# endif - -# define HAVE_LONG_LONG 1 -# define LONG_LONG long long # elif defined(__MWERKS__) diff --git a/include/boost/python/errors.hpp b/include/boost/python/errors.hpp index 66f15587..b9eb4363 100644 --- a/include/boost/python/errors.hpp +++ b/include/boost/python/errors.hpp @@ -9,57 +9,31 @@ #ifndef ERRORS_DWA052500_H_ # define ERRORS_DWA052500_H_ +# include # include +# include namespace boost { namespace python { struct error_already_set {}; struct argument_error : error_already_set {}; -struct object_functor_base -{ - typedef PyObject* result_type; - virtual PyObject* operator()() const = 0; - private: - static void* operator new(std::size_t); // don't allow dynamic allocation - void operator delete(void*); - void operator delete(void*, size_t); -}; - -template -struct object_functor : object_functor_base -{ - object_functor(T const& f) - : m_f(f) - { - } - - PyObject* operator()() const - { - return m_f(); - } - private: - T const& m_f; -}; - - // Handles exceptions caught just before returning to Python code. -PyObject* handle_exception_impl(object_functor_base const& f); +// Returns true iff an exception was caught. +BOOST_PYTHON_DECL bool handle_exception_impl(function0); template -PyObject* handle_exception(T const& f) +bool handle_exception(T f) { - return handle_exception_impl(object_functor(f)); + return handle_exception_impl(function0(boost::ref(f))); } -void handle_exception(void (*)()); +BOOST_PYTHON_DECL PyObject* expect_non_null(PyObject* x); template T* expect_non_null(T* x) { - if (x == 0) - throw error_already_set(); - return x; + return (T*)expect_non_null((PyObject*)x); } }} // namespace boost::python diff --git a/include/boost/python/export.hpp b/include/boost/python/export.hpp new file mode 100644 index 00000000..1229dffe --- /dev/null +++ b/include/boost/python/export.hpp @@ -0,0 +1,20 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef EXPORT_DWA20011220_HPP +# define EXPORT_DWA20011220_HPP + +# include +# ifdef _WIN32 +# ifdef BOOST_PYTHON_SOURCE +# define BOOST_PYTHON_EXPORT __declspec(dllexport) +# else +# define BOOST_PYTHON_EXPORT __declspec(dllimport) +# endif +# else +# define BOOST_PYTHON_EXPORT +# endif + +#endif // EXPORT_DWA20011220_HPP diff --git a/include/boost/python/make_function.hpp b/include/boost/python/make_function.hpp new file mode 100644 index 00000000..d824c0a4 --- /dev/null +++ b/include/boost/python/make_function.hpp @@ -0,0 +1,40 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef MAKE_FUNCTION_DWA20011221_HPP +# define MAKE_FUNCTION_DWA20011221_HPP + +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python { + +template +PyObject* make_function(F f) +{ + return new object::function( + object::py_function( + bind(detail::caller(), f, _1, _2))); +} + +template +PyObject* make_constructor(T* = 0, ArgList* = 0, Generator* = 0) +{ + enum { nargs = mpl::size::value }; + return new object::function( + object::py_function( + bind(detail::caller(), + object::make_holder + ::template apply::execute + , _1, _2))); +} + +}} // namespace boost::python + +#endif // MAKE_FUNCTION_DWA20011221_HPP diff --git a/include/boost/python/module.hpp b/include/boost/python/module.hpp new file mode 100644 index 00000000..c20279c3 --- /dev/null +++ b/include/boost/python/module.hpp @@ -0,0 +1,12 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef MODULE_DWA2001128_HPP +# define MODULE_DWA2001128_HPP + +# include +# include + +#endif // MODULE_DWA20011221_HPP diff --git a/include/boost/python/module_builder.hpp b/include/boost/python/module_builder.hpp index 6a8a9b4b..180a6200 100644 --- a/include/boost/python/module_builder.hpp +++ b/include/boost/python/module_builder.hpp @@ -16,30 +16,18 @@ namespace boost { namespace python { -class module_builder +class BOOST_PYTHON_DECL module_builder_base { public: // Create a module. REQUIRES: only one module_builder is created per module. - module_builder(const char* name); - ~module_builder(); + module_builder_base(const char* name); + ~module_builder_base(); // Add elements to the module void add(detail::function* x, const char* name); void add(PyTypeObject* x, const char* name = 0); void add(ref x, const char*name); - template - void def_raw(Fn fn, const char* name) - { - add(detail::new_raw_arguments_function(fn), name); - } - - template - void def(Fn fn, const char* name) - { - add(detail::new_wrapped_function(fn), name); - } - // Return true iff a module is currently being built. static bool initializing(); @@ -55,10 +43,29 @@ class module_builder static PyMethodDef initial_methods[1]; }; +class module_builder : public module_builder_base +{ + public: + module_builder(const char* name) + : module_builder_base(name) {} + + template + void def_raw(Fn fn, const char* name) + { + add(detail::new_raw_arguments_function(fn), name); + } + + template + void def(Fn fn, const char* name) + { + add(detail::new_wrapped_function(fn), name); + } +}; + // // inline implementations // -inline PyObject* module_builder::module() const +inline PyObject* module_builder_base::module() const { return m_module; } diff --git a/include/boost/python/object/class.hpp b/include/boost/python/object/class.hpp new file mode 100644 index 00000000..548d4053 --- /dev/null +++ b/include/boost/python/object/class.hpp @@ -0,0 +1,103 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef CLASS_DWA20011214_HPP +# define CLASS_DWA20011214_HPP + +# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace object { + +template struct holder; + +// Base class for all holders +struct BOOST_PYTHON_EXPORT holder_base : noncopyable +{ + public: + holder_base(converter::type_id_t id); + virtual ~holder_base(); + virtual bool held_by_value() const = 0; + + holder_base* next() const; + converter::type_id_t type() const; + + void install(PyObject* inst); + + struct iterator_policies : default_iterator_policies + { + template + void increment(Iterator& p) + { + p.base() = p.base()->next(); + } + }; + + typedef iterator_adaptor< + holder_base* + , iterator_policies + , value_type_is + , reference_is + , pointer_is + , iterator_category_is > iterator; + + private: + converter::type_id_t m_type; + holder_base* m_next; +}; + +// Abstract base class which holds a Held, somehow. Provides a uniform +// way to get a pointer to the held object +template +struct holder : holder_base +{ + typedef Held held_type; + holder(); + virtual Held* target() = 0; +}; + +// Each extension instance will be one of these +struct instance +{ + PyObject_HEAD + holder_base* objects; +}; + +BOOST_PYTHON_EXPORT holder_base* find_holder_impl(PyObject*, converter::type_id_t); + +template +holder* find_holder(PyObject* p, T* = 0) +{ + return static_cast*>(find_holder_impl(p, converter::type_id())); +} + +BOOST_PYTHON_EXPORT PyTypeObject* class_metatype(); +BOOST_PYTHON_EXPORT PyTypeObject* class_type(); + +// +// implementation +// +inline holder_base* holder_base::next() const +{ + return m_next; +} + +inline converter::type_id_t holder_base::type() const +{ + return m_type; +} + +template +holder::holder() + : holder_base(converter::type_id()) +{ +} + +}}} // namespace boost::python::object + +#endif // CLASS_DWA20011214_HPP diff --git a/include/boost/python/object/class_unwrapper.hpp b/include/boost/python/object/class_unwrapper.hpp new file mode 100644 index 00000000..4fa441e1 --- /dev/null +++ b/include/boost/python/object/class_unwrapper.hpp @@ -0,0 +1,40 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef CLASS_UNWRAPPER_DWA20011221_HPP +# define CLASS_UNWRAPPER_DWA20011221_HPP + +# include +# include + +namespace boost { namespace python { namespace object { + +template +struct class_unwrapper +{ + private: + template + struct reference_unwrapper : converter::unwrapper + { + bool convertible(PyObject* p) const + { + return find_holder(p) != 0; + } + + Target convert(PyObject* p, void*&) const + { + return *find_holder(p)->target(); + } + }; + + reference_unwrapper m_reference; +# ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + reference_unwrapper m_const_reference; +# endif +}; + +}}} // namespace boost::python::object + +#endif // CLASS_UNWRAPPER_DWA20011221_HPP diff --git a/include/boost/python/object/construct.hpp b/include/boost/python/object/construct.hpp new file mode 100644 index 00000000..3ff701d2 --- /dev/null +++ b/include/boost/python/object/construct.hpp @@ -0,0 +1,24 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef CONSTRUCT_DWA20011215_HPP +# define CONSTRUCT_DWA20011215_HPP + +namespace boost { namespace python { namespace object { + +template +struct construct +{ + static + template +# include +# include +# include + +namespace boost { namespace python { namespace object { + +// A little metaprogram which selects the type to pass through an +// intermediate forwarding function when the destination argument type +// is T. +template +struct forward +{ + typedef typename mpl::select_type< + is_scalar::value | is_reference::value + , T + , reference_wrapper< + typename add_const::type + > + >::type type; +}; + +}}} // namespace boost::python::object + +#endif // FORWARD_DWA20011215_HPP diff --git a/include/boost/python/object/function.hpp b/include/boost/python/object/function.hpp new file mode 100644 index 00000000..f550e8dc --- /dev/null +++ b/include/boost/python/object/function.hpp @@ -0,0 +1,36 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef FUNCTION_DWA20011214_HPP +# define FUNCTION_DWA20011214_HPP + +# include +# include +# include + +namespace boost { namespace python { namespace object { + +// We use boost::function to avoid generating lots of virtual tables +typedef boost::function2 py_function; + +struct BOOST_PYTHON_EXPORT function : PyObject +{ + function(py_function); + ~function(); + + PyObject* call(PyObject*, PyObject*) const; + private: + py_function m_fn; +}; + +extern BOOST_PYTHON_EXPORT PyTypeObject function_type; + +// +// implementations +// + +}}} // namespace boost::python::object + +#endif // FUNCTION_DWA20011214_HPP diff --git a/include/boost/python/object/make_holder.hpp b/include/boost/python/object/make_holder.hpp new file mode 100644 index 00000000..fb5ec382 --- /dev/null +++ b/include/boost/python/object/make_holder.hpp @@ -0,0 +1,124 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef MAKE_HOLDER_DWA20011215_HPP +# define MAKE_HOLDER_DWA20011215_HPP + +# include +# include +# include +# include + +namespace boost { namespace python { namespace object { + + +template struct undefined; +template +struct eval +{ +# if defined(BOOST_MSVC) && BOOST_MSVC <= 1200 + // based on the (non-conforming) MSVC trick from MPL + template + struct unarymetafunction_vc : UnaryMetaFunction {}; + + // illegal C++ which causes VC to admit that unarymetafunction_vc + // can have a nested template: + template<> + struct unarymetafunction_vc + { + template struct apply; + }; + + typedef typename unarymetafunction_vc< + ::boost::mpl::detail::msvc_never_true::value + >::template apply::type type; +# else + typedef typename UnaryMetaFunction::template apply::type type; +# endif +}; + + +template struct make_holder; + +template <> +struct make_holder<0> +{ + template + struct apply + { + typedef typename eval::type holder; + static void execute( + PyObject* p) + { + (new holder(p))->install(p); + } + }; +}; + + +template <> +struct make_holder<1> +{ + template + struct apply + { + typedef typename eval::type holder; + typedef typename mpl::at<0,ArgList>::type t0; + typedef typename forward::type f0; + + static void execute( + PyObject* p + , t0 a0) + { + (new holder(p, f0(a0)))->install(p); + } + }; +}; + +template <> +struct make_holder<2> +{ + template + struct apply + { + typedef typename eval::type holder; + typedef typename mpl::at<0,ArgList>::type t0; + typedef typename forward::type f0; + typedef typename mpl::at<1,ArgList>::type t1; + typedef typename forward::type f1; + + static void execute( + PyObject* p, t0 a0, t1 a1) + { + (new holder(p, f0(a0), f1(a1)))->install(p); + } + }; +}; + +template <> +struct make_holder<3> +{ + template + struct apply + { + typedef typename eval::type holder; + typedef typename mpl::at<0,ArgList>::type t0; + typedef typename forward::type f0; + typedef typename mpl::at<1,ArgList>::type t1; + typedef typename forward::type f1; + typedef typename mpl::at<2,ArgList>::type t2; + typedef typename forward::type f2; + + static void execute( + PyObject* p, t0 a0, t1 a1, t2 a2) + { + (new holder(p, f0(a0), f1(a1), f2(a2)))->install(p); + } + }; +}; + +}}} // namespace boost::python::object + +#endif // MAKE_HOLDER_DWA20011215_HPP diff --git a/include/boost/python/object/value_holder.hpp b/include/boost/python/object/value_holder.hpp new file mode 100644 index 00000000..128d170b --- /dev/null +++ b/include/boost/python/object/value_holder.hpp @@ -0,0 +1,80 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef VALUE_HOLDER_DWA20011215_HPP +# define VALUE_HOLDER_DWA20011215_HPP + +# include + +namespace boost { namespace python { namespace object { + +template +struct value_holder : holder +{ + // Forward construction to the held object + value_holder(PyObject*) + : m_held() {} + + template + value_holder(PyObject*, A1 a1) + : m_held(a1) {} + + template + value_holder(PyObject*, A1 a1, A2 a2) + : m_held(a1, a2) {} + + template + value_holder(PyObject*, A1 a1, A2 a2, A3 a3) + : m_held(a1, a2, a3) {} + + template + value_holder(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4) + : m_held(a1, a2, a3, a4) {} + + template + value_holder(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) + : m_held(a1, a2, a3, a4, a5) {} + + template + value_holder(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) + : m_held(a1, a2, a3, a4, a5, a6) {} + + template + value_holder(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) + : m_held(a1, a2, a3, a4, a5, a6, a7) {} + + template + value_holder(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) + : m_held(a1, a2, a3, a4, a5, a6, a7, a8) {} + + template + value_holder(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) + : m_held(a1, a2, a3, a4, a5, a6, a7, a8, a9) {} + + template + value_holder(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) + : m_held(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {} + + private: // required holder implementation + Held* target() { return &m_held; } + bool held_by_value() const { return true; } + + private: // data members + Held m_held; +}; + +// A generator metafunction which can be passed to make_holder +struct value_holder_generator +{ + template + struct apply + { + typedef value_holder type; + }; +}; + +}}} // namespace boost::python::object + +#endif // VALUE_HOLDER_DWA20011215_HPP diff --git a/include/boost/python/objects.hpp b/include/boost/python/objects.hpp index 3b1a9094..93173462 100644 --- a/include/boost/python/objects.hpp +++ b/include/boost/python/objects.hpp @@ -17,7 +17,7 @@ namespace boost { namespace python { -class object +class BOOST_PYTHON_DECL object { public: explicit object(ref p); @@ -32,15 +32,36 @@ class object ref m_p; }; -class tuple : public object +class tuple; + +class BOOST_PYTHON_DECL tuple_base : public object { public: - explicit tuple(std::size_t n = 0); - explicit tuple(ref p); + explicit tuple_base(std::size_t n = 0); + explicit tuple_base(ref p); + + static PyTypeObject* type_obj(); + static bool accepts(ref p); + std::size_t size() const; + ref operator[](std::size_t pos) const; + + void set_item(std::size_t pos, const ref& rhs); + + tuple slice(int low, int high) const; + + friend BOOST_PYTHON_DECL tuple operator+(const tuple&, const tuple&); + friend BOOST_PYTHON_DECL tuple& operator+=(tuple&, const tuple&); +}; + +class tuple : public tuple_base +{ + public: + explicit tuple(std::size_t n = 0) : tuple_base(n) {} + explicit tuple(ref p) : tuple_base(p) {} template tuple(const std::pair& x) - : object(ref(PyTuple_New(2))) + : tuple_base(ref(PyTuple_New(2))) { set_item(0, x.first); set_item(1, x.second); @@ -48,7 +69,7 @@ class tuple : public object template tuple(const First& first, const Second& second) - : object(ref(PyTuple_New(2))) + : tuple_base(ref(PyTuple_New(2))) { set_item(0, first); set_item(1, second); @@ -56,7 +77,7 @@ class tuple : public object template tuple(const First& first, const Second& second, const Third& third) - : object(ref(PyTuple_New(3))) + : tuple_base(ref(PyTuple_New(3))) { set_item(0, first); set_item(1, second); @@ -65,7 +86,7 @@ class tuple : public object template tuple(const First& first, const Second& second, const Third& third, const Fourth& fourth) - : object(ref(PyTuple_New(4))) + : tuple_base(ref(PyTuple_New(4))) { set_item(0, first); set_item(1, second); @@ -73,32 +94,31 @@ class tuple : public object set_item(3, fourth); } - static PyTypeObject* type_obj(); - static bool accepts(ref p); - std::size_t size() const; - ref operator[](std::size_t pos) const; - template void set_item(std::size_t pos, const T& rhs) { this->set_item(pos, make_ref(rhs)); } - - void set_item(std::size_t pos, const ref& rhs); - - tuple slice(int low, int high) const; - friend tuple operator+(const tuple&, const tuple&); - tuple& operator+=(const tuple& rhs); + void set_item(std::size_t pos, const ref& rhs) + { + tuple_base::set_item(pos, rhs); + } }; -class list : public object +class list; + +struct BOOST_PYTHON_DECL list_proxy; +struct BOOST_PYTHON_DECL list_slice_proxy; + +class BOOST_PYTHON_DECL list_base : public object { - struct proxy; - struct slice_proxy; + protected: + typedef list_proxy proxy; + typedef list_slice_proxy slice_proxy; public: - explicit list(ref p); - explicit list(std::size_t sz = 0); + explicit list_base(ref p); + explicit list_base(std::size_t sz = 0); static PyTypeObject* type_obj(); static bool accepts(ref p); std::size_t size() const; @@ -106,26 +126,14 @@ class list : public object proxy operator[](std::size_t pos); ref get_item(std::size_t pos) const; - template - void set_item(std::size_t pos, const T& x) - { this->set_item(pos, make_ref(x)); } void set_item(std::size_t pos, const ref& ); // void set_item(std::size_t pos, const object& ); - template - void insert(std::size_t index, const T& x) - { this->insert(index, make_ref(x)); } void insert(std::size_t index, const ref& item); - template - void push_back(const T& item) - { this->push_back(make_ref(item)); } void push_back(const ref& item); - template - void append(const T& item) - { this->append(make_ref(item)); } void append(const ref& item); list slice(int low, int high) const; @@ -135,7 +143,31 @@ class list : public object tuple as_tuple() const; }; -class string +class list : public list_base +{ + public: + explicit list(ref p) : list_base(p) {} + explicit list(std::size_t sz = 0) : list_base(sz) {} + template + void set_item(std::size_t pos, const T& x) + { this->set_item(pos, make_ref(x)); } + template + void insert(std::size_t index, const T& x) + { this->insert(index, make_ref(x)); } + template + void push_back(const T& item) + { this->push_back(make_ref(item)); } + template + void append(const T& item) + { this->append(make_ref(item)); } + + void set_item(std::size_t pos, const ref& x) { list_base::set_item(pos, x); } + void insert(std::size_t index, const ref& item) { list_base::insert(index, item); } + void push_back(const ref& item) { list_base::push_back(item); } + void append(const ref& item) { list_base::append(item); } +}; + +class BOOST_PYTHON_DECL string : public object, public boost::multipliable2 { public: @@ -175,48 +207,31 @@ class string friend string operator%(const string& format, const tuple& args); }; -class dictionary : public object +class dictionary; + +struct BOOST_PYTHON_DECL dictionary_proxy; + +class BOOST_PYTHON_DECL dictionary_base : public object { - private: - struct proxy; + protected: + typedef dictionary_proxy proxy; public: - explicit dictionary(ref p); - dictionary(); + explicit dictionary_base(ref p); + dictionary_base(); void clear(); static PyTypeObject* type_obj(); static bool accepts(ref p); public: - template - proxy operator[](const Key& key) - { return this->operator[](make_ref(key)); } proxy operator[](ref key); - - template - ref operator[](const Key& key) const - { return this->operator[](make_ref(key)); } ref operator[](ref key) const; - - template - ref get_item(const Key& key) const - { return this->get_item(make_ref(key)); } ref get_item(const ref& key) const; - - template - ref get_item(const Key& key, const Default& default_) const - { return this->get_item(make_ref(key), make_ref(default_)); } ref get_item(const ref& key, const ref& default_) const; - template - void set_item(const Key& key, const Value& value) - { this->set_item(make_ref(key), make_ref(value)); } void set_item(const ref& key, const ref& value); - template - void erase(const Key& key) - { this->erase(make_ref(key)); } void erase(ref key); // proxy operator[](const object& key); @@ -235,7 +250,7 @@ class dictionary : public object // TODO: iterator support }; -struct dictionary::proxy +struct BOOST_PYTHON_DECL dictionary_proxy { template const ref& operator=(const T& rhs) @@ -244,19 +259,63 @@ struct dictionary::proxy operator ref() const; private: - friend class dictionary; - proxy(const ref& dict, const ref& key); + friend class dictionary_base; + dictionary_proxy(const ref& dict, const ref& key); // This is needed to work around the very strange MSVC error report that the // return type of the built-in operator= differs from that of the ones // defined above. Couldn't hurt to make these un-assignable anyway, though. - const ref& operator=(const proxy&); // Not actually implemented + const ref& operator=(const dictionary_proxy&); // Not actually implemented private: ref m_dict; ref m_key; }; -struct list::proxy +class dictionary : public dictionary_base +{ + typedef dictionary_proxy proxy; + public: + explicit dictionary(ref p) : dictionary_base(p) {} + dictionary() : dictionary_base() {} + + template + proxy operator[](const Key& key) + { return this->operator[](make_ref(key)); } + proxy operator[](ref key) + { return dictionary_base::operator[](key); } + + template + ref operator[](const Key& key) const + { return this->operator[](make_ref(key)); } + ref operator[](ref key) const + { return dictionary_base::operator[](key); } + + template + ref get_item(const Key& key) const + { return this->get_item(make_ref(key)); } + ref get_item(const ref& key) const + { return dictionary_base::get_item(key); } + + template + ref get_item(const Key& key, const Default& default_) const + { return this->get_item(make_ref(key), make_ref(default_)); } + ref get_item(const ref& key, const ref& default_) const + { return dictionary_base::get_item(key, default_); } + + template + void set_item(const Key& key, const Value& value) + { this->set_item(make_ref(key), make_ref(value)); } + void set_item(const ref& key, const ref& value) + { dictionary_base::set_item(key, value); } + + template + void erase(const Key& key) + { this->erase(make_ref(key)); } + void erase(ref key) + { dictionary_base::erase(key); } +}; + +struct BOOST_PYTHON_DECL list_proxy { template const ref& operator=(const T& rhs) @@ -266,19 +325,19 @@ struct list::proxy operator ref() const; private: - friend class list; - proxy(const ref& list, std::size_t index); + friend class list_base; + list_proxy(const ref& list, std::size_t index); // This is needed to work around the very strange MSVC error report that the // return type of the built-in operator= differs from that of the ones // defined above. Couldn't hurt to make these un-assignable anyway, though. - const ref& operator=(const proxy&); // Not actually implemented + const ref& operator=(const list_proxy&); // Not actually implemented private: list m_list; std::size_t m_index; }; -struct list::slice_proxy +struct BOOST_PYTHON_DECL list_slice_proxy { const list& operator=(const list& rhs); operator ref() const; @@ -286,8 +345,8 @@ struct list::slice_proxy std::size_t size() const; ref operator[](std::size_t pos) const; private: - friend class list; - slice_proxy(const ref& list, int low, int high); + friend class list_base; + list_slice_proxy(const ref& list, int low, int high); private: ref m_list; int m_low, m_high; @@ -297,32 +356,32 @@ struct list::slice_proxy BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE -PyObject* to_python(const boost::python::tuple&); -boost::python::tuple from_python(PyObject* p, boost::python::type); +BOOST_PYTHON_DECL PyObject* to_python(const boost::python::tuple&); +BOOST_PYTHON_DECL boost::python::tuple from_python(PyObject* p, boost::python::type); inline boost::python::tuple from_python(PyObject* p, boost::python::type) { return from_python(p, boost::python::type()); } -PyObject* to_python(const boost::python::list&); -boost::python::list from_python(PyObject* p, boost::python::type); +BOOST_PYTHON_DECL PyObject* to_python(const boost::python::list&); +BOOST_PYTHON_DECL boost::python::list from_python(PyObject* p, boost::python::type); inline boost::python::list from_python(PyObject* p, boost::python::type) { return from_python(p, boost::python::type()); } -PyObject* to_python(const boost::python::string&); -boost::python::string from_python(PyObject* p, boost::python::type); +BOOST_PYTHON_DECL PyObject* to_python(const boost::python::string&); +BOOST_PYTHON_DECL boost::python::string from_python(PyObject* p, boost::python::type); inline boost::python::string from_python(PyObject* p, boost::python::type) { return from_python(p, boost::python::type()); } -PyObject* to_python(const boost::python::dictionary&); -boost::python::dictionary from_python(PyObject* p, boost::python::type); +BOOST_PYTHON_DECL PyObject* to_python(const boost::python::dictionary&); +BOOST_PYTHON_DECL boost::python::dictionary from_python(PyObject* p, boost::python::type); inline boost::python::dictionary from_python(PyObject* p, boost::python::type) { diff --git a/include/boost/python/operators.hpp b/include/boost/python/operators.hpp index 52e52eee..c766c8b6 100644 --- a/include/boost/python/operators.hpp +++ b/include/boost/python/operators.hpp @@ -31,7 +31,7 @@ namespace boost { namespace python { -tuple standard_coerce(ref l, ref r); +BOOST_PYTHON_DECL tuple standard_coerce(ref l, ref r); namespace detail { diff --git a/src/classes.cpp b/src/classes.cpp index f51d1a2f..b018c0ce 100644 --- a/src/classes.cpp +++ b/src/classes.cpp @@ -11,6 +11,8 @@ // 03 Mar 01 added: pickle safety measures (Ralf W. Grosse-Kunstleve) // 03 Mar 01 bug fix: use bound_function::create() (instead of new bound_function) +#define BOOST_PYTHON_SOURCE + #include #include #include @@ -997,7 +999,7 @@ namespace { } } -void adjust_slice_indices(PyObject* obj, int& start, int& finish) +BOOST_PYTHON_DECL void adjust_slice_indices(PyObject* obj, int& start, int& finish) { int length = callback::call_method(obj, "__len__"); diff --git a/src/conversions.cpp b/src/conversions.cpp index f1534dd9..e6b6161a 100644 --- a/src/conversions.cpp +++ b/src/conversions.cpp @@ -16,65 +16,16 @@ #define BOOST_PYTHON_SOURCE #include -#include +#include #include #include #ifndef BOOST_NO_LIMITS # include #endif -namespace boost { namespace python { - -// IMPORTANT: this function may only be called from within a catch block! -PyObject* handle_exception_impl(object_functor_base const& f) -{ - try - { - return f(); - } - catch(const boost::python::error_already_set&) - { - // The python error reporting has already been handled. - } - catch(const std::bad_alloc&) - { - PyErr_NoMemory(); - } - catch(const std::exception& x) - { - PyErr_SetString(PyExc_RuntimeError, x.what()); - } - catch(...) - { - PyErr_SetString(PyExc_RuntimeError, "unidentifiable C++ exception"); - } - return 0; -} - -void handle_exception(void (*f)()) -{ - handle_exception( - boost::python::detail::make_void_adaptor(f)); -} - -namespace detail { - - void expect_complex(PyObject* p) - { - if (!PyComplex_Check(p)) - { - PyErr_SetString(PyExc_TypeError, "expected a complex number"); - throw boost::python::argument_error(); - } - } - -} // namespace boost::python::detail - -}} // namespace boost::python - BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE -long from_python(PyObject* p, boost::python::type) +BOOST_PYTHON_DECL long from_python(PyObject* p, boost::python::type) { // Why am I clearing the error here before trying to convert? I know there's a reason... long result; @@ -86,7 +37,7 @@ long from_python(PyObject* p, boost::python::type) return result; } -double from_python(PyObject* p, boost::python::type) +BOOST_PYTHON_DECL double from_python(PyObject* p, boost::python::type) { double result; { @@ -151,48 +102,48 @@ PyObject* integer_to_python(T value) return to_python(value_as_long); } -int from_python(PyObject* p, boost::python::type type) +BOOST_PYTHON_DECL int from_python(PyObject* p, boost::python::type type) { return integer_from_python(p, type); } -PyObject* to_python(unsigned int i) +BOOST_PYTHON_DECL PyObject* to_python(unsigned int i) { return integer_to_python(i); } -unsigned int from_python(PyObject* p, boost::python::type type) +BOOST_PYTHON_DECL unsigned int from_python(PyObject* p, boost::python::type type) { return integer_from_python(p, type); } -short from_python(PyObject* p, boost::python::type type) +BOOST_PYTHON_DECL short from_python(PyObject* p, boost::python::type type) { return integer_from_python(p, type); } -float from_python(PyObject* p, boost::python::type) +BOOST_PYTHON_DECL float from_python(PyObject* p, boost::python::type) { return static_cast(from_python(p, boost::python::type())); } -PyObject* to_python(unsigned short i) +BOOST_PYTHON_DECL PyObject* to_python(unsigned short i) { return integer_to_python(i); } -unsigned short from_python(PyObject* p, boost::python::type type) +BOOST_PYTHON_DECL unsigned short from_python(PyObject* p, boost::python::type type) { return integer_from_python(p, type); } -PyObject* to_python(char c) +BOOST_PYTHON_DECL PyObject* to_python(char c) { if (c == '\0') return PyString_FromString(""); return PyString_FromStringAndSize(&c, 1); } -char from_python(PyObject* p, boost::python::type) +BOOST_PYTHON_DECL char from_python(PyObject* p, boost::python::type) { int l = -1; if (PyString_Check(p)) l = PyString_Size(p); @@ -204,37 +155,37 @@ char from_python(PyObject* p, boost::python::type) return PyString_AsString(p)[0]; } -PyObject* to_python(unsigned char i) +BOOST_PYTHON_DECL PyObject* to_python(unsigned char i) { return integer_to_python(i); } -unsigned char from_python(PyObject* p, boost::python::type type) +BOOST_PYTHON_DECL unsigned char from_python(PyObject* p, boost::python::type type) { return integer_from_python(p, type); } -PyObject* to_python(signed char i) +BOOST_PYTHON_DECL PyObject* to_python(signed char i) { return integer_to_python(i); } -signed char from_python(PyObject* p, boost::python::type type) +BOOST_PYTHON_DECL signed char from_python(PyObject* p, boost::python::type type) { return integer_from_python(p, type); } -PyObject* to_python(unsigned long x) +BOOST_PYTHON_DECL PyObject* to_python(unsigned long x) { return integer_to_python(x); } -unsigned long from_python(PyObject* p, boost::python::type type) +BOOST_PYTHON_DECL unsigned long from_python(PyObject* p, boost::python::type type) { return integer_from_python(p, type); } -void from_python(PyObject* p, boost::python::type) +BOOST_PYTHON_DECL void from_python(PyObject* p, boost::python::type) { if (p != Py_None) { PyErr_SetString(PyExc_TypeError, "expected argument of type None"); @@ -242,7 +193,7 @@ void from_python(PyObject* p, boost::python::type) } } -const char* from_python(PyObject* p, boost::python::type) +BOOST_PYTHON_DECL const char* from_python(PyObject* p, boost::python::type) { const char* s = PyString_AsString(p); if (!s) @@ -250,12 +201,12 @@ const char* from_python(PyObject* p, boost::python::type) return s; } -PyObject* to_python(const std::string& s) +BOOST_PYTHON_DECL PyObject* to_python(const std::string& s) { return PyString_FromStringAndSize(s.data(), s.size()); } -std::string from_python(PyObject* p, boost::python::type) +BOOST_PYTHON_DECL std::string from_python(PyObject* p, boost::python::type) { if (! PyString_Check(p)) { PyErr_SetString(PyExc_TypeError, "expected a string"); @@ -264,7 +215,7 @@ std::string from_python(PyObject* p, boost::python::type) return std::string(PyString_AsString(p), PyString_Size(p)); } -bool from_python(PyObject* p, boost::python::type) +BOOST_PYTHON_DECL bool from_python(PyObject* p, boost::python::type) { int value = from_python(p, boost::python::type()); if (value == 0) @@ -274,12 +225,12 @@ bool from_python(PyObject* p, boost::python::type) #ifdef BOOST_MSVC6_OR_EARLIER // An optimizer bug prevents these from being inlined. -PyObject* to_python(double d) +BOOST_PYTHON_DECL PyObject* to_python(double d) { return PyFloat_FromDouble(d); } -PyObject* to_python(float f) +BOOST_PYTHON_DECL PyObject* to_python(float f) { return PyFloat_FromDouble(f); } diff --git a/src/converter/body.cpp b/src/converter/body.cpp new file mode 100644 index 00000000..637f8c3e --- /dev/null +++ b/src/converter/body.cpp @@ -0,0 +1,18 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include + +namespace boost { namespace python { namespace converter { + +// default implementation is a no-op. Most handles will not hold any +// data that needs to be managed. Unwrap objects which convert +// by-value are an exception. Fortunately, the concrete body subclass +// has that knowledge. +void body::destroy_handle(handle*) const +{ +} + +}}} // namespace boost::python::converter diff --git a/src/converter/handle.cpp b/src/converter/handle.cpp new file mode 100644 index 00000000..1a2b8c31 --- /dev/null +++ b/src/converter/handle.cpp @@ -0,0 +1,35 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include +#include + +namespace boost { namespace python { namespace converter { + +bool handle::convertible() const +{ + for (handle const* p = this; p != 0; p = p->m_next) + { + if (p->m_body == 0) + return false; + } + return true; +} + +void handle::destroy() +{ + // Recurse down the chain releasing from tail to head + if (m_next != 0) + m_next->destroy(); + + // Our body knows how to destroy us. If we never got a body, + // there's nothing to do. + if (m_body) + m_body->destroy_handle(this); +} + +// void handle::dummy::nonnull() {} + +}}} // namespace boost::python::converter diff --git a/src/converter/registry.cpp b/src/converter/registry.cpp new file mode 100644 index 00000000..88d96637 --- /dev/null +++ b/src/converter/registry.cpp @@ -0,0 +1,177 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +# include +# include +# include +# include +# include +# include +# ifdef BOOST_PYTHON_TRACE +# include +# endif + +namespace boost { namespace python { namespace converter { + +namespace // +{ + typedef std::map registry_t; + + registry_t& entries() + { + static registry_t registry; + return registry; + } +} // namespace + +namespace registry +{ + entry* find(type_id_t type) + { + return &entries()[type]; + } + + entry::entry() + : m_wrapper(0) + { + } + + namespace // + { + // A UnaryFunction type which deletes its argument + struct delete_item + { + template + void operator()(T* x) const + { + delete x; + } + }; + + // A UnaryFunction type which returns true iff its argument is a + // unwrapper which can convert the given Python object. + struct convertible + { + convertible(PyObject* p) + : m_p(p) + {} + + bool operator()(unwrapper_base* converter) const + { + return converter->convertible(m_p); + } + + PyObject* m_p; + }; + } + + entry::~entry() + { + if (m_wrapper != 0) + m_wrapper->m_can_unregister = false; + + for (unwrappers::iterator p = m_unwrappers.begin(); p != m_unwrappers.end(); ++p) + { + (*p)->m_can_unregister = false; + } + } + + unwrapper_base* entry::unwrapper(PyObject* p) const + { + unwrappers::const_iterator q = + std::find_if(m_unwrappers.begin(), m_unwrappers.end(), convertible(p)); + + return q == m_unwrappers.end() ? 0 : *q; + } + + wrapper_base* entry::wrapper() const + { + return m_wrapper; + } + + entry::unwrappers::iterator entry::find(unwrapper_base const& x) + { + return std::find(m_unwrappers.begin(), m_unwrappers.end(), &x); + } + + void entry::insert(unwrapper_base& x) + { + unwrappers::iterator p = this->find(x); + + assert(p == m_unwrappers.end()); + if (p != m_unwrappers.end()) + { + throw std::runtime_error( + "trying to register unrapper which is already registered"); + } + m_unwrappers.push_back(&x); + } + + void entry::remove(unwrapper_base& x) + { + unwrappers::iterator p = find(x); + + // Be sure we're not removing a converter which hasn't been + // registered. + assert(p != m_unwrappers.end()); + if (p == m_unwrappers.end()) + { + throw std::runtime_error( + "trying to unregister unwrapper which is not registered"); + } + m_unwrappers.erase(p); + } + + void entry::insert(wrapper_base& x) + { + assert(m_wrapper == 0); // we have a problem otherwise + if (m_wrapper != 0) + { + throw std::runtime_error( + "trying to register wrapper for a type which already has a registered wrapper"); + } + m_wrapper = &x; + } + + void entry::remove(wrapper_base& x) + { + assert(m_wrapper == &x); + if (m_wrapper != &x) + { + throw std::runtime_error( + "trying to unregister a wrapper which is not registered"); + } + m_wrapper = 0; + } + + void insert(wrapper_base& w) + { +# ifdef BOOST_PYTHON_TRACE + std::cout << "inserting wrapper for " << w.key() << std::endl; +# endif + find(w.key())->insert(w); + } + + void insert(unwrapper_base& u) + { +# ifdef BOOST_PYTHON_TRACE + std::cout << "inserting unwrapper for " << u.key() << std::endl; +# endif + find(u.key())->insert(u); + } + + void remove(wrapper_base& w) + { + find(w.key())->remove(w); + } + + void remove(unwrapper_base& u) + { + find(u.key())->remove(u); + } +} // namespace registry + +}}} // namespace boost::python::converter diff --git a/src/converter/type_id.cpp b/src/converter/type_id.cpp new file mode 100644 index 00000000..86974638 --- /dev/null +++ b/src/converter/type_id.cpp @@ -0,0 +1,67 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include +#if !defined(__GNUC__) || __GNUC__ >= 3 || __SGI_STL_PORT +# include +#else +# include +#endif + +namespace boost { namespace python { namespace converter { + +#if 1 +bool type_id_before::operator()(type_id_t const& x, type_id_t const& y) const +{ + return x < y; +} + +BOOST_PYTHON_EXPORT std::ostream& operator<<(std::ostream& os, type_id_t const& x) +{ +# ifdef BOOST_PYTHON_TYPE_ID_NAME + os << x.m_base_type; +# else + os << x.m_base_type->name(); +# endif + // VC6 mistakenly distinguishes typeid(X) from typeid(X const) + // from typeid(X&)... so the name is already correct. I have it + // from Jason Shirk that VC7.0 has the same bug but it will be + // fixed in 7.1 +# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 + if (x.m_decoration & type_id_t::const_) + os << " const"; + if (x.m_decoration & type_id_t::volatile_) + os << " volatile"; + if (x.m_decoration & type_id_t::reference) + os << "&"; +# endif + return os; +} + +#else +bool type_id_before::operator()(type_id_t const& x, type_id_t const& y) const +{ + for (;;) + { + if (*y == 0) + { + return 0; + } + else if (*x == 0) + { + return 1; + } + else if (*x != *y) + { + return *x < *y; + } + ++x; + ++y; + } +} +#endif + +}}} // namespace boost::python::converter diff --git a/src/converter/unwrap.cpp b/src/converter/unwrap.cpp new file mode 100644 index 00000000..e0c09db6 --- /dev/null +++ b/src/converter/unwrap.cpp @@ -0,0 +1,35 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include + +namespace boost { namespace python { namespace converter { + +namespace +{ + struct pyobject_unwrapper : unwrapper_base + { + pyobject_unwrapper(); + bool convertible(PyObject*) const; + }; + + pyobject_unwrapper static_unwrapper; + + pyobject_unwrapper::pyobject_unwrapper() + : unwrapper_base(type_id()) + { + } + + bool pyobject_unwrapper::convertible(PyObject*) const + { + return true; + } +} + +BOOST_PYTHON_EXPORT unwrapper_base* +unwrap_more_::m_unwrapper = &static_unwrapper; + +}}} // namespace boost::python::converter diff --git a/src/converter/unwrapper.cpp b/src/converter/unwrapper.cpp new file mode 100644 index 00000000..2b0adbd0 --- /dev/null +++ b/src/converter/unwrapper.cpp @@ -0,0 +1,24 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include +#include +#include + +namespace boost { namespace python { namespace converter { + +unwrapper_base::unwrapper_base(type_id_t key) + : body(key) +{ + registry::insert(*this); +} + +unwrapper_base::~unwrapper_base() +{ + if (can_unregister()) + registry::remove(*this); +} + +}}} // namespace boost::python::converter diff --git a/src/converter/wrapper.cpp b/src/converter/wrapper.cpp new file mode 100644 index 00000000..0d817217 --- /dev/null +++ b/src/converter/wrapper.cpp @@ -0,0 +1,30 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include +#include + +namespace boost { namespace python { namespace converter { + +wrapper_base::wrapper_base(type_id_t type) + : body(type) +{ + // static assertions for target. These would go in a header, + // but Metrowerks only respects BOOST_STATIC_ASSERT if it is in an + // instantiated function +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +#else +#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + registry::insert(*this); +} + +wrapper_base::~wrapper_base() +{ + if (can_unregister()) + registry::remove(*this); +} + +}}} // namespace boost::python::converter diff --git a/src/cross_module.cpp b/src/cross_module.cpp index 5949be4d..2bce5a61 100644 --- a/src/cross_module.cpp +++ b/src/cross_module.cpp @@ -15,7 +15,8 @@ namespace python = boost::python; # include // MSVC6.0SP4 does not know std::fprintf # include // MSVC6.0SP4 does not know std::strcmp -namespace { +namespace +{ PyObject* get_module_dict(const char* module_name) { @@ -26,64 +27,68 @@ namespace { } } -namespace boost { namespace python { namespace detail { +namespace boost { namespace python { -const char* converters_attribute_name = "__converters__"; - -void* import_converter_object(const std::string& module_name, - const std::string& py_class_name, - const std::string& attribute_name) +namespace detail { - static std::string err; - PyObject* module_dict = get_module_dict(const_cast(module_name.c_str())); - PyObject* py_class = PyDict_GetItemString(module_dict, const_cast(py_class_name.c_str())); - if (py_class == 0) { - err = std::string("module ") + module_name + " has no attribute " + py_class_name; - PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); - throw python::import_error(); - } - python::ref c_obj(PyObject_GetAttrString(py_class, const_cast(attribute_name.c_str())), ref::null_ok); - if (c_obj.get() == 0) { - err = std::string("object ") + module_name + "." + py_class_name + BOOST_PYTHON_DECL const char* converters_attribute_name = "__converters__"; + + BOOST_PYTHON_DECL void* import_converter_object(const std::string& module_name, + const std::string& py_class_name, + const std::string& attribute_name) + { + static std::string err; + PyObject* module_dict = get_module_dict(const_cast(module_name.c_str())); + PyObject* py_class = PyDict_GetItemString(module_dict, const_cast(py_class_name.c_str())); + if (py_class == 0) { + err = std::string("module ") + module_name + " has no attribute " + py_class_name; + PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); + throw python::import_error(); + } + python::ref c_obj(PyObject_GetAttrString(py_class, const_cast(attribute_name.c_str())), ref::null_ok); + if (c_obj.get() == 0) { + err = std::string("object ") + module_name + "." + py_class_name + " has no attribute " + attribute_name; - PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); - throw python::import_error(); - } - if (! PyCObject_Check(c_obj.get())) { - err = std::string("object ") + module_name + "." + py_class_name + "." + PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); + throw python::import_error(); + } + if (! PyCObject_Check(c_obj.get())) { + err = std::string("object ") + module_name + "." + py_class_name + "." + attribute_name + " is not a PyCObject"; - PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); - throw python::import_error(); - } - return PyCObject_AsVoidPtr(c_obj.get()); + PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); + throw python::import_error(); + } + return PyCObject_AsVoidPtr(c_obj.get()); + } + + BOOST_PYTHON_DECL void check_export_converters_api(const int importing_major, + const int importing_minor, + const int imported_major, + const int imported_minor) + { + if (importing_major != imported_major) { + // Python uses fprintf(stderr, ...) for API warnings. + fprintf(stderr, + "Fatal: export_converters_api mismatch:" + " Importing module = %d.%d" + " Imported module = %d.%d\n", + importing_major, importing_minor, + imported_major, imported_minor); + PyErr_SetString(PyExc_RuntimeError, + "Fatal: export_converters_api mismatch"); + throw import_error(); + } + if (importing_minor != imported_minor) { + // Python uses fprintf(stderr, ...) for API warnings. + fprintf(stderr, + "Warning: export_converters_api mismatch:" + " Importing module = %d.%d" + " Imported module = %d.%d\n", + importing_major, importing_minor, + imported_major, imported_minor); + } + } + } -void check_export_converters_api(const int importing_major, - const int importing_minor, - const int imported_major, - const int imported_minor) -{ - if (importing_major != imported_major) { - // Python uses fprintf(stderr, ...) for API warnings. - fprintf(stderr, - "Fatal: export_converters_api mismatch:" - " Importing module = %d.%d" - " Imported module = %d.%d\n", - importing_major, importing_minor, - imported_major, imported_minor); - PyErr_SetString(PyExc_RuntimeError, - "Fatal: export_converters_api mismatch"); - throw import_error(); - } - if (importing_minor != imported_minor) { - // Python uses fprintf(stderr, ...) for API warnings. - fprintf(stderr, - "Warning: export_converters_api mismatch:" - " Importing module = %d.%d" - " Imported module = %d.%d\n", - importing_major, importing_minor, - imported_major, imported_minor); - } -} - -}}} // namespace boost::python::detail +}} // namespace boost::python::detail diff --git a/src/errors.cpp b/src/errors.cpp new file mode 100644 index 00000000..1290df50 --- /dev/null +++ b/src/errors.cpp @@ -0,0 +1,68 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#ifndef BOOST_PYTHON_SOURCE +# define BOOST_PYTHON_SOURCE +#endif + +#include + +namespace boost { namespace python { + +// IMPORTANT: this function may only be called from within a catch block! +BOOST_PYTHON_DECL bool handle_exception_impl(function0 f) +{ + try + { + f(); + return false; + } + catch(const boost::python::error_already_set&) + { + // The python error reporting has already been handled. + } + catch(const std::bad_alloc&) + { + PyErr_NoMemory(); + } + catch(const std::exception& x) + { + PyErr_SetString(PyExc_RuntimeError, x.what()); + } + catch(...) + { + PyErr_SetString(PyExc_RuntimeError, "unidentifiable C++ exception"); + } + return true; +} + +BOOST_PYTHON_DECL PyObject* expect_non_null(PyObject* x) +{ + if (x == 0) + throw error_already_set(); + return x; +} + +namespace detail { + + BOOST_PYTHON_DECL void expect_complex(PyObject* p) + { + if (!PyComplex_Check(p)) + { + PyErr_SetString(PyExc_TypeError, "expected a complex number"); + throw boost::python::argument_error(); + } + } + +// needed by void_adaptor (see void_adaptor.hpp) +BOOST_PYTHON_DECL PyObject arbitrary_object = { 0 }; + + +} // namespace boost::python::detail + +}} // namespace boost::python + + diff --git a/src/extension_class.cpp b/src/extension_class.cpp index e9183c82..f8bcf9ad 100644 --- a/src/extension_class.cpp +++ b/src/extension_class.cpp @@ -12,6 +12,7 @@ #define BOOST_PYTHON_SOURCE #include +#include #include #include #include @@ -52,7 +53,7 @@ BOOST_PYTHON_END_CONVERSION_NAMESPACE namespace boost { namespace python { -tuple standard_coerce(ref l, ref r) +BOOST_PYTHON_DECL tuple standard_coerce(ref l, ref r) { // Introduced sequence points for exception-safety. ref first(detail::operator_dispatcher::create(l, l)); @@ -487,21 +488,15 @@ void operator_dispatcher_dealloc(PyObject* self) int operator_dispatcher_coerce(PyObject** l, PyObject** r) { Py_INCREF(*l); - PyObject* new_r = handle_exception( - bind(operator_dispatcher::create, - ref(*r, ref::increment_count), - ref())); - if (new_r) - { - *r = new_r; - return 0; - } - else - { - return -1; - } -} + return handle_exception( + bind_return( + *r + , bind(operator_dispatcher::create, + ref(*r, ref::increment_count), + ref()))) + ? -1 : 0; +} #define PY_DEFINE_OPERATOR(id, symbol) \ PyObject* operator_dispatcher_call_##id(PyObject* left, PyObject* right) \ diff --git a/src/gen_call.py b/src/gen_call.py new file mode 100644 index 00000000..dd178648 --- /dev/null +++ b/src/gen_call.py @@ -0,0 +1,82 @@ +# (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and +# distribute this software is granted provided this copyright notice appears +# in all copies. This software is provided "as is" without express or implied +# warranty, and with no claim as to its suitability for any purpose. +# +# This work was funded in part by Lawrence Berkeley National Labs + +from gen_function import * +import string + +header = '''// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +// +// This work was funded in part by Lawrence Berkeley National Labs +// +// This file generated for %d-argument member functions and %d-argument free +// functions by gen_call.py + +#ifndef CALL_DWA20011214_HPP +# define CALL_DWA20011214_HPP + +# include + +namespace boost { namespace python { + +''' +_cv_qualifiers = ('', ' const', ' volatile', ' const volatile') + +def gen_call(member_function_args, free_function_args = None): + if free_function_args is None: + free_function_args = member_function_args + 1 + + return (header % (member_function_args, free_function_args) + + gen_functions( +'''template +PyObject* call(R (*f)(%(A%n%:, %)), PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +''', free_function_args) + + +'''// Member functions +''' + + reduce(lambda x,y: x+y + , map(lambda cv: + gen_functions( +'''template +PyObject* call(R (A0::*f)(%(A%+%:, %))%1, PyObject* args, PyObject* keywords) +{ + return detail::returning::call(f, args, keywords); +} + +''' + , member_function_args, cv) + , _cv_qualifiers)) + + +''' +}} // namespace boost::python + +#endif // CALL_DWA20011214_HPP +''') + +if __name__ == '__main__': + import sys + + if len(sys.argv) == 1: + member_function_args = 5 + free_function_args = 6 + else: + member_function_args = int(sys.argv[1]) + if len(sys.argv) > 2: + free_function_args = int(sys.argv[2]) + else: + free_function_args = member_function_args + + print gen_call(member_function_args, free_function_args) + + diff --git a/src/gen_returning.py b/src/gen_returning.py new file mode 100644 index 00000000..2b112cc0 --- /dev/null +++ b/src/gen_returning.py @@ -0,0 +1,191 @@ +# (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and +# distribute this software is granted provided this copyright notice appears +# in all copies. This software is provided "as is" without express or implied +# warranty, and with no claim as to its suitability for any purpose. +# +# This work was funded in part by Lawrence Berkeley National Labs + +from gen_function import * +import string + +header = '''// (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and +// distribute this software is granted provided this copyright notice appears +// in all copies. This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// This work was funded in part by Lawrence Berkeley National Labs +// +// This file generated for %d-argument member functions and %d-argument free +// functions by gen_returning.py +''' + +body_sections = ( +''' +#ifndef RETURNING_DWA20011201_HPP +# define RETURNING_DWA20011201_HPP + +//# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace detail { + +// Calling C++ from Python +template +struct returning +{ +''', +''' +''', +''' // Free functions +''', +'''}; + +template <> +struct returning +{ + typedef void R; +''', +''' +''', +''' + // Free functions +''', +'''}; + +}}} // namespace boost::python::detail + +#endif // RETURNING_DWA20011201_HPP +''') + +#' + +member_function = ''' template + static PyObject* call(R (A0::*pmf)(%(A%+%:, %))%1, PyObject* args, PyObject* /* keywords */ ) + { + // check that each of the arguments is convertible + unwrap c0(PyTuple_GET_ITEM(args, 0)); +%( unwrap_more c%+(PyTuple_GET_ITEM(args, %+), c%n); +%) +%[r%: // find the result converter + wrap_more r(c%n); +%] if (!c0) return 0; + %[r%:return r( %]((*c0).*pmf)(%(*c%+%:, %))%[r%: )%];%[v%: + return detail::none();%] + }; +''' + +free_function = '''%{ template <%(class A%n%:, %)> +%} static PyObject* call(R (*pf)(%(A%n%:, %)), PyObject*%{ args%}, PyObject* /* keywords */ ) + {%{ + // check that each of the arguments is convertible +%}%( unwrap%{_more%} c%n(PyTuple_GET_ITEM(args, %n)%{, c%-%}); +%)%[r%: + // find the result converter + wrap%{_more%} r%{(c%-)%};%]%{ + if (!c0) return 0;%} + %[r%:return r( %](*pf)(%(*c%n%:, %))%[r%: )%];%[v%: + return detail::none();%] + }; +''' + +def _returns_value(key, n, args, value): + if key == 'r': + return value + # pass the value through gen_function again for recursive expansion +# return apply(gen_function, (value, n) + args +# , {'fill': _returns_value}) + else: + assert key == 'v' + return '' + +def _returns_void(key, n, args, value): + if key == 'v': + return value + else: + assert key == 'r' + # return the empty string, ignoring the value + return '' + +_cv_qualifiers = ('', ' const', ' volatile', ' const volatile') + +_prefix = { +# ' const': ''' + +# // missing cv-qualified -> cv-unqualified member pointer conversions +# # if defined(__MWERKS__) && __MWERKS__ <=0x2406 || defined(BOOST_MSVC) && BOOST_MSVC <= 1200 || defined(__BORLANDC__) +# ''', + ' const volatile': ''' +// missing const volatile type traits +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +'''}; + +def gen_returning(member_function_args, free_function_args = None): + if free_function_args is None: + free_function_args = member_function_args + 1 + + return_none = '''; + return detail::none();''' + + return (header % (member_function_args, free_function_args) + + body_sections[0] + # + # functions returning results + # + + + reduce(lambda x,y: x+y + , map(lambda cv: + _prefix.get(cv,'') + + gen_functions(member_function, + member_function_args, cv, + fill = _returns_value) + '\n' + , _cv_qualifiers)) + + '''# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +''' +## endif // missing cv-qualified -> cv-unqualified member pointer conversions +#''' + # free functions + + gen_functions(free_function, free_function_args, fill = _returns_value) + + body_sections[3] + + # + # functions returning void + # + + + reduce(lambda x,y: x+y + , map(lambda cv: + _prefix.get(cv,'') + + gen_functions(member_function, + member_function_args, cv, fill = + _returns_void) + '\n' + , _cv_qualifiers)) + + + '''# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +''' +## endif // missing cv-qualified -> cv-unqualified member pointer conversions +#''' + # free functions + + gen_functions(free_function, free_function_args, fill = _returns_void) + + body_sections[6] + ) + +if __name__ == '__main__': + import sys + + if len(sys.argv) == 1: + member_function_args = 5 + free_function_args = 6 + else: + member_function_args = int(sys.argv[1]) + if len(sys.argv) > 2: + free_function_args = int(sys.argv[2]) + else: + free_function_args = member_function_args + + print gen_returning(member_function_args, free_function_args) + + diff --git a/src/module_builder.cpp b/src/module_builder.cpp index bd04a89c..0a195621 100644 --- a/src/module_builder.cpp +++ b/src/module_builder.cpp @@ -16,19 +16,19 @@ namespace { ref name_holder; } -bool module_builder::initializing() +bool module_builder_base::initializing() { return name_holder.get() != 0; } -string module_builder::name() +string module_builder_base::name() { // If this fails, you haven't created a module_builder object assert(initializing()); return string(name_holder); } -module_builder::module_builder(const char* name) +module_builder_base::module_builder_base(const char* name) : m_module(Py_InitModule(const_cast(name), initial_methods)) { // If this fails, you've created more than 1 module_builder object in your module @@ -36,29 +36,29 @@ module_builder::module_builder(const char* name) name_holder = ref(PyObject_GetAttrString(m_module, const_cast("__name__"))); } -module_builder::~module_builder() +module_builder_base::~module_builder_base() { name_holder.reset(); } void -module_builder::add(detail::function* x, const char* name) +module_builder_base::add(detail::function* x, const char* name) { reference f(x); // First take possession of the object. detail::function::add_to_namespace(f, name, PyModule_GetDict(m_module)); } -void module_builder::add(ref x, const char* name) +void module_builder_base::add(ref x, const char* name) { PyObject* dictionary = PyModule_GetDict(m_module); PyDict_SetItemString(dictionary, const_cast(name), x.get()); } -void module_builder::add(PyTypeObject* x, const char* name /*= 0*/) +void module_builder_base::add(PyTypeObject* x, const char* name /*= 0*/) { this->add(ref(as_object(x)), name ? name : x->tp_name); } -PyMethodDef module_builder::initial_methods[] = { { 0, 0, 0, 0 } }; +PyMethodDef module_builder_base::initial_methods[] = { { 0, 0, 0, 0 } }; }} // namespace boost::python diff --git a/src/object/class.cpp b/src/object/class.cpp new file mode 100644 index 00000000..cc3903e3 --- /dev/null +++ b/src/object/class.cpp @@ -0,0 +1,165 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace python { namespace object { + +holder_base::holder_base(converter::type_id_t id) + : m_type(id) + , m_next(0) +{ +} + +holder_base::~holder_base() +{ +} + +//BOOST_PYTHON_EXPORT +PyTypeObject class_metatype_object = { + PyObject_HEAD_INIT(0)//&PyType_Type) + 0, + "Boost.Python.class", + PyType_Type.tp_basicsize, + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | // Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, //&PyType_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, + // PyType_GenericNew /* tp_new */ +}; + +//BOOST_PYTHON_EXPORT +PyTypeObject class_type_object = { + PyObject_HEAD_INIT(0) //&class_metatype_object) + 0, + "Boost.Python.instance", + sizeof(instance), + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, //&PyBaseObject_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew +}; + +BOOST_PYTHON_EXPORT PyTypeObject* class_metatype() +{ + if (class_metatype_object.tp_dict == 0) + { + class_metatype_object.ob_type = &PyType_Type; + class_metatype_object.tp_base = &PyType_Type; + if (PyType_Ready(&class_metatype_object)) + return 0; + } + Py_INCREF(&class_metatype_object); + return &class_metatype_object; +} + +BOOST_PYTHON_EXPORT PyTypeObject* class_type() +{ + if (class_type_object.tp_dict == 0) + { + class_type_object.ob_type = class_metatype(); + class_type_object.tp_base = &PyBaseObject_Type; + if (PyType_Ready(&class_type_object)) + return 0; + } + Py_INCREF(&class_type_object); + return &class_type_object; +} + +void holder_base::install(PyObject* self) +{ + assert(self->ob_type->ob_type == &class_metatype_object); + m_next = ((instance*)self)->objects; + ((instance*)self)->objects = this; +} + +BOOST_PYTHON_EXPORT holder_base* +find_holder_impl(PyObject* inst, converter::type_id_t type) +{ + if (inst->ob_type->ob_type != &class_metatype_object) + return 0; + instance* self = reinterpret_cast(inst); + + holder_base::iterator match = std::find_if( + holder_base::iterator(self->objects), holder_base::iterator(0) + , bind(std::equal_to() + , bind(mem_fn(&holder_base::type), _1) + , type)); + + return match != holder_base::iterator(0) + ? match.base() : 0; +} + +}}} // namespace boost::python::object diff --git a/src/object/function.cpp b/src/object/function.cpp new file mode 100644 index 00000000..4c2de3c7 --- /dev/null +++ b/src/object/function.cpp @@ -0,0 +1,95 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include + +namespace boost { namespace python { namespace object { + + +function::function(py_function implementation) + : m_fn(implementation) +{ + PyObject* p = this; + PyObject_INIT(p, &function_type); +} + +function::~function() +{ +} + +PyObject* function::call(PyObject* args, PyObject* keywords) const +{ + return m_fn(args, keywords); +} + +extern "C" +{ + // Stolen from Python's funcobject.c + static PyObject * + function_descr_get(PyObject *func, PyObject *obj, PyObject *type) + { + if (obj == Py_None) + obj = NULL; + return PyMethod_New(func, obj, type); + } + + static void + function_dealloc(PyObject* p) + { + delete static_cast(p); + } + + static PyObject * + function_call(PyObject *func, PyObject *arg, PyObject *kw) + { + return static_cast(func)->call(arg, kw); + } +} + +PyTypeObject function_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "Boost.Python.function", + sizeof(function), + 0, + (destructor)function_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, //(reprfunc)func_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + function_call, /* tp_call */ + 0, /* tp_str */ + 0, // PyObject_GenericGetAttr, /* tp_getattro */ + 0, // PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */ + 0, /* tp_doc */ + 0, // (traverseproc)func_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, //offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, // func_memberlist, /* tp_members */ + 0, //func_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + function_descr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, //offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, + 0 /* tp_new */ +}; + +}}} // namespace boost::python::object diff --git a/src/objects.cpp b/src/objects.cpp index 70257388..90417dac 100644 --- a/src/objects.cpp +++ b/src/objects.cpp @@ -51,42 +51,42 @@ PyObject* object::get() const BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE -PyObject* to_python(const boost::python::tuple& x) +BOOST_PYTHON_DECL PyObject* to_python(const boost::python::tuple& x) { return object_to_python(x); } -boost::python::tuple from_python(PyObject* p, boost::python::type type) +BOOST_PYTHON_DECL boost::python::tuple from_python(PyObject* p, boost::python::type type) { return boost::python::object_from_python(p, type); } -PyObject* to_python(const boost::python::list& x) +BOOST_PYTHON_DECL PyObject* to_python(const boost::python::list& x) { return object_to_python(x); } -boost::python::list from_python(PyObject* p, boost::python::type type) +BOOST_PYTHON_DECL boost::python::list from_python(PyObject* p, boost::python::type type) { return boost::python::object_from_python(p, type); } -PyObject* to_python(const boost::python::dictionary& x) +BOOST_PYTHON_DECL PyObject* to_python(const boost::python::dictionary& x) { return object_to_python(x); } -boost::python::dictionary from_python(PyObject* p, boost::python::type type) +BOOST_PYTHON_DECL boost::python::dictionary from_python(PyObject* p, boost::python::type type) { return boost::python::object_from_python(p, type); } -PyObject* to_python(const boost::python::string& x) +BOOST_PYTHON_DECL PyObject* to_python(const boost::python::string& x) { return object_to_python(x); } -boost::python::string from_python(PyObject* p, boost::python::type type) +BOOST_PYTHON_DECL boost::python::string from_python(PyObject* p, boost::python::type type) { return boost::python::object_from_python(p, type); } @@ -95,14 +95,14 @@ BOOST_PYTHON_END_CONVERSION_NAMESPACE namespace boost { namespace python { -tuple::tuple(std::size_t n) +tuple_base::tuple_base(std::size_t n) : object(ref(PyTuple_New(n))) { for (std::size_t i = 0; i < n; ++i) PyTuple_SET_ITEM(get(), i, detail::none()); } -tuple::tuple(ref p) +tuple_base::tuple_base(ref p) : object(p) { assert(accepts(p)); @@ -113,28 +113,28 @@ tuple::tuple(ref p) } } -PyTypeObject* tuple::type_obj() +PyTypeObject* tuple_base::type_obj() { return &PyTuple_Type; } -bool tuple::accepts(ref p) +bool tuple_base::accepts(ref p) { return PyTuple_Check(p.get()); } -std::size_t tuple::size() const +std::size_t tuple_base::size() const { return PyTuple_Size(get()); } -ref tuple::operator[](std::size_t pos) const +ref tuple_base::operator[](std::size_t pos) const { return ref(PyTuple_GetItem(get(), static_cast(pos)), ref::increment_count); } -void tuple::set_item(std::size_t pos, const ref& rhs) +void tuple_base::set_item(std::size_t pos, const ref& rhs) { int failed = PyTuple_SetItem( get(), static_cast(pos), ref(rhs).release()); // A reference is stolen here. @@ -142,14 +142,14 @@ void tuple::set_item(std::size_t pos, const ref& rhs) assert(failed == 0); } -tuple tuple::slice(int low, int high) const +tuple tuple_base::slice(int low, int high) const { return tuple(ref(PyTuple_GetSlice(get(), low, high))); } -tuple& tuple::operator+=(const tuple& rhs) +BOOST_PYTHON_DECL tuple& operator+=(tuple& self, const tuple& rhs) { - return *this = *this + rhs; + return self = self + rhs; } @@ -216,7 +216,7 @@ string& string::operator*=(unsigned int repeat_count) return *this; } -dictionary::dictionary(ref p) +dictionary_base::dictionary_base(ref p) : object(p) { assert(accepts(p)); @@ -227,49 +227,49 @@ dictionary::dictionary(ref p) } } -dictionary::dictionary() +dictionary_base::dictionary_base() : object(ref(PyDict_New())) {} -PyTypeObject* dictionary::type_obj() +PyTypeObject* dictionary_base::type_obj() { return &PyDict_Type; } -bool dictionary::accepts(ref p) +bool dictionary_base::accepts(ref p) { return PyDict_Check(p.get()); } -void dictionary::clear() +void dictionary_base::clear() { PyDict_Clear(get()); } -const ref& dictionary::proxy::operator=(const ref& rhs) +const ref& dictionary_proxy::operator=(const ref& rhs) { if (PyDict_SetItem(m_dict.get(), m_key.get(), rhs.get()) == -1) throw error_already_set(); return rhs; } -dictionary::proxy::operator ref() const +dictionary_proxy::operator ref() const { return ref(m_dict->ob_type->tp_as_mapping->mp_subscript(m_dict.get(), m_key.get()), ref::increment_count); } -dictionary::proxy::proxy(const ref& dict, const ref& key) +dictionary_proxy::dictionary_proxy(const ref& dict, const ref& key) : m_dict(dict), m_key(key) {} -dictionary::proxy dictionary::operator[](ref key) +dictionary_proxy dictionary_base::operator[](ref key) { return proxy(reference(), key); } -ref dictionary::operator[](ref key) const { +ref dictionary_base::operator[](ref key) const { // An odd MSVC bug causes the ".operator Ptr()" to be needed return proxy(reference(), key).operator ref(); } -ref dictionary::get_item(const ref& key) const +ref dictionary_base::get_item(const ref& key) const { return get_item(key, ref()); } -ref dictionary::get_item(const ref& key, const ref& default_) const +ref dictionary_base::get_item(const ref& key, const ref& default_) const { PyObject* value_or_null = PyDict_GetItem(get(), key.get()); if (value_or_null == 0 && !PyErr_Occurred()) @@ -278,22 +278,22 @@ ref dictionary::get_item(const ref& key, const ref& default_) const return ref(value_or_null, ref::increment_count); // Will throw if there was another error } -void dictionary::set_item(const ref& key, const ref& value) +void dictionary_base::set_item(const ref& key, const ref& value) { if (PyDict_SetItem(get(), key.get(), value.get()) == -1) throw error_already_set(); } -void dictionary::erase(ref key) { +void dictionary_base::erase(ref key) { if (PyDict_DelItem(get(), key.get()) == -1) throw error_already_set(); } -list dictionary::items() const { return list(ref(PyDict_Items(get()))); } -list dictionary::keys() const { return list(ref(PyDict_Keys(get()))); } -list dictionary::values() const { return list(ref(PyDict_Values(get()))); } +list dictionary_base::items() const { return list(ref(PyDict_Items(get()))); } +list dictionary_base::keys() const { return list(ref(PyDict_Keys(get()))); } +list dictionary_base::values() const { return list(ref(PyDict_Values(get()))); } -std::size_t dictionary::size() const { return static_cast(PyDict_Size(get())); } +std::size_t dictionary_base::size() const { return static_cast(PyDict_Size(get())); } string operator+(string x, string y) { @@ -338,7 +338,7 @@ tuple operator+(const tuple& x, const tuple& y) } -list::list(ref p) +list_base::list_base(ref p) : object(p) { assert(accepts(p)); @@ -349,97 +349,97 @@ list::list(ref p) } } -list::list(std::size_t sz) +list_base::list_base(std::size_t sz) : object(ref(PyList_New(sz))) { } -PyTypeObject* list::type_obj() +PyTypeObject* list_base::type_obj() { return &PyList_Type; } -bool list::accepts(ref p) +bool list_base::accepts(ref p) { return PyList_Check(p.get()); } -std::size_t list::size() const +std::size_t list_base::size() const { return PyList_Size(get()); } -ref list::operator[](std::size_t pos) const +ref list_base::operator[](std::size_t pos) const { return ref(PyList_GetItem(get(), pos), ref::increment_count); } -list::proxy list::operator[](std::size_t pos) +list_proxy list_base::operator[](std::size_t pos) { return proxy(reference(), pos); } -void list::insert(std::size_t index, const ref& item) +void list_base::insert(std::size_t index, const ref& item) { if (PyList_Insert(get(), index, item.get()) == -1) throw error_already_set(); } -void list::push_back(const ref& item) +void list_base::push_back(const ref& item) { if (PyList_Append(get(), item.get()) == -1) throw error_already_set(); } -void list::append(const ref& item) +void list_base::append(const ref& item) { this->push_back(item); } -list list::slice(int low, int high) const +list list_base::slice(int low, int high) const { return list(ref(PyList_GetSlice(get(), low, high))); } -list::slice_proxy list::slice(int low, int high) +list_slice_proxy list_base::slice(int low, int high) { - return slice_proxy(reference(), low, high); + return list_slice_proxy(reference(), low, high); } -void list::sort() +void list_base::sort() { if (PyList_Sort(get()) == -1) throw error_already_set(); } -void list::reverse() +void list_base::reverse() { if (PyList_Reverse(get()) == -1) throw error_already_set(); } -tuple list::as_tuple() const +tuple list_base::as_tuple() const { return tuple(ref(PyList_AsTuple(get()))); } -const ref& list::proxy::operator=(const ref& rhs) +const ref& list_proxy::operator=(const ref& rhs) { m_list.set_item(m_index, rhs); return rhs; } -list::proxy::operator ref() const +list_proxy::operator ref() const { return ref(PyList_GetItem(m_list.get(), m_index), ref::increment_count); } -ref list::get_item(std::size_t pos) const +ref list_base::get_item(std::size_t pos) const { return ref(PyList_GetItem(this->get(), pos), ref::increment_count); } -void list::set_item(std::size_t pos, const ref& rhs) +void list_base::set_item(std::size_t pos, const ref& rhs) { int result = PyList_SetItem(this->get(), pos, rhs.get()); if (result == -1) @@ -447,39 +447,39 @@ void list::set_item(std::size_t pos, const ref& rhs) Py_INCREF(rhs.get()); } -list::proxy::proxy(const ref& list, std::size_t index) +list_proxy::list_proxy(const ref& list, std::size_t index) : m_list(list), m_index(index) { } -const list& list::slice_proxy::operator=(const list& rhs) +const list& list_slice_proxy::operator=(const list& rhs) { if (PyList_SetSlice(m_list.get(), m_low, m_high, rhs.get()) == -1) throw error_already_set(); return rhs; } -list::slice_proxy::operator ref() const +list_slice_proxy::operator ref() const { return ref(PyList_GetSlice(m_list.get(), m_low, m_high)); } -list::slice_proxy::operator list() const +list_slice_proxy::operator list() const { return list(this->operator ref()); } -std::size_t list::slice_proxy::size() const +std::size_t list_slice_proxy::size() const { return this->operator list().size(); } -ref list::slice_proxy::operator[](std::size_t pos) const +ref list_slice_proxy::operator[](std::size_t pos) const { return this->operator list()[pos].operator ref(); } -list::slice_proxy::slice_proxy(const ref& list, int low, int high) +list_slice_proxy::list_slice_proxy(const ref& list, int low, int high) : m_list(list), m_low(low), m_high(high) { } diff --git a/src/types.cpp b/src/types.cpp index f411aa42..e76503d2 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -8,6 +8,7 @@ #define BOOST_PYTHON_SOURCE +#include #include #include // for handle_exception() #include @@ -25,9 +26,11 @@ namespace boost { namespace python { -namespace { - +namespace +{ using detail::type_object_base; + using detail::call_object; + // Define a family of forwarding functions that can be called from a // PyTypeObject's slots. These functions dispatch through a (virtual) member @@ -35,7 +38,6 @@ namespace { // uniform way, preventing us from having to rewrite the dispatching code over // and over. - // Given a function object f with signature // // PyObject* f(PyTypeObject*,PyObject*) @@ -43,88 +45,24 @@ namespace { // calls f inside of handle_exception, and returns the result. If an exception // is thrown by f, returns 0. template - PyObject* obj_call(PyObject* obj, F const& f) + PyObject* obj_call(PyObject* obj, F f) { - return handle_exception( - boost::bind(f, static_cast(obj->ob_type), obj)); + PyObject* result; + return call_object(result, obj, f) ? 0 : result; } - - // int_converter/value_holder - // - // A simple function object which converts its argument to a PyObject*. We - // need this because handle_exception needs to return a PyObject*, even if the - // function being called is supposed to return int. It has two parts... - - // holds the value actually returned by the underlying function - template - struct value_holder : PyObject - { - value_holder() : is_set(false), value(-1) {} - - // Tricky constructor allows us to grab the result even if rhs == 0. - explicit value_holder(value_holder const* rhs) - : is_set(rhs ? rhs->is_set : false), value(rhs ? rhs->value : -1) {} - - // true if the function object was ever called (false if an exception occurred) - bool is_set; - - // The returned value - T value; - }; - - // The function object - template - struct int_converter - { - typedef PyObject* result_type; - - PyObject* operator()(R const& x) - { - m_holder.is_set = true; - m_holder.value = x; - return &m_holder; // returns - } - - value_holder m_holder; - }; - - // Call the given int-returning function object inside of handle_exception, - // returning a value_holder. F is a function object with "signature" + // Call the given integer-returning function object inside of + // handle_exception, returning a value_holder. F is a function + // object with "signature" // // R F(PyTypeObject*, PyObject*) // // where R is an integer type. template - value_holder int_call_holder(PyObject* obj, F f) + R int_call(PyObject* obj, F f, R* = 0) { - return value_holder( - - // The int_converter object containing the value_holder is valid - // through the life of the full-expression, so we can construct from - // the pointer - static_cast*>( - handle_exception( - - boost::bind( - // Add an int_converter back-end to f - int_converter() - // Bind the object's type and the object itself into f - , boost::bind(f, static_cast(obj->ob_type), obj) - ) - - ) - ) - ); - } - - // Just like int_call_holder (above), but returns the integer directly. If F - // throws an exception, returns -1 - template - R int_call(PyObject* obj, F f) - { - value_holder const v(int_call_holder(obj, f)); - return v.value; + R result; + return call_object(result, obj, f) ? -1 : result; } // Implemented in terms of obj_call, above @@ -171,27 +109,18 @@ namespace { int call_length_function(PyObject* obj, int (type_object_base::*f)(PyObject*) const) { - value_holder const r(int_call_holder(obj, bind(f, _1, _2))); - - if (!r.is_set) - { + int result; + if (call_object(result, obj, bind(f, _1, _2))) return -1; - } - const int outcome = r.value; - if (outcome >= 0) - return outcome; + if (result >= 0) + return result; PyErr_SetString(PyExc_ValueError, "__len__() should return >= 0"); return -1; } } // anonymous namespace -namespace detail { - // needed by void_adaptor (see void_adaptor.hpp) - PyObject arbitrary_object; -} - extern "C" { // @@ -247,14 +176,11 @@ static PyObject* do_instance_call(PyObject* obj, PyObject* args, PyObject* keywo static void do_instance_dealloc(PyObject* obj) { - PyObject* success = handle_exception( - // translate the void return value of instance_dealloc into a PyObject* - // that can indicate no error. - detail::make_void_adaptor( + if (handle_exception( bind(&type_object_base::instance_dealloc - , static_cast(obj->ob_type) - , obj))); - if (!success) + , static_cast(obj->ob_type) + , obj)) + ) { assert(!"exception during destruction!"); } @@ -300,11 +226,9 @@ static PyObject* do_instance_sq_item(PyObject* obj, int index) return 0; } - return handle_exception( - bind(&type_object_base::instance_sequence_item - , static_cast(obj->ob_type) - , obj - , index)); + return obj_call( + obj + , bind(&type_object_base::instance_sequence_item, _1, _2, index)); } static int do_instance_mp_ass_subscript(PyObject* obj, PyObject* index, PyObject* value) diff --git a/test/complicated.hpp b/test/complicated.hpp new file mode 100644 index 00000000..123c53fe --- /dev/null +++ b/test/complicated.hpp @@ -0,0 +1,39 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef COMPLICATED_DWA20011215_HPP +# define COMPLICATED_DWA20011215_HPP +# include + +# include "simple_type.hpp" + +struct complicated +{ + complicated(simple const&, int = 0); + ~complicated(); + + int get_n() const; + + char* s; + int n; +}; + +inline complicated::complicated(simple const&s, int n) + : s(s.s), n(n) +{ + std::cout << "constructing complicated: " << this->s << ", " << n << std::endl; +} + +inline complicated::~complicated() +{ + std::cout << "destroying complicated: " << this->s << ", " << n << std::endl; +} + +inline int complicated::get_n() const +{ + return n; +} + +#endif // COMPLICATED_DWA20011215_HPP diff --git a/test/m1.cpp b/test/m1.cpp new file mode 100644 index 00000000..f4ad6390 --- /dev/null +++ b/test/m1.cpp @@ -0,0 +1,281 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +// Seems to be neccessary to suppress an ICE with MSVC +#include "boost/mpl/comparison/less.hpp" + +#include "simple_type.hpp" +#include "complicated.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void +dealloc(PyObject* self) +{ + PyObject_Del(self); +} + +struct NoddyObject : PyObject +{ + int x; +}; + +PyTypeObject NoddyType = { + PyObject_HEAD_INIT(NULL) + 0, + "Noddy", + sizeof(NoddyObject), + 0, + dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ +}; + +struct SimpleObject : PyObject +{ + simple x; +}; + +PyTypeObject SimpleType = { + PyObject_HEAD_INIT(NULL) + 0, + "Simple", + sizeof(SimpleObject), + 0, + dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ +}; + +extern "C" PyObject* +new_noddy(PyObject* self, PyObject* args) +{ + NoddyObject* noddy; + + if (!PyArg_ParseTuple(args,":new_noddy")) + return NULL; + + noddy = PyObject_New(NoddyObject, &NoddyType); + noddy->x = 42; + + return (PyObject*)noddy; +} + +extern "C" PyObject* +new_simple(PyObject* self, PyObject* args) +{ + SimpleObject* simple; + + if (!PyArg_ParseTuple(args,":new_simple")) + return NULL; + + simple = PyObject_New(SimpleObject, &SimpleType); + simple->x.s = "hello, world"; + + return (PyObject*)simple; +} + +static PyMethodDef methods[] = { + { "new_noddy", new_noddy, METH_VARARGS }, + { "new_simple", new_simple, METH_VARARGS }, + {0, 0, 0, 0} +}; + +struct int_wrapper + : boost::python::converter::wrapper +{ + PyObject* convert(int const& x) const + { + return PyInt_FromLong(x); + } +}; + +struct simple_wrapper + : boost::python::converter::wrapper +{ + PyObject* convert(simple const& x) const + { + SimpleObject* p = PyObject_New(SimpleObject, &SimpleType); + p->x = x; + return p; + } +}; + +struct simple_ref_wrapper + : boost::python::converter::wrapper +{ + PyObject* convert(simple& x) const + { + SimpleObject* p = PyObject_New(SimpleObject, &SimpleType); + p->x = x; + return p; + } +}; + +struct native_int_unwrapper + : boost::python::converter::unwrapper +{ + bool convertible(PyObject* p) const + { + return PyInt_Check(p); + } + + int convert(PyObject* p, void*&) const + { + return PyInt_AsLong(p); + } +}; + +struct noddy_int_unwrapper + : boost::python::converter::unwrapper +{ + bool convertible(PyObject* p) const + { + return p->ob_type == &NoddyType; + } + + int convert(PyObject* p, void*&) const + { + return static_cast(p)->x; + } +}; + +struct noddy_int_ref_unwrapper + : boost::python::converter::unwrapper +{ + bool convertible(PyObject* p) const + { + return p->ob_type == &NoddyType; + } + + int& convert(PyObject* p, void*&) const + { + return static_cast(p)->x; + } +}; + +struct simple_ref_unwrapper + : boost::python::converter::unwrapper +{ + bool convertible(PyObject* p) const + { + return p->ob_type == &SimpleType; + } + + simple& convert(PyObject* p, void*&) const + { + return static_cast(p)->x; + } +}; + +struct simple_const_ref_unwrapper + : boost::python::converter::unwrapper +{ + bool convertible(PyObject* p) const + { + return p->ob_type == &SimpleType; + } + + simple const& convert(PyObject* p, void*&) const + { + return static_cast(p)->x; + } +}; + +int f(simple const& s) +{ + return strlen(s.s); +} + +simple const& g(simple const& x) +{ + return x; +} + +BOOST_PYTHON_MODULE_INIT(m1) +{ + PyObject* m1 = Py_InitModule(const_cast("m1"), methods); + + static int_wrapper wrap_int; + static simple_wrapper wrap_simple; + static native_int_unwrapper unwrap_int1; + static noddy_int_unwrapper unwrap_int2; + static noddy_int_ref_unwrapper unwrap_int3; + static simple_ref_unwrapper unwrap_simple; +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + // These compilers will need additional converters + static simple_const_ref_unwrapper unwrap_simple_const_ref; + static simple_ref_wrapper wrap_simple_ref; +#endif + static boost::python::object::class_unwrapper unwrap_complicated; + + PyObject* d = PyModule_GetDict(m1); + if (d == NULL) + return; + + if (PyDict_SetItemString( + d, "xclass", (PyObject *)boost::python::object::class_metatype()) < 0) + return; + + if (PyDict_SetItemString( + d, "xinst", (PyObject *)boost::python::object::class_type()) < 0) + return; + + if (PyDict_SetItemString( + d, "f", boost::python::make_function(f)) < 0) + return; + + if (PyDict_SetItemString( + d, "g", boost::python::make_function(g)) < 0) + return; + + if (PyDict_SetItemString( + d, "get_n", boost::python::make_function(&complicated::get_n)) < 0) + return; + + if (PyDict_SetItemString( + d, "init1" + , boost::python::make_constructor< + complicated + , boost::mpl::type_list + , boost::python::object::value_holder_generator>() + ) < 0) + return; + + if (PyDict_SetItemString( + d, "init2" + , boost::python::make_constructor< + complicated + , boost::mpl::type_list + , boost::python::object::value_holder_generator>() + ) < 0) + return; +} + +#include "module_tail.cpp" diff --git a/test/m2.cpp b/test/m2.cpp new file mode 100644 index 00000000..d2093a20 --- /dev/null +++ b/test/m2.cpp @@ -0,0 +1,197 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include +#include +#include "simple_type.hpp" + +using boost::python::wrap; +using boost::python::unwrap; + +extern "C" { + PyObject* + unwrap_simple(PyObject* self, PyObject* args) + { + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + boost::python::unwrap in(p); + if (!in) + return 0; + + simple x = *in; + + return PyString_FromString(x.s); + }; + + PyObject* + unwrap_simple_ref(PyObject* self, PyObject* args) + { + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + unwrap in(p); + if (!in) + return 0; + + simple& x = *in; + + return PyString_FromString(x.s); + }; + + PyObject* + unwrap_simple_const_ref(PyObject* self, PyObject* args) + { + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + unwrap in(p); + if (!in) + return 0; + + simple const& x = *in; + + return PyString_FromString(x.s); + }; + + PyObject* + unwrap_int(PyObject* self, PyObject* args) + { + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + unwrap in(p); + if (!in) + return 0; + + int x = *in; + + return PyInt_FromLong(x); + }; + + PyObject* + unwrap_int_ref(PyObject* self, PyObject* args) + { + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + unwrap in(p); + if (!in) + return 0; + + int& x = *in; + + return PyInt_FromLong(x); + }; + + PyObject* + unwrap_int_const_ref(PyObject* self, PyObject* args) + { + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + unwrap in(p); + if (!in) + return 0; + + int const& x = *in; + + return PyInt_FromLong(x); + }; + + // ------------------- +} +template struct xxxx; + +template +PyObject* +rewrap(PyObject* self, PyObject* args, xxxx* = 0) +{ + PyObject* p; + if (!PyArg_ParseTuple(args, "O", &p)) + return 0; + + boost::python::unwrap in(p); + if (!in) + return 0; + + boost::python::wrap out; + if (!out) + return 0; + + T x = *in; + return out(x); +} + +extern "C" +{ + PyObject* + wrap_simple(PyObject* self, PyObject* args) + { + return rewrap(self, args); + }; + + PyObject* + wrap_simple_ref(PyObject* self, PyObject* args) + { + return rewrap(self, args); + }; + + PyObject* + wrap_simple_const_ref(PyObject* self, PyObject* args) + { + return rewrap(self, args); + }; + + PyObject* + wrap_int(PyObject* self, PyObject* args) + { + return rewrap(self, args); + }; + + PyObject* + wrap_int_ref(PyObject* self, PyObject* args) + { + return rewrap(self, args); + }; + + PyObject* + wrap_int_const_ref(PyObject* self, PyObject* args) + { + return rewrap(self, args); + }; +} + +PyMethodDef initial_methods[] = +{ + { "unwrap_int", unwrap_int, METH_VARARGS, 0 }, + { "unwrap_int_ref", unwrap_int_ref, METH_VARARGS, 0 }, + { "unwrap_int_const_ref", unwrap_int_const_ref, METH_VARARGS, 0 }, + { "unwrap_simple", unwrap_simple, METH_VARARGS, 0 }, + { "unwrap_simple_ref", unwrap_simple_ref, METH_VARARGS, 0 }, + { "unwrap_simple_const_ref", unwrap_simple_const_ref, METH_VARARGS, 0 }, + + { "wrap_int", wrap_int, METH_VARARGS, 0 }, + { "wrap_int_ref", wrap_int_ref, METH_VARARGS, 0 }, + { "wrap_int_const_ref", wrap_int_const_ref, METH_VARARGS, 0 }, + { "wrap_simple", wrap_simple, METH_VARARGS, 0 }, + { "wrap_simple_ref", wrap_simple_ref, METH_VARARGS, 0 }, + { "wrap_simple_const_ref", wrap_simple_const_ref, METH_VARARGS, 0 }, + { 0, 0, 0, 0 } +}; + +BOOST_PYTHON_MODULE_INIT(m2) +{ + Py_InitModule(const_cast("m2"), initial_methods); +} + +#include "module_tail.cpp" diff --git a/test/module_tail.cpp b/test/module_tail.cpp new file mode 100644 index 00000000..6849bf83 --- /dev/null +++ b/test/module_tail.cpp @@ -0,0 +1,39 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#if defined(_WIN32) +# ifdef __MWERKS__ +# pragma ANSI_strict off +# endif +# include +# ifdef __MWERKS__ +# pragma ANSI_strict reset +# endif + +extern "C" BOOL WINAPI DllMain ( HINSTANCE hInst, DWORD wDataSeg, LPVOID lpvReserved ); + +# ifdef BOOST_MSVC +extern "C" void structured_exception_translator(unsigned int, EXCEPTION_POINTERS*) +{ + throw; +} +# endif + +BOOL WINAPI DllMain( + HINSTANCE, //hDllInst + DWORD fdwReason, + LPVOID // lpvReserved + ) +{ +# ifdef BOOST_MSVC + _set_se_translator(structured_exception_translator); +# endif + (void)fdwReason; // warning suppression. + + return 1; +} +#endif // _WIN32 + diff --git a/test/newtest.py b/test/newtest.py new file mode 100644 index 00000000..783e2240 --- /dev/null +++ b/test/newtest.py @@ -0,0 +1,95 @@ +""" +>>> from m1 import * + +>>> from m2 import * + +>>> n = new_noddy() +>>> s = new_simple() +>>> unwrap_int(n) +42 +>>> unwrap_int_ref(n) +42 +>>> unwrap_int_const_ref(n) +42 +>>> unwrap_simple(s) +'hello, world' +>>> unwrap_simple_ref(s) +'hello, world' +>>> unwrap_simple_const_ref(s) +'hello, world' +>>> unwrap_int(5) +5 + +Can't get a reference to a built-in integer object +>>> try: +... unwrap_int_ref(7) +... except: pass +... else: print 'no exception' + +>>> try: +... unwrap_int_const_ref(9) +... except: pass +... else: print 'no exception' + +>>> wrap_int(n) +42 + +try: wrap_int_ref(n) +... except: pass +... else: print 'no exception' + +>>> wrap_int_const_ref(n) +42 + +>>> unwrap_simple_ref(wrap_simple(s)) +'hello, world' + +>>> unwrap_simple_ref(wrap_simple_ref(s)) +'hello, world' + +>>> unwrap_simple_ref(wrap_simple_const_ref(s)) +'hello, world' + +>>> f(s) +12 + +>>> unwrap_simple(g(s)) +'hello, world' + +>>> f(g(s)) +12 + +>>> C = xclass('C', (xinst,), {'__init__': init1, 'get_n': get_n}) +>>> c = C(s, 99) +>>> c.get_n() +99 + +>>> D = xclass('D', (xinst,), {'__init__': init2, 'get_n': get_n}) +>>> d = D(s) +>>> d.get_n() +0 + +""" + +def run(args = None): + + ### Strange bug somewhere: with Metrowerks: it will crash in + ### garbage-collection code unless traceback and sre have been + ### loaded before m1. + +# import traceback +# import sre +# import m2 +# import m1 + import sys + import doctest + + if args is not None: + sys.argv = args + # import sys + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + sys.exit(run()[0]) diff --git a/test/simple_type.hpp b/test/simple_type.hpp new file mode 100644 index 00000000..2df97cfd --- /dev/null +++ b/test/simple_type.hpp @@ -0,0 +1,14 @@ +// Copyright David Abrahams 2001. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef SIMPLE_TYPE_DWA2001128_HPP +# define SIMPLE_TYPE_DWA2001128_HPP + +struct simple +{ + char* s; +}; + +#endif // SIMPLE_TYPE_DWA2001128_HPP