From 2e5d8dbff7620d618c1e1fccb679452a3501eb15 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 26 Nov 2000 15:49:26 +0000 Subject: [PATCH 001/154] This commit was generated by cvs2svn to compensate for changes in r711, which included commits to RCS files with non-trunk default branches. [SVN r8328] --- .gitattributes | 96 ++ doc/#index.html# | 212 +++ doc/building.html | 43 + doc/comparisons.html | 220 +++ doc/enums.html | 94 ++ doc/example1.html | 129 ++ doc/extending.html | 73 + doc/index.html | 211 +++ doc/inheritance.html | 165 +++ doc/overloading.html | 156 ++ doc/overriding.html | 195 +++ doc/pointers.html | 145 ++ doc/special.html | 888 ++++++++++++ doc/template.html | 26 + doc/under-the-hood.html | 62 + example/example1.cpp | 54 + example/example1.py | 50 + include/boost/python/callback.hpp | 829 +++++++++++ include/boost/python/caller.hpp | 1279 +++++++++++++++++ include/boost/python/class_builder.hpp | 156 ++ include/boost/python/classes.hpp | 527 +++++++ include/boost/python/conversions.hpp | 325 +++++ include/boost/python/detail/base_object.hpp | 62 + include/boost/python/detail/cast.hpp | 81 ++ include/boost/python/detail/config.hpp | 56 + .../boost/python/detail/extension_class.hpp | 834 +++++++++++ include/boost/python/detail/functions.hpp | 306 ++++ include/boost/python/detail/init_function.hpp | 507 +++++++ include/boost/python/detail/none.hpp | 21 + include/boost/python/detail/signatures.hpp | 251 ++++ include/boost/python/detail/singleton.hpp | 68 + include/boost/python/detail/types.hpp | 389 +++++ include/boost/python/detail/wrap_python.hpp | 61 + include/boost/python/errors.hpp | 30 + include/boost/python/module_builder.hpp | 53 + include/boost/python/objects.hpp | 334 +++++ include/boost/python/operators.hpp | 504 +++++++ include/boost/python/reference.hpp | 173 +++ src/classes.cpp | 884 ++++++++++++ src/conversions.cpp | 241 ++++ src/extension_class.cpp | 683 +++++++++ src/functions.cpp | 167 +++ src/gen_all.py | 26 + src/gen_callback.py | 124 ++ src/gen_caller.py | 138 ++ src/gen_extclass.py | 830 +++++++++++ src/gen_function.py | 184 +++ src/gen_init_function.py | 166 +++ src/gen_signatures.py | 158 ++ src/gen_singleton.py | 58 + src/init_function.cpp | 36 + src/module_builder.cpp | 52 + src/objects.cpp | 485 +++++++ src/types.cpp | 1097 ++++++++++++++ test/comprehensive.cpp | 1133 +++++++++++++++ test/comprehensive.hpp | 231 +++ test/comprehensive.py | 1087 ++++++++++++++ 57 files changed, 17445 insertions(+) create mode 100644 .gitattributes create mode 100644 doc/#index.html# create mode 100644 doc/building.html create mode 100644 doc/comparisons.html create mode 100644 doc/enums.html create mode 100644 doc/example1.html create mode 100644 doc/extending.html create mode 100644 doc/index.html create mode 100644 doc/inheritance.html create mode 100644 doc/overloading.html create mode 100644 doc/overriding.html create mode 100644 doc/pointers.html create mode 100644 doc/special.html create mode 100644 doc/template.html create mode 100644 doc/under-the-hood.html create mode 100644 example/example1.cpp create mode 100644 example/example1.py create mode 100644 include/boost/python/callback.hpp create mode 100644 include/boost/python/caller.hpp create mode 100644 include/boost/python/class_builder.hpp create mode 100644 include/boost/python/classes.hpp create mode 100644 include/boost/python/conversions.hpp create mode 100644 include/boost/python/detail/base_object.hpp create mode 100644 include/boost/python/detail/cast.hpp create mode 100644 include/boost/python/detail/config.hpp create mode 100644 include/boost/python/detail/extension_class.hpp create mode 100644 include/boost/python/detail/functions.hpp create mode 100644 include/boost/python/detail/init_function.hpp create mode 100644 include/boost/python/detail/none.hpp create mode 100644 include/boost/python/detail/signatures.hpp create mode 100644 include/boost/python/detail/singleton.hpp create mode 100644 include/boost/python/detail/types.hpp create mode 100644 include/boost/python/detail/wrap_python.hpp create mode 100644 include/boost/python/errors.hpp create mode 100644 include/boost/python/module_builder.hpp create mode 100644 include/boost/python/objects.hpp create mode 100644 include/boost/python/operators.hpp create mode 100644 include/boost/python/reference.hpp create mode 100644 src/classes.cpp create mode 100644 src/conversions.cpp create mode 100644 src/extension_class.cpp create mode 100644 src/functions.cpp create mode 100644 src/gen_all.py create mode 100644 src/gen_callback.py create mode 100644 src/gen_caller.py create mode 100644 src/gen_extclass.py create mode 100644 src/gen_function.py create mode 100644 src/gen_init_function.py create mode 100644 src/gen_signatures.py create mode 100644 src/gen_singleton.py create mode 100644 src/init_function.cpp create mode 100644 src/module_builder.cpp create mode 100644 src/objects.cpp create mode 100644 src/types.cpp create mode 100644 test/comprehensive.cpp create mode 100644 test/comprehensive.hpp create mode 100644 test/comprehensive.py diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..3e84d7c7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/doc/#index.html# b/doc/#index.html# new file mode 100644 index 00000000..ff5946a8 --- /dev/null +++ b/doc/#index.html# @@ -0,0 +1,212 @@ + + + + py_cpp Python/C++ binding documentation + +

+ c++boost.gif (8819 bytes) py_cpp* +

+ +

+ The source code for py_cpp, including a MSVC demo project is available here. + +

Synopsis

+

+ py_cpp is a system for quickly and easily interfacing C++ code with Python such that the Python interface is + very similar to the C++ interface. It is designed to be minimally + intrusive on your C++ design. In most cases, you should not have to alter + your C++ classes in any way in order to use them with py_cpp. The system + should simply “reflect” your C++ classes and functions into + Python. The major features of py_cpp include support for: +

+among others. + + +

Supported Platforms

+

py_cpp has been tested in the following configurations: + +

+ +

Py_cpp requires the boost libraries, and is + has been accepted for inclusion into the boost libraries pending “boostification“ + (completion of the documentation, change in some naming conventions and + resolution of some namespace issues). + +

Credits

+ + +

Table of Contents

+ +
    +
  1. A Brief Introduction to writing Python + extension modules + +
  2. Comparisons between py_cpp and other + systems for extending Python + +
  3. A Simple Example Using py_cpp + +
  4. Overridable Virtual Functions + +
  5. Function Overloading + +
  6. Inheritance + +
  7. Special Method and Operator Support + +
  8. A Peek Under the Hood + +
  9. Building a Module with Py_cpp + +
  10. Advanced Topics + +
      +
    1. class_builder<> + +
    2. enums + +
    3. References + +
    4. Pointers and Smart Pointers + +
    5. Built-in Python Types + +
    6. Other Extension Types + +
    7. Templates +
    + +
+ +

+ More sophisticated examples are given in + extclass_demo.cpp, extclass_demo.h, and + test_extclass.py in the source code + archive. There's much more here, and much more documentation to + come... +

+ Questions should be directed to the boost mailing list. + +

Naming Contest

+ +

+ Yes, I know py_cpp is a lousy name. Problem is, the best names my puny + imagination can muster (IDLE and GRAIL) are taken, so I'm holding a + naming contest. First prize? You get to pick the name<0.2wink> and + you will be credited in the documentation. Names that have been suggested + so far include: +

+ Please post or send me your suggestions!
+
+ +

+ © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided “as is” without + express or implied warranty, and with no claim as to its suitability for + any purpose. +

+ Updated: Nov 26, 2000 + + diff --git a/doc/building.html b/doc/building.html new file mode 100644 index 00000000..9c0452e7 --- /dev/null +++ b/doc/building.html @@ -0,0 +1,43 @@ + + + Building a Module with Py_cpp + +

+

+ c++boost.gif (8819 bytes)Building a Module with Py_cpp +

+

+ Right now, the only supported configuration is one in which the py_cpp + source files are statically linked with the source for your extension + module. You may first build them into a library and link it with your + extension module source, but the effect is the same as compiling all + the source files together. Some users have successfully built the + py_cpp sources into a shared library, and support for a shared library + build is planned, but not yet implemented. The py_cpp source files are: +

+
+extclass.cpp
+functions.cpp
+init_function.cpp
+module.cpp
+newtypes.cpp
+objects.cpp
+py.cpp
+subclass.cpp
+         
+
+

+ Previous: A Peek Under the Hood + Up: Top +

+ © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided “as + is” without express or implied warranty, and with no claim as to + its suitability for any purpose. +

+ Updated: Nov 26, 2000 +

+ diff --git a/doc/comparisons.html b/doc/comparisons.html new file mode 100644 index 00000000..d0c31d9f --- /dev/null +++ b/doc/comparisons.html @@ -0,0 +1,220 @@ + + + Comparisons with Other Systems + +
+

+ c++boost.gif (8819 bytes)Comparisons with + Other Systems +

+ +

CXX

+

+ Like py_cpp, CXX attempts to + provide a C++-oriented interface to Python. In most cases, like py_cpp, + it relieves the user from worrying about reference-counts. As far as I + can tell, there is no support for subclassing C++ extension types in + Python. An even more-significant difference is that a user's C++ code is + still basically “dealing with Python objects”, though they are wrapped + in C++ classes. This means such jobs as argument parsing and conversion + are still left to be done explicitly by the user. + +

+ CXX claims to interoperate well with the C++ Standard Library + (a.k.a. STL) by providing iterators into Python Lists and Dictionaries, + but the claim is unfortunately unsupportable. The problem is that in + general, access to Python sequence and mapping elements through + iterators requires the use of proxy objects as the return value of + iterator dereference operations. This usage conflicts with the basic + ForwardIterator requirements in + section 24.1.3 of the standard (dereferencing must produce a + reference). Although you may be able to use these iterators with some + operations in some standard library implementations, it is neither + guaranteed to work nor portable. + +

+ As far as I can tell, CXX enables one to write what is essentially + idiomatic Python code in C++, manipulating Python objects through the + same fully-generic interfaces we use in Python. I think it would be fair + to say that while you're not programming directly to the “bare + metal” with CXX, in comparison to py_cpp, it presents a low-level + interface to Python. That use is also supported by the py_cpp object + wrappers. + +

+ Paul F. Dubois, the original + author of CXX, has told me that what I've described is only half of the + picture with CXX, but I never understood his explanation well-enough to + fill in the other half. Here is his response to the commentary above: + +

+“My intention with CXX was not to do what you are doing. It was to enable a +person to write an extension directly in C++ rather than C. I figured others had +the wrapping business covered. I thought maybe CXX would provide an easier +target language for those making wrappers, but I never explored +that.”
-Paul Dubois +
+ +

SWIG

+

+ SWIG is an impressively mature tool + for exporting an existing ANSI 'C' interface into various scripting + languages. Swig relies on a parser to read your source code and produce + additional source code files which can be compiled into a Python (or + Perl or Tcl) extension module. It has been successfully used to create + many Python extension modules. Like py_cpp, SWIG is trying to allow an + existing interface to be wrapped with little or no change to the + existing code. The documentation says “SWIG parses a form of ANSI C + syntax that has been extended with a number of special directives. As a + result, interfaces are usually built by grabbing a header file and + tweaking it a little bit.” For C++ interfaces, the tweaking has often + proven to amount to more than just a little bit. One user + writes: + +

“The problem with swig (when I used it) is that it + couldnt handle templates, didnt do func overloading properly etc. For + ANSI C libraries this was fine. But for usual C++ code this was a + problem. Simple things work. But for anything very complicated (or + realistic), one had to write code by hand. I believe py_cpp doesn't have + this problem[sic]... IMHO overloaded functions are very important to + wrap correctly.”
-Prabhu Ramachandran +
+ +

+ By contrast, py_cpp doesn't attempt to parse C++ - the problem is simply + too complex to do correctly. Technically, one does + write code by hand to use py_cpp. The goal, however, has been to make + that code nearly as simple as listing the names of the classes and + member functions you want to expose in Python. + +

SIP

+

+ SIP + is a system similar to SWIG, though seemingly more + C++-oriented. The author says that like py_cpp, SIP supports overriding + extension class member functions in Python subclasses. It appears to + have been designed specifically to directly support some features of + PyQt/PyKDE, which is its primary client. Documentation is almost + entirely missing at the time of this writing, so a detailed comparison + is difficult. + +

ILU

+

+ ILU + is a very ambitious project which tries to describe a module's interface + (types and functions) in terms of an Interface + Specification Language (ISL) so that it can be uniformly interfaced + to a wide range of computer languages, including Common Lisp, C++, C, + Modula-3, and Python. ILU can parse the ISL to generate a C++ language + header file describing the interface, of which the user is expected to + provide an implementation. Unlike py_cpp, this means that the system + imposes implementation details on your C++ code at the deepest level. It + is worth noting that some of the C++ names generated by ILU are supposed + to be reserved to the C++ implementation. It is unclear from the + documentation whether ILU supports overriding C++ virtual functions in Python. + +

GRAD

+

+ GRAD + is another very ambitious project aimed at generating Python wrappers for + interfaces written in “legacy languages”, among which C++ is the first one + implemented. Like SWIG, it aims to parse source code and automatically + generate wrappers, though it appears to take a more sophisticated approach + to parsing in general and C++ in particular, so it should do a much better + job with C++. It appears to support function overloading. The + documentation is missing a lot of information I'd like to see, so it is + difficult to give an accurate and fair assessment. I am left with the + following questions: +

+

+ Anyone in the possession of the answers to these questions will earn my + gratitude for a write-up ;-) + +

Zope ExtensionClasses

+

+ + ExtensionClasses in Zope use the same underlying mechanism as py_cpp + to support subclassing of extension types in Python, including + multiple-inheritance. Both systems support pickling/unpickling of + extension class instances in very similar ways. Both systems rely on the + same “Don + Beaudry Hack” that also inspired Don's MESS System. +

+ The major differences are: +

+

+ Previous: A Brief Introduction to writing Python Extension Modules + Next: A Simple Example Using py_cpp + Up: Top +

+ © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided “as is” without + express or implied warranty, and with no claim as to its suitability + for any purpose. +

+ Updated: Nov 26, 2000 +

+ diff --git a/doc/enums.html b/doc/enums.html new file mode 100644 index 00000000..57aef35f --- /dev/null +++ b/doc/enums.html @@ -0,0 +1,94 @@ + + + Wrapping enums + +
+

+ c++boost.gif (8819 bytes)Wrapping enums +

+

Because there is in general no way to deduce that a value of arbitrary type T +is an enumeration constant, py_cpp cannot automatically convert enum values to +and from Python. To handle this case, you need to decide how you want the enum +to show up in Python (since Python doesn't have enums). Once you have done that, +you can write some simple from_python() and +to_python() functions. + +

If you are satisfied with a Python int as a way to represent your enum +values, py_cpp provides a shorthand for these functions. You just need to +instantiate boost::python::enum_as_int_converters<EnumType> where +EnumType is your enumerated type. There are two convenient ways to do this: + +

    +
  1. +
    +// drop into namespace python and explicitly instantiate
    +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
    +  template class enum_as_int_converters;
    +BOOST_PYTHON_END_CONVERSION_NAMESPACE
    +
    +
    +
  2. +// instantiate as base class in any namespace
    +struct EnumTypeConverters
    +    : boost::python::py_enum_as_int_converters
    +{
    +};
    +
    +
+ +

Either of the above is equivalent to the following declarations: +

+BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
+
+  MyEnumType from_python(PyObject* x, boost::python::type<MyEnumType>)
+  {
+      return static_cast<MyEnum>(
+        from_python(x, boost::python::type<long>()));
+  }
+
+  MyEnumType from_python(PyObject* x, boost::python::type<const MyEnumType&>)
+  {
+      return static_cast<MyEnum>(
+        from_python(x, boost::python::type<long>()));
+  }
+
+  PyObject* to_python(MyEnumType x)
+  {
+      return to_python(static_cast<long>(x));
+  }
+BOOST_PYTHON_END_CONVERSION_NAMESPACE
+
+ +

This technique defines the conversions of +MyEnumType in terms of the conversions for the built-in + long type. + +You may also want to add a bunch of lines like this to your module +initialization: + +

+mymodule.add(boost::python::to_python(enum_value_1), "enum_value_1");
+mymodule.add(boost::python::to_python(enum_value_2), "enum_value_2");
+...
+
+ +You can also add these to an extension class definition, if your enum happens to +be local to a class and you want the analogous interface in Python: + +
+my_class.add(boost::python::to_python(enum_value_1), "enum_value_1");
+my_class.add(boost::python::to_python(enum_value_2), "enum_value_2");
+...
+
+

+ © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided “as + is” without express or implied warranty, and with no claim as to + its suitability for any purpose. +

+ Updated: Nov 26, 2000 +

+ diff --git a/doc/example1.html b/doc/example1.html new file mode 100644 index 00000000..9bf9e280 --- /dev/null +++ b/doc/example1.html @@ -0,0 +1,129 @@ + + + A Simple Example Using py_cpp + +
+

+ + +

+

+ A Simple Example Using py_cpp +

+

+ Suppose we have the following C++ API which we want to expose in + Python: +

+
+#include <string>
+
+namespace hello {
+  class world
+  {
+   public:
+      world(int);
+      ~world();
+      std::string get() const { return "hi, world"; }
+    ...
+  };
+  std::size_t length(const world& x) { return std::strlen(x.get()); }
+}
+
+
+
+

+ Here is the C++ code for a python module called hello + which exposes the API using py_cpp: +

+
+#include 
+// Python requires an exported function called init<module-name> in every
+// extension module. This is where we build the module contents.
+extern "C"
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void inithello()
+{
+    try
+    {
+       // create an object representing this extension module
+       boost::python::module_builder hello("hello");
+       // Create the Python type object for our extension class
+       boost::python::class_builder<hello::world> world_class(hello, "world");
+       // Add the __init__ function
+       world_class.def(boost::python::constructor<int>());
+       // Add a regular member function
+       world_class.def(&hello::world::get, "get");
+       // Add a regular function to the module
+       hello.def(hello::length, "length");
+    }
+    catch(...)
+    {
+       boost::python::handle_exception();    // Deal with the exception for Python
+    }
+}
+// Win32 DLL boilerplate
+#if defined(_WIN32)
+#include <windows.h>
+extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID)
+{
+    return 1;
+}
+#endif // _WIN32
+
+
+

+ That's it! If we build this shared library and put it on our + PYTHONPATH we can now access our C++ class and function from + Python. +

+
+>>> import hello
+>>> hi_world = hello.world(3)
+>>> hi_world.get()
+'hi, world'
+>>> hello.length(hi_world)
+9
+
+
+

+ We can even make a subclass of hello.world: +

+
+>>> class my_subclass(hello.world):
+...     def get(self):
+...         return 'hello, world'
+...
+>>> y = my_subclass(4)
+>>> y.get()
+'hello, world'
+
+
+

+ Pretty cool! You can't do that with an ordinary Python extension type! +

+
+>>> hello.length(y)
+9
+
+
+

+ Of course, you may now have a slightly empty feeling in the pit of + your little pythonic stomach. Perhaps you feel your subclass deserves + to have a length() of 12? If so, read on... +

+ Previous: Comparisons with other systems Next: Overridable virtual functions Up: + Top +

+ © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided "as is" without + express or implied warranty, and with no claim as to its suitability + for any purpose. +

+ Updated: Nov 26, 2000 +

+ diff --git a/doc/extending.html b/doc/extending.html new file mode 100644 index 00000000..47341389 --- /dev/null +++ b/doc/extending.html @@ -0,0 +1,73 @@ + + + + A Brief Introduction to writing Python extension modules + +

+ c++boost.gif (8819 bytes) +

+

+ A Brief Introduction to writing Python extension modules +

+

+ Interfacing any language to Python involves building a module which can + be loaded by the Python interpreter, but which isn't written in Python. + This is known as an extension module. Many of the built-in Python + libraries are constructed in 'C' this way; Python even supplies its + fundamental + types using the same mechanism. An extension module can be statically + linked with the Python interpreter, but it more commonly resides in a + shared library or DLL. +

+ As you can see from The Python Extending + and Embedding Tutorial, writing an extension module normally means + worrying about +

+ This last item typically occupies a great deal of code in an extension + module. Remember that Python is a completely dynamic language. A callable + object receives its arguments in a tuple; it is up to that object to + extract those arguments from the tuple, check their types, and raise + appropriate exceptions. There are numerous other tedious details that need + to be managed; too many to mention here. Py_cpp is designed to lift most of + that burden.
+
+ +

+ Another obstacle that most people run into eventually when extending + Python is that there's no way to make a true Python class in an extension + module. The typical solution is to create a new Python type in the + extension module, and then write an additional module in 100% Python. The + Python module defines a Python class which dispatches to an instance of + the extension type, which it contains. This allows users to write + subclasses of the class in the Python module, almost as though they were + sublcassing the extension type. Aside from being tedious, it's not really + the same as having a true class, because there's no way for the user to + override a method of the extension type which is called from the + extension module. Py_cpp solves this problem by taking advantage of Python's metaclass + feature to provide objects which look, walk, and hiss almost exactly + like regular Python classes. Py_cpp classes are actually cleaner than + Python classes in some subtle ways; a more detailed discussion will + follow (someday).

+

Next: Comparisons with Other Systems Up: Top

+

+ © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided "as is" without + express or implied warranty, and with no claim as to its suitability for + any purpose.

+ diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 00000000..7ed767a1 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,211 @@ + + + + py_cpp Python/C++ binding documentation + +

+ c++boost.gif (8819 bytes) py_cpp* +

+ +

+ The source code for py_cpp, including a MSVC demo project is available here. + +

Synopsis

+

+ py_cpp is a system for quickly and easily interfacing C++ code with Python such that the Python interface is + very similar to the C++ interface. It is designed to be minimally + intrusive on your C++ design. In most cases, you should not have to alter + your C++ classes in any way in order to use them with py_cpp. The system + should simply “reflect” your C++ classes and functions into + Python. The major features of py_cpp include support for: +

+among others. + + +

Supported Platforms

+

py_cpp has been tested in the following configurations: + +

+ +

Py_cpp requires the boost libraries, and is + has been accepted for inclusion into the boost libraries pending “boostification“ + (completion of the documentation, change in some naming conventions and + resolution of some namespace issues). + +

Credits

+ + +

Table of Contents

+ +
    +
  1. A Brief Introduction to writing Python + extension modules + +
  2. Comparisons between py_cpp and other + systems for extending Python + +
  3. A Simple Example Using py_cpp + +
  4. Overridable Virtual Functions + +
  5. Function Overloading + +
  6. Inheritance + +
  7. Special Method and Operator Support + +
  8. A Peek Under the Hood + +
  9. Building a Module with Py_cpp + +
  10. Advanced Topics + +
      +
    1. class_builder<> + +
    2. enums + +
    3. References + +
    4. Pointers and Smart Pointers + +
    5. Built-in Python Types + +
    6. Other Extension Types + +
    7. Templates +
    + +
+ +

+ More sophisticated examples are given in + extclass_demo.cpp, extclass_demo.h, and + test_extclass.py in the source code + archive. There's much more here, and much more documentation to + come... +

+ Questions should be directed to the boost mailing list. + +

Naming Contest

+ +

+ Yes, I know py_cpp is a lousy name. Problem is, the best names my puny + imagination can muster (IDLE and GRAIL) are taken, so I'm holding a + naming contest. First prize? You get to pick the name<0.2wink> and + you will be credited in the documentation. Names that have been suggested + so far include: +

+ Please post or send me your suggestions!
+
+ +

+ © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided “as is” without + express or implied warranty, and with no claim as to its suitability for + any purpose. +

+ Updated: Nov 26, 2000 + diff --git a/doc/inheritance.html b/doc/inheritance.html new file mode 100644 index 00000000..2dd8071b --- /dev/null +++ b/doc/inheritance.html @@ -0,0 +1,165 @@ + + + Inheritance + +

+

+ c++boost.gif (8819 bytes)Inheritance +

+ +

Inheritance in Python

+ +

+ Py_cpp extension classes support single and multiple-inheritance in + Python, just like regular Python classes. You can mix built-in Python + classes with py_cpp extension classes in a derived class' tuple of + bases. Whenever a py_cpp extension class is among the bases for a new + class in Python, the result is an extension class: +

+
+>>> class MyPythonClass:
+...     def f(): return 'MyPythonClass.f()'
+...
+>>> import my_extension_module
+>>> class Derived(my_extension_module.MyExtensionClass, MyPythonClass):
+...     '''This is an extension class'''
+...     pass
+...
+>>> x = Derived()
+>>> x.f()
+'MyPythonClass.f()'
+>>> x.g()
+'MyExtensionClass.g()'
+
+
+ +

Reflecting C++ Inheritance Relationships

+

+ Py_cpp also allows us to represent C++ inheritance relationships so that + wrapped derived classes may be passed where values, pointers, or + references to a base class are expected as arguments. The + declare_base member function of + class_builder<> is used to establish the relationship + between base and derived classes: + +

+
+#include <memory> // for std::auto_ptr<>
+
+struct Base {
+    virtual ~Base() {}
+    virtual const char* name() const { return "Base"; }
+};
+
+struct Derived : Base {
+    Derived() : x(-1) {}
+    virtual const char* name() const { return "Derived"; }
+    int x;
+};
+
+std::auto_ptr<Base> derived_as_base() {
+    return std::auto_ptr<Base>(new Derived);
+}
+
+const char* get_name(const Base& b) {
+    return b.name();
+}
+
+int get_derived_x(const Derived& d) {
+    return d.x;
+}
+    
+#include +extern "C" +#ifdef _WIN32 +__declspec(dllexport) +#endif +void initmy_module() +{ +    try +    { +       boost::python::module_builder my_module("my_module"); + +       boost::python::class_builder<Base> base_class(my_module, "Base"); +       base_class.def(boost::python::constructor<void>()); + +       boost::python::class_builder<Derived> derived_class(my_module, "Derived"); +       derived_class.def(boost::python::constructor<void>()); + // Establish the inheritance relationship between Base and Derived + derived_class.declare_base(base_class); + + my_module.def(derived_as_base, "derived_as_base"); + my_module.def(get_name, "get_name"); + my_module.def(get_derived_x, "get_derived_x"); +    } +    catch(...) +    { +       boost::python::handle_exception();    // Deal with the exception for Python +    } +} +
+
+ +

+ Then, in Python: +

+
+>>> from my_module import *
+>>> base = Base()
+>>> derived = Derived()
+>>> get_name(base)
+'Base'
+
objects of wrapped class Derived may be passed where Base is expected
+>>> get_name(derived) 
+'Derived'
+
objects of wrapped class Derived can be passed where Derived is +expected but where type information has been lost.
+>>> get_derived_x(derived_as_base()) 
+-1
+
+
+ +

Inheritance Without Virtual Functions

+ +

+ If for some reason your base class has no virtual functions but you still want + to represent the inheritance relationship between base and derived classes, + pass the special symbol boost::python::without_downcast as the 2nd parameter + to declare_base: + +

+
+struct Base2 {};
+struct Derived2 { int f(); };
+
+ ... +   boost::python::class_builder<Base> base2_class(my_module, "Base2"); +   base2_class.def(boost::python::constructor<void>()); + +   boost::python::class_builder<Derived2> derived2_class(my_module, "Derived2"); +   derived2_class.def(boost::python::constructor<void>()); + derived_class.declare_base(base_class, boost::python::without_downcast); +
+
+ +

This approach will allow Derived2 objects to be passed where + Base2 is expected, but does not attempt to implicitly convert (downcast) + smart-pointers to Base2 into Derived2 pointers, + references, or values. + +

+ Previous: Function Overloading + Next: Special Method Names + Up: Top +

+ © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided "as is" without + express or implied warranty, and with no claim as to its suitability + for any purpose. +

+ Updated: Nov 26, 2000 +

+ diff --git a/doc/overloading.html b/doc/overloading.html new file mode 100644 index 00000000..6197b230 --- /dev/null +++ b/doc/overloading.html @@ -0,0 +1,156 @@ + + + Function Overloading + +
+

+ c++boost.gif (8819 bytes)Function Overloading +

+ +

An Example

+

+ To expose overloaded functions in Python, simply def() each + one with the same Python name: +

+
+inline int f1() { return 3; }
+inline int f2(int x) { return x + 1; }
+
+class X {
+public:
+    X() : m_value(0) {}
+    X(int n) : m_value(n) {}
+    int value() const { return m_value; }
+    void value(int v) { m_value = v; }
+private:
+    int m_value;
+};
+  ...
+
+void initoverload_demo()
+{
+    try
+    {
+        boost::python::module_builder overload_demo("overload_demo");
+        // Overloaded functions at module scope
+        overload_demo.def(f1, "f");
+        overload_demo.def(f2, "f");
+
+        boost::python::class_builder<X> x_class(overload_demo, "X");
+        // Overloaded constructors
+        x_class.def(boost::python::constructor<>());
+        x_class.def(boost::python::constructor<int>());
+
+        // Overloaded member functions
+        x_class.def((int (X::*)() const)&X::value, "value");
+        x_class.def((void (X::*)(int))&X::value, "value");
+  ...
+
+
+ +

+ Now in Python: +

+
+>>> from overload_demo import *
+>>> x0 = X()
+>>> x1 = X(1)
+>>> x0.value()
+0
+>>> x1.value()
+1
+>>> x0.value(3)
+>>> x0.value()
+3
+>>> X('hello')
+TypeError: No overloaded functions match (X, string). Candidates are:
+void (*)()
+void (*)(int)
+>>> f()
+3
+>>> f(4)
+5
+
+
+ +

Discussion

+

+ Notice that overloading in the Python module was produced three ways:

    +
  1. by combining the non-overloaded C++ functions int f1() + and int f2(int) and exposing them as f in Python. +
  2. by exposing the overloaded constructors of class X +
  3. by exposing the overloaded member functions X::value. +
+

+ Techniques 1. and 3. above are really alternatives. In case 3, you need + to form a pointer to each of the overloaded functions. The casting + syntax shown above is one way to do that in C++. Case 1 does not require + complicated-looking casts, but may not be viable if you can't change + your C++ interface. N.B. There's really nothing unsafe about casting an + overloaded (member) function address this way: the compiler won't let + you write it at all unless you get it right. + +

An Alternative to Casting

+

+ This approach is not neccessarily better, but may be preferable for some + people who have trouble writing out the types of (member) function + pointers or simply prefer to avoid all casts as a matter of principle: +

+
+// Forwarding functions for X::value
+inline void set_x_value(X& self, int v) { self.value(v); }
+inline int get_x_value(X& self) { return self.value(); }
+   ...
+        // Overloaded member functions
+        x_class.def(set_x_value, "value");
+        x_class.def(get_x_value, "value");
+
+
+

Here we are taking advantage of the ability to expose C++ functions at +namespace scope as Python member functions. + +

Overload Resolution

+

+ The function overload resolution mechanism in py_cpp works as + follows: + +

+ +

+ Prev: Overridable Virtual Functions + Next: Special Method Names + Up: Top +

+ © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided “as + is” without express or implied warranty, and with no claim as to + its suitability for any purpose. +

+ Updated: Nov 26, 2000 +

+ diff --git a/doc/overriding.html b/doc/overriding.html new file mode 100644 index 00000000..f8810ca1 --- /dev/null +++ b/doc/overriding.html @@ -0,0 +1,195 @@ + + + + Overridable Virtual Functions + + c++boost.gif (8819 bytes) + +

Overridable Virtual Functions

+ +

+ In the previous example we exposed a simple + C++ class in Python and showed that we could write a subclass. We even + redefined one of the functions in our derived class. Now we will learn + how to make the function behave virtually when called from C++. + + +

Example

+ +

In this example, it is assumed that world::get() is a virtual +member function: + +

+class world
+{
+ public:
+    world(int);
+    virtual ~world();
+    virtual std::string get() const { return "hi, world"; }
+};
+
+ +

+ We'll need a derived class* to help us + dispatch the call to Python. In our derived class, we need the following + elements: + +

    + +
  1. A PyObject* data member that holds a + reference to the corresponding Python object. + +
  2. A constructor for each exposed constructor of the + base class which stores an additional initial PyObject* argument + in the data member described above. + +
  3. An implementation of each virtual function you may + wish to override in Python which uses + boost::python::callback<return-type>::call_method() to call + the Python override. + +
  4. For each non-pure virtual function meant to be + overridable from Python, a static member function (or a free function) taking + a reference or pointer to the base type as the first parameter and which + forwards any additional parameters neccessary to the default + implementation of the virtual function. See also this + note if the base class virtual function is private. + +
+ +
+struct world_callback : world
+{
+    world_callback(PyObject* self, int x) // 2
+        : world(x),
+          m_self(self) {}
+
+    std::string get() const // 3
+        { return boost::python::callback<std::string>::call_method(m_self, "get"); }
+
+    static std::string default_get(const hello::world& self) const // 4
+        { return self.world::get(); }
+ private:
+    PyObject* m_self; // 1
+};
+
+ +

+ Finally, we add world_callback to the + class_builder<> declaration in our module initialization + function, and when we define the function, we must tell py_cpp about the default + implementation: + +

+// Create the Python type object for our extension class
+boost::python::class_builder<hello::world,world_callback> world_class(hello, "world");
+// Add a virtual member function
+world_class.def(&world::get, "get", &world_callback::default_get);
+
+ +

+ Now our subclass of hello.world behaves as expected: + +

+>>> class my_subclass(hello.world):
+...     def get(self):
+...         return 'hello, world'
+...
+>>> hello.length(my_subclass())
+12
+
+ +

+ *You may ask, "Why do we need this derived + class? This could have been designed so that everything gets done right + inside of hello::world." One of the goals of py_cpp is to be + minimally intrusive on an existing C++ design. In principle, it should be + possible to expose the interface for a 3rd party library without changing + it. To unintrusively hook into the virtual functions so that a Python + override may be called, we must use a derived class. + +

Pure Virtual Functions

+ +

+ A pure virtual function with no implementation is actually a lot easier to + deal with than a virtual function with a default implementation. First of + all, you obviously don't need to supply + a default implementation. Secondly, you don't need to call + def() on the extension_class<> instance + for the virtual function. In fact, you wouldn't want to: if the + corresponding attribute on the Python class stays undefined, you'll get an + AttributeError in Python when you try to call the function, + indicating that it should have been implemented. For example: +

+
+struct baz {
+    virtual int pure(int) = 0;
+};
+
+struct baz_callback {
+    int pure(int x) { boost::python::callback<int>::call_method(m_self, "pure", x); }
+};
+
+extern "C"
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+initfoobar()
+{
+    try
+    {
+       boost::python::module_builder foobar("foobar");
+       boost::python::class_builder<baz,baz_callback> baz_class("baz");
+       baz_class.def(&baz::pure, "pure");
+    }
+    catch(...)
+    {
+       boost::python::handle_exception();    // Deal with the exception for Python
+    }
+}
+
+
+

+ Now in Python: +

+
+>>> from foobar import baz
+>>> x = baz()
+>>> x.pure(1)
+Traceback (innermost last):
+  File "<stdin>", line 1, in ?
+AttributeError: pure
+>>> class mumble(baz):
+...    def pure(self, x): return x + 1
+...
+>>> y = mumble()
+>>> y.pure(99)
+100
+
+ +

Private Non-Pure Virtual Functions

+ +

This is one area where some minor intrusiveness on the wrapped library is +required. Once it has been overridden, the only way to call the base class +implementation of a private virtual function is to make the derived class a +friend of the base class. You didn't hear it from me, but most C++ +implementations will allow you to change the declaration of the base class in +this limited way without breaking binary compatibility (though it will certainly +break the ODR). + +

+ Prev: A Simple Example Using py_cpp Next: Function Overloading Up: Top +

+ © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided "as is" without + express or implied warranty, and with no claim as to its suitability for + any purpose. +

+ Updated: Nov 26, 2000 + diff --git a/doc/pointers.html b/doc/pointers.html new file mode 100644 index 00000000..fe30af0b --- /dev/null +++ b/doc/pointers.html @@ -0,0 +1,145 @@ + + + Pointers + +

+

+ c++boost.gif (8819 bytes)Pointers +

+ +

The Problem With Pointers

+ +

+In general, raw pointers passed to or returned from functions are problematic +for py_cpp because pointers have too many potential meanings. Is it an iterator? +A pointer to a single element? An array? When used as a return value, is the +caller expected to manage (delete) the pointed-to object or is the pointer +really just a reference? If the latter, what happens to Python references to the +referent when some C++ code deletes it? +

+There are a few cases in which pointers are converted automatically: +

+ +

Can you avoid the problem?

+ +

My first piece of advice to anyone with a case not covered above is +“find a way to avoid the problem.” For example, if you have just one +or two functions returning a pointer to a single (not an array of) const +T* for some wrapped T, you may be able to write a “thin +converting wrapper” over those two functions as follows (Since py_cpp +converts const T& values to_python by copying the T +into a new extension instance, Foo must have a public copy constructor): + +

+const Foo* f(); // original function
+const Foo& f_wrapper() { return *f(); }
+  ...
+my_module.def(f_wrapper, "f");
+
+ +

Dealing with the problem

+ +

The first step in handling the remaining cases is to figure out what the pointer +means. Several potential solutions are provided in the examples that follow: + +

Returning a pointer to a wrapped type

+ +

Returning a const pointer

+ +

If you have lots of functions returning a const T* for some +wrapped T, you may want to provide an automatic +to_python conversion function so you don't have to write lots of +thin wrappers. You can do this simply as follows: + +

+BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
+  PyObject* to_python(const Foo* p) {
+     return to_python(*p); // convert const Foo* in terms of const Foo&
+  }
+BOOST_PYTHON_END_CONVERSION_NAMESPACE
+
+ +

If you can't (afford to) copy the referent, or the pointer is non-const

+ +

If the wrapped type doesn't have a public copy constructor, if copying is +extremely costly (remember, we're dealing with Python here), or if the +pointer is non-const and you really need to be able to modify the referent from +Python, you can use the following dangerous trick. Why dangerous? Because python +can not control the lifetime of the referent, so it may be destroyed by your C++ +code before the last Python reference to it disappears: + +

+BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
+  PyObject* to_python(Foo* p)
+  {
+      return boost::python::PyExtensionClassConverters::ptr_to_python(p);
+  }
+
+  PyObject* to_python(const Foo* p)
+  {
+      return to_python(const_cast(p));
+  }
+BOOST_PYTHON_END_CONVERSION_NAMESPACE
+
+ +This will cause the Foo* to be treated as though it were an owning smart +pointer, even though it's not. Be sure you don't use the reference for anything +from Python once the pointer becomes invalid, though. Don't worry too much about +the const_cast<> above: Const-correctness is completely lost +to Python anyway! + +

[In/]Out Parameters and Immutable Types

+ +

If you have an interface that uses non-const pointers (or references) as +in/out parameters to types which in Python are immutable (e.g. int, string), +there simply is no way to get the same interface in Python. You must +resort to transforming your interface with simple thin wrappers as shown below: +

+const void f(int* in_out_x); // original function
+const int f_wrapper(int in_x) { f(in_x); return in_x; }
+  ...
+my_module.def(f_wrapper, "f");
+
+ +

Of course, [in/]out parameters commonly occur only when there is already a +return value. You can handle this case by returning a Python tuple: +

+typedef unsigned ErrorCode;
+const char* f(int* in_out_x); // original function
+ ...
+#include 
+const boost::python::tuple f_wrapper(int in_x) { 
+  const char* s = f(in_x); 
+  return boost::python::tuple(s, in_x);
+}
+  ...
+my_module.def(f_wrapper, "f");
+
+

Now, in Python: +

+>>> str,out_x = f(3)
+
+ + + +

+ © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided "as is" without + express or implied warranty, and with no claim as to its suitability + for any purpose. +

+ Updated: Nov 26, 2000 +

+ diff --git a/doc/special.html b/doc/special.html new file mode 100644 index 00000000..4c314fcf --- /dev/null +++ b/doc/special.html @@ -0,0 +1,888 @@ + + + Special Method and Operator Support + +
+

+ c++boost.gif (8819 bytes)Special Method and + Operator Support +

+

+ Overview +

+

+ Py_cpp supports all of the standard + special method names supported by real Python class instances + except __complex__ (more on the reasons below). In addition, it can quickly and easily expose + suitable C++ functions and operators as Python operators. The following + categories of special method names are supported: +

+ +

Basic Customization

+ + +

+ Python provides a number of special operators for basic customization of a + class. Only a brief description is provided below; more complete + documentation can be found here. + +

+
+ __init__(self) +
+ Initialize the class instance. For extension classes not subclassed in + Python, this is provided by the + boost::python::constructor<...>() construct and should not be explicitly defed. +
+ __del__(self) +
+ Called when the extension instance is about to be destroyed. +
+ __repr__(self) +
+ Create a string representation from which the object can be + reconstructed. +
+ __str__(self) +
+ Create a string representation which is suitable for printing. +
+ __cmp__(self, other) +
+ Three-way compare function, used to implement comparison operators + (< etc.) Should return a negative integer if self < other + , zero if self == other , a positive integer if + self > other . +
+ __hash__(self) +
+ Called for the key object for dictionary operations, and by the + built-in function hash(). Should return a 32-bit integer usable as a + hash value for dictionary operations (only allowed if __cmp__ is also + defined) +
+ __nonzero__(self) +
+ called if the object is used as a truth value (e.g. in an if + statement) +
+ __call__ (self[, args...]) +
+Called when the instance is “called” as a function; if this method +is defined, x(arg1, arg2, ...) is a shorthand for +x.__call__(arg1, arg2, ...). +
+ + If we have a suitable C++ function that supports any of these features, + we can export it like any other function, using its Python special name. + For example, suppose that class Foo provides a string + conversion function: +
+std::string to_string(Foo const& f)
+{
+    std::ostringstream s;
+    s << f;
+    return s.str();
+}
+
+ This function would be wrapped like this: +
+boost::python::class_builder<Foo> foo_class(my_module, "Foo");
+foo_class.def(&to_string, "__str__");
+
+ Note that py_cpp also supports automatic wrapping of + __str__ and __cmp__. This is explained in the next section and the Table of + Automatically Wrapped Methods. + +

Numeric Operators

+ +

+ Numeric operators can be exposed manually, by defing C++ + [member] functions that support the standard Python numeric + protocols. This is the basic same technique used to expose + to_string() as __str__() above, and is covered in detail below. Py_cpp also supports + automatic wrapping of numeric operators whenever they have already + been defined in C++. + +

Exposing C++ Operators Automatically

+ +

+Supose we wanted to expose a C++ class + BigNum which supports addition, so that we can write (in C++): +

+BigNum a, b, c;
+...
+c = a + b;
+
+

+ To enable the same functionality in Python, we first wrap the + BigNum class as usual: +

+boost::python::class_builder<BigNum> bignum_class(my_module, "BigNum");
+bignum_class.def(boost::python::constructor<>());
+...
+
+ Then we export the addition operator like this: + +
+bignum_class.def(boost::python::operators<boost::python::op_add>());
+
+ + Since BigNum also supports subtraction, multiplication, and division, we + want to export those also. This can be done in a single command by + “or”ing the operator identifiers together (a complete list of these + identifiers and the corresponding operators can be found in the Table of Automatically Wrapped Methods): +
+bignum_class.def(boost::python::operators<(boost::python::op_sub | boost::python::op_mul | boost::python::op_div)>());
+
+ [Note that the or-expression must be enclosed in parentheses.] + +

This form of operator definition can be used to wrap unary and + homogeneous binary operators (a homogeneous operator has left and + right operands of the same type). Now suppose that our C++ library also + supports addition of BigNums and plain integers: + +

+BigNum a, b;
+int i;
+...
+a = b + i;
+a = i + b;
+
+ To wrap these heterogeneous operators, we need to specify a different type for + one of the operands. This is done using the right_operand + and left_operand templates: +
+bignum_class.def(boost::python::operators<boost::python::op_add>(), boost::python::right_operand<int>());
+bignum_class.def(boost::python::operators<boost::python::op_add>(), boost::python::left_operand<int>());
+
+ Py_cpp uses overloading to register several variants of the same + operation (more on this in the context of + coercion). Again, several operators can be exported at once: +
+bignum_class.def(boost::python::operators<(boost::python::op_sub | boost::python::op_mul | boost::python::op_div)>(),
+                 boost::python::right_operand<int>());
+bignum_class.def(boost::python::operators<(boost::python::op_sub | boost::python::op_mul | boost::python::op_div)>(), 
+                 boost::python::left_operand<int>());
+
+ The type of the operand not mentioned is taken from the class being wrapped. In + our example, the class object is bignum_class, and thus the + other operand's type is “BigNum const&”. You can override + this default by explicitly specifying a type in the + operators template: +
+bignum_class.def(boost::python::operators<boost::python::op_add, BigNum>(), boost::python::right_operand<int>());
+
+

+ Note that automatic wrapping uses the expression + “left + right” and can be used uniformly + regardless of whether the C++ operators are supplied as free functions +

+BigNum operator+(BigNum, BigNum)
+
+ or as member + functions
+BigNum::operator+(BigNum).
+
+ +

+ For the Python built-in functions pow() and + abs(), there is no corresponding C++ operator. Instead, + automatic wrapping attempts to wrap C++ functions of the same name. This + only works if those functions are known in namespace + python. On some compilers (e.g. MSVC) it might be + necessary to add a using declaration prior to wrapping: + +

+namespace boost { namespace python { 
+  using my_namespace::pow;
+  using my_namespace::abs;
+}
+
+ +

Wrapping Numeric Operators Manually

+

+ In some cases, automatic wrapping of operators may be impossible or + undesirable. Suppose, for example, that the modulo operation for BigNums + is defined by a set of functions mod() (for automatic + wrapping, we would need operator%()): + +

+BigNum mod(BigNum const& left, BigNum const& right);
+BigNum mod(BigNum const& left, int right);
+BigNum mod(int left, BigNum const& right);
+
+ +

+ In order to create the Python operator "__mod__" from these functions, we + have to wrap them manually: + +

+bignum_class.def((BigNum (*)(BigNum const&, BigNum const&))&mod, "__mod__");
+bignum_class.def((BigNum (*)(BigNum const&, int))&mod, "__mod__");
+
+ +

+ The third form (with int as left operand) cannot be wrapped + this way. We must first create a function rmod() with the + operands reversed: + +

+BigNum rmod(BigNum const& right, int left)
+{
+    return mod(left, right);
+}
+
+ + This function must be wrapped under the name "__rmod__": + +
+bignum_class.def(&rmod,  "__rmod__");
+
+ + Many of the possible operator names can be found in the Table of Automatically Wrapped Methods. Special treatment is + necessary to export the ternary pow operator. + +

+ Automatic and manual wrapping can be mixed arbitrarily. Note that you + cannot overload the same operator for a given extension class on both + “int” and “float”, because Python implicitly + converts these types into each other. Thus, the overloaded variant + found first (be it “int“ or “float”) will be + used for either of the two types. + +

Coercion

+ + + Plain Python can only execute operators with identical types on the left + and right hand side. If it encounters an expression where the types of + the left and right operand differ, it tries to coerce these type to a + common type before invoking the actual operator. Implementing good + coercion functions can be difficult if many type combinations must be + supported. +

+ Py_cpp solves this problem the same way that C++ does: with overloading. This technique drastically + simplifies the code neccessary to support operators: you just register + operators for all desired type combinations, and py_cpp automatically + ensures that the correct function is called in each case; there is no + need for user-defined coercion functions. To enable operator + overloading, py_cpp provides a standard coercion which is implicitly + registered whenever automatic operator wrapping is used. +

+ If you wrap all operator functions manually, but still want to use + operator overloading, you have to register the standard coercion + function explicitly: + +

+// this is not necessary if automatic operator wrapping is used
+bignum_class.def_standard_coerce();
+
+ + If you encounter a situation where you absolutely need a customized + coercion, you can overload the "__coerce__" operator itself. The signature + of a coercion function should look like one of the following (the first is + the safest): + +
+boost::python::tuple custom_coerce(boost::python::reference left, boost::python::reference right);
+boost::python::tuple custom_coerce(PyObject* left, PyObject* right);
+PyObject* custom_coerce(PyObject* left, PyObject* right);
+
+ + The resulting tuple must contain two elements which + represent the values of left and right + converted to the same type. Such a function is wrapped as usual: + +
+some_class.def(&custom_coerce, "__coerce__");
+
+ + Note that the later use of automatic operator wrapping on a + class_builder or a call to + “some_class.def_standard_coerce()” will cause any + custom coercion function to be replaced by the standard one. + +

The Ternary pow() Operator

+ +

+ In addition to the usual binary pow(x, y) operator (meaning + xy), Python also provides a ternary variant that implements + xy mod z, presumably using a more efficient algorithm than + concatenation of power and modulo operators. Automatic operator wrapping + can only be used with the binary variant. Ternary pow() must + always be wrapped manually. For a homgeneous ternary pow(), + this is done as usual: + +

+BigNum power(BigNum const& first, BigNum const& second, BigNum const& module);
+typedef BigNum (ternary_function1)(const BigNum&, const BigNum&, const BigNum&);
+...
+bignum_class.def((ternary_function1)&power,  "__pow__");
+
+ + If you want to support this function with non-uniform argument + types, wrapping is a little more involved. Suppose you have to wrap: + +
+BigNum power(BigNum const& first, int second, int modulus);
+BigNum power(int first, BigNum const& second, int modulus);
+BigNum power(int first, int second, BigNum const& modulus);
+
+ + The first variant can be wrapped as usual: + +
+typedef BigNum (ternary_function2)(const BigNum&, int, int);
+bignum_class.def((ternary_function2)&power,  "__pow__");
+
+ + In the second variant, however, BigNum appears only as second + argument, and in the last one it is the third argument. These functions + must be presented to py_cpp such that that the BigNum + argument appears in first position: + +
+BigNum rpower(BigNum const& second, int first, int modulus)
+{
+    return power(first, second, third);
+}
+
+BigNum rrpower(BigNum const& third, int first, int second)
+{
+    return power(first, second, third);
+}
+
+ +

These functions must be wrapped under the names "__rpow__" and "__rrpow__" + respectively: + +

+bignum_class.def((ternary_function2)&rpower,  "__rpow__");
+bignum_class.def((ternary_function2)&rrpower,  "__rrpow__");
+
+ +Note that "__rrpow__" is an extension not present in plain Python. + +

Table of Automatically Wrapped Methods

+

+ Py_cpp can automatically wrap the following + special methods: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ Python Operator Name + + Python Expression + + C++ Operator Id + + C++ Expression Used For Automatic Wrapping
+ with cpp_left = from_python(left, + type<Left>()),
+ cpp_right = from_python(right, + type<Right>()),
+ and cpp_oper = from_python(oper, type<Oper>()) +
+ __add__, __radd__ + + left + right + + op_add + + cpp_left + cpp_right +
+ __sub__, __rsub__ + + left - right + + op_sub + + cpp_left - cpp_right +
+ __mul__, __rmul__ + + left * right + + op_mul + + cpp_left * cpp_right +
+ __div__, __rdiv__ + + left / right + + op_div + + cpp_left / cpp_right +
+ __mod__, __rmod__ + + left % right + + op_mod + + cpp_left % cpp_right +
+ __divmod__, __rdivmod__ + + (quotient, remainder)
+ = divmod(left, right)
+
+ op_divmod + + cpp_left / cpp_right +
cpp_left % cpp_right +
+ __pow__, __rpow__ + + pow(left, right)
+ (binary power) +
+ op_pow + + pow(cpp_left, cpp_right) +
+ __rrpow__ + + pow(left, right, modulo)
+ (ternary power modulo) +
+ no automatic wrapping, special treatment + required +
+ __lshift__, __rlshift__ + + left << right + + op_lshift + + cpp_left << cpp_right +
+ __rshift__, __rrshift__ + + left >> right + + op_rshift + + cpp_left >> cpp_right +
+ __and__, __rand__ + + left & right + + op_and + + cpp_left & cpp_right +
+ __xor__, __rxor__ + + left ^ right + + op_xor + + cpp_left ^ cpp_right +
+ __or__, __ror__ + + left | right + + op_or + + cpp_left | cpp_right + +
+ __cmp__, __rcmp__ + + cmp(left, right)
+ left < right
+ left <= right
+ left > right
+ left >= right
+ left == right
+ left != right +
+ op_cmp + + cpp_left < cpp_right  +
cpp_right < cpp_left + +
+ __neg__ + + -oper  (unary negation) + + op_neg + + -cpp_oper +
+ __pos__ + + +oper  (identity) + + op_pos + + +cpp_oper +
+ __abs__ + + abs(oper)  (absolute value) + + op_abs + + abs(cpp_oper) +
+ __invert__ + + ~oper  (bitwise inversion) + + op_invert + + ~cpp_oper +
+ __int__ + + int(oper)  (integer conversion) + + op_int + + long(cpp_oper) +
+ __long__ + + long(oper) 
+ (infinite precision integer conversion) +
+ op_long + + PyLong_FromLong(cpp_oper) +
+ __float__ + + float(oper)  (float conversion) + + op_float + + double(cpp_oper) +
+ __str__ + + str(oper)  (string conversion) + + op_str + + std::ostringstream s; s << oper; +
+ __coerce__ + + coerce(left, right) + + usually defined automatically, otherwise + special treatment required +
+ +

Sequence and Mapping Operators

+ +

+ Sequence and mapping operators let wrapped objects behave in accordance + to Python's iteration and access protocols. These protocols differ + considerably from the ones found in C++. For example, Python's typical + iteration idiom looks like +

+for i in S:
+
+ +while in C++ one writes + +
+for (iterator i = S.begin(), end = S.end(); i != end)
+
+ +

One could try to wrap C++ iterators in order to carry the C++ idiom into + Python. However, this does not work very well because + +

    +
  1. It leads to + non-uniform Python code (wrapped sequences support a usage different from + Python built-in sequences) and + +
  2. Iterators (e.g. std::vector::iterator) are often implemented as plain C++ + pointers which are problematic for any automatic + wrapping system. +
+ +

+ It is a better idea to support the standard Python + sequence and mapping protocols for your wrapped containers. These + operators have to be wrapped manually because there are no corresponding + C++ operators that could be used for automatic wrapping. The Python + documentation lists the relevant + container operators. In particular, expose __getitem__, __setitem__ + and remember to raise the appropriate Python exceptions + (PyExc_IndexError for sequences, + PyExc_KeyError for mappings) when the requested item is not + present. + +

+ In the following example, we expose std::map<std::size_t,std::string>: +

+
+typedef std::map<std::size_t, std::string> StringMap;
+
+// A helper function for dealing with errors. Throw a Python exception
+// if p == m.end().
+void throw_key_error_if_end(
+        const StringMap& m, 
+        StringMap::const_iterator p, 
+        std::size_t key)
+{
+    if (p == m.end())
+    {
+        PyErr_SetObject(PyExc_KeyError, boost::python::converters::to_python(key));
+        throw boost::python::error_already_set();
+    }
+}
+
+// Define some simple wrapper functions which match the Python  protocol
+// for __getitem__, __setitem__, and __delitem__.  Just as in Python, a
+// free function with a “self” first parameter makes a fine class method.
+
+const std::string& get_item(const StringMap& self, std::size_t key)
+{
+    const StringMap::const_iterator p = self.find(key);
+    throw_key_error_if_end(self, p, key);
+    return p->second;
+}
+
+// Sets the item corresponding to key in the map.
+void StringMapPythonClass::set_item(StringMap& self, std::size_t key, const std::string& value)
+{
+    self[key] = value;
+}
+
+// Deletes the item corresponding to key from the map.
+void StringMapPythonClass::del_item(StringMap& self, std::size_t key)
+{
+    const StringMap::iterator p = self.find(key);
+    throw_key_error_if_end(self, p, key);
+    self.erase(p);
+}
+
+class_builder<StringMap> string_map(my_module, "StringMap");
+string_map.def(boost::python::constructor<>());
+string_map.def(&StringMap::size, "__len__");
+string_map.def(get_item, "__getitem__");
+string_map.def(set_item, "__setitem__");
+string_map.def(del_item, "__delitem__");
+
+
+

+ Then in Python: +

+
+>>> m = StringMap()
+>>> m[1]
+Traceback (innermost last):
+  File "<stdin>", line 1, in ?
+KeyError: 1
+>>> m[1] = 'hello'
+>>> m[1]
+'hello'
+>>> del m[1]
+>>> m[1]            # prove that it's gone
+Traceback (innermost last):
+  File "<stdin>", line 1, in ?
+KeyError: 1
+>>> del m[2]
+Traceback (innermost last):
+  File "<stdin>", line 1, in ?
+KeyError: 2
+>>> len(m)
+0
+>>> m[0] = 'zero'
+>>> m[1] = 'one'
+>>> m[2] = 'two'
+>>> m[3] = 'three'
+>>> len(m)
+4
+
+
+ +

Customized Attribute Access

+ +

+ Just like built-in Python classes, py_cpp extension classes support special + the usual attribute access methods __getattr__, + __setattr__, and __delattr__. + Because writing these functions can + be tedious in the common case where the attributes being accessed are + known statically, py_cpp checks the special names + +

+ + to provide functional access to the attribute <name>. This + facility can be used from C++ or entirely from Python. For example, the + following shows how we can implement a “computed attribute” in Python: +
+
+>>> class Range(AnyPy_cppExtensionClass):
+...    def __init__(self, start, end):
+...        self.start = start
+...        self.end = end
+...    def __getattr__length__(self):
+...        return self.end - self.start
+...
+>>> x = Range(3, 9)
+>>> x.length
+6
+
+
+

+ Direct Access to Data Members +

+

+ Py_cpp uses the special + __xxxattr__<name>__ functionality described above + to allow direct access to data members through the following special + functions on class_builder<> and + extension_class<>: +

+

+ Note that the first two functions, used alone, may produce surprising + behavior. For example, when def_getter() is used, the + default functionality for setattr() and + delattr() remains in effect, operating on items in the extension + instance's name-space (i.e., its __dict__). For that + reason, you'll usually want to stick with def_readonly and + def_read_write. +

+ For example, to expose a std::pair<int,long> we + might write: +

+
+typedef std::pair<int,long> Pil;
+int first(const Pil& x) { return x.first; }
+long second(const Pil& x) { return x.second; }
+   ...
+my_module.def(first, "first");
+my_module.def(second, "second");
+
+class_builder<Pil> pair_int_long(my_module, "Pair");
+pair_int_long.def(boost::python::constructor<>());
+pair_int_long.def(boost::python::constructor<int,long>());
+pair_int_long.def_read_write(&Pil::first, "first");
+pair_int_long.def_read_write(&Pil::second, "second");
+
+
+

+ Now your Python class has attributes first and + second which, when accessed, actually modify or reflect the + values of corresponding data members of the underlying C++ object. Now + in Python: +

+
+>>> x = Pair(3,5)
+>>> x.first
+3
+>>> x.second
+5
+>>> x.second = 8
+>>> x.second
+8
+>>> second(x) # Prove that we're not just changing the instance __dict__
+8
+
+
+

+ And what about __complex__? +

+

+ That, dear reader, is one problem we don't know how to solve. The + Python source contains the following fragment, indicating the + special-case code really is hardwired: +

+
+/* XXX Hack to support classes with __complex__ method */
+if (PyInstance_Check(r)) { ...
+
+
+

+ Previous: Inheritance Next: A Peek Under the Hood Up: Top +

+ © Copyright David Abrahams and Ullrich Köthe 2000. + Permission to copy, use, modify, sell and distribute this document is + granted provided this copyright notice appears in all copies. This + document is provided “as is” without express or implied + warranty, and with no claim as to its suitability for any purpose. +

+ Updated: Nov 26, 2000 +

+ diff --git a/doc/template.html b/doc/template.html new file mode 100644 index 00000000..1d0cd7a4 --- /dev/null +++ b/doc/template.html @@ -0,0 +1,26 @@ + + + The Title Of This Page + +
+

+ c++boost.gif (8819 bytes)The Title Of This + Page +

+

+

+ Prev: Previous + Next: Next + Up: Top +

+ © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided "as is" without + express or implied warranty, and with no claim as to its suitability + for any purpose. +

+ Updated: Nov 26, 2000 +

+ diff --git a/doc/under-the-hood.html b/doc/under-the-hood.html new file mode 100644 index 00000000..288021cf --- /dev/null +++ b/doc/under-the-hood.html @@ -0,0 +1,62 @@ + + + + A Peek Under the Hood + +

+ c++boost.gif (8819 bytes) +

+

+ A Peek Under the Hood +

+

+ Declaring a class_builder<T> causes the instantiation + of an extension_class<T> to which it forwards all + member function calls and which is doing most of the real work. + extension_class<T> is a subclass of + PyTypeObject, the struct which Python's 'C' API uses + to describe a type. An instance of the + extension_class<> becomes the Python type object + corresponding to hello::world. When we add it to the module it goes into the + module's dictionary to be looked up under the name "world". +

+ Py_cpp uses C++'s template argument deduction mechanism to determine the + types of arguments to functions (except constructors, for which we must + provide an argument list + because they can't be named in C++). Then, it calls the appropriate + overloaded functions PyObject* + to_python(S) and + S'from_python(PyObject*, + type<S>) which convert between any C++ + type S and a PyObject*, the type which represents a + reference to any Python object in its 'C' API. The extension_class<T> + template defines a whole raft of these conversions (for T, T*, + T&, std::auto_ptr<T>, etc.), using the same inline + friend function technique employed by the boost operators + library. +

+ Because the to_python and from_python functions + for a user-defined class are defined by + extension_class<T>, it is important that an instantiation of + extension_class<T> is visible to any code which wraps + a C++ function with a T, T*, const T&, etc. parameter or + return value. In particular, you may want to create all of the classes at + the top of your module's init function, then def the member + functions later to avoid problems with inter-class dependencies. +

+ Previous: Function Overloading + Next: Building a Module with Py_cpp + Up: Top +

+ © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided "as is" without + express or implied warranty, and with no claim as to its suitability for + any purpose. +

+ Updated: Nov 26, 2000 + diff --git a/example/example1.cpp b/example/example1.cpp new file mode 100644 index 00000000..467ac0dc --- /dev/null +++ b/example/example1.cpp @@ -0,0 +1,54 @@ +#include + +namespace hello { + class world + { + public: + world(int) {} + ~world() {} + const char* get() const { return "hi, world"; } + }; + + size_t length(const world& x) { return strlen(x.get()); } +} + +#include + +// Python requires an exported function called init in every +// extension module. This is where we build the module contents. +extern "C" +#ifdef _WIN32 +__declspec(dllexport) +#endif +void inithello() +{ + try + { + // create an object representing this extension module + boost::python::module_builder hello("hello"); + + // Create the Python type object for our extension class + boost::python::class_builder world_class(hello, "world"); + + // Add the __init__ function + world_class.def(boost::python::constructor()); + // Add a regular member function + world_class.def(&hello::world::get, "get"); + + // Add a regular function to the module + hello.def(hello::length, "length"); + } + catch(...) + { + boost::python::handle_exception(); // Deal with the exception for Python + } +} + +// Win32 DLL boilerplate +#if defined(_WIN32) +#include +extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) +{ + return 1; +} +#endif // _WIN32 diff --git a/example/example1.py b/example/example1.py new file mode 100644 index 00000000..0e3a9a18 --- /dev/null +++ b/example/example1.py @@ -0,0 +1,50 @@ +r''' +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +That's it! If we build this shared library and put it on our PYTHONPATH we can +now access our C++ class and function from Python. + + >>> import hello + >>> hi_world = hello.world(3) + >>> hi_world.get() + 'hi, world' + >>> hello.length(hi_world) + 9 + +We can even make a subclass of hello.world: + + + >>> class my_subclass(hello.world): + ... def get(self): + ... return 'hello, world' + ... + >>> y = my_subclass(2) + >>> y.get() + 'hello, world' + +Pretty cool! You can't do that with an ordinary Python extension type! + + >>> hello.length(y) + 9 + +Of course, you may now have a slightly empty feeling in the pit of your little +pythonic stomach. Perhaps you feel your subclass deserves to have a length() of +12? If so, read on... +''' +from hello import * + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_example1 + doctest.testmod(test_example1) + +if __name__ == '__main__': + run() diff --git a/include/boost/python/callback.hpp b/include/boost/python/callback.hpp new file mode 100644 index 00000000..7240b5b7 --- /dev/null +++ b/include/boost/python/callback.hpp @@ -0,0 +1,829 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. +// +// This file was generated for 10-argument python callbacks by gen_callback.python + +#ifndef CALLBACK_DWA_052100_H_ +# define CALLBACK_DWA_052100_H_ + +# include +# include + +namespace boost { namespace python { + +namespace detail { + template + inline void callback_adjust_refcount(PyObject*, type) {} + + inline void callback_adjust_refcount(PyObject* p, type) + { Py_INCREF(p); } +} + +// Calling Python from C++ +template +struct callback +{ + static R call_method(PyObject* self, const char* name) + { + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("()"))); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + static R call(PyObject* self) + { + ref result(PyEval_CallFunction(self, const_cast("()"))); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1) + { + ref p1(to_python(a1)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(O)"), + p1.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call(PyObject* self, const A1& a1) + { + ref p1(to_python(a1)); + ref result(PyEval_CallFunction(self, const_cast("(O)"), + p1.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OO)"), + p1.get(), + p2.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call(PyObject* self, const A1& a1, const A2& a2) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref result(PyEval_CallFunction(self, const_cast("(OO)"), + p1.get(), + p2.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOO)"), + p1.get(), + p2.get(), + p3.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref result(PyEval_CallFunction(self, const_cast("(OOO)"), + p1.get(), + p2.get(), + p3.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref result(PyEval_CallFunction(self, const_cast("(OOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref result(PyEval_CallFunction(self, const_cast("(OOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref result(PyEval_CallFunction(self, const_cast("(OOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref result(PyEval_CallFunction(self, const_cast("(OOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get(), + p8.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get(), + p8.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get(), + p8.get(), + p9.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); + ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get(), + p8.get(), + p9.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); + ref p10(to_python(a10)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get(), + p8.get(), + p9.get(), + p10.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + + template + static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); + ref p10(to_python(a10)); + ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get(), + p8.get(), + p9.get(), + p10.get())); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } +}; + +// This specialization wouldn't be needed, but MSVC6 doesn't correctly allow the following: +// void g(); +// void f() { return g(); } +template <> +struct callback +{ + + static void call_method(PyObject* self, const char* name) + { + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("()"))); + } + + static void call(PyObject* self) + { + ref result(PyEval_CallFunction(self, const_cast("()"))); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1) + { + ref p1(to_python(a1)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(O)"), + p1.get())); + } + + template + static void call(PyObject* self, const A1& a1) + { + ref p1(to_python(a1)); + ref result(PyEval_CallFunction(self, const_cast("(O)"), + p1.get())); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OO)"), + p1.get(), + p2.get())); + } + + template + static void call(PyObject* self, const A1& a1, const A2& a2) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref result(PyEval_CallFunction(self, const_cast("(OO)"), + p1.get(), + p2.get())); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOO)"), + p1.get(), + p2.get(), + p3.get())); + } + + template + static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref result(PyEval_CallFunction(self, const_cast("(OOO)"), + p1.get(), + p2.get(), + p3.get())); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get())); + } + + template + static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref result(PyEval_CallFunction(self, const_cast("(OOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get())); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get())); + } + + template + static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref result(PyEval_CallFunction(self, const_cast("(OOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get())); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get())); + } + + template + static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref result(PyEval_CallFunction(self, const_cast("(OOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get())); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get())); + } + + template + static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref result(PyEval_CallFunction(self, const_cast("(OOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get())); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get(), + p8.get())); + } + + template + static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get(), + p8.get())); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get(), + p8.get(), + p9.get())); + } + + template + static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); + ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get(), + p8.get(), + p9.get())); + } + + template + static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); + ref p10(to_python(a10)); + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(OOOOOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get(), + p8.get(), + p9.get(), + p10.get())); + } + + template + static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) + { + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); + ref p10(to_python(a10)); + ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOOOO)"), + p1.get(), + p2.get(), + p3.get(), + p4.get(), + p5.get(), + p6.get(), + p7.get(), + p8.get(), + p9.get(), + p10.get())); + } +}; + +// Make it a compile-time error to try to return a const char* from a virtual +// function. The standard conversion +// +// from_python(PyObject* string, boost::python::type) +// +// returns a pointer to the character array which is internal to string. The +// problem with trying to do this in a standard callback function is that the +// Python string would likely be destroyed upon return from the calling function +// (boost::python::callback::call[_method]) when its reference count is +// decremented. If you absolutely need to do this and you're sure it's safe (it +// usually isn't), you can use +// +// boost::python::string result(boost::python::callback::call[_method](...args...)); +// ...result.c_str()... // access the char* array +template <> +struct callback +{ + // Try hard to generate a readable error message + typedef struct unsafe_since_python_string_may_be_destroyed {} call, call_method; +}; + +}} // namespace boost::python + +#endif // CALLBACK_DWA_052100_H_ diff --git a/include/boost/python/caller.hpp b/include/boost/python/caller.hpp new file mode 100644 index 00000000..35b2d618 --- /dev/null +++ b/include/boost/python/caller.hpp @@ -0,0 +1,1279 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. +// +// This file generated for 10-argument member functions and 11-argument free +// functions by gen_caller.python + +#ifndef CALLER_DWA05090_H_ +# define CALLER_DWA05090_H_ + +# include +# include +# include +# include +# include + +namespace boost { namespace python { + +// Calling C++ from Python +template +struct caller +{ + template + static PyObject* call(R (T::*pmf)(), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + if (!PyArg_ParseTuple(args, const_cast("O"), &self)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)()); + } + + template + static PyObject* call(R (T::*pmf)(A1), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + if (!PyArg_ParseTuple(args, const_cast("OO"), &self, &a1)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + if (!PyArg_ParseTuple(args, const_cast("OOO"), &self, &a1, &a2)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + if (!PyArg_ParseTuple(args, const_cast("OOOO"), &self, &a1, &a2, &a3)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + if (!PyArg_ParseTuple(args, const_cast("OOOOO"), &self, &a1, &a2, &a3, &a4)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &self, &a1, &a2, &a3, &a4, &a5)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + PyObject* a10; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type()), + from_python(a10, type()))); + } + + + template + static PyObject* call(R (T::*pmf)() const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + if (!PyArg_ParseTuple(args, const_cast("O"), &self)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)()); + } + + template + static PyObject* call(R (T::*pmf)(A1) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + if (!PyArg_ParseTuple(args, const_cast("OO"), &self, &a1)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + if (!PyArg_ParseTuple(args, const_cast("OOO"), &self, &a1, &a2)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + if (!PyArg_ParseTuple(args, const_cast("OOOO"), &self, &a1, &a2, &a3)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + if (!PyArg_ParseTuple(args, const_cast("OOOOO"), &self, &a1, &a2, &a3, &a4)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &self, &a1, &a2, &a3, &a4, &a5)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type()))); + } + + template + static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + PyObject* a10; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type()), + from_python(a10, type()))); + } + + // Free functions + static PyObject* call(R (*f)(), PyObject* args, PyObject* /* keywords */ ) { + if (!PyArg_ParseTuple(args, const_cast(""))) + return 0; + return to_python(f()); + } + + template + static PyObject* call(R (*f)(A1), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + if (!PyArg_ParseTuple(args, const_cast("O"), &a1)) + return 0; + return to_python(f(from_python(a1, type()))); + } + + template + static PyObject* call(R (*f)(A1, A2), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + if (!PyArg_ParseTuple(args, const_cast("OO"), &a1, &a2)) + return 0; + return to_python(f(from_python(a1, type()), + from_python(a2, type()))); + } + + template + static PyObject* call(R (*f)(A1, A2, A3), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + if (!PyArg_ParseTuple(args, const_cast("OOO"), &a1, &a2, &a3)) + return 0; + return to_python(f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()))); + } + + template + static PyObject* call(R (*f)(A1, A2, A3, A4), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + if (!PyArg_ParseTuple(args, const_cast("OOOO"), &a1, &a2, &a3, &a4)) + return 0; + return to_python(f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()))); + } + + template + static PyObject* call(R (*f)(A1, A2, A3, A4, A5), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + if (!PyArg_ParseTuple(args, const_cast("OOOOO"), &a1, &a2, &a3, &a4, &a5)) + return 0; + return to_python(f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()))); + } + + template + static PyObject* call(R (*f)(A1, A2, A3, A4, A5, A6), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6)) + return 0; + return to_python(f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()))); + } + + template + static PyObject* call(R (*f)(A1, A2, A3, A4, A5, A6, A7), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7)) + return 0; + return to_python(f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()))); + } + + template + static PyObject* call(R (*f)(A1, A2, A3, A4, A5, A6, A7, A8), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) + return 0; + return to_python(f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()))); + } + + template + static PyObject* call(R (*f)(A1, A2, A3, A4, A5, A6, A7, A8, A9), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) + return 0; + return to_python(f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type()))); + } + + template + static PyObject* call(R (*f)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + PyObject* a10; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) + return 0; + return to_python(f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type()), + from_python(a10, type()))); + } + + template + static PyObject* call(R (*f)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + PyObject* a10; + PyObject* a11; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10, &a11)) + return 0; + return to_python(f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type()), + from_python(a10, type()), + from_python(a11, type()))); + } + +}; + +template <> +struct caller +{ + template + static PyObject* call(void (T::*pmf)(), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + if (!PyArg_ParseTuple(args, const_cast("O"), &self)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + if (!PyArg_ParseTuple(args, const_cast("OO"), &self, &a1)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + if (!PyArg_ParseTuple(args, const_cast("OOO"), &self, &a1, &a2)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + if (!PyArg_ParseTuple(args, const_cast("OOOO"), &self, &a1, &a2, &a3)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + if (!PyArg_ParseTuple(args, const_cast("OOOOO"), &self, &a1, &a2, &a3, &a4)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &self, &a1, &a2, &a3, &a4, &a5)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + PyObject* a10; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type()), + from_python(a10, type())); + return detail::none(); + } + + + template + static PyObject* call(void (T::*pmf)() const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + if (!PyArg_ParseTuple(args, const_cast("O"), &self)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + if (!PyArg_ParseTuple(args, const_cast("OO"), &self, &a1)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + if (!PyArg_ParseTuple(args, const_cast("OOO"), &self, &a1, &a2)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + if (!PyArg_ParseTuple(args, const_cast("OOOO"), &self, &a1, &a2, &a3)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + if (!PyArg_ParseTuple(args, const_cast("OOOOO"), &self, &a1, &a2, &a3, &a4)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &self, &a1, &a2, &a3, &a4, &a5)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type())); + return detail::none(); + } + + template + static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + PyObject* a10; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) + return 0; + T& target = from_python(self, type()); + (target.*pmf)(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type()), + from_python(a10, type())); + return detail::none(); + } + + + // Free functions + static PyObject* call(void (*f)(), PyObject* args, PyObject* /* keywords */ ) { + if (!PyArg_ParseTuple(args, const_cast(""))) + return 0; + f(); + return detail::none(); + } + + template + static PyObject* call(void (*f)(A1), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + if (!PyArg_ParseTuple(args, const_cast("O"), &a1)) + return 0; + f(from_python(a1, type())); + return detail::none(); + } + + template + static PyObject* call(void (*f)(A1, A2), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + if (!PyArg_ParseTuple(args, const_cast("OO"), &a1, &a2)) + return 0; + f(from_python(a1, type()), + from_python(a2, type())); + return detail::none(); + } + + template + static PyObject* call(void (*f)(A1, A2, A3), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + if (!PyArg_ParseTuple(args, const_cast("OOO"), &a1, &a2, &a3)) + return 0; + f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type())); + return detail::none(); + } + + template + static PyObject* call(void (*f)(A1, A2, A3, A4), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + if (!PyArg_ParseTuple(args, const_cast("OOOO"), &a1, &a2, &a3, &a4)) + return 0; + f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type())); + return detail::none(); + } + + template + static PyObject* call(void (*f)(A1, A2, A3, A4, A5), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + if (!PyArg_ParseTuple(args, const_cast("OOOOO"), &a1, &a2, &a3, &a4, &a5)) + return 0; + f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type())); + return detail::none(); + } + + template + static PyObject* call(void (*f)(A1, A2, A3, A4, A5, A6), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6)) + return 0; + f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type())); + return detail::none(); + } + + template + static PyObject* call(void (*f)(A1, A2, A3, A4, A5, A6, A7), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7)) + return 0; + f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type())); + return detail::none(); + } + + template + static PyObject* call(void (*f)(A1, A2, A3, A4, A5, A6, A7, A8), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) + return 0; + f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type())); + return detail::none(); + } + + template + static PyObject* call(void (*f)(A1, A2, A3, A4, A5, A6, A7, A8, A9), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) + return 0; + f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type())); + return detail::none(); + } + + template + static PyObject* call(void (*f)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + PyObject* a10; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) + return 0; + f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type()), + from_python(a10, type())); + return detail::none(); + } + + template + static PyObject* call(void (*f)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11), PyObject* args, PyObject* /* keywords */ ) { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + PyObject* a10; + PyObject* a11; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10, &a11)) + return 0; + f(from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()), + from_python(a4, type()), + from_python(a5, type()), + from_python(a6, type()), + from_python(a7, type()), + from_python(a8, type()), + from_python(a9, type()), + from_python(a10, type()), + from_python(a11, type())); + return detail::none(); + } + +}; + +}} // namespace boost::python + +#endif diff --git a/include/boost/python/class_builder.hpp b/include/boost/python/class_builder.hpp new file mode 100644 index 00000000..9e88f049 --- /dev/null +++ b/include/boost/python/class_builder.hpp @@ -0,0 +1,156 @@ +#ifndef CLASS_WRAPPER_DWA101000_H_ +# define CLASS_WRAPPER_DWA101000_H_ + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace python { + +// Syntactic sugar to make wrapping classes more convenient +template > +class class_builder + : python_extension_class_converters // Works around MSVC6.x/GCC2.95.2 bug described below +{ + public: + class_builder(module_builder& module, const char* name) + : m_class(new detail::extension_class(name)) + { + module.add(ref(as_object(m_class.get()), ref::increment_count), name); + } + + ~class_builder() + {} + + // define constructors + template + void def(const signature& signature) + { m_class->def(signature); } + + // export heterogeneous reverse-argument operators + // (type of lhs: 'left', of rhs: 'right') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub), Foo>(), + // boost::python::left_operand()); + template + void def(operators o1, left_operand o2) + { m_class->def(o1, o2); } + + // export heterogeneous operators (type of lhs: 'left', of rhs: 'right') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub), Foo>(), + // boost::python::right_operand()); + template + void def(operators o1, right_operand o2) + { m_class->def(o1, o2); } + + // define a function that passes Python arguments and keywords + // to C++ verbatim (as a 'tuple const &' and 'dictionary const &' + // respectively). This is useful for manual argument passing. + // It's also the only possibility to pass keyword arguments to C++. + // Fn must have a signatur that is compatible to + // PyObject * (*)(PyObject * aTuple, PyObject * aDictionary) + template + void def_raw(Fn fn, const char* name) + { m_class->def_raw(fn, name); } + + // define member functions. In fact this works for free functions, too - + // they act like static member functions, or if they start with the + // appropriate self argument (as a pointer or reference), they can be used + // just like ordinary member functions -- just like Python! + template + void def(Fn fn, const char* name) + { m_class->def(fn, name); } + + // Define a virtual member function with a default implementation. + // default_fn should be a function which provides the default implementation. + // Be careful that default_fn does not in fact call fn virtually! + template + void def(Fn fn, const char* name, DefaultFn default_fn) + { m_class->def(fn, name, default_fn); } + + // Provide a function which implements x., reading from the given + // member (pm) of the T obj + template + void def_getter(MemberType T::*pm, const char* name) + { m_class->def_getter(pm, name); } + + // Provide a function which implements assignment to x., writing to + // the given member (pm) of the T obj + template + void def_setter(MemberType T::*pm, const char* name) + { m_class->def_getter(pm, name); } + + // Expose the given member (pm) of the T obj as a read-only attribute + template + void def_readonly(MemberType T::*pm, const char* name) + { m_class->def_readonly(pm, name); } + + // Expose the given member (pm) of the T obj as a read/write attribute + template + void def_read_write(MemberType T::*pm, const char* name) + { m_class->def_read_write(pm, name); } + + // define the standard coercion needed for operator overloading + void def_standard_coerce() + { m_class->def_standard_coerce(); } + + // declare the given class a base class of this one and register + // conversion functions + template + void declare_base(class_builder const & base) + { + m_class->declare_base(base.get_extension_class()); + } + + // declare the given class a base class of this one and register + // upcast conversion function + template + void declare_base(class_builder const & base, without_downcast_t) + { + m_class->declare_base(base.get_extension_class(), without_downcast); + } + + // get the embedded ExtensioClass object + detail::extension_class * get_extension_class() const + { + return m_class.get(); + } + + // set an arbitrary attribute. Useful for non-function class data members, + // e.g. enums + void add(PyObject* x, const char* name) + { m_class->set_attribute(name, x); } + void add(ref x, const char* name) + { m_class->set_attribute(name, x); } + private: + // declare the given class a base class of this one and register + // conversion functions + template + void declare_base(detail::extension_class * base) + { + m_class->declare_base(base); + } + + // declare the given class a base class of this one and register + // upcast conversion function + template + void declare_base(detail::extension_class * base, without_downcast_t) + { + m_class->declare_base(base, without_downcast); + } + + reference > m_class; +}; + +// The bug mentioned at the top of this file is that on certain compilers static +// global functions declared within the body of a class template will only be +// generated when the class template is constructed, and when (for some reason) +// the construction does not occur via a new-expression. Otherwise, we could +// rely on the initialization of the m_class data member to cause all of the +// to_/from_python functions to come into being. + +}} // namespace boost::python + +#endif // CLASS_WRAPPER_DWA101000_H_ diff --git a/include/boost/python/classes.hpp b/include/boost/python/classes.hpp new file mode 100644 index 00000000..d38fbba5 --- /dev/null +++ b/include/boost/python/classes.hpp @@ -0,0 +1,527 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef SUBCLASS_DWA051500_H_ +# define SUBCLASS_DWA051500_H_ + +# include +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python { + +// A simple type which acts something like a built-in Python class obj. +class instance + : public boost::python::detail::python_object +{ + public: + instance(PyTypeObject* class_); + ~instance(); + + // Standard Python functions. + PyObject* repr(); + int compare(PyObject*); + PyObject* str(); + long hash(); + PyObject* call(PyObject* args, PyObject* keywords); + PyObject* getattr(const char* name, bool use_special_function = true); + int setattr(const char* name, PyObject* value); + + // Mapping methods + int length(); + PyObject* get_subscript(PyObject* key); + void set_subscript(PyObject* key, PyObject* value); + + // Sequence methods + PyObject* get_slice(int start, int finish); + void set_slice(int start, int finish, PyObject* value); + + // Number methods + PyObject* add(PyObject* other); + PyObject* subtract(PyObject* other); + PyObject* multiply(PyObject* other); + PyObject* divide(PyObject* other); + PyObject* remainder(PyObject* other); + PyObject* divmod(PyObject* other); + PyObject* power(PyObject*, PyObject*); + PyObject* negative(); + PyObject* positive(); + PyObject* absolute(); + int nonzero(); + PyObject* invert(); + PyObject* lshift(PyObject* other); + PyObject* rshift(PyObject* other); + PyObject* do_and(PyObject* other); + PyObject* do_xor(PyObject* other); + PyObject* do_or(PyObject* other); + int coerce(PyObject**, PyObject**); + PyObject* as_int(); + PyObject* as_long(); + PyObject* as_float(); + PyObject* oct(); + PyObject* hex(); + + private: // noncopyable, without the size bloat + instance(const instance&); + void operator=(const instance&); + + private: // helper functions + int setattr_dict(PyObject* value); + + private: + dictionary m_name_space; +}; + +template class meta_class; + +namespace detail { + class class_base : public type_object_base + { + public: + class_base(PyTypeObject* meta_class_obj, string name, tuple bases, const dictionary& name_space); + tuple bases() const; + string name() const; + dictionary& dict(); + + // Standard Python functions. + PyObject* getattr(const char* name); + int setattr(const char* name, PyObject* value); + PyObject* repr() const; + void add_base(ref base); + + protected: + bool initialize_instance(instance* obj, PyObject* args, PyObject* keywords); + + private: // virtual functions + // Subclasses should override this to delete the particular obj type + virtual void delete_instance(PyObject*) const = 0; + + private: // boost::python::type_object_base required interface implementation + void instance_dealloc(PyObject*) const; // subclasses should not override this + + private: + string m_name; + tuple m_bases; + dictionary m_name_space; + }; + + void enable_named_method(class_base* type_obj, const char* name); +} + +// A type which acts a lot like a built-in Python class. T is the obj type, +// so class_t is a very simple "class-alike". +template +class class_t + : public boost::python::detail::class_base +{ + public: + class_t(meta_class* meta_class_obj, string name, tuple bases, const dictionary& name_space); + + // Standard Python functions. + PyObject* call(PyObject* args, PyObject* keywords); + + private: // Implement mapping methods on instances + PyObject* instance_repr(PyObject*) const; + int instance_compare(PyObject*, PyObject* other) const; + PyObject* instance_str(PyObject*) const; + long instance_hash(PyObject*) const; + int instance_mapping_length(PyObject*) const; + PyObject* instance_mapping_subscript(PyObject*, PyObject*) const; + int instance_mapping_ass_subscript(PyObject*, PyObject*, PyObject*) const; + + private: // Implement sequence methods on instances + int instance_sequence_length(PyObject*) const; + PyObject* instance_sequence_item(PyObject* obj, int n) const; + int instance_sequence_ass_item(PyObject* obj, int n, PyObject* value) const; + PyObject* instance_sequence_slice(PyObject*, int start, int finish) const; + int instance_sequence_ass_slice(PyObject*, int start, int finish, PyObject* value) const; + + private: // Implement number methods on instances + PyObject* instance_number_add(PyObject*, PyObject*) const; + PyObject* instance_number_subtract(PyObject*, PyObject*) const; + PyObject* instance_number_multiply(PyObject*, PyObject*) const; + PyObject* instance_number_divide(PyObject*, PyObject*) const; + PyObject* instance_number_remainder(PyObject*, PyObject*) const; + PyObject* instance_number_divmod(PyObject*, PyObject*) const; + PyObject* instance_number_power(PyObject*, PyObject*, PyObject*) const; + PyObject* instance_number_negative(PyObject*) const; + PyObject* instance_number_positive(PyObject*) const; + PyObject* instance_number_absolute(PyObject*) const; + int instance_number_nonzero(PyObject*) const; + PyObject* instance_number_invert(PyObject*) const; + PyObject* instance_number_lshift(PyObject*, PyObject*) const; + PyObject* instance_number_rshift(PyObject*, PyObject*) const; + PyObject* instance_number_and(PyObject*, PyObject*) const; + PyObject* instance_number_xor(PyObject*, PyObject*) const; + PyObject* instance_number_or(PyObject*, PyObject*) const; + int instance_number_coerce(PyObject*, PyObject**, PyObject**) const; + PyObject* instance_number_int(PyObject*) const; + PyObject* instance_number_long(PyObject*) const; + PyObject* instance_number_float(PyObject*) const; + PyObject* instance_number_oct(PyObject*) const; + PyObject* instance_number_hex(PyObject*) const; + + private: // Miscellaneous "special" methods + PyObject* instance_call(PyObject* obj, PyObject* args, PyObject* keywords) const; + PyObject* instance_getattr(PyObject* obj, const char* name) const; + int instance_setattr(PyObject* obj, const char* name, PyObject* value) const; + + private: // Implementation of boost::python::detail::class_base required interface + void delete_instance(PyObject*) const; + + private: // noncopyable, without the size bloat + class_t(const class_t&); + void operator=(const class_t&); +}; + +// The type of a class_t object. +template +class meta_class + : public boost::python::detail::reprable< + boost::python::detail::callable< + boost::python::detail::getattrable< + boost::python::detail::setattrable< + boost::python::detail::type_object > > > > >, + boost::noncopyable +{ + public: + meta_class(); + + // Standard Python functions. + PyObject* call(PyObject* args, PyObject* keywords); + + struct type_object + : boost::python::detail::singleton > > + { + type_object() : singleton_base(&PyType_Type) {} + }; +}; + +// +// Member function implementations. +// +template +meta_class::meta_class() + : properties(type_object::instance()) +{ +} + +template +class_t::class_t(meta_class* meta_class_obj, string name, tuple bases, const dictionary& name_space) + : boost::python::detail::class_base(meta_class_obj, name, bases, name_space) +{ +} + +template +void class_t::delete_instance(PyObject* obj) const +{ + delete downcast(obj); +} + +template +PyObject* class_t::call(PyObject* args, PyObject* keywords) +{ + reference result(new T(this)); + if (!this->initialize_instance(result.get(), args, keywords)) + return 0; + else + return result.release(); +} + +template +PyObject* class_t::instance_repr(PyObject* obj) const +{ + return downcast(obj)->repr(); +} + +template +int class_t::instance_compare(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->compare(other); +} + +template +PyObject* class_t::instance_str(PyObject* obj) const +{ + return downcast(obj)->str(); +} + +template +long class_t::instance_hash(PyObject* obj) const +{ + return downcast(obj)->hash(); +} + +template +int class_t::instance_mapping_length(PyObject* obj) const +{ + return downcast(obj)->length(); +} + +template +int class_t::instance_sequence_length(PyObject* obj) const +{ + return downcast(obj)->length(); +} + +template +PyObject* class_t::instance_mapping_subscript(PyObject* obj, PyObject* key) const +{ + return downcast(obj)->get_subscript(key); +} + +template +PyObject* class_t::instance_sequence_item(PyObject* obj, int n) const +{ + ref key(to_python(n)); + return downcast(obj)->get_subscript(key.get()); +} + +template +int class_t::instance_sequence_ass_item(PyObject* obj, int n, PyObject* value) const +{ + ref key(to_python(n)); + downcast(obj)->set_subscript(key.get(), value); + return 0; +} + +template +int class_t::instance_mapping_ass_subscript(PyObject* obj, PyObject* key, PyObject* value) const +{ + downcast(obj)->set_subscript(key, value); + return 0; +} + +void adjust_slice_indices(PyObject* obj, int& start, int& finish); + +template +PyObject* class_t::instance_sequence_slice(PyObject* obj, int start, int finish) const +{ + adjust_slice_indices(obj, start, finish); + return downcast(obj)->get_slice(start, finish); +} + +template +int class_t::instance_sequence_ass_slice(PyObject* obj, int start, int finish, PyObject* value) const +{ + adjust_slice_indices(obj, start, finish); + downcast(obj)->set_slice(start, finish, value); + return 0; +} + +template +PyObject* class_t::instance_call(PyObject* obj, PyObject* args, PyObject* keywords) const +{ + return downcast(obj)->call(args, keywords); +} + +template +PyObject* class_t::instance_getattr(PyObject* obj, const char* name) const +{ + return downcast(obj)->getattr(name); +} + + +template +int class_t::instance_setattr(PyObject* obj, const char* name, PyObject* value) const +{ + return downcast(obj)->setattr(name, value); +} + +template +PyObject* class_t::instance_number_add(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->add(other); +} + +template +PyObject* class_t::instance_number_subtract(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->subtract(other); +} + +template +PyObject* class_t::instance_number_multiply(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->multiply(other); +} + +template +PyObject* class_t::instance_number_divide(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->divide(other); +} + +template +PyObject* class_t::instance_number_remainder(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->remainder(other); +} + +template +PyObject* class_t::instance_number_divmod(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->divmod(other); +} + +template +PyObject* class_t::instance_number_power(PyObject* obj, PyObject* exponent, PyObject* modulus) const +{ + return downcast(obj)->power(exponent, modulus); +} + +template +PyObject* class_t::instance_number_negative(PyObject* obj) const +{ + return downcast(obj)->negative(); +} + +template +PyObject* class_t::instance_number_positive(PyObject* obj) const +{ + return downcast(obj)->positive(); +} + +template +PyObject* class_t::instance_number_absolute(PyObject* obj) const +{ + return downcast(obj)->absolute(); +} + +template +int class_t::instance_number_nonzero(PyObject* obj) const +{ + return downcast(obj)->nonzero(); +} + +template +PyObject* class_t::instance_number_invert(PyObject* obj) const +{ + return downcast(obj)->invert(); +} + +template +PyObject* class_t::instance_number_lshift(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->lshift(other); +} + +template +PyObject* class_t::instance_number_rshift(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->rshift(other); +} + +template +PyObject* class_t::instance_number_and(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->do_and(other); +} + +template +PyObject* class_t::instance_number_xor(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->do_xor(other); +} + +template +PyObject* class_t::instance_number_or(PyObject* obj, PyObject* other) const +{ + return downcast(obj)->do_or(other); +} + +template +int class_t::instance_number_coerce(PyObject* obj, PyObject** x, PyObject** y) const +{ + return downcast(obj)->coerce(x, y); +} + +template +PyObject* class_t::instance_number_int(PyObject* obj) const +{ + return downcast(obj)->as_int(); +} + +template +PyObject* class_t::instance_number_long(PyObject* obj) const +{ + return downcast(obj)->as_long(); +} + +template +PyObject* class_t::instance_number_float(PyObject* obj) const +{ + return downcast(obj)->as_float(); +} + +template +PyObject* class_t::instance_number_oct(PyObject* obj) const +{ + return downcast(obj)->oct(); +} + +template +PyObject* class_t::instance_number_hex(PyObject* obj) const +{ + return downcast(obj)->hex(); +} + +namespace detail { + inline dictionary& class_base::dict() + { + return m_name_space; + } + + inline tuple class_base::bases() const + { + return m_bases; + } +} + +template +PyObject* meta_class::call(PyObject* args, PyObject* /*keywords*/) +{ + PyObject* name; + PyObject* bases; + PyObject* name_space; + + if (!PyArg_ParseTuple(args, const_cast("O!O!O!"), + &PyString_Type, &name, + &PyTuple_Type, &bases, + &PyDict_Type, &name_space)) + { + return 0; + } + + return as_object( + new class_t(this, string(ref(name, ref::increment_count)), + tuple(ref(bases, ref::increment_count)), + dictionary(ref(name_space, ref::increment_count))) + ); +} + +namespace detail { + const string& setattr_string(); + const string& getattr_string(); + const string& delattr_string(); + + inline string class_base::name() const + { + return m_name; + } +} + + +}} // namespace boost::python +#endif diff --git a/include/boost/python/conversions.hpp b/include/boost/python/conversions.hpp new file mode 100644 index 00000000..d11f7f14 --- /dev/null +++ b/include/boost/python/conversions.hpp @@ -0,0 +1,325 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef METHOD_DWA122899_H_ +# define METHOD_DWA122899_H_ + +# include +# include +# include +# include +# include +# include +# include + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround + +// This can be instantiated on an enum to provide the to_python/from_python +// conversions, provided the values can fit in a long. +template +class py_enum_as_int_converters +{ + friend EnumType from_python(PyObject* x, boost::python::type) + { + return static_cast( + from_python(x, boost::python::type())); + } + + friend EnumType from_python(PyObject* x, boost::python::type) + { + return static_cast( + from_python(x, boost::python::type())); + } + + friend PyObject* to_python(EnumType x) + { + return to_python(static_cast(x)); + } +}; +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +namespace boost { namespace python { +template class enum_as_int_converters + : public BOOST_PYTHON_CONVERSION::py_enum_as_int_converters {}; + +template class wrapped_pointer; + +//#pragma warn_possunwant off +inline void decref_impl(PyObject* p) { Py_DECREF(p); } +inline void xdecref_impl(PyObject* p) { Py_XDECREF(p); } +//#pragma warn_possunwant reset + +template +inline void decref(T* p) +{ + char* const raw_p = reinterpret_cast(p); + char* const p_base = raw_p - offsetof(PyObject, ob_refcnt); + decref_impl(reinterpret_cast(p_base)); +} + +template +inline void xdecref(T* p) +{ + char* const raw_p = reinterpret_cast(p); + char* const p_base = raw_p - offsetof(PyObject, ob_refcnt); + xdecref_impl(reinterpret_cast(p_base)); +} + +}} // namespace boost::python + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE +// +// Converters +// +PyObject* to_python(long); +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); +unsigned long from_python(PyObject* p, boost::python::type); + +PyObject* to_python(int); +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); +unsigned int from_python(PyObject*, boost::python::type); + +PyObject* to_python(short); +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); +unsigned short from_python(PyObject*, boost::python::type); + +PyObject* to_python(signed char); +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); +unsigned char from_python(PyObject*, boost::python::type); + +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); +double from_python(PyObject*, boost::python::type); + +PyObject* to_python(bool); +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); + +PyObject* to_python(const char* s); +const char* from_python(PyObject*, boost::python::type); + +PyObject* to_python(const std::string& s); +std::string from_python(PyObject*, boost::python::type); +std::string from_python(PyObject*, boost::python::type); + +// For when your C++ function really wants to pass/return a PyObject* +PyObject* to_python(PyObject*); +PyObject* from_python(PyObject*, boost::python::type); + +// Some standard conversions to/from smart pointer types. You can add your own +// from these examples. These are not generated using the friend technique from +// wrapped_pointer because: +// +// 1. We want to be able to extend conversion to/from WrappedPointers using +// arbitrary smart pointer types. +// +// 2. It helps with compilation independence. This way, code which creates +// wrappers for functions accepting and returning smart_ptr does not +// have to have already seen the invocation of wrapped_type. +// + +// Unfortunately, MSVC6 is so incredibly lame that we have to rely on the friend +// technique to auto_generate standard pointer conversions for wrapped +// types. This means that you need to write a non-templated function for each +// specific smart_ptr which you want to convert from_python. For example, +// +// namespace boost { namespace python { +// #ifdef MUST_SUPPORT_MSVC +// +// MyPtr from_python(PyObject*p, type >) +// { return smart_ptr_from_python(p, type >(), type());} +// } +// +// MyPtr from_python(PyObject*p, type >) +// { return smart_ptr_from_python(p, type >(), type());} +// +// ... // definitions for MyPtr, MyPtr, etc. +// +// #else +// +// // Just once for all MyPtr +// template +// MyPtr from_python(PyObject*p, type >) +// { +// return smart_ptr_from_python(p, type >(), type()); +// } +// +// #endif +// }} // namespace boost::python + +#if !defined(BOOST_MSVC6_OR_EARLIER) +template +boost::shared_ptr from_python(PyObject*p, boost::python::type >) +{ + return smart_ptr_from_python(p, boost::python::type >(), boost::python::type()); +} +#endif + +#if 0 +template +PyObject* to_python(std::auto_ptr p) +{ + return new boost::python::wrapped_pointer, T>(p); +} + +template +PyObject* to_python(boost::shared_ptr p) +{ + return new boost::python::wrapped_pointer, T>(p); +} +#endif + +// +// inline implementations +// + +#ifndef BOOST_MSVC6_OR_EARLIER +inline PyObject* to_python(double d) +{ + return PyFloat_FromDouble(d); +} + +inline PyObject* to_python(float f) +{ + return PyFloat_FromDouble(f); +} +#endif // BOOST_MSVC6_OR_EARLIER + +inline PyObject* to_python(long l) +{ + return PyInt_FromLong(l); +} + +inline PyObject* to_python(int x) +{ + return PyInt_FromLong(x); +} + +inline PyObject* to_python(short x) +{ + return PyInt_FromLong(x); +} + +inline PyObject* to_python(bool b) +{ + return PyInt_FromLong(b); +} + +inline PyObject* to_python(void) +{ + return boost::python::detail::none(); +} + +inline PyObject* to_python(const char* s) +{ + return PyString_FromString(s); +} + +inline std::string from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + +inline PyObject* to_python(PyObject* p) +{ + Py_INCREF(p); + return p; +} + +inline PyObject* from_python(PyObject* p, boost::python::type) +{ + return p; +} + +inline const char* from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + +inline double from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + +inline float from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + +inline int from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + +inline short from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + +inline long from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + +inline bool from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + +inline unsigned int from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + +inline unsigned short from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + +inline signed char from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + +inline unsigned char from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + +inline unsigned long from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +#endif // METHOD_DWA122899_H_ diff --git a/include/boost/python/detail/base_object.hpp b/include/boost/python/detail/base_object.hpp new file mode 100644 index 00000000..f8ed665b --- /dev/null +++ b/include/boost/python/detail/base_object.hpp @@ -0,0 +1,62 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef BASE_OBJECT_DWA051600_H_ +# define BASE_OBJECT_DWA051600_H_ + +# include +# include // really just for type<> +# include +# include + +namespace boost { namespace python { namespace detail { + +// base_object - adds a constructor and non-virtual destructor to a +// base Python type (e.g. PyObject, PyTypeObject). +template +struct base_object : python_type +{ + typedef python_type base_python_type; + + // Initializes type and reference count. All other fields of base_python_type are 0 + base_object(PyTypeObject* type_obj); + + // Decrements reference count on the type + ~base_object(); +}; + +// Easy typedefs for common usage +typedef base_object python_object; +typedef base_object python_type; + + +// +// class_t template member function implementations +// +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)); + ob_refcnt = 1; + ob_type = type_obj; + Py_INCREF(type_obj); +} + +template +inline base_object::~base_object() +{ + Py_DECREF(ob_type); +} + +}}} // namespace boost::python::detail + +#endif // BASE_OBJECT_DWA051600_H_ diff --git a/include/boost/python/detail/cast.hpp b/include/boost/python/detail/cast.hpp new file mode 100644 index 00000000..a6f2f046 --- /dev/null +++ b/include/boost/python/detail/cast.hpp @@ -0,0 +1,81 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef CAST_DWA052500_H_ +# define CAST_DWA052500_H_ + +# include +# include + +namespace boost { namespace python { + +namespace detail { + // The default way of converting a PyObject* or PyTypeObject* to a T* + template + struct downcast_traits + { + template + static T* cast(U* p) { return static_cast(p); } + }; + + inline PyTypeObject* as_base_object(const PyTypeObject*, PyObject* p) + { + return reinterpret_cast(p); + } + + inline PyObject* as_base_object(const PyObject*, PyObject* p) + { + return p; + } + + inline const PyTypeObject* as_base_object(const PyTypeObject*, const PyObject* p) + { + return reinterpret_cast(p); + } + + inline const PyObject* as_base_object(const PyObject*, const PyObject* p) + { + return p; + } +} // namespace detail + +// Convert a pointer to any type derived from PyObject or PyTypeObject to a PyObject* +inline PyObject* as_object(PyObject* p) { return p; } +inline PyObject* as_object(PyTypeObject* p) { return reinterpret_cast(p); } + +// If I didn't have to support stupid MSVC6 we could just use a simple template function: +// template T* downcast(PyObject*). +template +struct downcast : boost::dereferenceable, T*> +{ + downcast(PyObject* p) + : m_p(detail::downcast_traits::cast(detail::as_base_object((T*)0, p))) + {} + + downcast(const PyObject* p) + : m_p(detail::downcast_traits::cast(detail::as_base_object((const T*)0, p))) + {} + + downcast(PyTypeObject* p) + : m_p(detail::downcast_traits::cast(p)) + {} + + downcast(const PyTypeObject* p) + : m_p(detail::downcast_traits::cast(p)) + {} + + operator T*() const { return m_p; } + T* get() const { return m_p; } + T& operator*() const { return *m_p; } + private: + T* m_p; +}; + +}} // namespace boost::python + +#endif // CAST_DWA052500_H_ diff --git a/include/boost/python/detail/config.hpp b/include/boost/python/detail/config.hpp new file mode 100644 index 00000000..2488bd8e --- /dev/null +++ b/include/boost/python/detail/config.hpp @@ -0,0 +1,56 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef CONFIG_DWA052200_H_ +# define CONFIG_DWA052200_H_ + +# include +# include + +# ifdef BOOST_NO_OPERATORS_IN_NAMESPACE + // A gcc bug forces some symbols into the global namespace +# define BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE +# define BOOST_PYTHON_END_CONVERSION_NAMESPACE +# define BOOST_PYTHON_CONVERSION +# define BOOST_PYTHON_IMPORT_CONVERSION(x) using ::x +# else +# define BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE namespace boost { namespace python { +# define BOOST_PYTHON_END_CONVERSION_NAMESPACE }} // namespace boost::python +# define BOOST_PYTHON_CONVERSION python +# define BOOST_PYTHON_IMPORT_CONVERSION(x) void never_defined() // so we can follow the macro with a ';' +# endif + +# if defined(BOOST_MSVC) +# if _MSC_VER <= 1200 +# define BOOST_MSVC6_OR_EARLIER 1 +# endif + +# pragma warning (disable : 4786) + +# endif + +// Work around the broken library implementation/strict ansi checking on some +// EDG-based compilers (e.g. alpha), which incorrectly warn that the result of +// offsetof() is not an integer constant expression. +# if defined(__DECCXX_VER) && __DECCXX_VER <= 60290024 +# define BOOST_OFFSETOF(s_name, s_member) \ + ((size_t)__INTADDR__(&(((s_name *)0)->s_member))) +# else +# define BOOST_OFFSETOF(s_name, s_member) \ + offsetof(s_name, s_member) +# endif + +// The STLport puts all of the standard 'C' library names in std (as far as the +// user is concerned), but without it you need a fix if you're using MSVC. +# if defined(BOOST_MSVC6_OR_EARLIER) && !defined(__STLPORT) +# define BOOST_CSTD_ +# else +# define BOOST_CSTD_ std +# endif + +#endif // CONFIG_DWA052200_H_ diff --git a/include/boost/python/detail/extension_class.hpp b/include/boost/python/detail/extension_class.hpp new file mode 100644 index 00000000..20d48796 --- /dev/null +++ b/include/boost/python/detail/extension_class.hpp @@ -0,0 +1,834 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. +// +// This file automatically generated for 5-argument constructors by +// gen_extclass.python + +#ifndef EXTENSION_CLASS_DWA052000_H_ +# define EXTENSION_CLASS_DWA052000_H_ + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python { + +// forward declarations +template struct operators; +template struct left_operand; +template struct right_operand; + +enum without_downcast_t { without_downcast }; + +namespace detail { + +// forward declarations +class extension_instance; +class extension_class_base; +template class instance_holder; +template class instance_value_holder; +template class instance_ptr_holder; +template struct operand_select; + template struct choose_op; + template struct choose_rop; + template struct choose_unary_op; + template struct define_operator; + +meta_class* extension_meta_class(); +extension_instance* get_extension_instance(PyObject* p); +void report_missing_instance_data(extension_instance*, class_t*, const std::type_info&); +void report_missing_ptr_data(extension_instance*, class_t*, const std::type_info&); +void report_missing_class_object(const std::type_info&); +void report_released_smart_pointer(const std::type_info&); + +template +T* check_non_null(T* p) +{ + if (p == 0) + report_released_smart_pointer(typeid(T)); + return p; +} + +template class held_instance; + +typedef void* (*conversion_function_ptr)(void*); + +struct base_class_info +{ + base_class_info(extension_class_base* t, conversion_function_ptr f) + :class_object(t), convert(f) + {} + + extension_class_base* class_object; + conversion_function_ptr convert; +}; + +typedef base_class_info derived_class_info; + +struct add_operator_base; + +class extension_class_base : public class_t +{ + public: + extension_class_base(const char* name); + + public: + // the purpose of try_class_conversions() and its related functions + // is explained in extclass.cpp + void* try_class_conversions(instance_holder_base*) const; + void* try_base_class_conversions(instance_holder_base*) const; + void* try_derived_class_conversions(instance_holder_base*) const; + + void set_attribute(const char* name, PyObject* x); + void set_attribute(const char* name, ref x); + + private: + virtual void* extract_object_from_holder(instance_holder_base* v) const = 0; + virtual std::vector const& base_classes() const = 0; + virtual std::vector const& derived_classes() const = 0; + + protected: + friend struct add_operator_base; + void add_method(reference method, const char* name); + void add_method(function* method, const char* name); + + void add_constructor_object(function*); + void add_setter_method(function*, const char* name); + void add_getter_method(function*, const char* name); +}; + +template +class class_registry +{ + public: + static extension_class_base* class_object() + { return static_class_object; } + + // Register/unregister the Python class object corresponding to T + static void register_class(extension_class_base*); + static void unregister_class(extension_class_base*); + + // Establish C++ inheritance relationships + static void register_base_class(base_class_info const&); + static void register_derived_class(derived_class_info const&); + + // Query the C++ inheritance relationships + static std::vector const& base_classes(); + static std::vector const& derived_classes(); + private: + static extension_class_base* static_class_object; + static std::vector static_base_class_info; + static std::vector static_derived_class_info; +}; + +}}} // namespace boost::python::detail + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + +// This class' only job is to define from_python and to_python converters for T +// and U. T is the class the user really intends to wrap. U is a class derived +// from T with some virtual function overriding boilerplate, or if there are no +// virtual functions, U = held_instance. +template > +class python_extension_class_converters +{ + public: + // Get an object which can be used to convert T to/from python. This is used + // as a kind of concept check by the global template + // + // PyObject* to_python(const T& x) + // + // below this class, to prevent the confusing messages that would otherwise + // pop up. Now, if T hasn't been wrapped as an extension class, the user + // will see an error message about the lack of an eligible + // py_extension_class_converters() function. + friend python_extension_class_converters py_extension_class_converters(boost::python::type) + { + return python_extension_class_converters(); + } + + // This is a member function because in a conforming implementation, friend + // funcitons defined inline in the class body are all instantiated as soon + // as the enclosing class is instantiated. If T is not copyable, that causes + // a compiler error. Instead, we access this function through the global + // template + // + // PyObject* to_python(const T& x) + // + // defined below this class. Since template functions are instantiated only + // on demand, errors will be avoided unless T is noncopyable and the user + // writes code which causes us to try to copy a T. + PyObject* to_python(const T& x) const + { + boost::python::reference result(create_instance()); + result->add_implementation( + std::auto_ptr( + new boost::python::detail::instance_value_holder(result.get(), x))); + return result.release(); + } + + // Convert to T* + friend T* from_python(PyObject* obj, boost::python::type) + { + // downcast to an extension_instance, then find the actual T + boost::python::detail::extension_instance* self = boost::python::detail::get_extension_instance(obj); + typedef std::vector::const_iterator iterator; + for (iterator p = self->wrapped_objects().begin(); + p != self->wrapped_objects().end(); ++p) + { + boost::python::detail::instance_holder* held = dynamic_cast*>(*p); + if (held != 0) + return held->target(); + + // see extclass.cpp for an explanation of try_class_conversions() + void* target = boost::python::detail::class_registry::class_object()->try_class_conversions(*p); + if(target) + return static_cast(target); + } + boost::python::detail::report_missing_instance_data(self, boost::python::detail::class_registry::class_object(), typeid(T)); + throw boost::python::argument_error(); + } + + // Convert to PtrType, where PtrType can be dereferenced to obtain a T. + template + static PtrType& ptr_from_python(PyObject* obj, boost::python::type) + { + // downcast to an extension_instance, then find the actual T + boost::python::detail::extension_instance* self = boost::python::detail::get_extension_instance(obj); + typedef std::vector::const_iterator iterator; + for (iterator p = self->wrapped_objects().begin(); + p != self->wrapped_objects().end(); ++p) + { + boost::python::detail::instance_ptr_holder* held = + dynamic_cast*>(*p); + if (held != 0) + return held->ptr(); + } + boost::python::detail::report_missing_ptr_data(self, boost::python::detail::class_registry::class_object(), typeid(T)); + throw boost::python::argument_error(); + } + + template + static PyObject* ptr_to_python(PtrType x) + { + boost::python::reference result(create_instance()); + result->add_implementation( + std::auto_ptr( + new boost::python::detail::instance_ptr_holder(x))); + return result.release(); + } + + static boost::python::reference create_instance() + { + PyTypeObject* class_object = boost::python::detail::class_registry::class_object(); + if (class_object == 0) + boost::python::detail::report_missing_class_object(typeid(T)); + + return boost::python::reference( + new boost::python::detail::extension_instance(class_object)); + } + + // Convert to const T* + friend const T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to const T* const& + friend const T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T* const& + friend T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T& + friend T& from_python(PyObject* p, boost::python::type) + { return *boost::python::detail::check_non_null(from_python(p, boost::python::type())); } + + // Convert to const T& + friend const T& from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T + friend const T& from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + friend std::auto_ptr& from_python(PyObject* p, boost::python::type&>) + { return ptr_from_python(p, boost::python::type >()); } + + friend std::auto_ptr& from_python(PyObject* p, boost::python::type >) + { return ptr_from_python(p, boost::python::type >()); } + + friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&>) + { return ptr_from_python(p, boost::python::type >()); } + + friend PyObject* to_python(std::auto_ptr x) + { return ptr_to_python(x); } + + friend boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) + { return ptr_from_python(p, boost::python::type >()); } + + friend boost::shared_ptr& from_python(PyObject* p, boost::python::type >) + { return ptr_from_python(p, boost::python::type >()); } + + friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) + { return ptr_from_python(p, boost::python::type >()); } + + friend PyObject* to_python(boost::shared_ptr x) + { return ptr_to_python(x); } +}; + +// Convert T to_python, instantiated on demand and only if there isn't a +// non-template overload for this function. This version is the one invoked when +// T is a wrapped class. See the first 2 functions declared in +// python_extension_class_converters above for more info. +template +PyObject* to_python(const T& x) +{ + return py_extension_class_converters(boost::python::type()).to_python(x); +} + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +namespace boost { namespace python { + +BOOST_PYTHON_IMPORT_CONVERSION(python_extension_class_converters); + +namespace detail { + +template class instance_holder; + +class read_only_setattr_function : public function +{ + public: + read_only_setattr_function(const char* name); + PyObject* do_call(PyObject* args, PyObject* keywords) const; + const char* description() const; + private: + string m_name; +}; + + template + struct define_conversion + { + static void* upcast_ptr(void* v) + { + return static_cast(static_cast(v)); + } + + static void* downcast_ptr(void* v) + { + return dynamic_cast(static_cast(v)); + } + }; + +// An easy way to make an extension base class which wraps T. Note that Python +// subclasses of this class will simply be class_t objects. +// +// U should be a class derived from T which overrides virtual functions with +// boilerplate code to call back into Python. See extclass_demo.h for examples. +// +// U is optional, but you won't be able to override any member functions in +// Python which are called from C++ if you don't supply it. If you just want to +// be able to use T in python without overriding member functions, you can omit +// U. +template > +class extension_class + : public python_extension_class_converters, // This generates the to_python/from_python functions + public extension_class_base +{ + public: + typedef T wrapped_type; + typedef U callback_type; + + // Construct with a name that comes from typeid(T).name(). The name only + // affects the objects of this class are represented through repr() + extension_class(); + + // Construct with the given name. The name only affects the objects of this + // class are represented through repr() + extension_class(const char* name); + + ~extension_class(); + + // define constructors + template + inline void def(constructor) + // The following incantation builds a signature1, signature2,... object. It + // should _all_ get optimized away. + { add_constructor( + prepend(type::id(), + prepend(type::id(), + prepend(type::id(), + prepend(type::id(), + prepend(type::id(), + signature0())))))); + } + + + // export homogeneous operators (type of both lhs and rhs is 'operator') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub), Foo>()); + + // export homogeneous operators (type of both lhs and rhs is 'T const&') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>()); + template + inline void def(operators) + { + typedef typename operand_select::template wrapped::type true_operand; + def_operators(operators()); + } + + // export heterogeneous operators (type of lhs: 'left', of rhs: 'right') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub), Foo>(), + // boost::python::right_operand()); + + // export heterogeneous operators (type of lhs: 'T const&', of rhs: 'right') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>(), + // boost::python::right_operand()); + template + inline void def(operators, right_operand r) + { + typedef typename operand_select::template wrapped::type true_left; + def_operators(operators(), r); + } + + // export heterogeneous reverse-argument operators + // (type of lhs: 'left', of rhs: 'right') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub), Foo>(), + // boost::python::left_operand()); + + // export heterogeneous reverse-argument operators + // (type of lhs: 'left', of rhs: 'T const&') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>(), + // boost::python::left_operand()); + template + inline void def(operators, left_operand l) + { + typedef typename operand_select::template wrapped::type true_right; + def_operators(operators(), l); + } + + // define a function that passes Python arguments and keywords + // to C++ verbatim (as a 'tuple const&' and 'dictionary const&' + // respectively). This is useful for manual argument passing. + // It's also the only possibility to pass keyword arguments to C++. + // Fn must have a signatur that is compatible to + // PyObject* (*)(PyObject* aTuple, PyObject* aDictionary) + template + inline void def_raw(Fn fn, const char* name) + { + this->add_method(new_raw_arguments_function(fn), name); + } + + // define member functions. In fact this works for free functions, too - + // they act like static member functions, or if they start with the + // appropriate self argument (as a pointer), they can be used just like + // ordinary member functions -- just like Python! + template + inline void def(Fn fn, const char* name) + { + this->add_method(new_wrapped_function(fn), name); + } + + // Define a virtual member function with a default implementation. + // default_fn should be a function which provides the default implementation. + // Be careful that default_fn does not in fact call fn virtually! + template + inline void def(Fn fn, const char* name, DefaultFn default_fn) + { + this->add_method(new_virtual_function(type(), fn, default_fn), name); + } + + // Provide a function which implements x., reading from the given + // member (pm) of the T obj + template + inline void def_getter(MemberType T::*pm, const char* name) + { + this->add_getter_method(new getter_function(pm), name); + } + + // Provide a function which implements assignment to x., writing to + // the given member (pm) of the T obj + template + inline void def_setter(MemberType T::*pm, const char* name) + { + this->add_setter_method(new setter_function(pm), name); + } + + // Expose the given member (pm) of the T obj as a read-only attribute + template + inline void def_readonly(MemberType T::*pm, const char* name) + { + this->add_setter_method(new read_only_setattr_function(name), name); + this->def_getter(pm, name); + } + + // Expose the given member (pm) of the T obj as a read/write attribute + template + inline void def_read_write(MemberType T::*pm, const char* name) + { + this->def_getter(pm, name); + this->def_setter(pm, name); + } + + // define the standard coercion needed for operator overloading + void def_standard_coerce(); + + // declare the given class a base class of this one and register + // up and down conversion functions + template + void declare_base(extension_class* base) + { + // see extclass.cpp for an explanation of why we need to register + // conversion functions + base_class_info baseInfo(base, + &define_conversion::downcast_ptr); + class_registry::register_base_class(baseInfo); + add_base(ref(as_object(base), ref::increment_count)); + + derived_class_info derivedInfo(this, + &define_conversion::upcast_ptr); + class_registry::register_derived_class(derivedInfo); + } + + // declare the given class a base class of this one and register + // only up conversion function + template + void declare_base(extension_class* base, without_downcast_t) + { + // see extclass.cpp for an explanation of why we need to register + // conversion functions + base_class_info baseInfo(base, 0); + class_registry::register_base_class(baseInfo); + add_base(ref(as_object(base), ref::increment_count)); + + derived_class_info derivedInfo(this, + &define_conversion::upcast_ptr); + class_registry::register_derived_class(derivedInfo); + } + + private: // types + typedef instance_value_holder holder; + + private: // extension_class_base virtual function implementations + std::vector const& base_classes() const; + std::vector const& derived_classes() const; + void* extract_object_from_holder(instance_holder_base* v) const; + + private: // Utility functions + template + inline void def_operators(operators) + { + def_standard_coerce(); + + // for some strange reason, this prevents MSVC from having an + // "unrecoverable block scoping error"! + typedef choose_op<(which & op_add)> choose_add; + + choose_op<(which & op_add)>::template args::add(this); + choose_op<(which & op_sub)>::template args::add(this); + choose_op<(which & op_mul)>::template args::add(this); + choose_op<(which & op_div)>::template args::add(this); + choose_op<(which & op_mod)>::template args::add(this); + choose_op<(which & op_divmod)>::template args::add(this); + choose_op<(which & op_pow)>::template args::add(this); + choose_op<(which & op_lshift)>::template args::add(this); + choose_op<(which & op_rshift)>::template args::add(this); + choose_op<(which & op_and)>::template args::add(this); + choose_op<(which & op_xor)>::template args::add(this); + choose_op<(which & op_or)>::template args::add(this); + choose_unary_op<(which & op_neg)>::template args::add(this); + choose_unary_op<(which & op_pos)>::template args::add(this); + choose_unary_op<(which & op_abs)>::template args::add(this); + choose_unary_op<(which & op_invert)>::template args::add(this); + choose_unary_op<(which & op_int)>::template args::add(this); + choose_unary_op<(which & op_long)>::template args::add(this); + choose_unary_op<(which & op_float)>::template args::add(this); + choose_op<(which & op_cmp)>::template args::add(this); + choose_unary_op<(which & op_str)>::template args::add(this); + } + + template + inline void def_operators(operators, right_operand) + { + def_standard_coerce(); + + choose_op<(which & op_add)>::template args::add(this); + choose_op<(which & op_sub)>::template args::add(this); + choose_op<(which & op_mul)>::template args::add(this); + choose_op<(which & op_div)>::template args::add(this); + choose_op<(which & op_mod)>::template args::add(this); + choose_op<(which & op_divmod)>::template args::add(this); + choose_op<(which & op_pow)>::template args::add(this); + choose_op<(which & op_lshift)>::template args::add(this); + choose_op<(which & op_rshift)>::template args::add(this); + choose_op<(which & op_and)>::template args::add(this); + choose_op<(which & op_xor)>::template args::add(this); + choose_op<(which & op_or)>::template args::add(this); + choose_op<(which & op_cmp)>::template args::add(this); + } + + template + inline void def_operators(operators, left_operand) + { + def_standard_coerce(); + + choose_rop<(which & op_add)>::template args::add(this); + choose_rop<(which & op_sub)>::template args::add(this); + choose_rop<(which & op_mul)>::template args::add(this); + choose_rop<(which & op_div)>::template args::add(this); + choose_rop<(which & op_mod)>::template args::add(this); + choose_rop<(which & op_divmod)>::template args::add(this); + choose_rop<(which & op_pow)>::template args::add(this); + choose_rop<(which & op_lshift)>::template args::add(this); + choose_rop<(which & op_rshift)>::template args::add(this); + choose_rop<(which & op_and)>::template args::add(this); + choose_rop<(which & op_xor)>::template args::add(this); + choose_rop<(which & op_or)>::template args::add(this); + choose_rop<(which & op_cmp)>::template args::add(this); + } + + template + void add_constructor(signature sig) + { + this->add_constructor_object(init_function::create(sig)); + } +}; + +// A simple wrapper over a T which allows us to use extension_class with a +// single template parameter only. See extension_class, above. +template +class held_instance : public T +{ + // There are no member functions: we want to avoid inadvertently overriding + // any virtual functions in T. +public: + held_instance(PyObject*) : T() {} + template + held_instance(PyObject*, A1 a1) : T(a1) {} + template + held_instance(PyObject*, A1 a1, A2 a2) : T(a1, a2) {} + template + held_instance(PyObject*, A1 a1, A2 a2, A3 a3) : T(a1, a2, a3) {} + template + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4) : T(a1, a2, a3, a4) {} + template + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : T(a1, a2, a3, a4, a5) {} +}; + +// Abstract base class for all obj holders. Base for template class +// instance_holder<>, below. +class instance_holder_base +{ +public: + virtual ~instance_holder_base() {} + virtual bool held_by_value() = 0; +}; + +// Abstract base class which holds a Held, somehow. Provides a uniform way to +// get a pointer to the held object +template +class instance_holder : public instance_holder_base +{ +public: + virtual Held*target() = 0; +}; + +// Concrete class which holds a Held by way of a wrapper class Wrapper. If Held +// can be constructed with arguments (A1...An), Wrapper must have a +// corresponding constructor for arguments (PyObject*, A1...An). Wrapper is +// neccessary to implement virtual function callbacks (there must be a +// back-pointer to the actual Python object so that we can call any +// overrides). held_instance (above) is used as a default Wrapper class when +// there are no virtual functions. +template +class instance_value_holder : public instance_holder +{ +public: + Held* target() { return &m_held; } + Wrapper* value_target() { return &m_held; } + + instance_value_holder(extension_instance* p) : + m_held(p) {} + template + instance_value_holder(extension_instance* p, A1 a1) : + m_held(p, a1) {} + template + instance_value_holder(extension_instance* p, A1 a1, A2 a2) : + m_held(p, a1, a2) {} + template + instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3) : + m_held(p, a1, a2, a3) {} + template + instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4) : + m_held(p, a1, a2, a3, a4) {} + template + instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : + m_held(p, a1, a2, a3, a4, a5) {} + + public: // implementation of instance_holder_base required interface + bool held_by_value() { return true; } + + private: + Wrapper m_held; +}; + +// Concrete class which holds a HeldType by way of a (possibly smart) pointer +// PtrType. By default, these are only generated for PtrType == +// std::auto_ptr and PtrType == boost::shared_ptr. +template +class instance_ptr_holder : public instance_holder +{ + public: + HeldType* target() { return &*m_ptr; } + PtrType& ptr() { return m_ptr; } + + instance_ptr_holder(PtrType ptr) : m_ptr(ptr) {} + + public: // implementation of instance_holder_base required interface + bool held_by_value() { return false; } + private: + PtrType m_ptr; +}; + +class extension_instance : public instance +{ + public: + extension_instance(PyTypeObject* class_); + ~extension_instance(); + + void add_implementation(std::auto_ptr holder); + + typedef std::vector held_objects; + const held_objects& wrapped_objects() const + { return m_wrapped_objects; } + private: + held_objects m_wrapped_objects; +}; + +// +// Template function implementations +// + +tuple extension_class_coerce(ref l, ref r); + +template +extension_class::extension_class() + : extension_class_base(typeid(T).name()) +{ + class_registry::register_class(this); +} + +template +extension_class::extension_class(const char* name) + : extension_class_base(name) +{ + class_registry::register_class(this); +} + +template +void extension_class::def_standard_coerce() +{ + ref coerce_fct = dict().get_item(string("__coerce__")); + + if(coerce_fct.get() == 0) // not yet defined + this->def(&extension_class_coerce, "__coerce__"); +} + +template +inline +std::vector const& +extension_class::base_classes() const +{ + return class_registry::base_classes(); +} + +template +inline +std::vector const& +extension_class::derived_classes() const +{ + return class_registry::derived_classes(); +} + +template +void* extension_class::extract_object_from_holder(instance_holder_base* v) const +{ + instance_holder* held = dynamic_cast*>(v); + if(held) + return held->target(); + return 0; +} + +template +extension_class::~extension_class() +{ + class_registry::unregister_class(this); +} + +template +inline void class_registry::register_class(extension_class_base* p) +{ + // You're not expected to create more than one of these! + assert(static_class_object == 0); + static_class_object = p; +} + +template +inline void class_registry::unregister_class(extension_class_base* p) +{ + // The user should be destroying the same object they created. + assert(static_class_object == p); + (void)p; // unused in shipping version + static_class_object = 0; +} + +template +void class_registry::register_base_class(base_class_info const& i) +{ + static_base_class_info.push_back(i); +} + +template +void class_registry::register_derived_class(derived_class_info const& i) +{ + static_derived_class_info.push_back(i); +} + +template +std::vector const& class_registry::base_classes() +{ + return static_base_class_info; +} + +template +std::vector const& class_registry::derived_classes() +{ + return static_derived_class_info; +} + +// +// Static data member declaration. +// +template +extension_class_base* class_registry::static_class_object; +template +std::vector class_registry::static_base_class_info; +template +std::vector class_registry::static_derived_class_info; + +}}} // namespace boost::python::detail + +#endif // EXTENSION_CLASS_DWA052000_H_ + diff --git a/include/boost/python/detail/functions.hpp b/include/boost/python/detail/functions.hpp new file mode 100644 index 00000000..055255e7 --- /dev/null +++ b/include/boost/python/detail/functions.hpp @@ -0,0 +1,306 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef FUNCTIONS_DWA051400_H_ +# define FUNCTIONS_DWA051400_H_ + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace detail { + +// forward declaration +class extension_instance; + + +// function -- +// the common base class for all overloadable function and method objects +// supplied by the library. +class function : public python_object +{ + public: + function(); + // function objects are reasonably rare, so we guess we can afford a virtual table. + // This cuts down on the number of distinct type objects which need to be defined. + virtual ~function() {} + + PyObject* call(PyObject* args, PyObject* keywords) const; + static void add_to_namespace(reference f, const char* name, PyObject* dict); + + private: + virtual PyObject* do_call(PyObject* args, PyObject* keywords) const = 0; + virtual const char* description() const = 0; + private: + struct type_object; + private: + reference m_overloads; +}; + +// wrapped_function_pointer<> -- +// A single function or member function pointer wrapped and presented to +// Python as a callable object. +// +// Template parameters: +// R - the return type of the function pointer +// F - the complete type of the wrapped function pointer +template +struct wrapped_function_pointer : function +{ + typedef F ptr_fun; // pointer-to--function or pointer-to-member-function + + wrapped_function_pointer(ptr_fun pf) + : m_pf(pf) {} + + private: + PyObject* do_call(PyObject* args, PyObject* keywords) const + { return caller::call(m_pf, args, keywords); } + + const char* description() const + { return typeid(F).name(); } + + private: + const ptr_fun m_pf; +}; + +// raw_arguments_function +// A function that passes the Python argument tuple and keyword dictionary +// verbatim to C++ (useful for customized argument parsing and variable +// argument lists) +template +struct raw_arguments_function : function +{ + typedef Ret (*ptr_fun)(Args, Keywords); + + raw_arguments_function(ptr_fun pf) + : m_pf(pf) {} + + private: + PyObject* do_call(PyObject* args, PyObject* keywords) const + { + ref dict(keywords ? + ref(keywords, ref::increment_count) : + ref(PyDict_New())); + + return to_python( + (*m_pf)(from_python(args, boost::python::type()), + from_python(dict.get(), boost::python::type()))); + } + + const char* description() const + { return typeid(ptr_fun).name(); } + + private: + const ptr_fun m_pf; +}; + +// virtual_function<> -- +// A virtual function with a default implementation wrapped and presented +// to Python as a callable object. +// +// Template parameters: +// T - the type of the target class +// R - the return type of the function pointer +// V - the virtual function pointer being wrapped +// (should be of the form R(T::*)(), or R (*)(T, )) +// D - a function which takes a T&, const T&, T*, or const T* first +// parameter and calls T::f on it /non-virtually/, where V +// approximates &T::f. +template +class virtual_function : public function +{ + public: + virtual_function(V virtual_function_ptr, D default_implementation) + : m_virtual_function_ptr(virtual_function_ptr), + m_default_implementation(default_implementation) + {} + + private: + PyObject* do_call(PyObject* args, PyObject* keywords) const; + + const char* description() const + { return typeid(V).name(); } + + private: + const V m_virtual_function_ptr; + const D m_default_implementation; +}; + +// A helper function for new_member_function(), below. Implements the core +// functionality once the return type has already been deduced. R is expected to +// be type, where X is the actual return type of pmf. +template +function* new_wrapped_function_aux(R, F pmf) +{ + // We can't just use "typename R::Type" below because MSVC (incorrectly) pukes. + typedef typename R::type return_type; + return new wrapped_function_pointer(pmf); +} + +// Create and return a new member function object wrapping the given +// pointer-to-member function +template +inline function* new_wrapped_function(F pmf) +{ + // Deduce the return type and pass it off to the helper function above + return new_wrapped_function_aux(return_value(pmf), pmf); +} + +template +function* new_raw_arguments_function(R (*pmf)(Args, keywords)) +{ + return new raw_arguments_function(pmf); +} + + +// A helper function for new_virtual_function(), below. Implements the core +// functionality once the return type has already been deduced. R is expected to +// be type, where X is the actual return type of V. +template +inline function* new_virtual_function_aux( + type, R, V virtual_function_ptr, D default_implementation + ) +{ + // We can't just use "typename R::Type" below because MSVC (incorrectly) pukes. + typedef typename R::type return_type; + return new virtual_function( + virtual_function_ptr, default_implementation); +} + +// Create and return a new virtual_function object wrapping the given +// virtual_function_ptr and default_implementation +template +inline function* new_virtual_function( + type, V virtual_function_ptr, D default_implementation + ) +{ + // Deduce the return type and pass it off to the helper function above + return new_virtual_function_aux( + type(), return_value(virtual_function_ptr), + virtual_function_ptr, default_implementation); +} + +// A function with a bundled "bound target" object. This is what is produced by +// the expression a.b where a is an instance or extension_instance object and b +// is a callable object not found in the obj namespace but on its class or +// a base class. +class bound_function : public python_object +{ + public: + static bound_function* create(const ref& target, const ref& fn); + + bound_function(const ref& target, const ref& fn); + PyObject* call(PyObject*args, PyObject* keywords) const; + PyObject* getattr(const char* name) const; + + private: + struct type_object; + friend struct type_object; + + ref m_target; + ref m_unbound_function; + + private: // data members for allocation/deallocation optimization + bound_function* m_free_list_link; + + static bound_function* free_list; +}; + +// Special functions designed to access data members of a wrapped C++ object. +template +class getter_function : public function +{ + public: + typedef MemberType ClassType::* pointer_to_member; + + getter_function(pointer_to_member pm) + : m_pm(pm) {} + + private: + PyObject* do_call(PyObject* args, PyObject* keywords) const; + + const char* description() const + { return typeid(MemberType (*)(const ClassType&)).name(); } + private: + pointer_to_member m_pm; +}; + +template +class setter_function : public function +{ + public: + typedef MemberType ClassType::* pointer_to_member; + + setter_function(pointer_to_member pm) + : m_pm(pm) {} + + private: + PyObject* do_call(PyObject* args, PyObject* keywords) const; + + const char* description() const + { return typeid(void (*)(const ClassType&, const MemberType&)).name(); } + private: + pointer_to_member m_pm; +}; + +template +PyObject* getter_function::do_call( + PyObject* args, PyObject* /* keywords */) const +{ + PyObject* self; + if (!PyArg_ParseTuple(args, const_cast("O"), &self)) + return 0; + + return to_python( + from_python(self, type())->*m_pm); +} + +template +PyObject* setter_function::do_call( + PyObject* args, PyObject* /* keywords */) const +{ + PyObject* self; + PyObject* value; + if (!PyArg_ParseTuple(args, const_cast("OO"), &self, &value)) + return 0; + + typedef typename boost::call_traits::const_reference extract_type; + from_python(self, type())->*m_pm + = from_python(value, type()); + + return none(); +} + +template +PyObject* virtual_function::do_call(PyObject* args, PyObject* keywords) const +{ + // If the target object is held by pointer, we must call through the virtual + // function pointer to the most-derived override. + PyObject* target = PyTuple_GetItem(args, 0); + if (target != 0) + { + extension_instance* self = get_extension_instance(target); + if (self->wrapped_objects().size() == 1 + && !self->wrapped_objects()[0]->held_by_value()) + { + return caller::call(m_virtual_function_ptr, args, keywords); + } + } + return caller::call(m_default_implementation, args, keywords); +} + +}}} // namespace boost::python::detail + +#endif // FUNCTIONS_DWA051400_H_ diff --git a/include/boost/python/detail/init_function.hpp b/include/boost/python/detail/init_function.hpp new file mode 100644 index 00000000..e53f8aa9 --- /dev/null +++ b/include/boost/python/detail/init_function.hpp @@ -0,0 +1,507 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. +// +// This file was generated for %d-argument constructors by gen_init_function.python + +#ifndef INIT_FUNCTION_DWA052000_H_ +# define INIT_FUNCTION_DWA052000_H_ + +# include +# include +# include +# include + +namespace boost { namespace python { + +namespace detail { + + // parameter_traits - so far, this is a way to pass a const T& when we can be + // sure T is not a reference type, and a raw T otherwise. This should be + // rolled into boost::call_traits. Ordinarily, parameter_traits would be + // written: + // + // template struct parameter_traits + // { + // typedef const T& const_reference; + // }; + // + // template struct parameter_traits + // { + // typedef T& const_reference; + // }; + // + // template <> struct parameter_traits + // { + // typedef void const_reference; + // }; + // + // ...but since we can't partially specialize on reference types, we need this + // long-winded but equivalent incantation. + + // const_ref_selector -- an implementation detail of parameter_traits (below). This uses + // the usual "poor man's partial specialization" hack for MSVC. + template + struct const_ref_selector + { + template + struct const_ref + { + typedef const T& type; + }; + }; + + template <> + struct const_ref_selector + { + template + struct const_ref + { + typedef T type; + }; + }; + +# ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4181) +# endif // BOOST_MSVC + template + struct parameter_traits + { + private: + typedef const_ref_selector::value> selector; + public: + typedef typename selector::template const_ref::type const_reference; + }; +# ifdef BOOST_MSVC +# pragma warning(pop) +# endif // BOOST_MSVC + + // Full spcialization for void + template <> + struct parameter_traits + { + typedef void const_reference; + }; + + template + class reference_parameter + { + typedef typename parameter_traits::const_reference const_reference; + public: + reference_parameter(const_reference value) + : value(value) {} + operator const_reference() { return value; } + private: + const_reference value; + }; + +class extension_instance; +class instance_holder_base; + +class init; +template struct init0; +template struct init1; +template struct init2; +template struct init3; +template struct init4; +template struct init5; +template struct Init6; +template struct Init7; +template struct Init8; +template struct Init9; +template struct Init10; + +template +struct init_function +{ + static init* create(signature0) { + return new init0; + } + + template + static init* create(signature1) { + return new init1::const_reference>; + } + + template + static init* create(signature2) { + return new init2::const_reference, + detail::parameter_traits::const_reference>; + } + + template + static init* create(signature3) { + return new init3::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference>; + } + + template + static init* create(signature4) { + return new init4::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference>; + } + + template + static init* create(signature5) { + return new init5::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference>; + } + + template + static init* create(signature6) { + return new Init6::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference>; + } + + template + static init* create(signature7) { + return new Init7::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference>; + } + + template + static init* create(signature8) { + return new Init8::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference>; + } + + template + static init* create(signature9) { + return new Init9::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference>; + } + + template + static init* create(signature10) { + return new Init10::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference, + detail::parameter_traits::const_reference>; + } +}; + +class init : public function +{ +private: // override function hook + PyObject* do_call(PyObject* args, PyObject* keywords) const; +private: + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* tail_args, PyObject* keywords) const = 0; +}; + + +template +struct init0 : init +{ + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const + { + if (!PyArg_ParseTuple(args, const_cast(""))) + throw argument_error(); + return new T(self + ); + } + const char* description() const + { return typeid(void (*)(T&)).name(); } +}; + +template +struct init1 : init +{ + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const + { + PyObject* a1; + if (!PyArg_ParseTuple(args, const_cast("O"), &a1)) + throw argument_error(); + return new T(self, + boost::python::detail::reference_parameter(from_python(a1, type())) + ); + } + const char* description() const + { return typeid(void (*)(T&, A1)).name(); } +}; + +template +struct init2 : init +{ + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const + { + PyObject* a1; + PyObject* a2; + if (!PyArg_ParseTuple(args, const_cast("OO"), &a1, &a2)) + throw argument_error(); + return new T(self, + boost::python::detail::reference_parameter(from_python(a1, type())), + boost::python::detail::reference_parameter(from_python(a2, type())) + ); + } + const char* description() const + { return typeid(void (*)(T&, A1, A2)).name(); } +}; + +template +struct init3 : init +{ + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const + { + PyObject* a1; + PyObject* a2; + PyObject* a3; + if (!PyArg_ParseTuple(args, const_cast("OOO"), &a1, &a2, &a3)) + throw argument_error(); + return new T(self, + boost::python::detail::reference_parameter(from_python(a1, type())), + boost::python::detail::reference_parameter(from_python(a2, type())), + boost::python::detail::reference_parameter(from_python(a3, type())) + ); + } + const char* description() const + { return typeid(void (*)(T&, A1, A2, A3)).name(); } +}; + +template +struct init4 : init +{ + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const + { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + if (!PyArg_ParseTuple(args, const_cast("OOOO"), &a1, &a2, &a3, &a4)) + throw argument_error(); + return new T(self, + boost::python::detail::reference_parameter(from_python(a1, type())), + boost::python::detail::reference_parameter(from_python(a2, type())), + boost::python::detail::reference_parameter(from_python(a3, type())), + boost::python::detail::reference_parameter(from_python(a4, type())) + ); + } + const char* description() const + { return typeid(void (*)(T&, A1, A2, A3, A4)).name(); } +}; + +template +struct init5 : init +{ + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const + { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + if (!PyArg_ParseTuple(args, const_cast("OOOOO"), &a1, &a2, &a3, &a4, &a5)) + throw argument_error(); + return new T(self, + boost::python::detail::reference_parameter(from_python(a1, type())), + boost::python::detail::reference_parameter(from_python(a2, type())), + boost::python::detail::reference_parameter(from_python(a3, type())), + boost::python::detail::reference_parameter(from_python(a4, type())), + boost::python::detail::reference_parameter(from_python(a5, type())) + ); + } + const char* description() const + { return typeid(void (*)(T&, A1, A2, A3, A4, A5)).name(); } +}; + +template +struct Init6 : init +{ + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const + { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6)) + throw argument_error(); + return new T(self, + boost::python::detail::reference_parameter(from_python(a1, type())), + boost::python::detail::reference_parameter(from_python(a2, type())), + boost::python::detail::reference_parameter(from_python(a3, type())), + boost::python::detail::reference_parameter(from_python(a4, type())), + boost::python::detail::reference_parameter(from_python(a5, type())), + boost::python::detail::reference_parameter(from_python(a6, type())) + ); + } + const char* description() const + { return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6)).name(); } +}; + +template +struct Init7 : init +{ + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const + { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7)) + throw argument_error(); + return new T(self, + boost::python::detail::reference_parameter(from_python(a1, type())), + boost::python::detail::reference_parameter(from_python(a2, type())), + boost::python::detail::reference_parameter(from_python(a3, type())), + boost::python::detail::reference_parameter(from_python(a4, type())), + boost::python::detail::reference_parameter(from_python(a5, type())), + boost::python::detail::reference_parameter(from_python(a6, type())), + boost::python::detail::reference_parameter(from_python(a7, type())) + ); + } + const char* description() const + { return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7)).name(); } +}; + +template +struct Init8 : init +{ + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const + { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) + throw argument_error(); + return new T(self, + boost::python::detail::reference_parameter(from_python(a1, type())), + boost::python::detail::reference_parameter(from_python(a2, type())), + boost::python::detail::reference_parameter(from_python(a3, type())), + boost::python::detail::reference_parameter(from_python(a4, type())), + boost::python::detail::reference_parameter(from_python(a5, type())), + boost::python::detail::reference_parameter(from_python(a6, type())), + boost::python::detail::reference_parameter(from_python(a7, type())), + boost::python::detail::reference_parameter(from_python(a8, type())) + ); + } + const char* description() const + { return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7, A8)).name(); } +}; + +template +struct Init9 : init +{ + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const + { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) + throw argument_error(); + return new T(self, + boost::python::detail::reference_parameter(from_python(a1, type())), + boost::python::detail::reference_parameter(from_python(a2, type())), + boost::python::detail::reference_parameter(from_python(a3, type())), + boost::python::detail::reference_parameter(from_python(a4, type())), + boost::python::detail::reference_parameter(from_python(a5, type())), + boost::python::detail::reference_parameter(from_python(a6, type())), + boost::python::detail::reference_parameter(from_python(a7, type())), + boost::python::detail::reference_parameter(from_python(a8, type())), + boost::python::detail::reference_parameter(from_python(a9, type())) + ); + } + const char* description() const + { return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7, A8, A9)).name(); } +}; + +template +struct Init10 : init +{ + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const + { + PyObject* a1; + PyObject* a2; + PyObject* a3; + PyObject* a4; + PyObject* a5; + PyObject* a6; + PyObject* a7; + PyObject* a8; + PyObject* a9; + PyObject* a10; + if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) + throw argument_error(); + return new T(self, + boost::python::detail::reference_parameter(from_python(a1, type())), + boost::python::detail::reference_parameter(from_python(a2, type())), + boost::python::detail::reference_parameter(from_python(a3, type())), + boost::python::detail::reference_parameter(from_python(a4, type())), + boost::python::detail::reference_parameter(from_python(a5, type())), + boost::python::detail::reference_parameter(from_python(a6, type())), + boost::python::detail::reference_parameter(from_python(a7, type())), + boost::python::detail::reference_parameter(from_python(a8, type())), + boost::python::detail::reference_parameter(from_python(a9, type())), + boost::python::detail::reference_parameter(from_python(a10, type())) + ); + } + const char* description() const + { return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)).name(); } +}; + +}}} // namespace boost::python::detail + +#endif // INIT_FUNCTION_DWA052000_H_ diff --git a/include/boost/python/detail/none.hpp b/include/boost/python/detail/none.hpp new file mode 100644 index 00000000..8cb21004 --- /dev/null +++ b/include/boost/python/detail/none.hpp @@ -0,0 +1,21 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef NONE_DWA_052000_H_ +# define NONE_DWA_052000_H_ + +# include +# include + +namespace boost { namespace python { namespace detail { + +inline PyObject* none() { Py_INCREF(Py_None); return Py_None; } + +}}} // namespace boost::python::detail + +#endif // NONE_DWA_052000_H_ diff --git a/include/boost/python/detail/signatures.hpp b/include/boost/python/detail/signatures.hpp new file mode 100644 index 00000000..2be75b52 --- /dev/null +++ b/include/boost/python/detail/signatures.hpp @@ -0,0 +1,251 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. +// +// This file automatically generated by gen_signatures.python for 10 arguments. +#ifndef SIGNATURES_DWA050900_H_ +# define SIGNATURES_DWA050900_H_ + +# include + +namespace boost { namespace python { + +namespace detail { +// A stand-in for the built-in void. This one can be passed to functions and +// (under MSVC, which has a bug, be used as a default template type parameter). +struct void_t {}; +} + +// An envelope in which type information can be delivered for the purposes +// of selecting an overloaded from_python() function. This is needed to work +// around MSVC's lack of partial specialiation/ordering. Where normally we'd +// want to form a function call like void f(), We instead pass +// type as one of the function parameters to select a particular +// overload. +// +// The id typedef helps us deal with the lack of partial ordering by generating +// unique types for constructor signatures. In general, type::id is type, +// but type::id is just void_t. +template +struct type +{ + typedef type id; +}; + +template <> +struct type +{ + typedef boost::python::detail::void_t id; +}; + +namespace detail { +// These basically encapsulate a chain of types, , used to make the syntax of +// add(constructor()) work. We need to produce a unique type for each number +// of non-default parameters to constructor<>. Q: why not use a recursive +// formulation for infinite extensibility? A: MSVC6 seems to choke on constructs +// that involve recursive template nesting. +// +// signature chaining +template +struct signature10 {}; + +template +struct signature9 {}; + +template +inline signature10 prepend(type, signature9) + { return signature10(); } + +template +struct signature8 {}; + +template +inline signature9 prepend(type, signature8) + { return signature9(); } + +template +struct signature7 {}; + +template +inline signature8 prepend(type, signature7) + { return signature8(); } + +template +struct signature6 {}; + +template +inline signature7 prepend(type, signature6) + { return signature7(); } + +template +struct signature5 {}; + +template +inline signature6 prepend(type, signature5) + { return signature6(); } + +template +struct signature4 {}; + +template +inline signature5 prepend(type, signature4) + { return signature5(); } + +template +struct signature3 {}; + +template +inline signature4 prepend(type, signature3) + { return signature4(); } + +template +struct signature2 {}; + +template +inline signature3 prepend(type, signature2) + { return signature3(); } + +template +struct signature1 {}; + +template +inline signature2 prepend(type, signature1) + { return signature2(); } + +struct signature0 {}; + +template +inline signature1 prepend(type, signature0) + { return signature1(); } + + +// This one terminates the chain. Prepending void_t to the head of a void_t +// signature results in a void_t signature again. +inline signature0 prepend(void_t, signature0) { return signature0(); } + +} // namespace detail + +template +struct constructor +{ +}; + +namespace detail { +// Return value extraction: + +// This is just another little envelope for carrying a typedef (see type, +// above). I could have re-used type, but that has a very specific purpose. I +// thought this would be clearer. +template +struct return_value_select { typedef T type; }; + +// free functions +template +return_value_select return_value(R (*)()) { return return_value_select(); } + +template +return_value_select return_value(R (*)(A1)) { return return_value_select(); } + +template +return_value_select return_value(R (*)(A1, A2)) { return return_value_select(); } + +template +return_value_select return_value(R (*)(A1, A2, A3)) { return return_value_select(); } + +template +return_value_select return_value(R (*)(A1, A2, A3, A4)) { return return_value_select(); } + +template +return_value_select return_value(R (*)(A1, A2, A3, A4, A5)) { return return_value_select(); } + +template +return_value_select return_value(R (*)(A1, A2, A3, A4, A5, A6)) { return return_value_select(); } + +template +return_value_select return_value(R (*)(A1, A2, A3, A4, A5, A6, A7)) { return return_value_select(); } + +template +return_value_select return_value(R (*)(A1, A2, A3, A4, A5, A6, A7, A8)) { return return_value_select(); } + +template +return_value_select return_value(R (*)(A1, A2, A3, A4, A5, A6, A7, A8, A9)) { return return_value_select(); } + +template +return_value_select return_value(R (*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)) { return return_value_select(); } + +// TODO(?): handle 'const void' + +// member functions +template +return_value_select return_value(R (T::*)()) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1)) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2)) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3)) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4)) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4, A5)) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4, A5, A6)) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7)) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7, A8)) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9)) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)() const) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1) const) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2) const) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3) const) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4) const) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4, A5) const) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4, A5, A6) const) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7) const) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7, A8) const) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9) const) { return return_value_select(); } + +template +return_value_select return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) const) { return return_value_select(); } + +}}} // namespace boost::python::detail + +#endif diff --git a/include/boost/python/detail/singleton.hpp b/include/boost/python/detail/singleton.hpp new file mode 100644 index 00000000..07d794ac --- /dev/null +++ b/include/boost/python/detail/singleton.hpp @@ -0,0 +1,68 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef SINGLETON_DWA051900_H_ +# define SINGLETON_DWA051900_H_ + +# include + +namespace boost { namespace python { namespace detail { + +struct empty {}; +template +struct singleton : Base +{ + typedef singleton singleton_base; // Convenience type for derived class constructors + + static Derived* instance(); + + // Pass-through constructors + singleton() : Base() {} + + template + singleton(const A1& a1) : Base(a1) {} + + template + singleton(const A1& a1, const A2& a2) : Base(a1, a2) {} + + template + singleton(const A1& a1, const A2& a2, const A3& a3) : Base(a1, a2, a3) {} + + template + singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4) : Base(a1, a2, a3, a4) {} + + template + singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) : Base(a1, a2, a3, a4, a5) {} + + template + singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) : Base(a1, a2, a3, a4, a5, a6) {} + + template + singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) : Base(a1, a2, a3, a4, a5, a6, a7) {} + + template + singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) : Base(a1, a2, a3, a4, a5, a6, a7, a8) {} + + template + singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) : Base(a1, a2, a3, a4, a5, a6, a7, a8, a9) {} + + template + singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) : Base(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {} + +}; + +template +Derived* singleton::instance() +{ + static Derived x; + return &x; +} + +}}} // namespace boost::python::detail + +#endif diff --git a/include/boost/python/detail/types.hpp b/include/boost/python/detail/types.hpp new file mode 100644 index 00000000..ee33ce04 --- /dev/null +++ b/include/boost/python/detail/types.hpp @@ -0,0 +1,389 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef TYPES_DWA051800_H_ +# define TYPES_DWA051800_H_ + +// Usage: +// class X : public +// boost::python::callable< +// boost::python::getattrable < +// boost::python::setattrable > > +// { +// public: +// ref call(args, kw); +// ref getattr(args, kw); +// ref setattr(args, kw); +// }; + +# include +# include // really just for type<> +# include +# include +# include +# include +# include + +namespace boost { namespace python { + +class string; + +namespace detail { + +class instance_holder_base; + +class type_object_base : public python_type +{ + public: + explicit type_object_base(PyTypeObject* type_type); + virtual ~type_object_base(); + + public: + enum capability { + hash, call, str, getattr, setattr, compare, repr, + + mapping_length, mapping_subscript, mapping_ass_subscript, + + sequence_length, sequence_item, sequence_ass_item, + sequence_concat, sequence_repeat, sequence_slice, sequence_ass_slice, + + number_add, number_subtract, number_multiply, number_divide, + number_remainder, number_divmod, number_power, number_negative, + number_positive, number_absolute, number_nonzero, number_invert, + number_lshift, number_rshift, number_and, number_xor, number_or, + number_coerce, number_int, number_long, number_float, number_oct, + number_hex + }; + + void enable(capability); + + // + // type behaviors + // + public: // Callbacks for basic type functionality. + virtual PyObject* instance_repr(PyObject*) const; + virtual int instance_compare(PyObject*, PyObject* other) const; + virtual PyObject* instance_str(PyObject*) const; + virtual long instance_hash(PyObject*) const; + virtual PyObject* instance_call(PyObject* obj, PyObject* args, PyObject* kw) const; + virtual PyObject* instance_getattr(PyObject* obj, const char* name) const; + virtual int instance_setattr(PyObject* obj, const char* name, PyObject* value) const; + + // Dealloc is a special case, since every type needs a nonzero tp_dealloc slot. + virtual void instance_dealloc(PyObject*) const = 0; + + public: // Callbacks for mapping methods + virtual int instance_mapping_length(PyObject*) const; + virtual PyObject* instance_mapping_subscript(PyObject*, PyObject*) const ; + virtual int instance_mapping_ass_subscript(PyObject*, PyObject*, PyObject*) const; + + public: // Callbacks for sequence methods + virtual int instance_sequence_length(PyObject* obj) const; + virtual PyObject* instance_sequence_concat(PyObject* obj, PyObject* other) const; + virtual PyObject* instance_sequence_repeat(PyObject* obj, int n) const; + virtual PyObject* instance_sequence_item(PyObject* obj, int n) const; + virtual PyObject* instance_sequence_slice(PyObject* obj, int start, int finish) const; + virtual int instance_sequence_ass_item(PyObject* obj, int n, PyObject* value) const; + virtual int instance_sequence_ass_slice(PyObject* obj, int start, int finish, PyObject* value) const; + + public: // Callbacks for number methods + virtual PyObject* instance_number_add(PyObject*, PyObject*) const; + virtual PyObject* instance_number_subtract(PyObject*, PyObject*) const; + virtual PyObject* instance_number_multiply(PyObject*, PyObject*) const; + virtual PyObject* instance_number_divide(PyObject*, PyObject*) const; + virtual PyObject* instance_number_remainder(PyObject*, PyObject*) const; + virtual PyObject* instance_number_divmod(PyObject*, PyObject*) const; + virtual PyObject* instance_number_power(PyObject*, PyObject*, PyObject*) const; + virtual PyObject* instance_number_negative(PyObject*) const; + virtual PyObject* instance_number_positive(PyObject*) const; + virtual PyObject* instance_number_absolute(PyObject*) const; + virtual int instance_number_nonzero(PyObject*) const; + virtual PyObject* instance_number_invert(PyObject*) const; + virtual PyObject* instance_number_lshift(PyObject*, PyObject*) const; + virtual PyObject* instance_number_rshift(PyObject*, PyObject*) const; + virtual PyObject* instance_number_and(PyObject*, PyObject*) const; + virtual PyObject* instance_number_xor(PyObject*, PyObject*) const; + virtual PyObject* instance_number_or(PyObject*, PyObject*) const; + virtual int instance_number_coerce(PyObject*, PyObject**, PyObject**) const; + virtual PyObject* instance_number_int(PyObject*) const; + virtual PyObject* instance_number_long(PyObject*) const; + virtual PyObject* instance_number_float(PyObject*) const; + virtual PyObject* instance_number_oct(PyObject*) const; + virtual PyObject* instance_number_hex(PyObject*) const; +}; + +template +class type_object : public type_object_base +{ + public: + typedef T instance; + + type_object(PyTypeObject* type_type, const char* name) + : type_object_base(type_type) + { + assert(name != 0); + this->tp_name = const_cast(name); + } + + type_object(PyTypeObject* type_type) + : type_object_base(type_type) + { + this->tp_name = const_cast(typeid(instance).name()); + } + + private: // Overridable behaviors. + // Called when the reference count goes to zero. The default implementation + // is "delete p". If you have not allocated your object with operator new or + // you have other constraints, you'll need to override this + virtual void dealloc(T* p) const; + + private: // Implementation of type_object_base hooks. Do not reimplement in derived classes. + void instance_dealloc(PyObject*) const; +}; + +// +// type objects +// +template +class callable : public Base +{ + public: + typedef callable properties; // Convenience for derived class construction + typedef typename Base::instance instance; + callable(PyTypeObject* type_type, const char* name); + callable(PyTypeObject* type_type); + private: + PyObject* instance_call(PyObject* obj, PyObject* args, PyObject* kw) const; +}; + +template +class getattrable : public Base +{ + public: + typedef getattrable properties; // Convenience for derived class construction + typedef typename Base::instance instance; + getattrable(PyTypeObject* type_type, const char* name); + getattrable(PyTypeObject* type_type); + private: + PyObject* instance_getattr(PyObject* obj, const char* name) const; +}; + +template +class setattrable : public Base +{ + public: + typedef setattrable properties; // Convenience for derived class construction + typedef typename Base::instance instance; + setattrable(PyTypeObject* type_type, const char* name); + setattrable(PyTypeObject* type_type); + private: + int instance_setattr(PyObject* obj, const char* name, PyObject* value) const; +}; + +template +class reprable : public Base +{ + public: + typedef reprable properties; // Convenience for derived class construction + typedef typename Base::instance instance; + reprable(PyTypeObject* type_type, const char* name); + reprable(PyTypeObject* type_type); + private: + PyObject* instance_repr(PyObject* obj) const; +}; + +// +// Member function definitions +// + +// type_object<> +template +void type_object::instance_dealloc(PyObject* obj) const +{ + this->dealloc(downcast(obj).get()); +} + +template +void type_object::dealloc(T* obj) const +{ + delete obj; +} + +// callable +template +callable::callable(PyTypeObject* type_type, const char* name) + : Base(type_type, name) +{ + this->enable(call); +} + +template +callable::callable(PyTypeObject* type_type) + : Base(type_type) +{ + this->enable(call); +} + +template +PyObject* callable::instance_call(PyObject* obj, PyObject* args, PyObject* kw) const +{ + return downcast(obj)->call(args, kw); +} + +// getattrable +template +getattrable::getattrable(PyTypeObject* type_type, const char* name) + : Base(type_type, name) +{ + this->enable(getattr); +} + +template +getattrable::getattrable(PyTypeObject* type_type) + : Base(type_type) +{ + this->enable(getattr); +} + +template +PyObject* getattrable::instance_getattr(PyObject* obj, const char* name) const +{ + return downcast(obj)->getattr(name); +} + +// setattrable +template +setattrable::setattrable(PyTypeObject* type_type, const char* name) + : Base(type_type, name) +{ + this->enable(setattr); +} + +template +setattrable::setattrable(PyTypeObject* type_type) + : Base(type_type) +{ + this->enable(setattr); +} + +template +int setattrable::instance_setattr(PyObject* obj, const char* name, PyObject* value) const +{ + return downcast(obj)->setattr(name, value); +} + +// reprable +template +reprable::reprable(PyTypeObject* type_type, const char* name) + : Base(type_type, name) +{ + this->enable(repr); +} + +template +reprable::reprable(PyTypeObject* type_type) + : Base(type_type) +{ + this->enable(repr); +} + +template +PyObject* reprable::instance_repr(PyObject* obj) const +{ + return downcast(obj)->repr(); +} + + // Helper class for optimized allocation of PODs: If two PODs + // happen to contain identical byte patterns, they may share their + // memory. Reference counting is used to free unused memory. + // This is useful because method tables of related extension classes tend + // to be identical, so less memory is needed for them. + class shared_pod_manager + { + typedef std::pair holder; + typedef std::vector storage; + + public: + static shared_pod_manager& obj(); + ~shared_pod_manager(); + + // Allocate memory for POD T and fill it with zeros. + // This memory is initially not shared. + template + static void create(T*& t) + { + t = reinterpret_cast(obj().create(sizeof(T))); + } + + // Decrement the refcount for the memory t points to. If the count + // goes to zero, the memory is freed. + template + static void dispose(T* t) + { + obj().dec_ref(t, sizeof(T)); + } + + // Attempt to share the memory t points to. If memory with the same + // contents already exists, t is replaced by a pointer to this memory, + // and t's old memory is disposed. Otherwise, t will be registered for + // potential future sharing. + template + static void replace_if_equal(T*& t) + { + t = reinterpret_cast(obj().replace_if_equal(t, sizeof(T))); + } + + // Create a copy of t's memory that is guaranteed to be private to t. + // Afterwards t points to the new memory, unless it was already private, in + // which case there is no change (except that t's memory will no longer + // be considered for future sharing - see raplade_if_equal()) + // This function *must* be called before the contents of (*t) can + // be overwritten. Otherwise, inconsistencies and crashes may result. + template + static void make_unique_copy(T*& t) + { + t = reinterpret_cast(obj().make_unique_copy(t, sizeof(T))); + } + + private: + void* replace_if_equal(void* pod, std::size_t size); + void* make_unique_copy(void* pod, std::size_t size); + void* create(std::size_t size); + void dec_ref(void* pod, std::size_t size); + void erase_from_list(void* pod); + + struct compare; + struct identical; + + private: + shared_pod_manager() {} // instance + +#ifdef TYPE_OBJECT_BASE_STANDALONE_TEST + public: +#endif + storage m_storage; + }; + + + void add_capability(type_object_base::capability capability, + PyTypeObject* dest); + +// This macro gets the length of an array as a compile-time constant, and will +// fail to compile if the parameter is a pointer. +# define PY_ARRAY_LENGTH(a) \ + (sizeof(::boost::python::detail::countof_validate(a, &(a))) ? sizeof(a) / sizeof((a)[0]) : 0) + + template + inline void countof_validate(T* const, T* const*); + + template + inline int countof_validate(const void*, T); + +}}} // namespace boost::python::detail + +#endif // TYPES_DWA051800_H_ diff --git a/include/boost/python/detail/wrap_python.hpp b/include/boost/python/detail/wrap_python.hpp new file mode 100644 index 00000000..7c6dd5be --- /dev/null +++ b/include/boost/python/detail/wrap_python.hpp @@ -0,0 +1,61 @@ +#ifdef _DEBUG +# ifndef DEBUG_PYTHON +# undef _DEBUG // Don't let Python force the debug library just because we're debugging. +# define DEBUG_UNDEFINED_FROM_WRAP_PYTHON_H +# endif +#endif + +// +// Some things we need in order to get Python.h to work with compilers other +// than MSVC on Win32 +// +#if defined(_WIN32) +# ifdef __GNUC__ + +typedef int pid_t; +# define WORD_BIT 32 +# define hypot _hypot +# include +# define HAVE_CLOCK +# define HAVE_STRFTIME +# define HAVE_STRERROR +# 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__) + +# ifndef _MSC_VER +# define PY_MSC_VER_DEFINED_FROM_WRAP_PYTHON_H 1 +# define _MSC_VER 900 +# endif + +# endif + +#endif // _WIN32 + +#include + +#ifdef PY_MSC_VER_DEFINED_FROM_WRAP_PYTHON_H +# undef _MSC_VER +#endif + +#ifdef DEBUG_UNDEFINED_FROM_WRAP_PYTHON_H +# undef DEBUG_UNDEFINED_FROM_WRAP_PYTHON_H +# define _DEBUG +#endif + diff --git a/include/boost/python/errors.hpp b/include/boost/python/errors.hpp new file mode 100644 index 00000000..a1cdbbb0 --- /dev/null +++ b/include/boost/python/errors.hpp @@ -0,0 +1,30 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef ERRORS_DWA052500_H_ +# define ERRORS_DWA052500_H_ + +namespace boost { namespace python { + +struct error_already_set {}; +struct argument_error : error_already_set {}; + +// Handles exceptions caught just before returning to Python code. +void handle_exception(); + +template +T* expect_non_null(T* x) +{ + if (x == 0) + throw error_already_set(); + return x; +} + +}} // namespace boost::python + +#endif // ERRORS_DWA052500_H_ diff --git a/include/boost/python/module_builder.hpp b/include/boost/python/module_builder.hpp new file mode 100644 index 00000000..57507e59 --- /dev/null +++ b/include/boost/python/module_builder.hpp @@ -0,0 +1,53 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef MODULE_DWA051000_H_ +# define MODULE_DWA051000_H_ + +# include +# include +# include +# include + +namespace boost { namespace python { + +class module_builder +{ + typedef PyObject * (*raw_function_ptr)(boost::python::tuple const &, boost::python::dictionary const &); + + public: + // Create a module. REQUIRES: only one module_builder is created per module. + module_builder(const char* name); + + // 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); + } + + static string name(); + + private: + PyObject* m_module; + static PyMethodDef initial_methods[1]; +}; + +}} // namespace boost::python + +#endif diff --git a/include/boost/python/objects.hpp b/include/boost/python/objects.hpp new file mode 100644 index 00000000..34052e1f --- /dev/null +++ b/include/boost/python/objects.hpp @@ -0,0 +1,334 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef OBJECTS_DWA051100_H_ +# define OBJECTS_DWA051100_H_ + +# include +# include +# include +# include "boost/operators.hpp" +# include + +namespace boost { namespace python { + +class object +{ + public: + explicit object(ref p); + + // Return a reference to the held object + ref reference() const; + + // Return a raw pointer to the held object + PyObject* get() const; + + private: + ref m_p; +}; + +class tuple : public object +{ + public: + explicit tuple(std::size_t n = 0); + explicit tuple(ref p); + + template + tuple(const std::pair& x) + : object(ref(PyTuple_New(2))) + { + set_item(0, x.first); + set_item(1, x.second); + } + + template + tuple(const First& first, const Second& second) + : object(ref(PyTuple_New(2))) + { + set_item(0, first); + set_item(1, second); + } + + template + tuple(const First& first, const Second& second, const Third& third) + : object(ref(PyTuple_New(3))) + { + set_item(0, first); + set_item(1, second); + set_item(2, third); + } + + template + tuple(const First& first, const Second& second, const Third& third, const Fourth& fourth) + : object(ref(PyTuple_New(4))) + { + set_item(0, first); + set_item(1, second); + set_item(2, third); + 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); +}; + +class list : public object +{ + struct proxy; + struct slice_proxy; + public: + explicit list(ref p); + explicit list(std::size_t sz = 0); + static PyTypeObject* type_obj(); + static bool accepts(ref p); + std::size_t size(); + ref operator[](std::size_t pos) const; + 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; + slice_proxy slice(int low, int high); + void sort(); + void reverse(); + tuple as_tuple() const; +}; + +class string + : public object, public boost::multipliable2 +{ + public: + // Construct from an owned PyObject*. + // Precondition: p must point to a python string. + explicit string(ref p); + explicit string(const char* s); + string(const char* s, std::size_t length); + string(const string& rhs); + + enum interned_t { interned }; + string(const char* s, interned_t); + + // Get the type object for Strings + static PyTypeObject* type_obj(); + + // Return true if the given object is a python string + static bool accepts(ref o); + + // Return the length of the string. + std::size_t size() const; + + // Returns a null-terminated representation of the contents of string. + // The pointer refers to the internal buffer of string, not a copy. + // The data must not be modified in any way. It must not be de-allocated. + const char* c_str() const; + + string& operator*=(unsigned int repeat_count); + string& operator+=(const string& rhs); + friend string operator+(string x, string y); + string& operator+=(const char* rhs); + friend string operator+(string x, const char* y); + friend string operator+(const char* x, string y); + + void intern(); + + friend string operator%(const string& format, const tuple& args); +}; + +class dictionary : public object +{ + private: + struct proxy; + + public: + explicit dictionary(ref p); + dictionary(); + 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); +// ref operator[](const object& key) const; + +// ref get_item(const object& key, ref default_ = ref()) const; +// void set_item(const object& key, const ref& value); + +// void erase(const object& key); + + list items() const; + list keys() const; + list values() const; + + std::size_t size() const; + // TODO: iterator support +}; + +struct dictionary::proxy +{ + template + const ref& operator=(const T& rhs) + { return (*this) = make_ref(rhs); } + const ref& operator=(const ref& rhs); + + operator ref() const; + private: + friend class 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 + private: + ref m_dict; + ref m_key; +}; + +struct list::proxy +{ + template + const ref& operator=(const T& rhs) + { return (*this) = make_ref(rhs); } + const ref& operator=(const ref& rhs); + + operator ref() const; + + private: + friend class 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 + private: + list m_list; + std::size_t m_index; +}; + +struct list::slice_proxy +{ + const list& operator=(const list& rhs); + operator ref() const; + operator list() const; + std::size_t size(); + ref operator[](std::size_t pos) const; + private: + friend class list; + slice_proxy(const ref& list, int low, int high); + private: + ref m_list; + int m_low, m_high; +}; + +}} // namespace boost::python + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + +PyObject* to_python(const boost::python::tuple&); +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); + +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); + +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); + +inline boost::python::dictionary from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +#endif // OBJECTS_DWA051100_H_ diff --git a/include/boost/python/operators.hpp b/include/boost/python/operators.hpp new file mode 100644 index 00000000..d0c06895 --- /dev/null +++ b/include/boost/python/operators.hpp @@ -0,0 +1,504 @@ +#ifndef OPERATORS_UK112000_H_ +#define OPERATORS_UK112000_H_ + +#include +#if !defined(__GNUC__) || defined(__SGI_STL_PORT) +# include +#else +# include +#endif + +namespace boost { namespace python { + +namespace detail { + + // helper class for automatic operand type detection + // during operator wrapping. + struct auto_operand {}; +} + +// Define operator ids that can be or'ed together +// (boost::python::op_add | boost::python::op_sub | boost::python::op_mul). +// This allows to wrap several operators in one line. +enum operator_id +{ + op_add = 0x1, + op_sub = 0x2, + op_mul = 0x4, + op_div = 0x8, + op_mod = 0x10, + op_divmod =0x20, + op_pow = 0x40, + op_lshift = 0x80, + op_rshift = 0x100, + op_and = 0x200, + op_xor = 0x400, + op_or = 0x800, + op_neg = 0x1000, + op_pos = 0x2000, + op_abs = 0x4000, + op_invert = 0x8000, + op_int = 0x10000, + op_long = 0x20000, + op_float = 0x40000, + op_str = 0x80000, + op_cmp = 0x100000 +}; + +// Wrap the operators given by "which". Usage: +// foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>()); +template +struct operators {}; + +// Wrap heterogeneous operators with given left operand type. Usage: +// foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>(), +// boost::python::left_operand()); +template +struct left_operand {}; + +// Wrap heterogeneous operators with given right operand type. Usage: +// foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>(), +// boost::python::right_operand()); +template +struct right_operand {}; + +namespace detail +{ + template + struct operand_select + { + template + struct wrapped + { + typedef Specified type; + }; + }; + + template <> + struct operand_select + { + template + struct wrapped + { + typedef const wrapped_type& type; + }; + }; + + template struct define_operator; + + // Base class which grants access to extension_class_base::add_method() to its derived classes + struct add_operator_base + { + protected: + static inline void add_method(extension_class_base* target, function* method, const char* name) + { target->add_method(method, name); } + }; + +// +// choose_op, choose_unary_op, and choose_rop +// +// These templates use "poor man's partial specialization" to generate the +// appropriate add_method() call (if any) for a given operator and argument set. +// +// Usage: +// choose_op<(which & op_add)>::template args::add(ext_class); +// +// (see extension_class<>::def_operators() for more examples). +// + template + struct choose_op + { + template + struct args : add_operator_base + { + static inline void add(extension_class_base* target) + { + typedef define_operator def_op; + add_method(target, + new typename def_op::template operator_function(), + def_op::name()); + } + + }; + }; + + // specialization for 0 has no effect + template <> + struct choose_op<0> + { + template + struct args + { + static inline void add(extension_class_base*) + { + } + + }; + }; + + template + struct choose_unary_op + { + template + struct args : add_operator_base + { + static inline void add(extension_class_base* target) + { + typedef define_operator def_op; + add_method(target, + new typename def_op::template operator_function(), + def_op::name()); + } + + }; + }; + + // specialization for 0 has no effect + template <> + struct choose_unary_op<0> + { + template + struct args + { + static inline void add(extension_class_base*) + { + } + + }; + }; + + template + struct choose_rop + { + template + struct args : add_operator_base + { + static inline void add(extension_class_base* target) + { + typedef define_operator def_op; + add_method(target, + new typename def_op::template roperator_function(), + def_op::rname()); + } + + }; + }; + + // specialization for 0 has no effect + template <> + struct choose_rop<0> + { + template + struct args + { + static inline void add(extension_class_base*) + { + } + + }; + }; + + +// Fully specialize define_operator for all operators defined in operator_id above. +// Every specialization defines one function object for normal operator calls and one +// for operator calls with operands reversed ("__r*__" function variants). +// Specializations for most operators follow a standard pattern: execute the expression +// that uses the operator in question. This standard pattern is realized by the following +// macros so that the actual specialization can be done by just calling a macro. +#define PY_DEFINE_BINARY_OPERATORS(id, oper) \ + template <> \ + struct define_operator \ + { \ + template \ + struct operator_function : function \ + { \ + PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \ + { \ + tuple args(ref(arguments, ref::increment_count)); \ + \ + return BOOST_PYTHON_CONVERSION::to_python( \ + BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) oper \ + BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type())); \ + } \ + \ + const char* description() const \ + { return "__" #id "__"; } \ + }; \ + \ + template \ + struct roperator_function : function \ + { \ + PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \ + { \ + tuple args(ref(arguments, ref::increment_count)); \ + \ + return BOOST_PYTHON_CONVERSION::to_python( \ + BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()) oper \ + BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type())); \ + } \ + \ + const char* description() const \ + { return "__r" #id "__"; } \ + \ + }; \ + \ + static const char * name() { return "__" #id "__"; } \ + static const char * rname() { return "__r" #id "__"; } \ + } + +#define PY_DEFINE_UNARY_OPERATORS(id, oper) \ + template <> \ + struct define_operator \ + { \ + template \ + struct operator_function : function \ + { \ + PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \ + { \ + tuple args(ref(arguments, ref::increment_count)); \ + \ + return BOOST_PYTHON_CONVERSION::to_python( \ + oper(BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()))); \ + } \ + \ + const char* description() const \ + { return "__" #id "__"; } \ + }; \ + \ + static const char * name() { return "__" #id "__"; } \ + } + + PY_DEFINE_BINARY_OPERATORS(add, +); + PY_DEFINE_BINARY_OPERATORS(sub, -); + PY_DEFINE_BINARY_OPERATORS(mul, *); + PY_DEFINE_BINARY_OPERATORS(div, /); + PY_DEFINE_BINARY_OPERATORS(mod, %); + PY_DEFINE_BINARY_OPERATORS(lshift, <<); + PY_DEFINE_BINARY_OPERATORS(rshift, >>); + PY_DEFINE_BINARY_OPERATORS(and, &); + PY_DEFINE_BINARY_OPERATORS(xor, ^); + PY_DEFINE_BINARY_OPERATORS(or, |); + + PY_DEFINE_UNARY_OPERATORS(neg, -); + PY_DEFINE_UNARY_OPERATORS(pos, +); + PY_DEFINE_UNARY_OPERATORS(abs, abs); + PY_DEFINE_UNARY_OPERATORS(invert, ~); + PY_DEFINE_UNARY_OPERATORS(int, long); + PY_DEFINE_UNARY_OPERATORS(long, PyLong_FromLong); + PY_DEFINE_UNARY_OPERATORS(float, double); + +#undef PY_DEFINE_BINARY_OPERATORS +#undef PY_DEFINE_UNARY_OPERATORS + +// Some operators need special treatment, e.g. because there is no corresponding +// expression in C++. These are specialized manually. + +// pow(): Manual specialization needed because an error message is required if this +// function is called with three arguments. The "power modulo" operator is not +// supported by define_operator, but can be wrapped manually (see special.html). + template <> + struct define_operator + { + template + struct operator_function : function + { + PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const + { + tuple args(ref(arguments, ref::increment_count)); + + if (args.size() == 3 && args[2]->ob_type != Py_None->ob_type) + { + PyErr_SetString(PyExc_TypeError, "expected 2 arguments, got 3"); + throw argument_error(); + } + + return BOOST_PYTHON_CONVERSION::to_python( + pow(BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()), + BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()))); + } + + const char* description() const + { return "__pow__"; } + + }; + + template + struct roperator_function : function + { + PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const + { + tuple args(ref(arguments, ref::increment_count)); + + if (args.size() == 3 && args[2]->ob_type != Py_None->ob_type) + { + PyErr_SetString(PyExc_TypeError, "bad operand type(s) for pow()"); + throw argument_error(); + } + + return BOOST_PYTHON_CONVERSION::to_python( + pow(BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()), + BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()))); + } + + const char* description() const + { return "__rpow__"; } + + }; + + static const char * name() { return "__pow__"; } + static const char * rname() { return "__rpow__"; } + }; + +// divmod(): Manual specialization needed because we must actually call two operators and +// return a tuple containing both results + template <> + struct define_operator + { + template + struct operator_function : function + { + PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const + { + tuple args(ref(arguments, ref::increment_count)); + PyObject * res = PyTuple_New(2); + + PyTuple_SET_ITEM(res, 0, + BOOST_PYTHON_CONVERSION::to_python( + BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) / + BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()))); + PyTuple_SET_ITEM(res, 1, + BOOST_PYTHON_CONVERSION::to_python( + BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) % + BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()))); + + return res; + } + + const char* description() const + { return "__divmod__"; } + + }; + + template + struct roperator_function : function + { + PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const + { + tuple args(ref(arguments, ref::increment_count)); + PyObject * res = PyTuple_New(2); + + PyTuple_SET_ITEM(res, 0, + BOOST_PYTHON_CONVERSION::to_python( + BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()) / + BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()))); + PyTuple_SET_ITEM(res, 1, + BOOST_PYTHON_CONVERSION::to_python( + BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()) % + BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()))); + + return res; + } + + const char* description() const + { return "__rdivmod__"; } + + }; + + static const char * name() { return "__divmod__"; } + static const char * rname() { return "__rdivmod__"; } + }; + +// cmp(): Manual specialization needed because there is no three-way compare in C++. +// It is implemented by two one-way comparisons with operators reversed in the second. + template <> + struct define_operator + { + template + struct operator_function : function + { + PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const + { + tuple args(ref(arguments, ref::increment_count)); + + return BOOST_PYTHON_CONVERSION::to_python( + (BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) < + BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type())) ? + - 1 : + (BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()) < + BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type())) ? + 1 : + 0) ; + } + + const char* description() const + { return "__cmp__"; } + + }; + + template + struct roperator_function : function + { + PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const + { + tuple args(ref(arguments, ref::increment_count)); + + return BOOST_PYTHON_CONVERSION::to_python( + (BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()) < + BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type())) ? + - 1 : + (BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) < + BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type())) ? + 1 : + 0) ; + } + + const char* description() const + { return "__rcmp__"; } + + }; + + static const char * name() { return "__cmp__"; } + static const char * rname() { return "__rcmp__"; } + }; + +// str(): Manual specialization needed because the string conversion does not follow +// the standard pattern relized by the macros. + template <> + struct define_operator + { + template + struct operator_function : function + { + PyObject* do_call(PyObject* arguments, PyObject*) const + { + tuple args(ref(arguments, ref::increment_count)); + +#if !defined(__GNUC__) || defined(__SGI_STL_PORT) + std::ostringstream s; + s << BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()); +#else + std::ostrstream s; + s << BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) << char(); +#endif + +#if !defined(__GNUC__) || defined(__SGI_STL_PORT) + return BOOST_PYTHON_CONVERSION::to_python(s.str()); +#else + return BOOST_PYTHON_CONVERSION::to_python(const_cast(s.str())); +#endif + } + + const char* description() const + { return "__str__"; } + + }; + + static const char * name() { return "__str__"; } + }; + + +} // namespace detail + +}} // namespace boost::python + +#endif /* OPERATORS_UK112000_H_ */ diff --git a/include/boost/python/reference.hpp b/include/boost/python/reference.hpp new file mode 100644 index 00000000..c633b9d7 --- /dev/null +++ b/include/boost/python/reference.hpp @@ -0,0 +1,173 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef PYPTR_DWA050400_H_ +# define PYPTR_DWA050400_H_ + +# include +# include +# include +# include +# include +# include +# include +# include + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + +template +struct py_ptr_conversions : Base +{ + inline friend T from_python(PyObject* x, boost::python::type) + { return T(boost::python::downcast(x).get(), T::increment_count); } + + inline friend T from_python(PyObject* x, boost::python::type) + { return T(boost::python::downcast(x).get(), T::increment_count); } + + inline friend PyObject* to_python(T x) + { return boost::python::as_object(x.release()); } + +}; + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +namespace boost { namespace python { + +BOOST_PYTHON_IMPORT_CONVERSION(py_ptr_conversions); + +template +class reference + : public py_ptr_conversions, T, + boost::dereferenceable, T*> > // supplies op-> +{ +public: + typedef T value_type; + + reference(const reference& rhs) + : m_p(rhs.m_p) + { + Py_XINCREF(object()); + } + +#if !defined(BOOST_MSVC6_OR_EARLIER) + template + reference(const reference& rhs) + : m_p(rhs.object()) + { + Py_XINCREF(object()); + } +#endif + + reference() : m_p(0) {} + + // These are two ways of spelling the same thing, that we need to increment + // the reference count on the pointer when we're initialized. + enum increment_count_t { increment_count }; + + enum allow_null { null_ok }; + + template + explicit reference(T2* x) + : m_p(expect_non_null(x)) {} + + template + reference(T2* x, increment_count_t) + : m_p(expect_non_null(x)) { Py_INCREF(object()); } + + template + reference(T2* x, allow_null) + : m_p(x) {} + + template + reference(T2* x, allow_null, increment_count_t) + : m_p(x) { Py_XINCREF(object()); } + + template + reference(T2* x, increment_count_t, allow_null) + : m_p(x) { Py_XINCREF(object()); } + +#if !defined(BOOST_MSVC6_OR_EARLIER) + template + reference& operator=(const reference& rhs) + { + Py_XDECREF(object()); + m_p = rhs.m_p; + Py_XINCREF(object()); + return *this; + } +#endif + + reference& operator=(const reference& rhs) + { + Py_XINCREF(static_cast(rhs.m_p)); + Py_XDECREF(object()); + m_p = rhs.m_p; + return *this; + } + + ~reference() + { + Py_XDECREF(m_p); + } + + T& operator*() const { return *m_p; } + + T* get() const { return m_p; } + + T* release() + { + T* p = m_p; + m_p = 0; + return p; + } + + void reset() + { Py_XDECREF(m_p); m_p = 0; } + + template + void reset(T2* x) + { Py_XDECREF(m_p); m_p = expect_non_null(x);} + + template + void reset(T2* x, increment_count_t) + { Py_XDECREF(m_p); m_p = expect_non_null(x); Py_INCREF(object()); } + + template + void reset(T2* x, allow_null) + { Py_XDECREF(m_p); m_p = x;} + + template + void reset(T2* x, allow_null, increment_count_t) + { Py_XDECREF(m_p); m_p = x; Py_XINCREF(object()); } + + template + void reset(T2* x, increment_count_t, allow_null) + { Py_XDECREF(m_p); m_p = x; Py_XINCREF(object()); } + +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) +private: + template friend class shared_ptr; +#endif + + inline PyObject* object() const + { return as_object(m_p); } + + T* m_p; +}; + +typedef reference ref; + +template +ref make_ref(const T& x) +{ + return ref(to_python(x)); +} + +}} // namespace boost::python + +#endif // PYPTR_DWA050400_H_ diff --git a/src/classes.cpp b/src/classes.cpp new file mode 100644 index 00000000..34b42c22 --- /dev/null +++ b/src/classes.cpp @@ -0,0 +1,884 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace python { + +namespace detail { + void enable_named_method(boost::python::detail::class_base* type_obj, const char* name); +} + +namespace { + // Add the name of the module currently being loaded to the name_space with the + // key "__module__". If no module is being loaded, or if name_space already has + // a key "__module", has no effect. This is not really a useful public + // interface; it's just used for class_t<>::class_t() below. + void add_current_module_name(dictionary&); + + bool is_prefix(const char* s1, const char* s2); + bool is_special_name(const char* name); + void enable_special_methods(boost::python::detail::class_base* derived, const tuple& bases, const dictionary& name_space); + + void report_ignored_exception(PyObject* source) + { + // This bit of code copied wholesale from classobject.c in the Python source. + PyObject *f, *t, *v, *tb; + PyErr_Fetch(&t, &v, &tb); + f = PySys_GetObject(const_cast("stderr")); + if (f != NULL) + { + PyFile_WriteString(const_cast("Exception "), f); + if (t) { + PyFile_WriteObject(t, f, Py_PRINT_RAW); + if (v && v != Py_None) { + PyFile_WriteString(const_cast(": "), f); + PyFile_WriteObject(v, f, 0); + } + } + PyFile_WriteString(const_cast(" in "), f); + PyFile_WriteObject(source, f, 0); + PyFile_WriteString(const_cast(" ignored\n"), f); + PyErr_Clear(); /* Just in case */ + } + Py_XDECREF(t); + Py_XDECREF(v); + Py_XDECREF(tb); + } + + // + // pickle support courtesy of "Ralf W. Grosse-Kunstleve" + // + PyObject* class_reduce(PyObject* klass) + { + return PyObject_GetAttrString(klass, const_cast("__name__")); + } + + ref global_class_reduce() + { + static ref result(detail::new_wrapped_function(class_reduce)); + return result; + } + + + tuple instance_reduce(PyObject* obj) + { + ref instance_class(PyObject_GetAttrString(obj, const_cast("__class__"))); + + ref getinitargs(PyObject_GetAttrString(obj, const_cast("__getinitargs__")), + ref::null_ok); + PyErr_Clear(); + ref initargs; + if (getinitargs.get() != 0) + { + initargs = ref(PyEval_CallObject(getinitargs.get(), NULL)); + initargs = ref(PySequence_Tuple(initargs.get())); + } + else + { + initargs = ref(PyTuple_New(0)); + } + + ref getstate(PyObject_GetAttrString(obj, const_cast("__getstate__")), + ref::null_ok); + PyErr_Clear(); + if (getstate.get() != 0) + { + ref state = ref(PyEval_CallObject(getstate.get(), NULL)); + return tuple(instance_class, initargs, state); + } + + ref state(PyObject_GetAttrString(obj, const_cast("__dict__")), ref::null_ok); + PyErr_Clear(); + if (state.get() != 0 && dictionary(state).size() > 0) + { + return tuple(instance_class, initargs, state); + } + + return tuple(instance_class, initargs); + } + + ref global_instance_reduce() + { + static ref result(detail::new_wrapped_function(instance_reduce)); + return result; + } +} + + +namespace detail { + + class_base::class_base(PyTypeObject* meta_class_obj, string name, tuple bases, const dictionary& name_space) + : type_object_base(meta_class_obj), + m_name(name), + m_bases(bases), + m_name_space(name_space) + { + this->tp_name = const_cast(name.c_str()); + enable(type_object_base::getattr); + enable(type_object_base::setattr); + add_current_module_name(m_name_space); + static const boost::python::string docstr("__doc__", boost::python::string::interned); + if (PyDict_GetItem(m_name_space.get(), docstr.get())== 0) + { + PyDict_SetItem(m_name_space.get(), docstr.get(), Py_None); + } + enable_special_methods(this, bases, name_space); + } + + void class_base::add_base(ref base) + { + tuple new_bases(m_bases.size() + 1); + for (std::size_t i = 0; i < m_bases.size(); ++i) + new_bases.set_item(i, m_bases[i]); + new_bases.set_item(m_bases.size(), base); + m_bases = new_bases; + } + + PyObject* class_base::getattr(const char* name) + { + if (!BOOST_CSTD_::strcmp(name, "__dict__")) + { + PyObject* result = m_name_space.get(); + Py_INCREF(result); + return result; + } + + if (!BOOST_CSTD_::strcmp(name, "__bases__")) + { + PyObject* result = m_bases.get(); + Py_INCREF(result); + return result; + } + + if (!BOOST_CSTD_::strcmp(name, "__name__")) + { + PyObject* result = m_name.get(); + Py_INCREF(result); + return result; + } + + // pickle support courtesy of "Ralf W. Grosse-Kunstleve" + if (!BOOST_CSTD_::strcmp(name, "__safe_for_unpickling__")) + { + return PyInt_FromLong(1); + } + if (!BOOST_CSTD_::strcmp(name, "__reduce__")) + { + ref target(as_object(this), ref::increment_count); + return new bound_function(target, global_class_reduce()); + } + + ref local_attribute = m_name_space.get_item(string(name).reference()); + + if (local_attribute.get()) + return local_attribute.release(); + + // In case there are no bases... + PyErr_SetString(PyExc_AttributeError, name); + + // Check bases + for (std::size_t i = 0; i < m_bases.size(); ++i) + { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); // we're going to try a base class + else if (PyErr_Occurred()) + break; // Other errors count, though! + + PyObject* base_attribute = PyObject_GetAttrString(m_bases[i].get(), const_cast(name)); + + if (base_attribute != 0) + { + // Unwind the actual underlying function from unbound Python class + // methods in case of multiple inheritance from real Python + // classes. Python stubbornly insists that the first argument to a + // method must be a true Python instance object otherwise. Do not + // unwrap bound methods; that would interfere with intended semantics. + if (PyMethod_Check(base_attribute) + && reinterpret_cast(base_attribute)->im_self == 0) + { + PyObject* function + = reinterpret_cast(base_attribute)->im_func; + Py_INCREF(function); + Py_DECREF(base_attribute); + return function; + } + else + { + return base_attribute; + } + } + } + return 0; + } + + // Mostly copied wholesale from Python's classobject.c + PyObject* class_base::repr() const + { + PyObject *mod = PyDict_GetItemString( + m_name_space.get(), const_cast("__module__")); + unsigned long address = reinterpret_cast(this); + string result = (mod == NULL || !PyString_Check(mod)) + ? string("") % tuple(m_name, address) + : string("") % tuple(ref(mod, ref::increment_count), m_name, address); + return result.reference().release(); + } + + + int class_base::setattr(const char* name, PyObject* value) + { + if (is_special_name(name) + && BOOST_CSTD_::strcmp(name, "__doc__") != 0 + && BOOST_CSTD_::strcmp(name, "__name__") != 0) + { + boost::python::string message("Special attribute names other than '__doc__' and '__name__' are read-only, in particular: "); + PyErr_SetObject(PyExc_TypeError, (message + name).get()); + throw error_already_set(); + } + + if (PyCallable_Check(value)) + detail::enable_named_method(this, name); + + return PyDict_SetItemString( + m_name_space.reference().get(), const_cast(name), value); + } + + bool class_base::initialize_instance(instance* obj, PyObject* args, PyObject* keywords) + { + // Getting the init function off the obj should result in a + // bound method. + PyObject* const init_function = obj->getattr("__init__", false); + + if (init_function == 0) + { + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); // no __init__? That's legal. + } + else { + return false; // Something else? Keep the error + } + } + else + { + // Manage the reference to the bound function + ref init_function_holder(init_function); + + // Declare a ref to manage the result of calling __init__ (which should be None). + ref init_result( + PyEval_CallObjectWithKeywords(init_function, args, keywords)); + } + return true; + } + + void class_base::instance_dealloc(PyObject* obj) const + { + Py_INCREF(obj); // This allows a __del__ function to revive the obj + + PyObject* exc_type; + PyObject* exc_value; + PyObject* exc_traceback; + PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); + + // This scope ensures that the reference held by del_function doesn't release + // the last reference and delete the object recursively (infinitely). + { + ref del_function; + try { + instance* const target = boost::python::downcast(obj); + del_function = ref(target->getattr("__del__", false), ref::null_ok); + } + catch(...) { + } + + if (del_function.get() != 0) + { + ref result(PyEval_CallObject(del_function.get(), (PyObject *)NULL), ref::null_ok); + + if (result.get() == NULL) + report_ignored_exception(del_function.get()); + } + } + PyErr_Restore(exc_type, exc_value, exc_traceback); + + if (--obj->ob_refcnt <= 0) + delete_instance(obj); + } + + +} + +instance::instance(PyTypeObject* class_) + : boost::python::detail::base_object(class_) +{ +} + +instance::~instance() +{ +} + +PyObject* instance::getattr(const char* name, bool use_special_function) +{ + if (!BOOST_CSTD_::strcmp(name, "__dict__")) + { + if (PyEval_GetRestricted()) { + PyErr_SetString(PyExc_RuntimeError, + "instance.__dict__ not accessible in restricted mode"); + return 0; + } + Py_INCREF(m_name_space.get()); + return m_name_space.get(); + } + + if (!BOOST_CSTD_::strcmp(name, "__class__")) + { + Py_INCREF(this->ob_type); + return as_object(this->ob_type); + } + + if (!BOOST_CSTD_::strcmp(name, "__reduce__")) + { + return new detail::bound_function(ref(this, ref::increment_count), global_instance_reduce()); + } + + ref local_attribute = m_name_space.get_item(string(name).reference()); + + if (local_attribute.get()) + return local_attribute.release(); + + // Check its class. + PyObject* function = + PyObject_GetAttrString(as_object(this->ob_type), const_cast(name)); + + if (function == 0 && !use_special_function) + { + return 0; + } + + ref class_attribute; + if (function != 0) + { + // This will throw if the attribute wasn't found + class_attribute = ref(function); + } + else + { + // Clear the error while we try special methods method (if any). + PyErr_Clear(); + + // First we try the special method that comes from concatenating + // "__getattr__" and and 2 trailing underscores. This is an + // extension to regular Python class functionality. + const string specific_getattr_name(detail::getattr_string() + name + "__"); + PyObject* getattr_method = PyObject_GetAttr( + as_object(this->ob_type), specific_getattr_name.get()); + + // Use just the first arg to PyEval_CallFunction if found + char* arg_format = const_cast("(O)"); + + // Try for the regular __getattr__ method if not found + if (getattr_method == 0) + { + PyErr_Clear(); + getattr_method = PyObject_GetAttrString( + as_object(this->ob_type), const_cast("__getattr__")); + + // Use both args to PyEval_CallFunction + arg_format = const_cast("(Os)"); + } + + // If there is no such method, throw now. + if (PyErr_Occurred()) + { + PyErr_SetString(PyExc_AttributeError, name); + return 0; + } + + // Take ownership of the method + ref owner(getattr_method); + + // Call it to get the attribute. + return PyEval_CallFunction(getattr_method, arg_format, this, name); + } + + if (!PyCallable_Check(class_attribute.get())) + { + PyErr_Clear(); + return class_attribute.release(); + } + else + { + return detail::bound_function::create(ref(this, ref::increment_count), class_attribute); + } +} + +// instance::setattr_dict +// +// Implements setattr() functionality for the "__dict__" attribute +// +int instance::setattr_dict(PyObject* value) +{ + if (PyEval_GetRestricted()) + { + PyErr_SetString(PyExc_RuntimeError, + "__dict__ not accessible in restricted mode"); + return -1; + } + + if (value == 0 || !PyDict_Check(value)) + { + PyErr_SetString(PyExc_TypeError, + "__dict__ must be set to a dictionary"); + return -1; + } + m_name_space = dictionary(ref(value, ref::increment_count)); + return 0; +} + +// instance::setattr - +// +// Implements the setattr() and delattr() functionality for our own instance +// objects, using the standard Python interface: if value == 0, we are deleting +// the attribute, and returns 0 unless an error occurred. +int instance::setattr(const char* name, PyObject* value) +{ + if (BOOST_CSTD_::strcmp(name, "__class__") == 0) + { + PyErr_SetString(PyExc_TypeError, "__class__ attribute is read-only"); + throw error_already_set(); + } + + if (BOOST_CSTD_::strcmp(name, "__dict__") == 0) + return setattr_dict(value); + + // Try to find an appropriate "specific" setter or getter method, either + // __setattr____(value) or __delattr____(). This is an extension + // to regular Python class functionality. + const string& base_name = value ? detail::setattr_string() : detail::delattr_string(); + const string specific_method_name(base_name + name + "__"); + + ref special_method( + PyObject_GetAttr(as_object(this->ob_type), specific_method_name.get()), + ref::null_ok); + + PyObject* result_object = 0; + if (special_method.get() != 0) + { + // The specific function was found; call it now. Note that if value is + // not included in the format string, it is ignored. + char* format_string = const_cast(value ? "(OO)" : "(O)"); + result_object = PyEval_CallFunction(special_method.get(), format_string, this, value); + } + else + { + // If not found, try the usual __setattr__(name, value) or + // __delattr__(name) functions. + PyErr_Clear(); + special_method.reset( + PyObject_GetAttr(as_object(this->ob_type), base_name.get()), + ref::null_ok); + + if (special_method.get() != 0) + { + // The special function was found; call it now. Note that if value + // is not included in the format string, it is ignored. + char* format_string = const_cast(value ? "(OsO)" : "(Os)"); + result_object = PyEval_CallFunction( + special_method.get(), format_string, this, name, value); + } + } + + // If we found an appropriate special method, handle the return value. + if (special_method.get() != 0) + { + ref manage_result(result_object); + return 0; + } + + PyErr_Clear(); // Nothing was found; clear the python error state + + if (value == 0) // Try to remove the attribute from our name space + { + const int result = PyDict_DelItemString(m_name_space.reference().get(), + const_cast(name)); + if (result < 0) + { + PyErr_Clear(); + PyErr_SetString(PyExc_AttributeError, "delete non-existing instance attribute"); + } + return result; + } + else // Change the specified item in our name space + { + return PyDict_SetItemString(m_name_space.reference().get(), + const_cast(name), value); + } +} + +PyObject* instance::call(PyObject* args, PyObject* keywords) +{ + return PyEval_CallObjectWithKeywords( + ref(getattr("__call__")).get(), // take possession of the result from getattr() + args, keywords); +} + +PyObject* instance::repr() +{ + return callback::call_method(this, "__repr__"); +} + +int instance::compare(PyObject* other) +{ + return callback::call_method(this, "__cmp__", other); +} + +PyObject* instance::str() +{ + return callback::call_method(this, "__str__"); +} + +long instance::hash() +{ + return callback::call_method(this, "__hash__"); +} + +int instance::length() +{ + return callback::call_method(this, "__len__"); +} + +PyObject* instance::get_subscript(PyObject* key) +{ + return callback::call_method(this, "__getitem__", key); +} + +void instance::set_subscript(PyObject* key, PyObject* value) +{ + if (value == 0) + callback::call_method(this, "__delitem__", key); + else + callback::call_method(this, "__setitem__", key, value); +} + +PyObject* instance::get_slice(int start, int finish) +{ + return callback::call_method(this, "__getslice__", start, finish); +} + +void instance::set_slice(int start, int finish, PyObject* value) +{ + if (value == 0) + callback::call_method(this, "__delslice__", start, finish); + else + callback::call_method(this, "__setslice__", start, finish, value); +} + +PyObject* instance::add(PyObject* other) +{ + return callback::call_method(this, "__add__", other); +} + +PyObject* instance::subtract(PyObject* other) +{ + return callback::call_method(this, "__sub__", other); +} + +PyObject* instance::multiply(PyObject* other) +{ + return callback::call_method(this, "__mul__", other); +} + +PyObject* instance::divide(PyObject* other) +{ + return callback::call_method(this, "__div__", other); +} + +PyObject* instance::remainder(PyObject* other) +{ + return callback::call_method(this, "__mod__", other); +} + +PyObject* instance::divmod(PyObject* other) +{ + return callback::call_method(this, "__divmod__", other); +} + +PyObject* instance::power(PyObject* exponent, PyObject* modulus) +{ + if (as_object(modulus->ob_type) == Py_None) + return callback::call_method(this, "__pow__", exponent); + else + return callback::call_method(this, "__pow__", exponent, modulus); +} + +PyObject* instance::negative() +{ + return callback::call_method(this, "__neg__"); +} + +PyObject* instance::positive() +{ + return callback::call_method(this, "__pos__"); +} + +PyObject* instance::absolute() +{ + return callback::call_method(this, "__abs__"); +} + +int instance::nonzero() +{ + return callback::call_method(this, "__nonzero__"); +} + +PyObject* instance::invert() +{ + return callback::call_method(this, "__invert__"); +} + +PyObject* instance::lshift(PyObject* other) +{ + return callback::call_method(this, "__lshift__", other); +} + +PyObject* instance::rshift(PyObject* other) +{ + return callback::call_method(this, "__rshift__", other); +} + +PyObject* instance::do_and(PyObject* other) +{ + return callback::call_method(this, "__and__", other); +} + +PyObject* instance::do_xor(PyObject* other) +{ + return callback::call_method(this, "__xor__", other); +} + +PyObject* instance::do_or(PyObject* other) +{ + return callback::call_method(this, "__or__", other); +} + +int instance::coerce(PyObject** x, PyObject** y) +{ + assert(this == *x); + + // Coerce must return a tuple + tuple result(callback::call_method(this, "__coerce__", *y)); + + *x = result[0].release(); + *y = result[1].release(); + return 0; +} + +PyObject* instance::as_int() +{ + return callback::call_method(this, "__int__"); +} + +PyObject* instance::as_long() +{ + return callback::call_method(this, "__long__"); +} + +PyObject* instance::as_float() +{ + return callback::call_method(this, "__float__"); +} + +PyObject* instance::oct() +{ + return callback::call_method(this, "__oct__"); +} + +PyObject* instance::hex() +{ + return callback::call_method(this, "__hex__"); +} + +namespace { + struct named_capability + { + const char* name; + detail::type_object_base::capability capability; + }; + + const named_capability enablers[] = + { + { "__hash__", detail::type_object_base::hash }, + { "__cmp__", detail::type_object_base::compare }, + { "__repr__", detail::type_object_base::repr }, + { "__str__", detail::type_object_base::str }, + { "__call__", detail::type_object_base::call }, + { "__getattr__", detail::type_object_base::getattr }, + { "__setattr__", detail::type_object_base::setattr }, + { "__len__", detail::type_object_base::mapping_length }, + { "__len__", detail::type_object_base::sequence_length }, + { "__getitem__", detail::type_object_base::mapping_subscript }, + { "__getitem__", detail::type_object_base::sequence_item }, + { "__setitem__", detail::type_object_base::mapping_ass_subscript }, + { "__setitem__", detail::type_object_base::sequence_ass_item }, + { "__delitem__", detail::type_object_base::mapping_ass_subscript }, + { "__delitem__", detail::type_object_base::sequence_ass_item }, + { "__getslice__", detail::type_object_base::sequence_slice }, + { "__setslice__", detail::type_object_base::sequence_ass_slice }, + { "__delslice__", detail::type_object_base::sequence_ass_slice }, + { "__add__", detail::type_object_base::number_add }, + { "__sub__", detail::type_object_base::number_subtract }, + { "__mul__", detail::type_object_base::number_multiply }, + { "__div__", detail::type_object_base::number_divide }, + { "__mod__", detail::type_object_base::number_remainder }, + { "__divmod__", detail::type_object_base::number_divmod }, + { "__pow__", detail::type_object_base::number_power }, + { "__neg__", detail::type_object_base::number_negative }, + { "__pos__", detail::type_object_base::number_positive }, + { "__abs__", detail::type_object_base::number_absolute }, + { "__nonzero__", detail::type_object_base::number_nonzero }, + { "__invert__", detail::type_object_base::number_invert }, + { "__lshift__", detail::type_object_base::number_lshift }, + { "__rshift__", detail::type_object_base::number_rshift }, + { "__and__", detail::type_object_base::number_and }, + { "__xor__", detail::type_object_base::number_xor }, + { "__or__", detail::type_object_base::number_or }, + { "__coerce__", detail::type_object_base::number_coerce }, + { "__int__", detail::type_object_base::number_int }, + { "__long__", detail::type_object_base::number_long }, + { "__float__", detail::type_object_base::number_float }, + { "__oct__", detail::type_object_base::number_oct }, + { "__hex__", detail::type_object_base::number_hex } + }; + + bool is_prefix(const char* s1, const char* s2) + { + while (*s1 != 0 && *s2 != 0 && *s1 == *s2) + ++s1, ++s2; + return *s1 == 0; + } + + bool is_special_name(const char* name) + { + if (name[0] != '_' || name[1] != '_' || name[2] == 0 || name[3] == 0) + return false; + + std::size_t name_length = BOOST_CSTD_::strlen(name); + return name[name_length - 1] == '_' && name[name_length - 2] == '_'; + } +} + +namespace detail { + // Enable the special handler for methods of the given name, if any. + void enable_named_method(boost::python::detail::class_base* type_obj, const char* name) + { + const std::size_t num_enablers = sizeof(enablers) / sizeof(enablers[0]); + + // Make sure this ends with "__" since we'll only compare the head of the + // string. This is done to make the __getattr____/__setattr____ + // extension work. + if (!is_special_name(name)) + return; + + for (std::size_t i = 0; i < num_enablers; ++i) + { + if (is_prefix(enablers[i].name + 2, name + 2)) + { + type_obj->enable(enablers[i].capability); + } + } + } +} + +namespace { + // Enable any special methods which are enabled in the base class. + void enable_special_methods(boost::python::detail::class_base* derived, const tuple& bases, const dictionary& name_space) + { + for (std::size_t i = 0; i < bases.size(); ++i) + { + PyObject* base = bases[i].get(); + + for (std::size_t n = 0; n < PY_ARRAY_LENGTH(enablers); ++n) + { + ref attribute( + PyObject_GetAttrString(base, const_cast(enablers[n].name)), + ref::null_ok); + PyErr_Clear(); + if (attribute.get() != 0 && PyCallable_Check(attribute.get())) + detail::add_capability(enablers[n].capability, derived); + } + } + + list keys(name_space.keys()); + for (std::size_t j = 0, len = keys.size(); j < len; ++j) + { + string name_obj(keys.get_item(j)); + const char* name = name_obj.c_str(); + + if (!is_special_name(name)) + continue; + + for (std::size_t i = 0; i < PY_ARRAY_LENGTH(enablers); ++i) + { + if (is_prefix(enablers[i].name + 2, name + 2)) + { + detail::add_capability(enablers[i].capability, derived); + } + } + } + } + + void add_current_module_name(dictionary& name_space) + { + static string module_key("__module__", string::interned); + name_space.set_item(module_key, module_builder::name()); + } +} + +void adjust_slice_indices(PyObject* obj, int& start, int& finish) +{ + int length = callback::call_method(obj, "__len__"); + + // This is standard Python class behavior. + if (start < 0) + start += length; + if (finish < 0) + finish += length; + + // This is not + if (start < 0) + start = 0; + if (finish < 0) + finish = 0; +} + +namespace detail { +const string& setattr_string() +{ + static string x("__setattr__", string::interned); + return x; +} + +const string& getattr_string() +{ + static string x("__getattr__", string::interned); + return x; +} + +const string& delattr_string() +{ + static string x("__delattr__", string::interned); + return x; +} +} + +}} // namespace boost::python diff --git a/src/conversions.cpp b/src/conversions.cpp new file mode 100644 index 00000000..ded01e0e --- /dev/null +++ b/src/conversions.cpp @@ -0,0 +1,241 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#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! +void handle_exception() +{ + try { + // re-toss the current exception so we can find out what type it is. + // NOTE: a heinous bug in MSVC6 causes exception objects re-thrown in + // this way to be double-destroyed. Thus, you must only use objects that + // can tolerate double-destruction with that compiler. Metrowerks + // Codewarrior doesn't suffer from this problem. + throw; + } + 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"); + } +} + +}} // namespace boost::python + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + +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; + { + result = PyInt_AsLong(p); + if (PyErr_Occurred()) + throw boost::python::argument_error(); + } + return result; +} + +double from_python(PyObject* p, boost::python::type) +{ + double result; + { + result = PyFloat_AsDouble(p); + if (PyErr_Occurred()) + throw boost::python::argument_error(); + } + return result; +} + +template +T integer_from_python(PyObject* p, boost::python::type) +{ + const long long_result = from_python(p, boost::python::type()); + +#ifndef BOOST_NO_LIMITS + try + { + return boost::numeric_cast(long_result); + } + catch(const boost::bad_numeric_cast&) +#else + if (static_cast(long_result) == long_result) + { + return static_cast(long_result); + } + else +#endif + { + char buffer[256]; + const char message[] = "%ld out of range for %s"; + sprintf(buffer, message, long_result, typeid(T).name()); + PyErr_SetString(PyExc_ValueError, buffer); + throw boost::python::argument_error(); + } +#if defined(__MWERKS__) && __MWERKS__ <= 0x2400 + return 0; // Not smart enough to know that the catch clause always rethrows +#endif +} + +template +PyObject* integer_to_python(T value) +{ + long value_as_long; + +#ifndef BOOST_NO_LIMITS + try + { + value_as_long = boost::numeric_cast(value); + } + catch(const boost::bad_numeric_cast&) +#else + value_as_long = static_cast(value); + if (value_as_long != value) +#endif + { + const char message[] = "value out of range for Python int"; + PyErr_SetString(PyExc_ValueError, message); + throw boost::python::error_already_set(); + } + + return to_python(value_as_long); +} + +int from_python(PyObject* p, boost::python::type type) +{ + return integer_from_python(p, type); +} + +PyObject* to_python(unsigned int i) +{ + return integer_to_python(i); +} + +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) +{ + return integer_from_python(p, type); +} + +float from_python(PyObject* p, boost::python::type) +{ + return static_cast(from_python(p, boost::python::type())); +} + +PyObject* to_python(unsigned short i) +{ + return integer_to_python(i); +} + +unsigned short from_python(PyObject* p, boost::python::type type) +{ + return integer_from_python(p, type); +} + +PyObject* to_python(unsigned char i) +{ + return integer_to_python(i); +} + +unsigned char from_python(PyObject* p, boost::python::type type) +{ + return integer_from_python(p, type); +} + +PyObject* to_python(signed char i) +{ + return integer_to_python(i); +} + +signed char from_python(PyObject* p, boost::python::type type) +{ + return integer_from_python(p, type); +} + +PyObject* to_python(unsigned long x) +{ + return integer_to_python(x); +} + +unsigned long from_python(PyObject* p, boost::python::type type) +{ + return integer_from_python(p, type); +} + +void from_python(PyObject* p, boost::python::type) +{ + if (p != Py_None) { + PyErr_SetString(PyExc_TypeError, "expected argument of type None"); + throw boost::python::argument_error(); + } +} + +const char* from_python(PyObject* p, boost::python::type) +{ + const char* s = PyString_AsString(p); + if (!s) + throw boost::python::argument_error(); + return s; +} + +PyObject* to_python(const std::string& s) +{ + return PyString_FromString(s.c_str()); +} + +std::string from_python(PyObject* p, boost::python::type) +{ + return std::string(from_python(p, boost::python::type())); +} + +bool from_python(PyObject* p, boost::python::type) +{ + int value = from_python(p, boost::python::type()); + if (value == 0) + return false; + return true; +} + +#ifdef BOOST_MSVC6_OR_EARLIER +// An optimizer bug prevents these from being inlined. +PyObject* to_python(double d) +{ + return PyFloat_FromDouble(d); +} + +PyObject* to_python(float f) +{ + return PyFloat_FromDouble(f); +} +#endif // BOOST_MSVC6_OR_EARLIER + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + diff --git a/src/extension_class.cpp b/src/extension_class.cpp new file mode 100644 index 00000000..cde3d836 --- /dev/null +++ b/src/extension_class.cpp @@ -0,0 +1,683 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#include +#include +#include + +namespace boost { namespace python { +namespace detail { + + struct operator_dispatcher + : public PyObject + { + static PyTypeObject type_obj; + static PyNumberMethods number_methods; + + static operator_dispatcher* create(const ref& o, const ref& s); + + ref m_object; + ref m_self; + + // data members for allocation/deallocation optimization + operator_dispatcher* m_free_list_link; + static operator_dispatcher* free_list; + + private: + // only accessible through create() + operator_dispatcher(const ref& o, const ref& s); + }; + + operator_dispatcher* operator_dispatcher::free_list = 0; + +}}} // namespace boost::python::detail + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + +inline PyObject* to_python(boost::python::detail::operator_dispatcher* n) { return n; } + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + + +namespace boost { namespace python { + +namespace detail { + + tuple extension_class_coerce(ref l, ref r) + { + // Introduced sequence points for exception-safety. + ref first(operator_dispatcher::create(l, l)); + ref second; + + if(r->ob_type == &operator_dispatcher::type_obj) + { + second = r; + } + else + { + second = ref(operator_dispatcher::create(r, ref())); + } + return boost::python::tuple(first, second); + } + + enum { unwrap_exception_code = -1000 }; + + int unwrap_args(PyObject* left, PyObject* right, PyObject*& self, PyObject*& other) + { + if (left->ob_type != &operator_dispatcher::type_obj || + right->ob_type != &operator_dispatcher::type_obj) + { + PyErr_SetString(PyExc_RuntimeError, "operator_dispatcher::unwrap_args(): expecting operator_dispatcher arguments only!"); + return unwrap_exception_code; + } + + typedef reference DPtr; + DPtr lwrapper(static_cast(left), DPtr::increment_count); + DPtr rwrapper(static_cast(right), DPtr::increment_count); + + if (lwrapper->m_self.get() != 0) + { + self = lwrapper->m_self.get(); + other = rwrapper->m_object.get(); + return 0; + } + else + { + self = rwrapper->m_self.get(); + other = lwrapper->m_object.get(); + return 1; + } + } + + int unwrap_pow_args(PyObject* left, PyObject* right, PyObject* m, + PyObject*& self, PyObject*& first, PyObject*& second) + { + if (left->ob_type != &operator_dispatcher::type_obj || + right->ob_type != &operator_dispatcher::type_obj || + m->ob_type != &operator_dispatcher::type_obj) + { + PyErr_SetString(PyExc_RuntimeError, "operator_dispatcher::unwrap_pow_args(): expecting operator_dispatcher arguments only!"); + return unwrap_exception_code; + } + + typedef reference DPtr; + DPtr lwrapper(static_cast(left), DPtr::increment_count); + DPtr rwrapper(static_cast(right), DPtr::increment_count); + DPtr mwrapper(static_cast(m), DPtr::increment_count); + + if (lwrapper->m_self.get() != 0) + { + self = lwrapper->m_self.get(); + first = rwrapper->m_object.get(); + second = mwrapper->m_object.get(); + return 0; + } + else if (rwrapper->m_self.get() != 0) + { + self = rwrapper->m_self.get(); + first = lwrapper->m_object.get(); + second = mwrapper->m_object.get(); + return 1; + } + else + { + self = mwrapper->m_self.get(); + first = lwrapper->m_object.get(); + second = rwrapper->m_object.get(); + return 2; + } + } + +extension_instance* get_extension_instance(PyObject* p) +{ + // The object's type will just be some class_t object, + // but if its meta-type is right, then it is an extension_instance. + if (p->ob_type->ob_type != extension_meta_class()) + { + PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name); + throw boost::python::argument_error(); + } + return static_cast(p); +} + +void +extension_instance::add_implementation(std::auto_ptr holder) +{ + for (held_objects::const_iterator p = m_wrapped_objects.begin(); + p != m_wrapped_objects.end(); ++p) + { + if (typeid(*holder) == typeid(**p)) + { + PyErr_SetString(PyExc_RuntimeError, "Base class already initialized"); + throw error_already_set(); + } + } + m_wrapped_objects.push_back(holder.release()); +} + +extension_instance::extension_instance(PyTypeObject* class_) + : instance(class_) +{ +} + +extension_instance::~extension_instance() +{ + for (held_objects::const_iterator p = m_wrapped_objects.begin(), + finish = m_wrapped_objects.end(); + p != finish; ++p) + { + delete *p; + } +} + +meta_class* extension_meta_class() +{ + static meta_class result; + return &result; +} + +typedef class_t extension_class_t; + +bool is_subclass(const extension_class_t* derived, + const PyObject* possible_base) +{ + + tuple bases = derived->bases(); + + for (std::size_t i = 0, size = bases.size(); i < size; ++i) + { + const PyObject* base = bases[i].get(); + + if (base == possible_base) + return true; + + if (base->ob_type == extension_meta_class()) + { + const extension_class_t* base_class = downcast(base); + if (is_subclass(base_class, possible_base)) + return true; + } + } + return false; +} + +// Return true iff obj is an obj of target_class +bool is_instance(extension_instance* obj, + class_t* target_class) +{ + if (obj->ob_type == target_class) + return true; + else + { + return is_subclass( + downcast >(obj->ob_type).get(), + as_object(target_class)); + } +} + +void two_string_error(PyObject* exception_object, const char* format, const char* s1, const char* s2) +{ + char buffer[256]; + std::size_t format_length = BOOST_CSTD_::strlen(format); + std::size_t length1 = BOOST_CSTD_::strlen(s1); + std::size_t length2 = BOOST_CSTD_::strlen(s2); + + std::size_t additional_length = length1 + length2; + if (additional_length + format_length > format_length - 1) + { + std::size_t difference = sizeof(buffer) - 1 - additional_length; + length1 -= difference / 2; + additional_length -= difference / 2; + } + + sprintf(buffer, format, length1, s1, length2, s2); + + PyErr_SetString(exception_object, buffer); + if (exception_object == PyExc_TypeError) + throw argument_error(); + else + throw error_already_set(); +} + +// This is called when an attempt has been made to convert the given obj to +// a C++ type for which it doesn't have any obj data. In that case, either +// the obj was not derived from the target_class, or the appropriate +// __init__ function wasn't called to initialize the obj data of the target class. +void report_missing_instance_data( + extension_instance* obj, // The object being converted + class_t* target_class, // the extension class of the C++ type + const std::type_info& target_typeid, // The typeid of the C++ type + bool target_is_ptr) +{ + char buffer[256]; + if (is_instance(obj, target_class)) + { + if (target_is_ptr) + { + two_string_error(PyExc_RuntimeError, + "Object of extension class '%.*s' does not wrap <%.*s>.", + obj->ob_type->tp_name, target_typeid.name()); + } + else + { + const char message[] = "__init__ function for extension class '%.*s' was never called."; + sprintf(buffer, message, sizeof(buffer) - sizeof(message) - 1, + target_class->tp_name); + } + PyErr_SetString(PyExc_RuntimeError, buffer); + } + else if (target_class == 0) + { + const char message[] = "Cannot convert to <%.*s>; its Python class was never created or has been deleted."; + sprintf(buffer, message, sizeof(buffer) - sizeof(message) - 1, target_typeid.name()); + PyErr_SetString(PyExc_RuntimeError, buffer); + } + else + { + two_string_error(PyExc_TypeError, "extension class '%.*s' is not convertible into '%.*s'.", + obj->ob_type->tp_name, target_class->tp_name); + } +} + +void report_missing_instance_data( + extension_instance* obj, // The object being converted + class_t* target_class, // the extension class of the C++ type + const std::type_info& target_typeid) // The typeid of the C++ type +{ + report_missing_instance_data(obj, target_class, target_typeid, false); +} + +void report_missing_ptr_data( + extension_instance* obj, // The object being converted + class_t* target_class, // the extension class of the C++ type + const std::type_info& target_typeid) // The typeid of the C++ type +{ + report_missing_instance_data(obj, target_class, target_typeid, true); +} + +void report_missing_class_object(const std::type_info& info) +{ + char buffer[256]; + const char message[] = "Cannot convert <%.*s> to python; its Python class was never created or has been deleted."; + sprintf(buffer, message, sizeof(buffer) - sizeof(message) - 1, info.name()); + PyErr_SetString(PyExc_RuntimeError, buffer); + throw error_already_set(); +} + +void report_released_smart_pointer(const std::type_info& info) +{ + char buffer[256]; + const char message[] = "Converting from python, pointer or smart pointer to <%.*s> is NULL."; + sprintf(buffer, message, sizeof(buffer) - sizeof(message) - 1, info.name()); + PyErr_SetString(PyExc_RuntimeError, buffer); + throw argument_error(); +} + +read_only_setattr_function::read_only_setattr_function(const char* name) + : m_name(name) +{ +} + +PyObject* read_only_setattr_function::do_call(PyObject* /*args*/, PyObject* /*keywords*/) const +{ + PyErr_SetObject(PyExc_AttributeError, ("'" + m_name + "' attribute is read-only").get()); + return 0; +} + +const char* read_only_setattr_function::description() const +{ + return "uncallable"; +} + +extension_class_base::extension_class_base(const char* name) + : class_t( + extension_meta_class(), string(name), tuple(), dictionary()) +{ +} + +// This function is used in from_python() to convert wrapped classes that are +// related by inheritance. The problem is this: although C++ provides all necessary +// conversion operators, source and target of a conversion must be known at compile +// time. However, in Python we want to convert classes at runtime. The solution is to +// generate conversion functions at compile time, register them within the appropriate +// class objects and call them when a particular runtime conversion is required. + +// If functions for any possible conversion have to be stored, their number will grow +// qudratically. To reduce this number, we actually store only conversion functions +// between adjacent levels in the inheritance tree. By traversing the tree recursively, +// we can build any allowed conversion as a concatenation of simple conversions. This +// traversal is done in the functions try_base_class_conversions() and +// try_derived_class_conversions(). If a particular conversion is impossible, all +// conversion functions will return a NULL pointer. + +// The function extract_object_from_holder() attempts to actually extract the pointer +// to the contained object from an instance_holder_base (a wrapper class). A conversion +// of the held object to 'T *' is allowed when the conversion +// 'dynamic_cast *>(an_instance_holder_base)' succeeds. +void* extension_class_base::try_class_conversions(instance_holder_base* object) const +{ + void* result = try_derived_class_conversions(object); + if (result) + return result; + + if (!object->held_by_value()) + return try_base_class_conversions(object); + else + return 0; +} + +void* extension_class_base::try_base_class_conversions(instance_holder_base* object) const +{ + for (std::size_t i = 0; i < base_classes().size(); ++i) + { + if (base_classes()[i].convert == 0) + continue; + void* result1 = base_classes()[i].class_object->extract_object_from_holder(object); + if (result1) + return (*base_classes()[i].convert)(result1); + + void* result2 = base_classes()[i].class_object->try_base_class_conversions(object); + if (result2) + return (*base_classes()[i].convert)(result2); + } + return 0; +} + +void* extension_class_base::try_derived_class_conversions(instance_holder_base* object) const +{ + for (std::size_t i = 0; i < derived_classes().size(); ++i) + { + void* result1 = derived_classes()[i].class_object->extract_object_from_holder(object); + if (result1) + return (*derived_classes()[i].convert)(result1); + + void* result2 = derived_classes()[i].class_object->try_derived_class_conversions(object); + if (result2) + return (*derived_classes()[i].convert)(result2); + } + return 0; +} + +void extension_class_base::add_method(function* method, const char* name) +{ + add_method(reference(method), name); +} + +void extension_class_base::add_method(reference method, const char* name) +{ + // Add the attribute to the computed target + function::add_to_namespace(method, name, this->dict().get()); + + // If it is a special member function it should be enabled both here and there. + detail::enable_named_method(this, name); +} + +void extension_class_base::add_constructor_object(function* init_fn) +{ + add_method(init_fn, "__init__"); +} + +void extension_class_base::add_setter_method(function* setter_, const char* name) +{ + reference setter(setter_); + add_method(setter, (detail::setattr_string() + name + "__").c_str()); +} + +void extension_class_base::add_getter_method(function* getter_, const char* name) +{ + reference getter(getter_); + add_method(getter, (detail::getattr_string() + name + "__").c_str()); +} + +void extension_class_base::set_attribute(const char* name, PyObject* x_) +{ + ref x(x_); + set_attribute(name, x); +} + +void extension_class_base::set_attribute(const char* name, ref x) +{ + dict().set_item(string(name), x); + if (PyCallable_Check(x.get())) + detail::enable_named_method(this, name); +} + +operator_dispatcher::operator_dispatcher(const ref& o, const ref& s) + : m_object(o), m_self(s), m_free_list_link(0) + +{ + ob_refcnt = 1; + ob_type = &type_obj; +} + +operator_dispatcher* +operator_dispatcher::create(const ref& object, const ref& self) +{ + operator_dispatcher* const result = free_list; + if (result == 0) + return new operator_dispatcher(object, self); + + free_list = result->m_free_list_link; + result->m_object = object; + result->m_self = self; + Py_INCREF(result); + return result; +} + +extern "C" +{ + +void operator_dispatcher_dealloc(PyObject* self) +{ + operator_dispatcher* obj = static_cast(self); + obj->m_free_list_link = operator_dispatcher::free_list; + operator_dispatcher::free_list = obj; + obj->m_object.reset(); + obj->m_self.reset(); +} + +int operator_dispatcher_coerce(PyObject** l, PyObject** r) +{ + Py_INCREF(*l); + try + { + *r = operator_dispatcher::create(ref(*r, ref::increment_count), ref()); + } + catch(...) + { + handle_exception(); + return -1; + } + return 0; +} + + +#define PY_DEFINE_OPERATOR(id, symbol) \ + PyObject* operator_dispatcher_call_##id(PyObject* left, PyObject* right) \ + { \ + /* unwrap the arguments from their OperatorDispatcher */ \ + PyObject* self; \ + PyObject* other; \ + int reverse = unwrap_args(left, right, self, other); \ + if (reverse == unwrap_exception_code) \ + return 0; \ + \ + /* call the function */ \ + PyObject* result = \ + PyEval_CallMethod(self, \ + const_cast(reverse ? "__r" #id "__" : "__" #id "__"), \ + const_cast("(O)"), \ + other); \ + if (result == 0 && PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)) \ + { \ + PyErr_Clear(); \ + PyErr_SetString(PyExc_TypeError, "bad operand type(s) for " #symbol); \ + } \ + return result; \ + } + +PY_DEFINE_OPERATOR(add, +) +PY_DEFINE_OPERATOR(sub, -) +PY_DEFINE_OPERATOR(mul, *) +PY_DEFINE_OPERATOR(div, /) +PY_DEFINE_OPERATOR(mod, %) +PY_DEFINE_OPERATOR(divmod, divmod) +PY_DEFINE_OPERATOR(lshift, <<) +PY_DEFINE_OPERATOR(rshift, >>) +PY_DEFINE_OPERATOR(and, &) +PY_DEFINE_OPERATOR(xor, ^) +PY_DEFINE_OPERATOR(or, |) + +/* coercion rules for heterogeneous pow(): + pow(Foo, int): left, right coerced; m: None => reverse = 0 + pow(int, Foo): left, right coerced; m: None => reverse = 1 + pow(Foo, int, int): left, right, m coerced => reverse = 0 + pow(int, Foo, int): left, right, m coerced => reverse = 1 + pow(int, int, Foo): left, right, m coerced => reverse = 2 + pow(Foo, Foo, int): left, right coerced; m coerced twice => reverse = 0 + pow(Foo, int, Foo): left, right, m coerced => reverse = 0 + pow(int, Foo, Foo): left, right, m coerced => reverse = 1 +*/ +PyObject* operator_dispatcher_call_pow(PyObject* left, PyObject* right, PyObject* m) +{ + int reverse; + PyObject* self; + PyObject* first; + PyObject* second; + + if (m->ob_type == Py_None->ob_type) + { + reverse = unwrap_args(left, right, self, first); + second = m; + } + else + { + reverse = unwrap_pow_args(left, right, m, self, first, second); + } + + if (reverse == unwrap_exception_code) + return 0; + + // call the function + PyObject* result = + PyEval_CallMethod(self, + const_cast((reverse == 0) + ? "__pow__" + : (reverse == 1) + ? "__rpow__" + : "__rrpow__"), + const_cast("(OO)"), + first, second); + if (result == 0 && + (PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_TypeError) || + PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError))) + { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, "bad operand type(s) for pow()"); + } + return result; +} + +int operator_dispatcher_call_cmp(PyObject* left, PyObject* right) +{ + // unwrap the arguments from their OperatorDispatcher + PyObject* self; + PyObject* other; + int reverse = unwrap_args(left, right, self, other); + if (reverse == unwrap_exception_code) + return -1; + + // call the function + PyObject* result = + PyEval_CallMethod(self, + const_cast(reverse ? "__rcmp__" : "__cmp__"), + const_cast("(O)"), + other); + if (result == 0) + { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, "bad operand type(s) for cmp() or <"); + return -1; + } + else + { + try + { + return BOOST_PYTHON_CONVERSION::from_python(result, type()); + } + catch(...) + { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, "cmp() didn't return int"); + return -1; + } + } +} + +} // extern "C" + +PyTypeObject operator_dispatcher::type_obj = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, + const_cast("operator_dispatcher"), + sizeof(operator_dispatcher), + 0, + &operator_dispatcher_dealloc, + 0, + 0, + 0, + &operator_dispatcher_call_cmp, + 0, + &operator_dispatcher::number_methods, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 +}; + +PyNumberMethods operator_dispatcher::number_methods = +{ + &operator_dispatcher_call_add, + &operator_dispatcher_call_sub, + &operator_dispatcher_call_mul, + &operator_dispatcher_call_div, + &operator_dispatcher_call_mod, + &operator_dispatcher_call_divmod, + &operator_dispatcher_call_pow, + 0, + 0, + 0, + 0, + 0, + &operator_dispatcher_call_lshift, + &operator_dispatcher_call_rshift, + &operator_dispatcher_call_and, + &operator_dispatcher_call_xor, + &operator_dispatcher_call_or, + &operator_dispatcher_coerce, + 0, + 0, + 0, + 0, + 0 +}; + +} // namespace detail + +}} // namespace boost::python diff --git a/src/functions.cpp b/src/functions.cpp new file mode 100644 index 00000000..e166c91c --- /dev/null +++ b/src/functions.cpp @@ -0,0 +1,167 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#include +#include +#include +#include +#include + +namespace boost { namespace python { namespace detail { + +struct function::type_object : + singleton > > +{ + type_object() : singleton_base(&PyType_Type) {} +}; + + +void function::add_to_namespace(reference new_function, const char* name, PyObject* dict) +{ + dictionary d(ref(dict, ref::increment_count)); + string key(name); + + ref existing_object = d.get_item(key.reference()); + if (existing_object.get() == 0) + { + d[key] = ref(new_function.get(), ref::increment_count); + } + else + { + if (existing_object->ob_type == type_object::instance()) + { + function* f = static_cast(existing_object.get()); + while (f->m_overloads.get() != 0) + f = f->m_overloads.get(); + f->m_overloads = new_function; + } + else + { + PyErr_SetObject(PyExc_RuntimeError, + (string("Attempt to overload ") + name + + " failed. The existing attribute has type " + + existing_object->ob_type->tp_name).get()); + throw error_already_set(); + } + } +} + +function::function() + : python_object(type_object::instance()) +{ +} + +PyObject* function::call(PyObject* args, PyObject* keywords) const +{ + for (const function* f = this; f != 0; f = f->m_overloads.get()) + { + PyErr_Clear(); + try + { + PyObject* const result = f->do_call(args, keywords); + if (result != 0) + return result; + } + catch(const argument_error&) + { + } + } + + if (m_overloads.get() == 0) + return 0; + + PyErr_Clear(); + string message("No overloaded functions match ("); + tuple arguments(ref(args, ref::increment_count)); + for (std::size_t i = 0; i < arguments.size(); ++i) + { + if (i != 0) + message += ", "; + message += arguments[i]->ob_type->tp_name; + } + + message += "). Candidates are:\n"; + for (const function* f1 = this; f1 != 0; f1 = f1->m_overloads.get()) + { + if (f1 != this) + message += "\n"; + message += f1->description(); + } + + PyErr_SetObject(PyExc_TypeError, message.get()); + return 0; +} + +bound_function* bound_function::create(const ref& target, const ref& fn) +{ + bound_function* const result = free_list; + if (result == 0) + return new bound_function(target, fn); + + free_list = result->m_free_list_link; + result->m_target = target; + result->m_unbound_function = fn; + Py_INCREF(result); + return result; +} + +// The instance class whose obj represents the type of bound_function +// objects in Python. bound_functions must be GetAttrable so the __doc__ +// attribute of built-in Python functions can be accessed when bound. +struct bound_function::type_object : + singleton > > > +{ + type_object() : singleton_base(&PyType_Type) {} + +private: // type_object hook override + void dealloc(bound_function*) const; +}; + +bound_function::bound_function(const ref& target, const ref& fn) + : python_object(type_object::instance()), + m_target(target), + m_unbound_function(fn), + m_free_list_link(0) +{ +} + +PyObject* +bound_function::call(PyObject* args, PyObject* keywords) const +{ + // Build a new tuple which prepends the target to the arguments + tuple tail_arguments(ref(args, ref::increment_count)); + ref all_arguments(PyTuple_New(tail_arguments.size() + 1)); + + PyTuple_SET_ITEM(all_arguments.get(), 0, m_target.get()); + Py_INCREF(m_target.get()); + for (std::size_t i = 0; i < tail_arguments.size(); ++i) + { + PyTuple_SET_ITEM(all_arguments.get(), i + 1, tail_arguments[i].get()); + Py_INCREF(tail_arguments[i].get()); + } + + return PyEval_CallObjectWithKeywords(m_unbound_function.get(), all_arguments.get(), keywords); +} + +PyObject* bound_function::getattr(const char* name) const +{ + return PyObject_GetAttrString(m_unbound_function.get(), const_cast(name)); +} + +void bound_function::type_object::dealloc(bound_function* obj) const +{ + obj->m_free_list_link = free_list; + free_list = obj; + obj->m_target.reset(); + obj->m_unbound_function.reset(); +} + +bound_function* bound_function::free_list; + +}}} // namespace boost::python::detail diff --git a/src/gen_all.py b/src/gen_all.py new file mode 100644 index 00000000..fd8d78cc --- /dev/null +++ b/src/gen_all.py @@ -0,0 +1,26 @@ +from gen_callback import * +from gen_caller import * +from gen_init_function import * +from gen_signatures import * +from gen_singleton import * +from gen_extclass import * + +def gen_all(args): + open('callback.h', 'w').write(gen_callback(args)) + open('caller.h', 'w').write(gen_caller(args)) + open('init_function.h', 'w').write(gen_init_function(args)) + open('signatures.h', 'w').write(gen_signatures(args)) + open('instance.h', 'w').write(gen_singleton(args)) + open('extclass.h', 'w').write(gen_extclass(args)) + +if __name__ == '__main__': + import sys + + if len(sys.argv) == 1: + args = 10 + else: + args = int(sys.argv[1]) + + print gen_all(args) + + diff --git a/src/gen_callback.py b/src/gen_callback.py new file mode 100644 index 00000000..f178212b --- /dev/null +++ b/src/gen_callback.py @@ -0,0 +1,124 @@ +from gen_function import * +import string + +def gen_callback(args): + return ( +"""// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. +// +// This file was generated for %d-argument python callbacks by gen_callback.python + +#ifndef CALLBACK_DWA_052100_H_ +# define CALLBACK_DWA_052100_H_ + +# include +# include + +namespace boost { namespace python { + +namespace detail { + template + inline void callback_adjust_refcount(PyObject*, type) {} + + inline void callback_adjust_refcount(PyObject* p, type) + { Py_INCREF(p); } +} + +// Calling Python from C++ +template +struct callback +{""" % args + + + gen_functions(''' +%{ template <%(class A%n%:, %)> +%} static R call_method(PyObject* self, const char* name%(, const A%n& a%n%)) + {%( + ref p%n(to_python(a%n));%) + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(%(O%))")%(, + p%n.get()%))); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } + +%{ template <%(class A%n%:, %)> +%} static R call(PyObject* self%(, const A%n& a%n%)) + {%( + ref p%n(to_python(a%n));%) + ref result(PyEval_CallFunction(self, const_cast("(%(O%))")%(, + p%n.get()%))); + detail::callback_adjust_refcount(result.get(), type()); + return from_python(result.get(), type()); + } +''', args) + + +"""}; + +// This specialization wouldn't be needed, but MSVC6 doesn't correctly allow the following: +// void g(); +// void f() { return g(); } +template <> +struct callback +{ +""" + + gen_functions(''' +%{ template <%(class A%n%:, %)> +%} static void call_method(PyObject* self, const char* name%(, const A%n& a%n%)) + {%( + ref p%n(to_python(a%n));%) + ref result(PyEval_CallMethod(self, const_cast(name), + const_cast("(%(O%))")%(, + p%n.get()%))); + } + +%{ template <%(class A%n%:, %)> +%} static void call(PyObject* self%(, const A%n& a%n%)) + {%( + ref p%n(to_python(a%n));%) + ref result(PyEval_CallFunction(self, const_cast("(%(O%))")%(, + p%n.get()%))); + } +''', args) + + +"""}; + +// Make it a compile-time error to try to return a const char* from a virtual +// function. The standard conversion +// +// from_python(PyObject* string, boost::python::type) +// +// returns a pointer to the character array which is internal to string. The +// problem with trying to do this in a standard callback function is that the +// Python string would likely be destroyed upon return from the calling function +// (boost::python::callback::call[_method]) when its reference count is +// decremented. If you absolutely need to do this and you're sure it's safe (it +// usually isn't), you can use +// +// boost::python::string result(boost::python::callback::call[_method](...args...)); +// ...result.c_str()... // access the char* array +template <> +struct callback +{ + // Try hard to generate a readable error message + typedef struct unsafe_since_python_string_may_be_destroyed {} call, call_method; +}; + +}} // namespace boost::python + +#endif // CALLBACK_DWA_052100_H_ +""") + +if __name__ == '__main__': + import sys + + if len(sys.argv) == 1: + args = 5 + else: + args = int(sys.argv[1]) + + print gen_callback(args) diff --git a/src/gen_caller.py b/src/gen_caller.py new file mode 100644 index 00000000..26bd88c6 --- /dev/null +++ b/src/gen_caller.py @@ -0,0 +1,138 @@ +# (C) Copyright David Abrahams 2000. 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. +# +# The author gratefully acknowleges the support of Dragon Systems, Inc., in +# producing this work. + +from gen_function import * +import string + +header = '''// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. +// +// This file generated for %d-argument member functions and %d-argument free +// functions by gen_caller.python +''' + +body_sections = ( +''' +#ifndef CALLER_DWA05090_H_ +# define CALLER_DWA05090_H_ + +# include +# include +# include +# include +# include + +namespace boost { namespace python { + +// Calling C++ from Python +template +struct caller +{ +''', +''' +''', +''' // Free functions +''', +'''}; + +template <> +struct caller +{ +''', +''' +''', +''' + // Free functions +''', +'''}; + +}} // namespace boost::python + +#endif +''') + +#' + +member_function = ''' template + static PyObject* call(%1 (T::*pmf)(%(A%n%:, %))%2, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; +%( PyObject* a%n; +%) if (!PyArg_ParseTuple(args, const_cast("O%(O%)"), &self%(, &a%n%))) + return 0; + T& target = from_python(self, type()); + %3(target.*pmf)(%(from_python(a%n, type())%:, + %))%4 + } + +''' + +free_function = '''%{ template <%(class A%n%:, %)> +%} static PyObject* call(%1 (*f)(%(A%n%:, %)), PyObject* args, PyObject* /* keywords */ ) { +%( PyObject* a%n; +%) if (!PyArg_ParseTuple(args, const_cast("%(O%)")%(, &a%n%))) + return 0; + %2f(%(from_python(a%n, type())%:, + %))%3 + } + +''' + +def gen_caller(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] + + gen_functions(member_function, member_function_args, + 'R', '', 'return to_python(', ');') + + body_sections[1] + + gen_functions(member_function, member_function_args, + 'R', ' const', 'return to_python(', ');') + + body_sections[2] + + + gen_functions(free_function, free_function_args, + 'R', 'return to_python(', ');') + + body_sections[3] + + # specialized part for void return values begins here + + gen_functions(member_function, member_function_args, + 'void', '', '', return_none) + + body_sections[4] + + gen_functions(member_function, member_function_args, + 'void', ' const', '', return_none) + + body_sections[5] + + + gen_functions(free_function, free_function_args, + 'void', '', return_none) + + 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_caller(member_function_args, free_function_args) + + diff --git a/src/gen_extclass.py b/src/gen_extclass.py new file mode 100644 index 00000000..5180a3de --- /dev/null +++ b/src/gen_extclass.py @@ -0,0 +1,830 @@ +from gen_function import * +import string + +def gen_extclass(args): + return ( +"""// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. +// +// This file automatically generated for %d-argument constructors by +// gen_extclass.python + +#ifndef EXTENSION_CLASS_DWA052000_H_ +# define EXTENSION_CLASS_DWA052000_H_ + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python { + +// forward declarations +template struct operators; +template struct left_operand; +template struct right_operand; + +enum without_downcast_t { without_downcast }; + +namespace detail { + +// forward declarations +class extension_instance; +class extension_class_base; +template class instance_holder; +template class instance_value_holder; +template class instance_ptr_holder; +template struct operand_select; + template struct choose_op; + template struct choose_rop; + template struct choose_unary_op; + template struct define_operator; + +meta_class* extension_meta_class(); +extension_instance* get_extension_instance(PyObject* p); +void report_missing_instance_data(extension_instance*, class_t*, const std::type_info&); +void report_missing_ptr_data(extension_instance*, class_t*, const std::type_info&); +void report_missing_class_object(const std::type_info&); +void report_released_smart_pointer(const std::type_info&); + +template +T* check_non_null(T* p) +{ + if (p == 0) + report_released_smart_pointer(typeid(T)); + return p; +} + +template class held_instance; + +typedef void* (*conversion_function_ptr)(void*); + +struct base_class_info +{ + base_class_info(extension_class_base* t, conversion_function_ptr f) + :class_object(t), convert(f) + {} + + extension_class_base* class_object; + conversion_function_ptr convert; +}; + +typedef base_class_info derived_class_info; + +struct add_operator_base; + +class extension_class_base : public class_t +{ + public: + extension_class_base(const char* name); + + public: + // the purpose of try_class_conversions() and its related functions + // is explained in extclass.cpp + void* try_class_conversions(instance_holder_base*) const; + void* try_base_class_conversions(instance_holder_base*) const; + void* try_derived_class_conversions(instance_holder_base*) const; + + void set_attribute(const char* name, PyObject* x); + void set_attribute(const char* name, ref x); + + private: + virtual void* extract_object_from_holder(instance_holder_base* v) const = 0; + virtual std::vector const& base_classes() const = 0; + virtual std::vector const& derived_classes() const = 0; + + protected: + friend struct add_operator_base; + void add_method(reference method, const char* name); + void add_method(function* method, const char* name); + + void add_constructor_object(function*); + void add_setter_method(function*, const char* name); + void add_getter_method(function*, const char* name); +}; + +template +class class_registry +{ + public: + static extension_class_base* class_object() + { return static_class_object; } + + // Register/unregister the Python class object corresponding to T + static void register_class(extension_class_base*); + static void unregister_class(extension_class_base*); + + // Establish C++ inheritance relationships + static void register_base_class(base_class_info const&); + static void register_derived_class(derived_class_info const&); + + // Query the C++ inheritance relationships + static std::vector const& base_classes(); + static std::vector const& derived_classes(); + private: + static extension_class_base* static_class_object; + static std::vector static_base_class_info; + static std::vector static_derived_class_info; +}; + +}}} // namespace boost::python::detail + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + +// This class' only job is to define from_python and to_python converters for T +// and U. T is the class the user really intends to wrap. U is a class derived +// from T with some virtual function overriding boilerplate, or if there are no +// virtual functions, U = held_instance. +template > +class python_extension_class_converters +{ + public: + // Get an object which can be used to convert T to/from python. This is used + // as a kind of concept check by the global template + // + // PyObject* to_python(const T& x) + // + // below this class, to prevent the confusing messages that would otherwise + // pop up. Now, if T hasn't been wrapped as an extension class, the user + // will see an error message about the lack of an eligible + // py_extension_class_converters() function. + friend python_extension_class_converters py_extension_class_converters(boost::python::type) + { + return python_extension_class_converters(); + } + + // This is a member function because in a conforming implementation, friend + // funcitons defined inline in the class body are all instantiated as soon + // as the enclosing class is instantiated. If T is not copyable, that causes + // a compiler error. Instead, we access this function through the global + // template + // + // PyObject* to_python(const T& x) + // + // defined below this class. Since template functions are instantiated only + // on demand, errors will be avoided unless T is noncopyable and the user + // writes code which causes us to try to copy a T. + PyObject* to_python(const T& x) const + { + boost::python::reference result(create_instance()); + result->add_implementation( + std::auto_ptr( + new boost::python::detail::instance_value_holder(result.get(), x))); + return result.release(); + } + + // Convert to T* + friend T* from_python(PyObject* obj, boost::python::type) + { + // downcast to an extension_instance, then find the actual T + boost::python::detail::extension_instance* self = boost::python::detail::get_extension_instance(obj); + typedef std::vector::const_iterator iterator; + for (iterator p = self->wrapped_objects().begin(); + p != self->wrapped_objects().end(); ++p) + { + boost::python::detail::instance_holder* held = dynamic_cast*>(*p); + if (held != 0) + return held->target(); + + // see extclass.cpp for an explanation of try_class_conversions() + void* target = boost::python::detail::class_registry::class_object()->try_class_conversions(*p); + if(target) + return static_cast(target); + } + boost::python::detail::report_missing_instance_data(self, boost::python::detail::class_registry::class_object(), typeid(T)); + throw boost::python::argument_error(); + } + + // Convert to PtrType, where PtrType can be dereferenced to obtain a T. + template + static PtrType& ptr_from_python(PyObject* obj, boost::python::type) + { + // downcast to an extension_instance, then find the actual T + boost::python::detail::extension_instance* self = boost::python::detail::get_extension_instance(obj); + typedef std::vector::const_iterator iterator; + for (iterator p = self->wrapped_objects().begin(); + p != self->wrapped_objects().end(); ++p) + { + boost::python::detail::instance_ptr_holder* held = + dynamic_cast*>(*p); + if (held != 0) + return held->ptr(); + } + boost::python::detail::report_missing_ptr_data(self, boost::python::detail::class_registry::class_object(), typeid(T)); + throw boost::python::argument_error(); + } + + template + static PyObject* ptr_to_python(PtrType x) + { + boost::python::reference result(create_instance()); + result->add_implementation( + std::auto_ptr( + new boost::python::detail::instance_ptr_holder(x))); + return result.release(); + } + + static boost::python::reference create_instance() + { + PyTypeObject* class_object = boost::python::detail::class_registry::class_object(); + if (class_object == 0) + boost::python::detail::report_missing_class_object(typeid(T)); + + return boost::python::reference( + new boost::python::detail::extension_instance(class_object)); + } + + // Convert to const T* + friend const T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to const T* const& + friend const T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T* const& + friend T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T& + friend T& from_python(PyObject* p, boost::python::type) + { return *boost::python::detail::check_non_null(from_python(p, boost::python::type())); } + + // Convert to const T& + friend const T& from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T + friend const T& from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + friend std::auto_ptr& from_python(PyObject* p, boost::python::type&>) + { return ptr_from_python(p, boost::python::type >()); } + + friend std::auto_ptr& from_python(PyObject* p, boost::python::type >) + { return ptr_from_python(p, boost::python::type >()); } + + friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&>) + { return ptr_from_python(p, boost::python::type >()); } + + friend PyObject* to_python(std::auto_ptr x) + { return ptr_to_python(x); } + + friend boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) + { return ptr_from_python(p, boost::python::type >()); } + + friend boost::shared_ptr& from_python(PyObject* p, boost::python::type >) + { return ptr_from_python(p, boost::python::type >()); } + + friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) + { return ptr_from_python(p, boost::python::type >()); } + + friend PyObject* to_python(boost::shared_ptr x) + { return ptr_to_python(x); } +}; + +// Convert T to_python, instantiated on demand and only if there isn't a +// non-template overload for this function. This version is the one invoked when +// T is a wrapped class. See the first 2 functions declared in +// python_extension_class_converters above for more info. +template +PyObject* to_python(const T& x) +{ + return py_extension_class_converters(boost::python::type()).to_python(x); +} + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +namespace boost { namespace python { + +BOOST_PYTHON_IMPORT_CONVERSION(python_extension_class_converters); + +namespace detail { + +template class instance_holder; + +class read_only_setattr_function : public function +{ + public: + read_only_setattr_function(const char* name); + PyObject* do_call(PyObject* args, PyObject* keywords) const; + const char* description() const; + private: + string m_name; +}; + + template + struct define_conversion + { + static void* upcast_ptr(void* v) + { + return static_cast(static_cast(v)); + } + + static void* downcast_ptr(void* v) + { + return dynamic_cast(static_cast(v)); + } + }; + +// An easy way to make an extension base class which wraps T. Note that Python +// subclasses of this class will simply be class_t objects. +// +// U should be a class derived from T which overrides virtual functions with +// boilerplate code to call back into Python. See extclass_demo.h for examples. +// +// U is optional, but you won't be able to override any member functions in +// Python which are called from C++ if you don't supply it. If you just want to +// be able to use T in python without overriding member functions, you can omit +// U. +template > +class extension_class + : public python_extension_class_converters, // This generates the to_python/from_python functions + public extension_class_base +{ + public: + typedef T wrapped_type; + typedef U callback_type; + + // Construct with a name that comes from typeid(T).name(). The name only + // affects the objects of this class are represented through repr() + extension_class(); + + // Construct with the given name. The name only affects the objects of this + // class are represented through repr() + extension_class(const char* name); + + ~extension_class(); + + // define constructors +""" % args + + gen_function( +""" template <%(class A%n%:, %)> + inline void def(constructor<%(A%n%:, %)>) + // The following incantation builds a signature1, signature2,... object. It + // should _all_ get optimized away. + { add_constructor( + %(prepend(type::id(), + %) signature0()%()%)); + } +""", args) + + +""" + + // export homogeneous operators (type of both lhs and rhs is 'operator') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub), Foo>()); + + // export homogeneous operators (type of both lhs and rhs is 'T const&') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>()); + template + inline void def(operators) + { + typedef typename operand_select::template wrapped::type true_operand; + def_operators(operators()); + } + + // export heterogeneous operators (type of lhs: 'left', of rhs: 'right') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub), Foo>(), + // boost::python::right_operand()); + + // export heterogeneous operators (type of lhs: 'T const&', of rhs: 'right') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>(), + // boost::python::right_operand()); + template + inline void def(operators, right_operand r) + { + typedef typename operand_select::template wrapped::type true_left; + def_operators(operators(), r); + } + + // export heterogeneous reverse-argument operators + // (type of lhs: 'left', of rhs: 'right') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub), Foo>(), + // boost::python::left_operand()); + + // export heterogeneous reverse-argument operators + // (type of lhs: 'left', of rhs: 'T const&') + // usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>(), + // boost::python::left_operand()); + template + inline void def(operators, left_operand l) + { + typedef typename operand_select::template wrapped::type true_right; + def_operators(operators(), l); + } + + // define a function that passes Python arguments and keywords + // to C++ verbatim (as a 'tuple const&' and 'dictionary const&' + // respectively). This is useful for manual argument passing. + // It's also the only possibility to pass keyword arguments to C++. + // Fn must have a signatur that is compatible to + // PyObject* (*)(PyObject* aTuple, PyObject* aDictionary) + template + inline void def_raw(Fn fn, const char* name) + { + this->add_method(new_raw_arguments_function(fn), name); + } + + // define member functions. In fact this works for free functions, too - + // they act like static member functions, or if they start with the + // appropriate self argument (as a pointer), they can be used just like + // ordinary member functions -- just like Python! + template + inline void def(Fn fn, const char* name) + { + this->add_method(new_wrapped_function(fn), name); + } + + // Define a virtual member function with a default implementation. + // default_fn should be a function which provides the default implementation. + // Be careful that default_fn does not in fact call fn virtually! + template + inline void def(Fn fn, const char* name, DefaultFn default_fn) + { + this->add_method(new_virtual_function(type(), fn, default_fn), name); + } + + // Provide a function which implements x., reading from the given + // member (pm) of the T obj + template + inline void def_getter(MemberType T::*pm, const char* name) + { + this->add_getter_method(new getter_function(pm), name); + } + + // Provide a function which implements assignment to x., writing to + // the given member (pm) of the T obj + template + inline void def_setter(MemberType T::*pm, const char* name) + { + this->add_setter_method(new setter_function(pm), name); + } + + // Expose the given member (pm) of the T obj as a read-only attribute + template + inline void def_readonly(MemberType T::*pm, const char* name) + { + this->add_setter_method(new read_only_setattr_function(name), name); + this->def_getter(pm, name); + } + + // Expose the given member (pm) of the T obj as a read/write attribute + template + inline void def_read_write(MemberType T::*pm, const char* name) + { + this->def_getter(pm, name); + this->def_setter(pm, name); + } + + // define the standard coercion needed for operator overloading + void def_standard_coerce(); + + // declare the given class a base class of this one and register + // up and down conversion functions + template + void declare_base(extension_class* base) + { + // see extclass.cpp for an explanation of why we need to register + // conversion functions + base_class_info baseInfo(base, + &define_conversion::downcast_ptr); + class_registry::register_base_class(baseInfo); + add_base(ref(as_object(base), ref::increment_count)); + + derived_class_info derivedInfo(this, + &define_conversion::upcast_ptr); + class_registry::register_derived_class(derivedInfo); + } + + // declare the given class a base class of this one and register + // only up conversion function + template + void declare_base(extension_class* base, without_downcast_t) + { + // see extclass.cpp for an explanation of why we need to register + // conversion functions + base_class_info baseInfo(base, 0); + class_registry::register_base_class(baseInfo); + add_base(ref(as_object(base), ref::increment_count)); + + derived_class_info derivedInfo(this, + &define_conversion::upcast_ptr); + class_registry::register_derived_class(derivedInfo); + } + + private: // types + typedef instance_value_holder holder; + + private: // extension_class_base virtual function implementations + std::vector const& base_classes() const; + std::vector const& derived_classes() const; + void* extract_object_from_holder(instance_holder_base* v) const; + + private: // Utility functions + template + inline void def_operators(operators) + { + def_standard_coerce(); + + // for some strange reason, this prevents MSVC from having an + // "unrecoverable block scoping error"! + typedef choose_op<(which & op_add)> choose_add; + + choose_op<(which & op_add)>::template args::add(this); + choose_op<(which & op_sub)>::template args::add(this); + choose_op<(which & op_mul)>::template args::add(this); + choose_op<(which & op_div)>::template args::add(this); + choose_op<(which & op_mod)>::template args::add(this); + choose_op<(which & op_divmod)>::template args::add(this); + choose_op<(which & op_pow)>::template args::add(this); + choose_op<(which & op_lshift)>::template args::add(this); + choose_op<(which & op_rshift)>::template args::add(this); + choose_op<(which & op_and)>::template args::add(this); + choose_op<(which & op_xor)>::template args::add(this); + choose_op<(which & op_or)>::template args::add(this); + choose_unary_op<(which & op_neg)>::template args::add(this); + choose_unary_op<(which & op_pos)>::template args::add(this); + choose_unary_op<(which & op_abs)>::template args::add(this); + choose_unary_op<(which & op_invert)>::template args::add(this); + choose_unary_op<(which & op_int)>::template args::add(this); + choose_unary_op<(which & op_long)>::template args::add(this); + choose_unary_op<(which & op_float)>::template args::add(this); + choose_op<(which & op_cmp)>::template args::add(this); + choose_unary_op<(which & op_str)>::template args::add(this); + } + + template + inline void def_operators(operators, right_operand) + { + def_standard_coerce(); + + choose_op<(which & op_add)>::template args::add(this); + choose_op<(which & op_sub)>::template args::add(this); + choose_op<(which & op_mul)>::template args::add(this); + choose_op<(which & op_div)>::template args::add(this); + choose_op<(which & op_mod)>::template args::add(this); + choose_op<(which & op_divmod)>::template args::add(this); + choose_op<(which & op_pow)>::template args::add(this); + choose_op<(which & op_lshift)>::template args::add(this); + choose_op<(which & op_rshift)>::template args::add(this); + choose_op<(which & op_and)>::template args::add(this); + choose_op<(which & op_xor)>::template args::add(this); + choose_op<(which & op_or)>::template args::add(this); + choose_op<(which & op_cmp)>::template args::add(this); + } + + template + inline void def_operators(operators, left_operand) + { + def_standard_coerce(); + + choose_rop<(which & op_add)>::template args::add(this); + choose_rop<(which & op_sub)>::template args::add(this); + choose_rop<(which & op_mul)>::template args::add(this); + choose_rop<(which & op_div)>::template args::add(this); + choose_rop<(which & op_mod)>::template args::add(this); + choose_rop<(which & op_divmod)>::template args::add(this); + choose_rop<(which & op_pow)>::template args::add(this); + choose_rop<(which & op_lshift)>::template args::add(this); + choose_rop<(which & op_rshift)>::template args::add(this); + choose_rop<(which & op_and)>::template args::add(this); + choose_rop<(which & op_xor)>::template args::add(this); + choose_rop<(which & op_or)>::template args::add(this); + choose_rop<(which & op_cmp)>::template args::add(this); + } + + template + void add_constructor(signature sig) + { + this->add_constructor_object(init_function::create(sig)); + } +}; + +// A simple wrapper over a T which allows us to use extension_class with a +// single template parameter only. See extension_class, above. +template +class held_instance : public T +{ + // There are no member functions: we want to avoid inadvertently overriding + // any virtual functions in T. +public:""" + + gen_functions("""%{ + template <%(class A%n%:, %)>%} + held_instance(PyObject*%(, A%n% a%n%)) : T(%(a%n%:, %)) {}""", args) + + """ +}; + +// Abstract base class for all obj holders. Base for template class +// instance_holder<>, below. +class instance_holder_base +{ +public: + virtual ~instance_holder_base() {} + virtual bool held_by_value() = 0; +}; + +// Abstract base class which holds a Held, somehow. Provides a uniform way to +// get a pointer to the held object +template +class instance_holder : public instance_holder_base +{ +public: + virtual Held*target() = 0; +}; + +// Concrete class which holds a Held by way of a wrapper class Wrapper. If Held +// can be constructed with arguments (A1...An), Wrapper must have a +// corresponding constructor for arguments (PyObject*, A1...An). Wrapper is +// neccessary to implement virtual function callbacks (there must be a +// back-pointer to the actual Python object so that we can call any +// overrides). held_instance (above) is used as a default Wrapper class when +// there are no virtual functions. +template +class instance_value_holder : public instance_holder +{ +public: + Held* target() { return &m_held; } + Wrapper* value_target() { return &m_held; } +""" + + gen_functions("""%{ + template <%(class A%n%:, %)>%} + instance_value_holder(extension_instance* p%(, A%n a%n%)) : + m_held(p%(, a%n%)) {}""", args) + + """ + + public: // implementation of instance_holder_base required interface + bool held_by_value() { return true; } + + private: + Wrapper m_held; +}; + +// Concrete class which holds a HeldType by way of a (possibly smart) pointer +// PtrType. By default, these are only generated for PtrType == +// std::auto_ptr and PtrType == boost::shared_ptr. +template +class instance_ptr_holder : public instance_holder +{ + public: + HeldType* target() { return &*m_ptr; } + PtrType& ptr() { return m_ptr; } + + instance_ptr_holder(PtrType ptr) : m_ptr(ptr) {} + + public: // implementation of instance_holder_base required interface + bool held_by_value() { return false; } + private: + PtrType m_ptr; +}; + +class extension_instance : public instance +{ + public: + extension_instance(PyTypeObject* class_); + ~extension_instance(); + + void add_implementation(std::auto_ptr holder); + + typedef std::vector held_objects; + const held_objects& wrapped_objects() const + { return m_wrapped_objects; } + private: + held_objects m_wrapped_objects; +}; + +// +// Template function implementations +// + +tuple extension_class_coerce(ref l, ref r); + +template +extension_class::extension_class() + : extension_class_base(typeid(T).name()) +{ + class_registry::register_class(this); +} + +template +extension_class::extension_class(const char* name) + : extension_class_base(name) +{ + class_registry::register_class(this); +} + +template +void extension_class::def_standard_coerce() +{ + ref coerce_fct = dict().get_item(string("__coerce__")); + + if(coerce_fct.get() == 0) // not yet defined + this->def(&extension_class_coerce, "__coerce__"); +} + +template +inline +std::vector const& +extension_class::base_classes() const +{ + return class_registry::base_classes(); +} + +template +inline +std::vector const& +extension_class::derived_classes() const +{ + return class_registry::derived_classes(); +} + +template +void* extension_class::extract_object_from_holder(instance_holder_base* v) const +{ + instance_holder* held = dynamic_cast*>(v); + if(held) + return held->target(); + return 0; +} + +template +extension_class::~extension_class() +{ + class_registry::unregister_class(this); +} + +template +inline void class_registry::register_class(extension_class_base* p) +{ + // You're not expected to create more than one of these! + assert(static_class_object == 0); + static_class_object = p; +} + +template +inline void class_registry::unregister_class(extension_class_base* p) +{ + // The user should be destroying the same object they created. + assert(static_class_object == p); + (void)p; // unused in shipping version + static_class_object = 0; +} + +template +void class_registry::register_base_class(base_class_info const& i) +{ + static_base_class_info.push_back(i); +} + +template +void class_registry::register_derived_class(derived_class_info const& i) +{ + static_derived_class_info.push_back(i); +} + +template +std::vector const& class_registry::base_classes() +{ + return static_base_class_info; +} + +template +std::vector const& class_registry::derived_classes() +{ + return static_derived_class_info; +} + +// +// Static data member declaration. +// +template +extension_class_base* class_registry::static_class_object; +template +std::vector class_registry::static_base_class_info; +template +std::vector class_registry::static_derived_class_info; + +}}} // namespace boost::python::detail + +#endif // EXTENSION_CLASS_DWA052000_H_ +""") + +if __name__ == '__main__': + import sys + + if len(sys.argv) == 1: + args = 5 + else: + args = int(sys.argv[1]) + + print gen_extclass(args) diff --git a/src/gen_function.py b/src/gen_function.py new file mode 100644 index 00000000..bebbc818 --- /dev/null +++ b/src/gen_function.py @@ -0,0 +1,184 @@ +import string + +def _find(s, sub, start=0, end=None): + """Just like string.find, except it returns end or len(s) when not found. + """ + if end == None: + end = len(s) + + pos = string.find(s, sub, start, end) + if pos < 0: + return end + else: + return pos + +def _gen_common_key(key, n, args): + if len(key) > 0 and key in '123456789': + return str(args[int(key) - 1]) + elif key == 'x': + return str(n) + else: + return key + +def _gen_arg(template, n, args, delimiter = '%'): + result = '' + i = 0 + while i < len(template): # until the template is consumed + # consume everything up to the first delimiter + delimiter_pos = _find(template, delimiter, i) + result = result + template[i:delimiter_pos] + + # The start position of whatever comes after the delimiter+key + start = delimiter_pos + 2 + key = template[start - 1 : start] # the key character. If there were no + # delimiters left, key will be empty + + if key == 'n': + result = result + `n` + else: + result = result + _gen_common_key(key, n, args) + + i = start + + return result + +def gen_function(template, n, *args, **keywords): + r"""gen_function(template, n, [args...] ) -> string + + Generate a function declaration based on the given template. + + Sections of the template between '%(', '%)' pairs are repeated n times. If '%:' + appears in the middle, it denotes the beginning of a delimiter. + + Sections of the template between '%{', '%}' pairs are ommitted if n == 0. + + %n is transformed into the string representation of 1..n for each repetition + of n. + + %x, where x is a digit, is transformed into the corresponding additional + argument. + + for example, + + >>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 2, 'void') + 'void abc(int a1, int a2); // all args are ints' + >>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 0, 'x') + 'x abc();' + + + >>> template = ''' template + ... static PyObject* call( %1(T::*pmf)(%(A%n%:, %))%2, PyObject* args, PyObject* /* keywords */ ) { + ... PyObject* self; + ... %( PyObject* a%n; + ... %) if (!PyArg_ParseTuple(args, const_cast("O%(O%)"), &self%(, &a%n%))) + ... return 0; + ... T& target = from_python(self, type()); + ... %3to_python((target.*pmf)(%( + ... from_python(a%n, type())%:,%) + ... ));%4 + ... }''' + + >>> print gen_function(template, 0, 'R ', '', 'return ', '') + template + static PyObject* call( R (T::*pmf)(), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + if (!PyArg_ParseTuple(args, const_cast("O"), &self)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)( + )); + } + + >>> print gen_function(template, 2, 'R ', '', 'return ', '') + template + static PyObject* call( R (T::*pmf)(A1, A2), PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + if (!PyArg_ParseTuple(args, const_cast("OOO"), &self, &a1, &a2)) + return 0; + T& target = from_python(self, type()); + return to_python((target.*pmf)( + from_python(a1, type()), + from_python(a2, type()) + )); + } + + >>> print gen_function(template, 3, 'void ', ' const', '', '\n'+8*' ' + 'return none();') + template + static PyObject* call( void (T::*pmf)(A1, A2, A3) const, PyObject* args, PyObject* /* keywords */ ) { + PyObject* self; + PyObject* a1; + PyObject* a2; + PyObject* a3; + if (!PyArg_ParseTuple(args, const_cast("OOOO"), &self, &a1, &a2, &a3)) + return 0; + T& target = from_python(self, type()); + to_python((target.*pmf)( + from_python(a1, type()), + from_python(a2, type()), + from_python(a3, type()) + )); + return none(); + } +""" + delimiter = keywords.get('delimiter', '%') + result = '' + i = 0 + while i < len(template): # until the template is consumed + # consume everything up to the first delimiter + delimiter_pos = _find(template, delimiter, i) + result = result + template[i:delimiter_pos] + + # The start position of whatever comes after the delimiter+key + start = delimiter_pos + 2 + key = template[start - 1 : start] # the key character. If there were no + # delimiters left, key will be empty + + pairs = { '(':')', '{':'}' } + + if key in pairs.keys(): + end = string.find(template, delimiter + pairs[key], start) + assert end >= 0, "Matching '" + delimiter + pairs[key] +"' not found!" + delimiter_pos = end + + if key == '{': + if n > 0: + result = result + gen_function(template[start:end], n, args, delimiter) + else: + separator_pos = _find(template, delimiter + ':', start, end) + separator = template[separator_pos+2 : end] + + for x in range(1, n + 1): + result = result + _gen_arg(template[start:separator_pos], x, args, + delimiter) + if x != n: + result = result + separator + + else: + result = result + _gen_common_key(key, n, args) + + i = delimiter_pos + 2 + + return result + +def gen_functions(template, n, *args): + r"""gen_functions(template, n, [args...]) -> string + + Call gen_function repeatedly with from 0..n and the given optional + arguments. + + >>> print gen_functions('%1 abc(%(int a%n%:, %));%{ // all args are ints%}\n', 2, 'void'), + void abc(); + void abc(int a1); // all args are ints + void abc(int a1, int a2); // all args are ints + + """ + result = '' + for x in range(n + 1): + result = result + apply(gen_function, (template, x) + args) + return result + +if __name__ == '__main__': + import doctest + doctest.testmod() diff --git a/src/gen_init_function.py b/src/gen_init_function.py new file mode 100644 index 00000000..69935230 --- /dev/null +++ b/src/gen_init_function.py @@ -0,0 +1,166 @@ +from gen_function import * +import string + +def gen_init_function(args): + + return ( +"""// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. +// +// This file was generated for %d-argument constructors by gen_init_function.python + +#ifndef INIT_FUNCTION_DWA052000_H_ +# define INIT_FUNCTION_DWA052000_H_ + +# include +# include +# include +# include + +namespace boost { namespace python { + +namespace detail { + + // parameter_traits - so far, this is a way to pass a const T& when we can be + // sure T is not a reference type, and a raw T otherwise. This should be + // rolled into boost::call_traits. Ordinarily, parameter_traits would be + // written: + // + // template struct parameter_traits + // { + // typedef const T& const_reference; + // }; + // + // template struct parameter_traits + // { + // typedef T& const_reference; + // }; + // + // template <> struct parameter_traits + // { + // typedef void const_reference; + // }; + // + // ...but since we can't partially specialize on reference types, we need this + // long-winded but equivalent incantation. + + // const_ref_selector -- an implementation detail of parameter_traits (below). This uses + // the usual "poor man's partial specialization" hack for MSVC. + template + struct const_ref_selector + { + template + struct const_ref + { + typedef const T& type; + }; + }; + + template <> + struct const_ref_selector + { + template + struct const_ref + { + typedef T type; + }; + }; + +# ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4181) +# endif // BOOST_MSVC + template + struct parameter_traits + { + private: + typedef const_ref_selector::value> selector; + public: + typedef typename selector::template const_ref::type const_reference; + }; +# ifdef BOOST_MSVC +# pragma warning(pop) +# endif // BOOST_MSVC + + // Full spcialization for void + template <> + struct parameter_traits + { + typedef void const_reference; + }; + + template + class reference_parameter + { + typedef typename parameter_traits::const_reference const_reference; + public: + reference_parameter(const_reference value) + : value(value) {} + operator const_reference() { return value; } + private: + const_reference value; + }; + +class extension_instance; +class instance_holder_base; + +class init; +""" + + gen_functions('template struct init%x;\n', args) + + """ +template +struct init_function +{ +""" + gen_functions("""%{ + template <%(class A%n%:, %)> +%} static init* create(signature%x%{<%(A%n%:, %)>%}) { + return new init%x::const_reference%)>; + } +""", args)+"""}; + +class init : public function +{ +private: // override function hook + PyObject* do_call(PyObject* args, PyObject* keywords) const; +private: + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* tail_args, PyObject* keywords) const = 0; +}; +""" + gen_functions(""" + +template +struct init%x : init +{ + virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const + { + %(PyObject* a%n; + %)if (!PyArg_ParseTuple(args, const_cast("%(O%)")%(, &a%n%))) + throw argument_error(); + return new T(self%(, + boost::python::detail::reference_parameter(from_python(a%n, type()))%) + ); + } + const char* description() const + { return typeid(void (*)(T&%(, A%n%%))).name(); } +};""", args) + """ + +}}} // namespace boost::python::detail + +#endif // INIT_FUNCTION_DWA052000_H_ +""") + +if __name__ == '__main__': + import sys + + if len(sys.argv) == 1: + args = 5 + else: + args = int(sys.argv[1]) + + print gen_init_function(args) + diff --git a/src/gen_signatures.py b/src/gen_signatures.py new file mode 100644 index 00000000..f5a97b17 --- /dev/null +++ b/src/gen_signatures.py @@ -0,0 +1,158 @@ +from gen_function import * +import string + +def gen_struct_signatures(args): + result = '' + for n in range(args, -1, -1): + result = ( + result + gen_function("""%{template <%(class T%n%:, %)> +%}struct signature%x {}; + +""", n) +# + ((n == args) and [""] or +# [gen_function(""" +# template +# static inline signature%1 prepend(type) +# { return signature%1(); }""", +# n, (str(n+1),)) +# ] +# )[0] +# +# + ((n != 0) and [""] or +# [""" +# // This one terminates the chain. Prepending void_t to the head of a void_t +# // signature results in a void_t signature again. +# static inline signature0 prepend(void_t) { return signature0(); }"""] +# )[0] +# + """ +#}; +# +#""" + + ((n == args) and [""] or + [gen_function( +"""template <%(class T%n%, %)class X> +inline signature%1 prepend(type, signature%x%{<%(T%n%:, %)>%}) + { return signature%1(); } + +""", n, str(n+1)) + ] + )[0] + ) + return result + +def gen_signatures(args): + return ( +"""// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. +// +// This file automatically generated by gen_signatures.python for %d arguments. +#ifndef SIGNATURES_DWA050900_H_ +# define SIGNATURES_DWA050900_H_ + +# include + +namespace boost { namespace python { + +namespace detail { +// A stand-in for the built-in void. This one can be passed to functions and +// (under MSVC, which has a bug, be used as a default template type parameter). +struct void_t {}; +} + +// An envelope in which type information can be delivered for the purposes +// of selecting an overloaded from_python() function. This is needed to work +// around MSVC's lack of partial specialiation/ordering. Where normally we'd +// want to form a function call like void f(), We instead pass +// type as one of the function parameters to select a particular +// overload. +// +// The id typedef helps us deal with the lack of partial ordering by generating +// unique types for constructor signatures. In general, type::id is type, +// but type::id is just void_t. +template +struct type +{ + typedef type id; +}; + +template <> +struct type +{ + typedef boost::python::detail::void_t id; +}; + +namespace detail { +// These basically encapsulate a chain of types, , used to make the syntax of +// add(constructor()) work. We need to produce a unique type for each number +// of non-default parameters to constructor<>. Q: why not use a recursive +// formulation for infinite extensibility? A: MSVC6 seems to choke on constructs +// that involve recursive template nesting. +// +// signature chaining +""" % args + + gen_struct_signatures(args) + + """ +// This one terminates the chain. Prepending void_t to the head of a void_t +// signature results in a void_t signature again. +inline signature0 prepend(void_t, signature0) { return signature0(); } + +} // namespace detail +""" + + gen_function(""" +template <%(class A%n% = detail::void_t%:, %)> +struct constructor +{ +}; +""", args) + + """ +namespace detail { +// Return value extraction: + +// This is just another little envelope for carrying a typedef (see type, +// above). I could have re-used type, but that has a very specific purpose. I +// thought this would be clearer. +template +struct return_value_select { typedef T type; }; + +// free functions""" + + gen_functions(""" +template +return_value_select return_value(R (*)(%(A%n%:, %))) { return return_value_select(); } +""", args) + + + +""" +// TODO(?): handle 'const void' + +// member functions""" + + gen_functions(""" +template +return_value_select return_value(R (T::*)(%(A%n%:, %))) { return return_value_select(); } +""", args) + + + gen_functions(""" +template +return_value_select return_value(R (T::*)(%(A%n%:, %)) const) { return return_value_select(); } +""", args) + + + """ +}}} // namespace boost::python::detail + +#endif +""") + +if __name__ == '__main__': + import sys + + if len(sys.argv) == 1: + args = 5 + else: + args = int(sys.argv[1]) + + print gen_signatures(args) + diff --git a/src/gen_singleton.py b/src/gen_singleton.py new file mode 100644 index 00000000..3a5ca7e3 --- /dev/null +++ b/src/gen_singleton.py @@ -0,0 +1,58 @@ +from gen_function import * +import string + +def gen_singleton(args): + return ( +"""// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef SINGLETON_DWA051900_H_ +# define SINGLETON_DWA051900_H_ + +# include + +namespace boost { namespace python { namespace detail { + +struct empty {}; +template +struct singleton : Base +{ + typedef singleton singleton_base; // Convenience type for derived class constructors + + static Derived* instance(); + + // Pass-through constructors +""" + + gen_functions("""%{ + template <%(class A%n%:, %)> +%} singleton(%(const A%n& a%n%:, %)) : Base(%(a%n%:, %)) {} +""", args) + + """ +}; + +template +Derived* singleton::instance() +{ + static Derived x; + return &x; +} + +}}} // namespace boost::python::detail + +#endif +""") + +if __name__ == '__main__': + import sys + + if len(sys.argv) == 1: + args = 5 + else: + args = int(sys.argv[1]) + + print gen_singleton(args) diff --git a/src/init_function.cpp b/src/init_function.cpp new file mode 100644 index 00000000..1667724c --- /dev/null +++ b/src/init_function.cpp @@ -0,0 +1,36 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#include +#include +#include +#include + +namespace boost { namespace python { namespace detail { + + PyObject* init::do_call(PyObject* args_, PyObject* keywords) const + { + tuple args(ref(args_, ref::increment_count)); + if (args[0]->ob_type->ob_type != extension_meta_class()) + { + PyErr_SetString(PyExc_TypeError, "argument 1 to __init__ must be an ExtensionInstance"); + return 0; + } + + extension_instance *self = static_cast(args[0].get()); + + tuple ctor_args = args.slice(1, args.size()); + + std::auto_ptr result( + create_holder(self, ctor_args.get(), keywords)); + + self->add_implementation(result); + return none(); + } + +}}} // namespace boost::python::detail diff --git a/src/module_builder.cpp b/src/module_builder.cpp new file mode 100644 index 00000000..ea00b71c --- /dev/null +++ b/src/module_builder.cpp @@ -0,0 +1,52 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#include + +namespace boost { namespace python { + +namespace { + ref name_holder; +} + +string module_builder::name() +{ + // If this fails, you haven't created a module_builder object + assert(name_holder.get() != 0); + return string(name_holder); +} + +module_builder::module_builder(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 + assert(name_holder.get() == 0); + name_holder = ref(PyObject_GetAttrString(m_module, const_cast("__name__"))); +} + +void +module_builder::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) +{ + PyObject* dictionary = PyModule_GetDict(m_module); + PyDict_SetItemString(dictionary, const_cast(name), x.get()); +} + +void module_builder::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 } }; + +}} // namespace boost::python diff --git a/src/objects.cpp b/src/objects.cpp new file mode 100644 index 00000000..cc46b2ba --- /dev/null +++ b/src/objects.cpp @@ -0,0 +1,485 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +// TODO: Move inline implementations from objects.cpp here + +#include +#include + +namespace boost { namespace python { + +template +T object_from_python(PyObject* p, type) +{ + ref x(p, ref::increment_count); + if (!T::accepts(x)) + { + PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name); + throw error_already_set(); + } + return T(x); +} + +inline PyObject* object_to_python(const object& x) +{ + return x.reference().release(); +} + +object::object(ref p) + : m_p(p) {} + +// Return a reference to the held object +ref object::reference() const +{ + return m_p; +} + +// Return a raw pointer to the held object +PyObject* object::get() const +{ + return m_p.get(); +} + +}} // namespace boost::python + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + +PyObject* to_python(const boost::python::tuple& x) +{ + return object_to_python(x); +} + +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) +{ + return object_to_python(x); +} + +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) +{ + return object_to_python(x); +} + +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) +{ + return object_to_python(x); +} + +boost::python::string from_python(PyObject* p, boost::python::type type) +{ + return boost::python::object_from_python(p, type); +} + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +namespace boost { namespace python { + +tuple::tuple(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) + : object(p) +{ + assert(accepts(p)); + if (!accepts(p)) + { + PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name); + throw error_already_set(); + } +} + +PyTypeObject* tuple::type_obj() +{ + return &PyTuple_Type; +} + +bool tuple::accepts(ref p) +{ + return PyTuple_Check(p.get()); +} + +std::size_t tuple::size() const +{ + return PyTuple_Size(get()); +} + +ref tuple::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) +{ + int failed = PyTuple_SetItem( + get(), static_cast(pos), ref(rhs).release()); // A reference is stolen here. + (void)failed; + assert(failed == 0); +} + +tuple tuple::slice(int low, int high) const +{ + return tuple(ref(PyTuple_GetSlice(get(), low, high))); +} + +tuple& tuple::operator+=(const tuple& rhs) +{ + return *this = *this + rhs; +} + + +// Construct from an owned PyObject*. +// Precondition: p must point to a python string. +string::string(ref p) + : object(p) +{ + assert(accepts(p)); + if (!accepts(p)) + { + PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name); + throw error_already_set(); + } +} + +string::string(const char* s) + : object(ref(PyString_FromString(s))) {} + +string::string(const char* s, std::size_t length) + : object(ref(PyString_FromStringAndSize(s, length))) {} + +string::string(const char* s, interned_t) + : object(ref(PyString_InternFromString(s))) {} + +#if 0 +string::string(const char* s, std::size_t length, interned_t) + : object(ref(PyString_InternFromStringAndSize(s, length))) {} +#endif + +string::string(const string& rhs) + : object(rhs.reference()) {} + +// Get the type object for Strings +PyTypeObject* string::type_obj() +{ return &PyString_Type; } + +// Return true if the given object is a python string +bool string::accepts(ref o) +{ return PyString_Check(o.get()); } + +// Return the length of the string. +std::size_t string::size() const +{ + int size = PyString_GET_SIZE(get()); + assert(size >= 0); + return static_cast(size); +} + +// Returns a null-terminated representation of the contents of string. +// The pointer refers to the internal buffer of string, not a copy. +// The data must not be modified in any way. It must not be de-allocated. +const char* string::c_str() const +{ return PyString_AS_STRING(get()); } + +void string::intern() +{ // UNTESTED!! + *this = string(ref(PyString_InternFromString(c_str()), ref::increment_count)); +} + +string& string::operator*=(unsigned int repeat_count) +{ + *this = string(ref(PySequence_Repeat(get(), repeat_count))); + return *this; +} + +dictionary::dictionary(ref p) + : object(p) +{ + assert(accepts(p)); + if (!accepts(p)) + { + PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name); + throw error_already_set(); + } +} + +dictionary::dictionary() + : object(ref(PyDict_New())) {} + +PyTypeObject* dictionary::type_obj() +{ return &PyDict_Type; } + +bool dictionary::accepts(ref p) +{ return PyDict_Check(p.get()); } + +void dictionary::clear() +{ PyDict_Clear(get()); } + +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 +{ + 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) + : m_dict(dict), m_key(key) {} + +dictionary::proxy dictionary::operator[](ref key) +{ return proxy(reference(), key); } + +ref dictionary::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 +{ + return get_item(key, ref()); +} + +ref dictionary::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()) + return default_; + else + 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) +{ + if (PyDict_SetItem(get(), key.get(), value.get()) == -1) + throw error_already_set(); +} + +void dictionary::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()))); } + +std::size_t dictionary::size() const { return static_cast(PyDict_Size(get())); } + +string operator+(string x, string y) +{ + PyObject* io_string = x.reference().release(); + PyString_Concat(&io_string, y.get()); + return string(ref(io_string)); +} + +string& string::operator+=(const string& rhs) +{ + return *this = *this + rhs; +} + +string& string::operator+=(const char* y) +{ + return *this += string(y); +} + +string operator%(const string& format, const tuple& args) +{ + return string(ref(PyString_Format(format.get(), args.reference().get()))); +} + +string operator+(string x, const char* y) +{ + return x + string(y); +} + +string operator+(const char* x, string y) +{ + return string(x) + y; +} + +tuple operator+(const tuple& x, const tuple& y) +{ + tuple result(x.size() + y.size()); + for (std::size_t xi = 0; xi < x.size(); ++xi) + result.set_item(xi, x[xi]); + for (std::size_t yi = 0; yi < y.size(); ++yi) + result.set_item(yi + x.size(), y[yi]); + return result; +} + + +list::list(ref p) + : object(p) +{ + assert(accepts(p)); + if (!accepts(p)) + { + PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name); + throw error_already_set(); + } +} + +list::list(std::size_t sz) + : object(ref(PyList_New(sz))) +{ +} + +PyTypeObject* list::type_obj() +{ + return &PyList_Type; +} + +bool list::accepts(ref p) +{ + return PyList_Check(p.get()); +} + +std::size_t list::size() +{ + return PyList_Size(get()); +} + +ref list::operator[](std::size_t pos) const +{ + return ref(PyList_GetItem(get(), pos), ref::increment_count); +} + +list::proxy list::operator[](std::size_t pos) +{ + return proxy(reference(), pos); +} + +void list::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) +{ + if (PyList_Append(get(), item.get()) == -1) + throw error_already_set(); +} + +void list::append(const ref& item) +{ + this->push_back(item); +} + +list list::slice(int low, int high) const +{ + return list(ref(PyList_GetSlice(get(), low, high))); +} + +list::slice_proxy list::slice(int low, int high) +{ + return slice_proxy(reference(), low, high); +} + +void list::sort() +{ + if (PyList_Sort(get()) == -1) + throw error_already_set(); +} + +void list::reverse() +{ + if (PyList_Reverse(get()) == -1) + throw error_already_set(); +} + +tuple list::as_tuple() const +{ + return tuple(ref(PyList_AsTuple(get()))); +} + +const ref& list::proxy::operator=(const ref& rhs) +{ + m_list.set_item(m_index, rhs); + return rhs; +} + +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 +{ + return ref(PyList_GetItem(this->get(), pos), ref::increment_count); +} + +void list::set_item(std::size_t pos, const ref& rhs) +{ + int result = PyList_SetItem(this->get(), pos, rhs.get()); + if (result == -1) + throw error_already_set(); + Py_INCREF(rhs.get()); +} + +list::proxy::proxy(const ref& list, std::size_t index) + : m_list(list), m_index(index) +{ +} + +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 +{ + return ref(PyList_GetSlice(m_list.get(), m_low, m_high)); +} + +list::slice_proxy::operator list() const +{ + return list(this->operator ref()); +} + +std::size_t list::slice_proxy::size() +{ + return this->operator list().size(); +} + +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) + : m_list(list), m_low(low), m_high(high) +{ +} + +}} // namespace boost::python diff --git a/src/types.cpp b/src/types.cpp new file mode 100644 index 00000000..7ba5840b --- /dev/null +++ b/src/types.cpp @@ -0,0 +1,1097 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#include +#include // for handle_exception() +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace python { + +namespace { + + using detail::type_object_base; + + PyObject* call(PyObject* obj, PyObject* (type_object_base::*f)(PyObject*) const) + { + try + { + return (static_cast(obj->ob_type)->*f)(obj); + } + catch(...) + { + handle_exception(); + return 0; + } + } + + // Naming this differently allows us to use it for functions returning long on + // compilers without partial ordering + template + R int_call(PyObject* obj, R (type_object_base::*f)(PyObject*) const) + { + try + { + return (static_cast(obj->ob_type)->*f)(obj); + } + catch(...) + { + handle_exception(); + return -1; + } + } + + // Implemented in terms of int_call, above + int call(PyObject* obj, int (type_object_base::*f)(PyObject*) const) + { + return int_call(obj, f); + } + + template + PyObject* call(PyObject* obj, PyObject* (type_object_base::*f)(PyObject*, A1) const, A1 a1) + { + try + { + return (static_cast(obj->ob_type)->*f)(obj, a1); + } + catch(...) + { + handle_exception(); + return 0; + } + } + + template + int call(PyObject* obj, int (type_object_base::*f)(PyObject*, A1) const, A1 a1) + { + try + { + return (static_cast(obj->ob_type)->*f)(obj, a1); + } + catch(...) + { + handle_exception(); + return -1; + } + } + + template + PyObject* call(PyObject* obj, PyObject* (type_object_base::*f)(PyObject*, A1, A2) const, A1 a1, A2 a2) + { + try + { + return (static_cast(obj->ob_type)->*f)(obj, a1, a2); + } + catch(...) + { + handle_exception(); + return 0; + } + } + + template + int call(PyObject* obj, int (type_object_base::*f)(PyObject*, A1, A2) const, A1 a1, A2 a2) + { + try + { + return (static_cast(obj->ob_type)->*f)(obj, a1, a2); + } + catch(...) + { + handle_exception(); + return -1; + } + } + + template + int call(PyObject* obj, int (type_object_base::*f)(PyObject*, A1, A2, A3) const, A1 a1, A2 a2, A3 a3) + { + try + { + return (static_cast(obj->ob_type)->*f)(obj, a1, a2, a3); + } + catch(...) + { + handle_exception(); + return -1; + } + } + + int call_length_function(PyObject* obj, int (type_object_base::*f)(PyObject*) const) + { + try + { + const int outcome = + (static_cast(obj->ob_type)->*f)(obj); + + if (outcome < 0) + { + PyErr_SetString(PyExc_ValueError, "__len__() should return >= 0"); + return -1; + } + return outcome; + } + catch(...) + { + handle_exception(); + return -1; + } + } + +} // anonymous namespace + +extern "C" { + +static PyObject* do_instance_repr(PyObject* obj) +{ + return call(obj, &type_object_base::instance_repr); +} + +static int do_instance_compare(PyObject* obj, PyObject* other) +{ + return call(obj, &type_object_base::instance_compare, other); +} + +static PyObject* do_instance_str(PyObject* obj) +{ + return call(obj, &type_object_base::instance_str); +} + +static long do_instance_hash(PyObject* obj) +{ + return int_call(obj, &type_object_base::instance_hash); +} + +static PyObject* do_instance_call(PyObject* obj, PyObject* args, PyObject* keywords) +{ + return call(obj, &type_object_base::instance_call, args, keywords); +} + +static void do_instance_dealloc(PyObject* obj) +{ + try + { + static_cast(obj->ob_type) + ->instance_dealloc(obj); + } + catch(...) + { + assert(!"exception during destruction!"); + handle_exception(); + } +} + +static PyObject* do_instance_getattr(PyObject* obj, char* name) +{ + const char* name_ = name; + return call(obj, &type_object_base::instance_getattr, name_); +} + +static int do_instance_setattr(PyObject* obj, char* name, PyObject* value) +{ + const char* name_ = name; + return call(obj, &type_object_base::instance_setattr, name_, value); +} + +static int do_instance_mp_length(PyObject* obj) +{ + return call_length_function(obj, &type_object_base::instance_mapping_length); +} + +static int do_instance_sq_length(PyObject* obj) +{ + return call_length_function(obj, &type_object_base::instance_sequence_length); +} + +static PyObject* do_instance_mp_subscript(PyObject* obj, PyObject* index) +{ + return call(obj, &type_object_base::instance_mapping_subscript, index); +} + +static PyObject* do_instance_sq_item(PyObject* obj, int index) +{ + try + { + const PyTypeObject* const type = obj->ob_type; + + // This is an extension to standard class behavior. If sequence_length + // is implemented and n >= sequence_length(), raise an IndexError. That + // keeps users from having to worry about raising it themselves + if (type->tp_as_sequence != 0 && type->tp_as_sequence->sq_length != 0 + && index >= type->tp_as_sequence->sq_length(obj)) + { + PyErr_SetString(PyExc_IndexError, type->tp_name); + return 0; + } + + return static_cast(obj->ob_type) + ->instance_sequence_item(obj, index); + } + catch(...) + { + handle_exception(); + return 0; + } +} + +static int do_instance_mp_ass_subscript(PyObject* obj, PyObject* index, PyObject* value) +{ + return call(obj, &type_object_base::instance_mapping_ass_subscript, index, value); +} + +static int do_instance_sq_ass_item(PyObject* obj, int index, PyObject* value) +{ + return call(obj, &type_object_base::instance_sequence_ass_item, index, value); +} + +static PyObject* do_instance_sq_concat(PyObject* obj, PyObject* other) +{ + return call(obj, &type_object_base::instance_sequence_concat, other); +} + +static PyObject* do_instance_sq_repeat(PyObject* obj, int n) +{ + return call(obj, &type_object_base::instance_sequence_repeat, n); +} + +static PyObject* do_instance_sq_slice( + PyObject* obj, int start, int finish) +{ + return call(obj, &type_object_base::instance_sequence_slice, start, finish); +} + +static int do_instance_sq_ass_slice( + PyObject* obj, int start, int finish, PyObject* value) +{ + return call(obj, &type_object_base::instance_sequence_ass_slice, start, finish, value); +} + +static PyObject* do_instance_nb_add(PyObject* obj, PyObject* other) +{ + return call(obj, &type_object_base::instance_number_add, other); +} + +static PyObject* do_instance_nb_subtract(PyObject* obj, PyObject* other) +{ + return call(obj, &type_object_base::instance_number_subtract, other); +} + +static PyObject* do_instance_nb_multiply(PyObject* obj, PyObject* other) +{ + return call(obj, &type_object_base::instance_number_multiply, other); +} + +static PyObject* do_instance_nb_divide(PyObject* obj, PyObject* other) +{ + return call(obj, &type_object_base::instance_number_divide, other); +} + +static PyObject* do_instance_nb_remainder(PyObject* obj, PyObject* other) +{ + return call(obj, &type_object_base::instance_number_remainder, other); +} + +static PyObject* do_instance_nb_divmod(PyObject* obj, PyObject* other) +{ + return call(obj, &type_object_base::instance_number_divmod, other); +} + +static PyObject* do_instance_nb_power(PyObject* obj, PyObject* exponent, PyObject* modulus) +{ + return call(obj, &type_object_base::instance_number_power, exponent, modulus); +} + +static PyObject* do_instance_nb_negative(PyObject* obj) +{ + return call(obj, &type_object_base::instance_number_negative); +} + +static PyObject* do_instance_nb_positive(PyObject* obj) +{ + return call(obj, &type_object_base::instance_number_positive); +} + +static PyObject* do_instance_nb_absolute(PyObject* obj) +{ + return call(obj, &type_object_base::instance_number_absolute); +} + +static int do_instance_nb_nonzero(PyObject* obj) +{ + return call(obj, &type_object_base::instance_number_nonzero); +} + +static PyObject* do_instance_nb_invert(PyObject* obj) +{ + return call(obj, &type_object_base::instance_number_invert); +} + + +static PyObject* do_instance_nb_lshift(PyObject* obj, PyObject* other) +{ + return call(obj, &type_object_base::instance_number_lshift, other); +} + +static PyObject* do_instance_nb_rshift(PyObject* obj, PyObject* other) +{ + return call(obj, &type_object_base::instance_number_rshift, other); +} + +static PyObject* do_instance_nb_and(PyObject* obj, PyObject* other) +{ + return call(obj, &type_object_base::instance_number_and, other); +} + +static PyObject* do_instance_nb_xor(PyObject* obj, PyObject* other) +{ + return call(obj, &type_object_base::instance_number_xor, other); +} + +static PyObject* do_instance_nb_or(PyObject* obj, PyObject* other) +{ + return call(obj, &type_object_base::instance_number_or, other); +} + +static int do_instance_nb_coerce(PyObject**obj, PyObject**other) +{ + return call(*obj, &type_object_base::instance_number_coerce, obj, other); +} +static PyObject* do_instance_nb_int(PyObject* obj) +{ + return call(obj, &type_object_base::instance_number_int); +} + +static PyObject* do_instance_nb_long(PyObject* obj) +{ + return call(obj, &type_object_base::instance_number_long); +} + +static PyObject* do_instance_nb_float(PyObject* obj) +{ + return call(obj, &type_object_base::instance_number_float); +} + +static PyObject* do_instance_nb_oct(PyObject* obj) +{ + return call(obj, &type_object_base::instance_number_oct); +} + +static PyObject* do_instance_nb_hex(PyObject* obj) +{ + return call(obj, &type_object_base::instance_number_hex); +} + +} // extern "C" + +namespace +{ + +#define ENABLE_GENERAL_CAPABILITY(field) \ + case type_object_base::field: \ + dest->tp_##field = &do_instance_##field; \ + return true + +bool add_capability_general(type_object_base::capability capability, PyTypeObject* dest) +{ + assert(dest != 0); + + switch(capability) + { + ENABLE_GENERAL_CAPABILITY(hash); + ENABLE_GENERAL_CAPABILITY(call); + ENABLE_GENERAL_CAPABILITY(str); + ENABLE_GENERAL_CAPABILITY(getattr); + ENABLE_GENERAL_CAPABILITY(setattr); + ENABLE_GENERAL_CAPABILITY(compare); + ENABLE_GENERAL_CAPABILITY(repr); + default: + return false; + } +} + + +template +void create_method_table_if_null(T*& table) +{ + if(table == 0) + { + detail::shared_pod_manager::create(table); + } + else + { + detail::shared_pod_manager::make_unique_copy(table); + } +} + +#define ENABLE_MAPPING_CAPABILITY(field) \ + case type_object_base::mapping_##field: \ + create_method_table_if_null(dest); \ + dest->mp_##field = &do_instance_mp_##field; \ + detail::shared_pod_manager::replace_if_equal(dest); \ + return true + +bool add_capability_mapping(type_object_base::capability capability, PyMappingMethods*& dest) +{ + switch(capability) + { + ENABLE_MAPPING_CAPABILITY(length); + ENABLE_MAPPING_CAPABILITY(subscript); + ENABLE_MAPPING_CAPABILITY(ass_subscript); + default: + return false; + } +} + +#define ENABLE_SEQUENCE_CAPABILITY(field) \ + case type_object_base::sequence_##field: \ + create_method_table_if_null(dest); \ + dest->sq_##field = &do_instance_sq_##field; \ + detail::shared_pod_manager::replace_if_equal(dest); \ + return true + +bool add_capability_sequence(type_object_base::capability capability, PySequenceMethods*& dest) +{ + switch(capability) + { + ENABLE_SEQUENCE_CAPABILITY(length); + ENABLE_SEQUENCE_CAPABILITY(item); + ENABLE_SEQUENCE_CAPABILITY(ass_item); + ENABLE_SEQUENCE_CAPABILITY(concat); + ENABLE_SEQUENCE_CAPABILITY(repeat); + ENABLE_SEQUENCE_CAPABILITY(slice); + ENABLE_SEQUENCE_CAPABILITY(ass_slice); + default: + return false; + } +} + +#define ENABLE_NUMBER_CAPABILITY(field) \ + case type_object_base::number_##field: \ + create_method_table_if_null(dest); \ + dest->nb_##field = &do_instance_nb_##field; \ + detail::shared_pod_manager::replace_if_equal(dest); \ + return true + +bool add_capability_number(type_object_base::capability capability, PyNumberMethods*& dest) +{ + switch(capability) + { + ENABLE_NUMBER_CAPABILITY(add); + ENABLE_NUMBER_CAPABILITY(subtract); + ENABLE_NUMBER_CAPABILITY(multiply); + ENABLE_NUMBER_CAPABILITY(divide); + ENABLE_NUMBER_CAPABILITY(remainder); + ENABLE_NUMBER_CAPABILITY(divmod); + ENABLE_NUMBER_CAPABILITY(power); + ENABLE_NUMBER_CAPABILITY(negative); + ENABLE_NUMBER_CAPABILITY(positive); + ENABLE_NUMBER_CAPABILITY(absolute); + ENABLE_NUMBER_CAPABILITY(nonzero); + ENABLE_NUMBER_CAPABILITY(invert); + ENABLE_NUMBER_CAPABILITY(lshift); + ENABLE_NUMBER_CAPABILITY(rshift); + ENABLE_NUMBER_CAPABILITY(and); + ENABLE_NUMBER_CAPABILITY(xor); + ENABLE_NUMBER_CAPABILITY(or); + ENABLE_NUMBER_CAPABILITY(coerce); + ENABLE_NUMBER_CAPABILITY(int); + ENABLE_NUMBER_CAPABILITY(long); + ENABLE_NUMBER_CAPABILITY(float); + ENABLE_NUMBER_CAPABILITY(oct); + ENABLE_NUMBER_CAPABILITY(hex); + default: + return false; + } +} + +#define ENABLE_BUFFER_CAPABILITY(field) \ + case type_object_base::buffer_##field: \ + create_method_table_if_null(dest); \ + dest->bf_##field = &do_instance_bf_##field; \ + detail::shared_pod_manager::replace_if_equal(dest); \ + return true + +bool add_capability_buffer(type_object_base::capability capability, PyBufferProcs*& dest) +{ + (void)dest; // suppress unused argument warning + (void)capability; // likwise +#if 0 + switch(capability) + { + // nothing defined yet + default: + return false; + } +#endif + return false; +} + +} // anonymous namespace + +namespace detail { + + void add_capability( + type_object_base::capability capability, + PyTypeObject* dest_) + { + if(add_capability_general(capability, dest_)) + return; + if(add_capability_mapping(capability, dest_->tp_as_mapping)) + return; + if(add_capability_sequence(capability, dest_->tp_as_sequence)) + return; + if(add_capability_number(capability, dest_->tp_as_number)) + return; + if(add_capability_buffer(capability, dest_->tp_as_buffer)) + return; + + // no one recognized the capability + throw std::runtime_error("py::detail::add_capability(): unknown capability"); + } +} // namespace detail + +type_object_base::~type_object_base() +{ + detail::shared_pod_manager::dispose(tp_as_mapping); + detail::shared_pod_manager::dispose(tp_as_sequence); + detail::shared_pod_manager::dispose(tp_as_number); + detail::shared_pod_manager::dispose(tp_as_buffer); +} + +void type_object_base::enable(type_object_base::capability capability) +{ + detail::add_capability(capability, this); +} + +type_object_base::type_object_base(PyTypeObject* t) + : python_type(t) +{ + this->tp_dealloc = do_instance_dealloc; +} + +namespace +{ + typedef long pod_refcount; + + inline pod_refcount pod_refcount_offset(std::size_t size) + { + const std::size_t alignment = boost::alignment_of::value; + return (size + alignment - 1) / alignment * alignment; + } + + inline pod_refcount* counted_pod_refcount(char* pod, std::size_t size) + { + if(pod == 0) + return 0; + + return reinterpret_cast(pod + pod_refcount_offset(size)); + } + + #ifdef TYPE_OBJECT_BASE_STANDALONE_TEST + int pod_instance_counter = 0; + #endif + + inline pod_refcount counted_pod_getref(char* pod, std::size_t size) + { + pod_refcount* ref_count = counted_pod_refcount(pod, size); + return ref_count == 0 ? -1 : *ref_count; + } + + inline pod_refcount counted_pod_decref(char* pod, std::size_t size) + { + pod_refcount* const ref_count = counted_pod_refcount(pod, size); + if (ref_count == 0) + return -1; + --(*ref_count); + if (*ref_count <= 0) + { + #ifdef TYPE_OBJECT_BASE_STANDALONE_TEST + --pod_instance_counter; + #endif + ::operator delete(pod); + return 0; + } + return *ref_count; + } + + pod_refcount counted_pod_incref(char* pod, std::size_t size) + { + pod_refcount* ref_count = counted_pod_refcount(pod, size); + return ref_count == 0 ? -1 : ++(*ref_count); + } + +} // anonymous namespace + +namespace detail +{ + struct shared_pod_manager::compare + { + bool operator()(const std::pair& x1, + const std::pair& x2) const + { + const std::size_t n1 = x1.second; + const std::size_t n2 = x2.second; + return n1 < n2 || n1 == n2 && BOOST_CSTD_::memcmp(x1.first, x2.first, n1) < 0; + } + }; + + struct shared_pod_manager::identical + { + identical(char* p) : pod(p) {} + + bool operator()(const std::pair& x) const + { + return pod == x.first; + } + + char* pod; + }; + + shared_pod_manager& shared_pod_manager::obj() + { + static shared_pod_manager spm; + return spm; + } + + shared_pod_manager::~shared_pod_manager() + { + } + + void* shared_pod_manager::replace_if_equal(void* pod, std::size_t size) + { + if(pod == 0) + return 0; + + const holder element(static_cast(pod), size); + + const storage::iterator found + = std::lower_bound(m_storage.begin(), m_storage.end(), element, compare()); + + if (found != m_storage.end() && pod == found->first) + { + // pod already in list => do nothing + return pod; + } + else if (found != m_storage.end() && !compare()(element, *found)) + { + // equal element in list => replace + void* replacement = found->first; + counted_pod_incref(found->first, size); + dec_ref(element.first, size); // invalidates iterator 'found' + return replacement; + } + else + { + // new element => insert + m_storage.insert(found, element); + return pod; + } + } + + void* shared_pod_manager::make_unique_copy(void* pod, std::size_t size) + { + if(pod == 0) + return 0; + if(counted_pod_getref(static_cast(pod), size) == 1) + { + erase_from_list(pod); + return pod; + } + else + { + void* copy = create(size); + memmove(copy, pod, size); + dec_ref(pod, size); + return copy; + } + } + + void* shared_pod_manager::create(std::size_t size) + { + std::size_t total_size = pod_refcount_offset(size) + sizeof(pod_refcount); + char* pod = static_cast(::operator new(total_size)); + #ifdef TYPE_OBJECT_BASE_STANDALONE_TEST + ++pod_instance_counter; + #endif + memset(pod, 0, total_size); + + *counted_pod_refcount(pod, size) = 1; + + return pod; + } + + void shared_pod_manager::dec_ref(void* pod, std::size_t size) + { + if(pod == 0) + return; + + int ref_count = counted_pod_decref(static_cast(pod), size); + + if(ref_count <= 0) + erase_from_list(pod); + } + + void shared_pod_manager::erase_from_list(void* pod) + { + if(pod == 0) + return; + + const storage::iterator found = + std::find_if(m_storage.begin(), m_storage.end(), + identical(static_cast(pod))); + + if(found != m_storage.end()) + { + m_storage.erase(found); + } + } +} // namespace detail + +namespace { + struct error_type { + operator PyObject*() const { return 0; } + operator int() const { return -1; } + }; + + error_type unimplemented(const char* name) + { + assert(!"Control should never reach here"); + string s("Unimplemented "); + s += string(name); + PyErr_SetObject(PyExc_RuntimeError, s.get()); + return error_type(); + } +} + +PyObject* type_object_base::instance_repr(PyObject*) const +{ + return unimplemented("instance_repr"); +} + +int type_object_base::instance_compare(PyObject*, PyObject*) const +{ + return unimplemented("instance_compare"); +} + +PyObject* type_object_base::instance_str(PyObject*) const +{ + return unimplemented("instance_str"); +} + +long type_object_base::instance_hash(PyObject* /* obj */) const +{ + return unimplemented("instance_hash"); +} + +PyObject* type_object_base::instance_call(PyObject* /*obj*/, PyObject* /*args*/, PyObject* /*kw*/) const +{ + return unimplemented("instance_call"); +} + +PyObject* type_object_base::instance_getattr(PyObject* /*obj*/, const char* /*name*/) const +{ + return unimplemented("instance_getattr"); +} + +int type_object_base::instance_setattr(PyObject* /*obj*/, const char* /*name*/, PyObject* /*value*/) const +{ + return unimplemented("instance_setattr"); +} + +int type_object_base::instance_mapping_length(PyObject*) const +{ + return unimplemented("instance_mapping_length"); +} + +int type_object_base::instance_sequence_length(PyObject*) const +{ + return unimplemented("instance_sequence_length"); +} + +PyObject* type_object_base::instance_mapping_subscript(PyObject*, PyObject*) const +{ + return unimplemented("instance_mapping_subscript"); +} + +PyObject* type_object_base::instance_sequence_item(PyObject*, int) const +{ + return unimplemented("instance_sequence_item"); +} + +int type_object_base::instance_mapping_ass_subscript(PyObject*, PyObject*, PyObject*) const +{ + return unimplemented("instance_mapping_ass_subscript"); +} + +int type_object_base::instance_sequence_ass_item(PyObject*, int, PyObject*) const +{ + return unimplemented("instance_sequence_ass_item"); +} + +PyObject* type_object_base::instance_sequence_concat(PyObject*, PyObject*) const +{ + return unimplemented("instance_sequence_concat"); +} + +PyObject* type_object_base::instance_sequence_repeat(PyObject*, int) const +{ + return unimplemented("instance_sequence_repeat"); +} + +PyObject* type_object_base::instance_sequence_slice(PyObject*, int, int) const +{ + return unimplemented("instance_sequence_slice"); +} + +int type_object_base::instance_sequence_ass_slice(PyObject*, int, int, PyObject*) const +{ + return unimplemented("instance_sequence_ass_slice"); +} + +PyObject* type_object_base::instance_number_add(PyObject*, PyObject*) const +{ + return unimplemented("instance_number_add"); +} + +PyObject* type_object_base::instance_number_subtract(PyObject*, PyObject*) const +{ + return unimplemented("instance_number_subtract"); +} + +PyObject* type_object_base::instance_number_multiply(PyObject*, PyObject*) const +{ + return unimplemented("instance_number_multiply"); +} + +PyObject* type_object_base::instance_number_divide(PyObject*, PyObject*) const +{ + return unimplemented("instance_number_divide"); +} + +PyObject* type_object_base::instance_number_remainder(PyObject*, PyObject*) const +{ + return unimplemented("instance_number_remainder"); +} + +PyObject* type_object_base::instance_number_divmod(PyObject*, PyObject*) const +{ + return unimplemented("instance_number_divmod"); +} + +PyObject* type_object_base::instance_number_power(PyObject*, PyObject*, PyObject*) const +{ + return unimplemented("instance_number_divmod"); +} + +PyObject* type_object_base::instance_number_negative(PyObject*) const +{ + return unimplemented("instance_number_negative"); +} + +PyObject* type_object_base::instance_number_positive(PyObject*) const +{ + return unimplemented("instance_number_positive"); +} + +PyObject* type_object_base::instance_number_absolute(PyObject*) const +{ + return unimplemented("instance_number_absolute"); +} + +int type_object_base::instance_number_nonzero(PyObject*) const +{ + return unimplemented("instance_number_nonzero"); +} + +PyObject* type_object_base::instance_number_invert(PyObject*) const +{ + return unimplemented("instance_number_invert"); +} + +PyObject* type_object_base::instance_number_lshift(PyObject*, PyObject*) const +{ + return unimplemented("instance_number_lshift"); +} + +PyObject* type_object_base::instance_number_rshift(PyObject*, PyObject*) const +{ + return unimplemented("instance_number_rshift"); +} + +PyObject* type_object_base::instance_number_and(PyObject*, PyObject*) const +{ + return unimplemented("instance_number_and"); +} + +PyObject* type_object_base::instance_number_xor(PyObject*, PyObject*) const +{ + return unimplemented("instance_number_xor"); +} + +PyObject* type_object_base::instance_number_or(PyObject*, PyObject*) const +{ + return unimplemented("instance_number_or"); +} + +int type_object_base::instance_number_coerce(PyObject*, PyObject**, PyObject**) const +{ + return unimplemented("instance_number_coerce"); +} + +PyObject* type_object_base::instance_number_int(PyObject*) const +{ + return unimplemented("instance_number_int"); +} + +PyObject* type_object_base::instance_number_long(PyObject*) const +{ + return unimplemented("instance_number_long"); +} + +PyObject* type_object_base::instance_number_float(PyObject*) const +{ + return unimplemented("instance_number_float"); +} + +PyObject* type_object_base::instance_number_oct(PyObject*) const +{ + return unimplemented("instance_number_oct"); +} + +PyObject* type_object_base::instance_number_hex(PyObject*) const +{ + return unimplemented("instance_number_hex"); +} + +}} // namespace boost::python + +#ifdef TYPE_OBJECT_BASE_STANDALONE_TEST + +struct TestTypeObject : boost::python::type_object_base +{ + TestTypeObject() + : boost::python::type_object_base(Py_None->ob_type->ob_type) + {} + + void instance_dealloc(PyObject*) const {} +}; + +struct POD1 +{ + unsigned char data; +}; + +int main() +{ + boost::python::type_object_base *o1, *o2, *o3; + +// POD1 * pod1; +// boost::python::detail::shared_pod_manager::create(pod1); + + o1 = new TestTypeObject; + o2 = new TestTypeObject; + o3 = new TestTypeObject; + + assert(boost::python::pod_instance_counter == 0); + + o1->enable(boost::python::type_object_base::number_add); + o1->enable(boost::python::type_object_base::compare); + + o2->enable(boost::python::type_object_base::number_add); + o2->enable(boost::python::type_object_base::mapping_length); + + o3->enable(boost::python::type_object_base::number_add); + o3->enable(boost::python::type_object_base::sequence_length); + + assert(boost::python::pod_instance_counter == 3); + assert(o1->tp_as_number && !o1->tp_as_mapping && !o1->tp_as_sequence); + assert(o2->tp_as_number && o2->tp_as_mapping && !o2->tp_as_sequence); + assert(o3->tp_as_number && !o3->tp_as_mapping && o3->tp_as_sequence); + assert(o1->tp_as_number == o2->tp_as_number); + assert(o1->tp_as_number == o3->tp_as_number); + assert((void*)o2->tp_as_number != o2->tp_as_mapping); + assert((void*)o2->tp_as_mapping != o3->tp_as_sequence); + + o1->enable(boost::python::type_object_base::number_subtract); + + assert(boost::python::pod_instance_counter == 4); + assert(o1->tp_as_number != o2->tp_as_number); + assert(o2->tp_as_number == o3->tp_as_number); + + o3->enable(boost::python::type_object_base::mapping_subscript); + + assert(boost::python::pod_instance_counter == 5); + assert(o3->tp_as_number && o3->tp_as_mapping && o3->tp_as_sequence); + assert(o2->tp_as_mapping != o3->tp_as_mapping); + + o2->enable(boost::python::type_object_base::mapping_subscript); + o3->enable(boost::python::type_object_base::mapping_length); + + assert(boost::python::pod_instance_counter == 4); + assert(o2->tp_as_number && o2->tp_as_mapping && !o2->tp_as_sequence); + assert(o3->tp_as_number && o3->tp_as_mapping && o3->tp_as_sequence); + assert(o2->tp_as_mapping == o3->tp_as_mapping); + + boost::python::type_object_base *o4 = new TestTypeObject; + + assert(boost::python::pod_instance_counter == 4); + + o4->enable(boost::python::type_object_base::number_add); + + assert(boost::python::pod_instance_counter == 4); + assert(o4->tp_as_number && !o4->tp_as_mapping && !o4->tp_as_sequence); + assert(o4->tp_as_number == o3->tp_as_number); + + delete o3; + + assert(boost::python::pod_instance_counter == 3); + assert(o1->tp_as_number && !o1->tp_as_mapping && !o1->tp_as_sequence); + assert(o2->tp_as_number && o2->tp_as_mapping && !o2->tp_as_sequence); + assert(o4->tp_as_number && !o4->tp_as_mapping && !o4->tp_as_sequence); + assert(o4->tp_as_number == o2->tp_as_number); + + o3 = new TestTypeObject; + + assert(boost::python::pod_instance_counter == 3); + + o3->enable(boost::python::type_object_base::number_add); + o3->enable(boost::python::type_object_base::sequence_length); + + assert(boost::python::pod_instance_counter == 4); + assert(o3->tp_as_number && !o3->tp_as_mapping && o3->tp_as_sequence); + assert(o1->tp_as_number != o3->tp_as_number); + assert(o2->tp_as_number == o3->tp_as_number); + + delete o1; + + assert(boost::python::pod_instance_counter == 3); + + delete o4; + + assert(boost::python::pod_instance_counter == 3); + + delete o3; + + assert(boost::python::pod_instance_counter == 2); + + delete o2; + + assert(boost::python::pod_instance_counter == 0); + + assert(boost::python::detail::shared_pod_manager::obj().m_storage.size() == 0); +} + +#endif + diff --git a/test/comprehensive.cpp b/test/comprehensive.cpp new file mode 100644 index 00000000..cae924e6 --- /dev/null +++ b/test/comprehensive.cpp @@ -0,0 +1,1133 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. +#include "comprehensive.hpp" +#include +#include // used for portability on broken compilers +#include // for pow() +#include + +namespace extclass_demo { + +FooCallback::FooCallback(PyObject* self, int x) + : Foo(x), m_self(self) +{ +} + +int FooCallback::add_len(const char* x) const +{ + // Try to call the "add_len" method on the corresponding Python object. + return boost::python::callback::call_method(m_self, "add_len", x); +} + +// A function which Python can call in case bar is not overridden from +// Python. In true Python style, we use a free function taking an initial self +// parameter. This function anywhere needn't be a static member of the callback +// class. The only reason to do it this way is that Foo::add_len is private, and +// FooCallback is already a friend of Foo. +int FooCallback::default_add_len(const Foo* self, const char* x) +{ + // Don't forget the Foo:: qualification, or you'll get an infinite + // recursion! + return self->Foo::add_len(x); +} + +// Since Foo::pure() is pure virtual, we don't need a corresponding +// default_pure(). A failure to override it in Python will result in an +// exception at runtime when pure() is called. +std::string FooCallback::pure() const +{ + return boost::python::callback::call_method(m_self, "pure"); +} + +Foo::PythonClass::PythonClass(boost::python::module_builder& m) + : boost::python::class_builder(m, "Foo") +{ + def(boost::python::constructor()); + def(&Foo::mumble, "mumble"); + def(&Foo::set, "set"); + def(&Foo::call_pure, "call_pure"); + def(&Foo::call_add_len, "call_add_len"); + + // This is the way we add a virtual function that has a default implementation. + def(&Foo::add_len, "add_len", &FooCallback::default_add_len); + + // Since pure() is pure virtual, we are leaving it undefined. +} + +BarPythonClass::BarPythonClass(boost::python::module_builder& m) + : boost::python::class_builder(m, "Bar") +{ + def(boost::python::constructor()); + def(&Bar::first, "first"); + def(&Bar::second, "second"); + def(&Bar::pass_baz, "pass_baz"); +} + +BazPythonClass::BazPythonClass(boost::python::module_builder& m) + : boost::python::class_builder(m, "Baz") // optional +{ + def(boost::python::constructor<>()); + def(&Baz::pass_bar, "pass_bar"); + def(&Baz::clone, "clone"); + def(&Baz::create_foo, "create_foo"); + def(&Baz::get_foo_value, "get_foo_value"); + def(&Baz::eat_baz, "eat_baz"); +} + +StringMapPythonClass::StringMapPythonClass(boost::python::module_builder& m) + : boost::python::class_builder(m, "StringMap") +{ + def(boost::python::constructor<>()); + def(&StringMap::size, "__len__"); + def(&get_item, "__getitem__"); + def(&set_item, "__setitem__"); + def(&del_item, "__delitem__"); +} + +int get_first(const IntPair& p) +{ + return p.first; +} + +void set_first(IntPair& p, int value) +{ + p.first = -value; +} + +void del_first(const IntPair&) +{ + PyErr_SetString(PyExc_AttributeError, "first can't be deleted!"); + throw boost::python::error_already_set(); +} + +IntPairPythonClass::IntPairPythonClass(boost::python::module_builder& m) + : boost::python::class_builder(m, "IntPair") +{ + def(boost::python::constructor()); + def(&getattr, "__getattr__"); + def(&setattr, "__setattr__"); + def(&delattr, "__delattr__"); + def(&get_first, "__getattr__first__"); + def(&set_first, "__setattr__first__"); + def(&del_first, "__delattr__first__"); +} + +void IntPairPythonClass::setattr(IntPair& x, const std::string& name, int value) +{ + if (name == "second") + { + x.second = value; + } + else + { + PyErr_SetString(PyExc_AttributeError, name.c_str()); + throw boost::python::error_already_set(); + } +} + +void IntPairPythonClass::delattr(IntPair&, const char*) +{ + PyErr_SetString(PyExc_AttributeError, "Attributes can't be deleted!"); + throw boost::python::error_already_set(); +} + +int IntPairPythonClass::getattr(const IntPair& p, const std::string& s) +{ + if (s == "second") + { + return p.second; + } + else + { + PyErr_SetString(PyExc_AttributeError, s.c_str()); + throw boost::python::error_already_set(); + } +#if defined(__MWERKS__) && __MWERKS__ <= 0x2400 + return 0; +#endif +} + +namespace { namespace file_local { +void throw_key_error_if_end(const StringMap& m, StringMap::const_iterator p, std::size_t key) +{ + if (p == m.end()) + { + PyErr_SetObject(PyExc_KeyError, BOOST_PYTHON_CONVERSION::to_python(key)); + throw boost::python::error_already_set(); + } +} +}} // namespace ::file_local + +const std::string& StringMapPythonClass::get_item(const StringMap& m, std::size_t key) +{ + const StringMap::const_iterator p = m.find(key); + file_local::throw_key_error_if_end(m, p, key); + return p->second; +} + +void StringMapPythonClass::set_item(StringMap& m, std::size_t key, const std::string& value) +{ + m[key] = value; +} + +void StringMapPythonClass::del_item(StringMap& m, std::size_t key) +{ + const StringMap::iterator p = m.find(key); + file_local::throw_key_error_if_end(m, p, key); + m.erase(p); +} + +// +// Show that polymorphism can work. a DerivedFromFoo object will be passed to +// Python in a smart pointer object. +// +class DerivedFromFoo : public Foo +{ +public: + DerivedFromFoo(int x) : Foo(x) {} + +private: + std::string pure() const + { return "this was never pure!"; } + + int add_len(const char*) const + { return 1000; } +}; + +// +// function implementations +// + +IntPair make_pair(int x, int y) +{ + return std::make_pair(x, y); +} + +const char* Foo::mumble() +{ + return "mumble"; +} + +void Foo::set(long x) +{ + m_x = x; +} + +std::string Foo::call_pure() +{ + return this->pure(); +} + +int Foo::call_add_len(const char* s) const +{ + return this->add_len(s); +} + +int Foo::add_len(const char* s) const // sum the held value and the length of s +{ + return BOOST_CSTD_::strlen(s) + static_cast(m_x); +} + +boost::shared_ptr Baz::create_foo() +{ + return boost::shared_ptr(new DerivedFromFoo(0)); +} + +// We can accept smart pointer parameters +int Baz::get_foo_value(boost::shared_ptr foo) +{ + return foo->call_add_len(""); +} + +// Show what happens in python when we take ownership from an auto_ptr +void Baz::eat_baz(std::auto_ptr baz) +{ + baz->clone(); // just do something to show that it is valid. +} + +Baz Bar::pass_baz(Baz b) +{ + return b; +} + +std::string stringpair_repr(const StringPair& sp) +{ + return "('" + sp.first + "', '" + sp.second + "')"; +} + +int stringpair_compare(const StringPair& sp1, const StringPair& sp2) +{ + return sp1 < sp2 ? -1 : sp2 < sp1 ? 1 : 0; +} + +boost::python::string range_str(const Range& r) +{ + char buf[200]; + sprintf(buf, "(%d, %d)", r.m_start, r.m_finish); + return boost::python::string(buf); +} + +int range_compare(const Range& r1, const Range& r2) +{ + int d = r1.m_start - r2.m_start; + if (d == 0) + d = r1.m_finish - r2.m_finish; + return d; +} + +long range_hash(const Range& r) +{ + return r.m_start * 123 + r.m_finish; +} + +/************************************************************/ +/* */ +/* some functions to test overloading */ +/* */ +/************************************************************/ + +static std::string testVoid() +{ + return std::string("Hello world!"); +} + +static int testInt(int i) +{ + return i; +} + +static std::string testString(std::string i) +{ + return i; +} + +static int test2(int i1, int i2) +{ + return i1+i2; +} + +static int test3(int i1, int i2, int i3) +{ + return i1+i2+i3; +} + +static int test4(int i1, int i2, int i3, int i4) +{ + return i1+i2+i3+i4; +} + +static int test5(int i1, int i2, int i3, int i4, int i5) +{ + return i1+i2+i3+i4+i5; +} + +/************************************************************/ +/* */ +/* a class to test overloading */ +/* */ +/************************************************************/ + +struct OverloadTest +{ + OverloadTest(): x_(1000) {} + OverloadTest(int x): x_(x) {} + OverloadTest(int x,int y): x_(x+y) { } + OverloadTest(int x,int y,int z): x_(x+y+z) {} + OverloadTest(int x,int y,int z, int a): x_(x+y+z+a) {} + OverloadTest(int x,int y,int z, int a, int b): x_(x+y+z+a+b) {} + + int x() const { return x_; } + void setX(int x) { x_ = x; } + + int p1(int x) { return x; } + int p2(int x, int y) { return x + y; } + int p3(int x, int y, int z) { return x + y + z; } + int p4(int x, int y, int z, int a) { return x + y + z + a; } + int p5(int x, int y, int z, int a, int b) { return x + y + z + a + b; } + private: + int x_; +}; + +static int getX(OverloadTest* u) +{ + return u->x(); +} + + +/************************************************************/ +/* */ +/* classes to test base declarations and conversions */ +/* */ +/************************************************************/ + +struct Dummy +{ + virtual ~Dummy() {} + int dummy_; +}; + +struct Base +{ + virtual int x() const { return 999; }; + virtual ~Base() {} +}; + +// inherit Dummy so that the Base part of Concrete starts at an offset +// otherwise, typecast tests wouldn't be very meaningful +struct Derived1 : public Dummy, public Base +{ + Derived1(int x): x_(x) {} + virtual int x() const { return x_; } + + private: + int x_; +}; + +struct Derived2 : public Dummy, public Base +{ + Derived2(int x): x_(x) {} + virtual int x() const { return x_; } + + private: + int x_; +}; + +static int testUpcast(Base* b) +{ + return b->x(); +} + +static std::auto_ptr derived1Factory(int i) +{ + return std::auto_ptr(new Derived1(i)); +} + +static std::auto_ptr derived2Factory(int i) +{ + return std::auto_ptr(new Derived2(i)); +} + +static int testDowncast1(Derived1* d) +{ + return d->x(); +} + +static int testDowncast2(Derived2* d) +{ + return d->x(); +} + +/************************************************************/ +/* */ +/* test classes for interaction of overloading, */ +/* base declarations, and callbacks */ +/* */ +/************************************************************/ + +struct CallbackTestBase +{ + virtual int testCallback(int i) { return callback(i); } + virtual int callback(int i) = 0; + virtual ~CallbackTestBase() {} +}; + +struct CallbackTest : public CallbackTestBase +{ + virtual int callback(int i) { return i + 1; } + virtual std::string callbackString(std::string const & i) { return i + " 1"; } +}; + +struct CallbackTestCallback : public CallbackTest +{ + CallbackTestCallback(PyObject* self) + : m_self(self) + {} + + int callback(int x) + { + return boost::python::callback::call_method(m_self, "callback", x); + } + std::string callbackString(std::string const & x) + { + return boost::python::callback::call_method(m_self, "callback", x); + } + + static int default_callback(CallbackTest* self, int x) + { + return self->CallbackTest::callback(x); + } + static std::string default_callbackString(CallbackTest* self, std::string x) + { + return self->CallbackTest::callbackString(x); + } + + PyObject* m_self; +}; + +int testCallback(CallbackTestBase* b, int i) +{ + return b->testCallback(i); +} + +/************************************************************/ +/* */ +/* test classes for interaction of method lookup */ +/* in the context of inheritance */ +/* */ +/************************************************************/ + +struct A1 { + virtual ~A1() {} + virtual std::string overrideA1() const { return "A1::overrideA1"; } + virtual std::string inheritA1() const { return "A1::inheritA1"; } +}; + +struct A2 { + virtual ~A2() {} + virtual std::string inheritA2() const { return "A2::inheritA2"; } +}; + +struct B1 : A1, A2 { + std::string overrideA1() const { return "B1::overrideA1"; } + virtual std::string overrideB1() const { return "B1::overrideB1"; } +}; + +struct B2 : A1, A2 { + std::string overrideA1() const { return "B2::overrideA1"; } + virtual std::string inheritB2() const { return "B2::inheritB2"; } +}; + +struct C : B1 { + std::string overrideB1() const { return "C::overrideB1"; } +}; + +std::string call_overrideA1(const A1& a) { return a.overrideA1(); } +std::string call_overrideB1(const B1& b) { return b.overrideB1(); } +std::string call_inheritA1(const A1& a) { return a.inheritA1(); } + +std::auto_ptr factoryA1asA1() { return std::auto_ptr(new A1); } +std::auto_ptr factoryB1asA1() { return std::auto_ptr(new B1); } +std::auto_ptr factoryB2asA1() { return std::auto_ptr(new B2); } +std::auto_ptr factoryCasA1() { return std::auto_ptr(new C); } +std::auto_ptr factoryA2asA2() { return std::auto_ptr(new A2); } +std::auto_ptr factoryB1asA2() { return std::auto_ptr(new B1); } +std::auto_ptr factoryB1asB1() { return std::auto_ptr(new B1); } +std::auto_ptr factoryCasB1() { return std::auto_ptr(new C); } + +struct B_callback : B1 { + B_callback(PyObject* self) : m_self(self) {} + + std::string overrideA1() const { return boost::python::callback::call_method(m_self, "overrideA1"); } + std::string overrideB1() const { return boost::python::callback::call_method(m_self, "overrideB1"); } + + static std::string default_overrideA1(B1& x) { return x.B1::overrideA1(); } + static std::string default_overrideB1(B1& x) { return x.B1::overrideB1(); } + + PyObject* m_self; +}; + +struct A_callback : A1 { + A_callback(PyObject* self) : m_self(self) {} + + std::string overrideA1() const { return boost::python::callback::call_method(m_self, "overrideA1"); } + std::string inheritA1() const { return boost::python::callback::call_method(m_self, "inheritA1"); } + + static std::string default_overrideA1(A1& x) { return x.A1::overrideA1(); } + static std::string default_inheritA1(A1& x) { return x.A1::inheritA1(); } + + PyObject* m_self; +}; + +/************************************************************/ +/* */ +/* RawTest */ +/* (test passing of raw arguments to C++) */ +/* */ +/************************************************************/ + +struct RawTest +{ + RawTest(int i) : i_(i) {} + + int i_; +}; + +PyObject* raw(boost::python::tuple const & args, boost::python::dictionary const & keywords); + +int raw1(PyObject* args, PyObject* keywords) +{ + return PyTuple_Size(args) + PyDict_Size(keywords); +} + +int raw2(boost::python::ref args, boost::python::ref keywords) +{ + return PyTuple_Size(args.get()) + PyDict_Size(keywords.get()); +} + + + +/************************************************************/ +/* */ +/* Ratio */ +/* */ +/************************************************************/ + +typedef boost::rational Ratio; + +boost::python::string ratio_str(const Ratio& r) +{ + char buf[200]; + + if (r.denominator() == 1) + sprintf(buf, "%d", r.numerator()); + else + sprintf(buf, "%d/%d", r.numerator(), r.denominator()); + + return boost::python::string(buf); +} + +boost::python::string ratio_repr(const Ratio& r) +{ + char buf[200]; + sprintf(buf, "Rational(%d, %d)", r.numerator(), r.denominator()); + return boost::python::string(buf); +} + +boost::python::tuple ratio_coerce(const Ratio& r1, int r2) +{ + return boost::python::tuple(r1, Ratio(r2)); +} + +// The most reliable way, across compilers, to grab the particular abs function +// we're interested in. +Ratio ratio_abs(const Ratio& r) +{ + return boost::abs(r); +} + +// An experiment, to be integrated into the py_cpp library at some point. +template +struct StandardOps +{ + static T add(const T& x, const T& y) { return x + y; } + static T sub(const T& x, const T& y) { return x - y; } + static T mul(const T& x, const T& y) { return x * y; } + static T div(const T& x, const T& y) { return x / y; } + static T cmp(const T& x, const T& y) { return std::less()(x, y) ? -1 : std::less()(y, x) ? 1 : 0; } +}; + +// This helps us prove that we can now pass non-const reference parameters to constructors +struct Fubar { + Fubar(Foo&) {} + Fubar(int) {} +}; + +/************************************************************/ +/* */ +/* Int */ +/* this class tests operator export */ +/* */ +/************************************************************/ + +#ifndef NDEBUG +int total_Ints = 0; +#endif + +struct Int +{ + explicit Int(int i) : i_(i) { +#ifndef NDEBUG + ++total_Ints; +#endif + } + +#ifndef NDEBUG + ~Int() { --total_Ints; } + Int(const Int& rhs) : i_(rhs.i_) { ++total_Ints; } +#endif + + int i() const { return i_; } + + int i_; +}; + +Int operator+(Int const & l, Int const & r) { return Int(l.i_ + r.i_); } +Int operator+(Int const & l, int const & r) { return Int(l.i_ + r); } +Int operator+(int const & l, Int const & r) { return Int(l + r.i_); } + +Int operator-(Int const & l, Int const & r) { return Int(l.i_ - r.i_); } +Int operator-(Int const & l, int const & r) { return Int(l.i_ - r); } +Int operator-(int const & l, Int const & r) { return Int(l - r.i_); } +Int operator-(Int const & r) { return Int(- r.i_); } + +Int mul(Int const & l, Int const & r) { return Int(l.i_ * r.i_); } +Int imul(Int const & l, int const & r) { return Int(l.i_ * r); } +Int rmul(Int const & r, int const & l) { return Int(l * r.i_); } + +Int operator/(Int const & l, Int const & r) { return Int(l.i_ / r.i_); } + +Int operator%(Int const & l, Int const & r) { return Int(l.i_ % r.i_); } + +bool operator<(Int const & l, Int const & r) { return l.i_ < r.i_; } +bool operator<(Int const & l, int const & r) { return l.i_ < r; } +bool operator<(int const & l, Int const & r) { return l < r.i_; } + +Int pow(Int const & l, Int const & r) { return Int(static_cast(::pow(l.i_, r.i_))); } +Int powmod(Int const & l, Int const & r, Int const & m) { return Int((int)::pow(l.i_, r.i_) % m.i_); } +Int pow(Int const & l, int const & r) { return Int(static_cast(::pow(l.i_, r))); } + +std::ostream & operator<<(std::ostream & o, Int const & r) { return (o << r.i_); } + +/************************************************************/ +/* */ +/* double tests from Mark Evans() */ +/* */ +/************************************************************/ +double sizelist(boost::python::list list) { return list.size(); } +void vd_push_back(std::vector& vd, const double& x) +{ + vd.push_back(x); +} + +/************************************************************/ +/* */ +/* What if I want to return a pointer? */ +/* */ +/************************************************************/ + +// +// This example exposes the pointer by copying its referent +// +struct Record { + Record(int x) : value(x){} + int value; +}; + +const Record* get_record() +{ + static Record v(1234); + return &v; +} + +template class boost::python::class_builder; // explicitly instantiate + +} // namespace extclass_demo + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE +inline PyObject* to_python(const extclass_demo::Record* p) +{ + return to_python(*p); +} +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +/************************************************************/ +/* */ +/* Enums and non-method class attributes */ +/* */ +/************************************************************/ + +namespace extclass_demo { + +struct EnumOwner +{ + public: + enum enum_type { one = 1, two = 2, three = 3 }; + + EnumOwner(enum_type a1, const enum_type& a2) + : m_first(a1), m_second(a2) {} + + void set_first(const enum_type& x) { m_first = x; } + void set_second(const enum_type& x) { m_second = x; } + + enum_type first() { return m_first; } + enum_type second() { return m_second; } + private: + enum_type m_first, m_second; +}; + +} + +namespace boost { namespace python { + template class enum_as_int_converters; + using extclass_demo::pow; +}} // namespace boost::python + +// This is just a way of getting the converters instantiated +//struct EnumOwner_enum_type_Converters +// : boost::python::py_enum_as_int_converters +//{ +//}; + +namespace extclass_demo { + +/************************************************************/ +/* */ +/* pickling support */ +/* */ +/************************************************************/ + class world + { + private: + std::string country; + int secret_number; + public: + world(const std::string& country) : secret_number(0) { + this->country = country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + void set_secret_number(int number) { secret_number = number; } + int get_secret_number() const { return secret_number; } + }; + + // Support for pickle. + boost::python::tuple world_getinitargs(const world& w) + { + boost::python::tuple result(1); + result.set_item(0, w.get_country()); + return result; + } + + boost::python::tuple world_getstate(const world& w) + { + boost::python::tuple result(1); + result.set_item(0, w.get_secret_number()); + return result; + } + + void world_setstate(world& w, boost::python::tuple state) + { + if (state.size() != 1) { + PyErr_SetString(PyExc_ValueError, + "Unexpected argument in call to __setstate__."); + throw boost::python::error_already_set(); + } + + const int number = BOOST_PYTHON_CONVERSION::from_python(state[0].get(), boost::python::type()); + if (number != 42) + w.set_secret_number(number); + } + +/************************************************************/ +/* */ +/* init the module */ +/* */ +/************************************************************/ + +void init_module(boost::python::module_builder& m) +{ + m.def(get_record, "get_record"); + boost::python::class_builder record_class(m, "Record"); + record_class.def_readonly(&Record::value, "value"); + + m.def(sizelist, "sizelist"); + + boost::python::class_builder > vector_double(m, "vector_double"); + vector_double.def(boost::python::constructor<>()); + vector_double.def(vd_push_back, "push_back"); + + boost::python::class_builder fubar(m, "Fubar"); + fubar.def(boost::python::constructor()); + fubar.def(boost::python::constructor()); + + Foo::PythonClass foo(m); + BarPythonClass bar(m); + BazPythonClass baz(m); + StringMapPythonClass string_map(m); + IntPairPythonClass int_pair(m); + m.def(make_pair, "make_pair"); + CompareIntPairPythonClass compare_int_pair(m); + + boost::python::class_builder string_pair(m, "StringPair"); + string_pair.def(boost::python::constructor()); + string_pair.def_readonly(&StringPair::first, "first"); + string_pair.def_read_write(&StringPair::second, "second"); + string_pair.def(&stringpair_repr, "__repr__"); + string_pair.def(&stringpair_compare, "__cmp__"); + m.def(first_string, "first_string"); + m.def(second_string, "second_string"); + + // This shows the wrapping of a 3rd-party numeric type. + boost::python::class_builder > rational(m, "Rational"); + rational.def(boost::python::constructor()); + rational.def(boost::python::constructor()); + rational.def(boost::python::constructor<>()); + rational.def(StandardOps::add, "__add__"); + rational.def(StandardOps::sub, "__sub__"); + rational.def(StandardOps::mul, "__mul__"); + rational.def(StandardOps::div, "__div__"); + rational.def(StandardOps::cmp, "__cmp__"); + rational.def(ratio_coerce, "__coerce__"); + rational.def(ratio_str, "__str__"); + rational.def(ratio_repr, "__repr__"); + rational.def(ratio_abs, "__abs__"); + + boost::python::class_builder range(m, "Range"); + range.def(boost::python::constructor()); + range.def(boost::python::constructor()); + range.def((void (Range::*)(std::size_t))&Range::length, "__len__"); + range.def((std::size_t (Range::*)() const)&Range::length, "__len__"); + range.def(&Range::operator[], "__getitem__"); + range.def(&Range::slice, "__getslice__"); + range.def(&range_str, "__str__"); + range.def(&range_compare, "__cmp__"); + range.def(&range_hash, "__hash__"); + range.def_readonly(&Range::m_start, "start"); + range.def_readonly(&Range::m_finish, "finish"); + + m.def(&testVoid, "overloaded"); + m.def(&testInt, "overloaded"); + m.def(&testString, "overloaded"); + m.def(&test2, "overloaded"); + m.def(&test3, "overloaded"); + m.def(&test4, "overloaded"); + m.def(&test5, "overloaded"); + + boost::python::class_builder over(m, "OverloadTest"); + over.def(boost::python::constructor<>()); + over.def(boost::python::constructor()); + over.def(boost::python::constructor()); + over.def(boost::python::constructor()); + over.def(boost::python::constructor()); + over.def(boost::python::constructor()); + over.def(boost::python::constructor()); + over.def(&getX, "getX"); + over.def(&OverloadTest::setX, "setX"); + over.def(&OverloadTest::x, "overloaded"); + over.def(&OverloadTest::p1, "overloaded"); + over.def(&OverloadTest::p2, "overloaded"); + over.def(&OverloadTest::p3, "overloaded"); + over.def(&OverloadTest::p4, "overloaded"); + over.def(&OverloadTest::p5, "overloaded"); + + boost::python::class_builder base(m, "Base"); + base.def(&Base::x, "x"); + + boost::python::class_builder derived1(m, "Derived1"); + // this enables conversions between Base and Derived1 + // and makes wrapped methods of Base available + derived1.declare_base(base); + derived1.def(boost::python::constructor()); + + boost::python::class_builder derived2(m, "Derived2"); + // don't enable downcast from Base to Derived2 + derived2.declare_base(base, boost::python::without_downcast); + derived2.def(boost::python::constructor()); + + m.def(&testUpcast, "testUpcast"); + m.def(&derived1Factory, "derived1Factory"); + m.def(&derived2Factory, "derived2Factory"); + m.def(&testDowncast1, "testDowncast1"); + m.def(&testDowncast2, "testDowncast2"); + + boost::python::class_builder callbackTestBase(m, "CallbackTestBase"); + callbackTestBase.def(&CallbackTestBase::testCallback, "testCallback"); + m.def(&testCallback, "testCallback"); + + boost::python::class_builder callbackTest(m, "CallbackTest"); + callbackTest.def(boost::python::constructor<>()); + callbackTest.def(&CallbackTest::callback, "callback", + &CallbackTestCallback::default_callback); + callbackTest.def(&CallbackTest::callbackString, "callback", + &CallbackTestCallback::default_callbackString); + + callbackTest.declare_base(callbackTestBase); + + boost::python::class_builder a1_class(m, "A1"); + a1_class.def(boost::python::constructor<>()); + a1_class.def(&A1::overrideA1, "overrideA1", &A_callback::default_overrideA1); + a1_class.def(&A1::inheritA1, "inheritA1", &A_callback::default_inheritA1); + + boost::python::class_builder a2_class(m, "A2"); + a2_class.def(boost::python::constructor<>()); + a2_class.def(&A2::inheritA2, "inheritA2"); + + boost::python::class_builder b1_class(m, "B1"); + b1_class.declare_base(a1_class); + b1_class.declare_base(a2_class); + + b1_class.def(boost::python::constructor<>()); + b1_class.def(&B1::overrideA1, "overrideA1", &B_callback::default_overrideA1); + b1_class.def(&B1::overrideB1, "overrideB1", &B_callback::default_overrideB1); + + boost::python::class_builder b2_class(m, "B2"); + b2_class.declare_base(a1_class); + b2_class.declare_base(a2_class); + + b2_class.def(boost::python::constructor<>()); + b2_class.def(&B2::overrideA1, "overrideA1"); + b2_class.def(&B2::inheritB2, "inheritB2"); + + m.def(call_overrideA1, "call_overrideA1"); + m.def(call_overrideB1, "call_overrideB1"); + m.def(call_inheritA1, "call_inheritA1"); + + m.def(factoryA1asA1, "factoryA1asA1"); + m.def(factoryB1asA1, "factoryB1asA1"); + m.def(factoryB2asA1, "factoryB2asA1"); + m.def(factoryCasA1, "factoryCasA1"); + m.def(factoryA2asA2, "factoryA2asA2"); + m.def(factoryB1asA2, "factoryB1asA2"); + m.def(factoryB1asB1, "factoryB1asB1"); + m.def(factoryCasB1, "factoryCasB1"); + + boost::python::class_builder rawtest_class(m, "RawTest"); + rawtest_class.def(boost::python::constructor()); + rawtest_class.def_raw(&raw, "raw"); + + m.def_raw(&raw, "raw"); + m.def_raw(&raw1, "raw1"); + m.def_raw(&raw2, "raw2"); + + boost::python::class_builder int_class(m, "Int"); + int_class.def(boost::python::constructor()); + int_class.def(&Int::i, "i"); + + // wrap homogeneous operators + int_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub | boost::python::op_neg | + boost::python::op_cmp | boost::python::op_str | boost::python::op_divmod | boost::python::op_pow )>()); + // export non-operator functions as homogeneous operators + int_class.def(&mul, "__mul__"); + int_class.def(&powmod, "__pow__"); + + // wrap heterogeneous operators (lhs: Int const &, rhs: int const &) + int_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub | boost::python::op_cmp | boost::python::op_pow)>(), + boost::python::right_operand()); + // export non-operator function as heterogeneous operator + int_class.def(&imul, "__mul__"); + + // wrap heterogeneous operators (lhs: int const &, rhs: Int const &) + int_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub | boost::python::op_cmp)>(), + boost::python::left_operand()); + // export non-operator function as heterogeneous reverse-argument operator + int_class.def(&rmul, "__rmul__"); + + + boost::python::class_builder enum_owner(m, "EnumOwner"); + enum_owner.def(boost::python::constructor()); + enum_owner.def(&EnumOwner::set_first, "__setattr__first__"); + enum_owner.def(&EnumOwner::set_second, "__setattr__second__"); + enum_owner.def(&EnumOwner::first, "__getattr__first__"); + enum_owner.def(&EnumOwner::second, "__getattr__second__"); + enum_owner.add(PyInt_FromLong(EnumOwner::one), "one"); + enum_owner.add(PyInt_FromLong(EnumOwner::two), "two"); + enum_owner.add(PyInt_FromLong(EnumOwner::three), "three"); + + // pickling support + + // Create the Python type object for our extension class. + boost::python::class_builder world_class(m, "world"); + + // Add the __init__ function. + world_class.def(boost::python::constructor()); + // Add a regular member function. + world_class.def(&world::greet, "greet"); + world_class.def(&world::get_secret_number, "get_secret_number"); + world_class.def(&world::set_secret_number, "set_secret_number"); + + // Support for pickle. + world_class.def(world_getinitargs, "__getinitargs__"); + world_class.def(world_getstate, "__getstate__"); + world_class.def(world_setstate, "__setstate__"); +} + +PyObject* raw(boost::python::tuple const& args, boost::python::dictionary const& keywords) +{ + if(args.size() != 2 || keywords.size() != 2) + { + PyErr_SetString(PyExc_TypeError, "wrong number of arguments"); + throw boost::python::argument_error(); + } + + RawTest* first = BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()); + int second = BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type()); + + int third = BOOST_PYTHON_CONVERSION::from_python(keywords[boost::python::string("third")].get(), boost::python::type()); + int fourth = BOOST_PYTHON_CONVERSION::from_python(keywords[boost::python::string("fourth")].get(), boost::python::type()); + + return BOOST_PYTHON_CONVERSION::to_python(first->i_ + second + third + fourth); +} + +void init_module() +{ + boost::python::module_builder demo("demo"); + init_module(demo); + + // Just for giggles, add a raw metaclass. + demo.add(new boost::python::meta_class); +} + +extern "C" +#ifdef _WIN32 +__declspec(dllexport) +#endif +void initdemo() +{ + try { + extclass_demo::init_module(); + } + catch(...) { + boost::python::handle_exception(); + } // Need a way to report other errors here +} + +CompareIntPairPythonClass::CompareIntPairPythonClass(boost::python::module_builder& m) + : boost::python::class_builder(m, "CompareIntPair") +{ + def(boost::python::constructor<>()); + def(&CompareIntPair::operator(), "__call__"); +} + +} // namespace extclass_demo + + +#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 + +#ifndef NDEBUG +namespace boost { namespace python { namespace detail { + extern int total_Dispatchers; +}}} // namespace boost::python::detail +#endif + +BOOL WINAPI DllMain( + HINSTANCE, //hDllInst + DWORD fdwReason, + LPVOID // lpvReserved + ) +{ +# ifdef BOOST_MSVC + _set_se_translator(structured_exception_translator); +#endif + (void)fdwReason; // warning suppression. + +#ifndef NDEBUG + switch(fdwReason) + { + case DLL_PROCESS_DETACH: + assert(extclass_demo::total_Ints == 0); + } +#endif + + return 1; +} +#endif // _WIN32 diff --git a/test/comprehensive.hpp b/test/comprehensive.hpp new file mode 100644 index 00000000..d8a8e8ea --- /dev/null +++ b/test/comprehensive.hpp @@ -0,0 +1,231 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +#ifndef EXTCLASS_DEMO_DWA052200_H_ +# define EXTCLASS_DEMO_DWA052200_H_ +// +// Example code demonstrating extension class usage +// + +# include +# include +# include +# include +# include +# include +# include +# include + +namespace extclass_demo { + +// +// example: Foo, Bar, and Baz are C++ classes we want to wrap. +// + +class Foo // prohibit copying, proving that it doesn't choke + : boost::noncopyable // our generation of to_python(). +{ + public: // constructor/destructor + Foo(int x) : m_x(x) {} + virtual ~Foo() {} + + public: // non-virtual functions + const char* mumble(); // mumble something + void set(long x); // change the held value + + // These two call virtual functions + std::string call_pure(); // call a pure virtual fuction + int call_add_len(const char* s) const; // virtual function with a default implementation + + private: + // by default, sum the held value and the length of s + virtual int add_len(const char* s) const; + + // Derived classes can do whatever they want here, but they must do something! + virtual std::string pure() const = 0; + + public: // friend declarations + // If you have private virtual functions such as add_len which you want to + // override in Python and have default implementations, they must be + // accessible by the thing making the def() call on the extension_class (in + // this case, the nested PythonClass itself), and by the C++ derived class + // which is used to cause the Python callbacks (in this case, + // FooCallback). See the definition of FooCallback::add_len() + struct PythonClass; + friend struct PythonClass; + friend class FooCallback; + + private: + int m_x; // the held value +}; + +// +// Bar and Baz have mutually-recursive type conversion dependencies (see +// pass_xxx functions). I've done this to prove that it doesn't cause a +// problem for Python class definitions, which happen later. +// +// Bar and Baz functions are only virtual to increase the likelihood of a crash +// if I inadvertently use a pointer to garbage memory (a likely thing to test +// for considering the amount of type casting needed to translate to and from +// Python). +struct Baz; +struct Bar +{ + Bar(int x, int y) : m_first(x), m_second(y) {} + virtual int first() const { return m_first; } + virtual int second() const { return m_second; } + virtual Baz pass_baz(Baz x); + + int m_first, m_second; +}; + +struct Baz +{ + virtual Bar pass_bar(const Bar& x) { return x; } + + // We can return smart pointers + virtual std::auto_ptr clone() { return std::auto_ptr(new Baz(*this)); } + + // This illustrates creating a polymorphic derived class of Foo + virtual boost::shared_ptr create_foo(); + + // We can accept smart pointer parameters + virtual int get_foo_value(boost::shared_ptr); + + // Show what happens in python when we take ownership from an auto_ptr + virtual void eat_baz(std::auto_ptr); +}; + +typedef std::map StringMap; +typedef std::pair IntPair; + +IntPair make_pair(int, int); + +typedef std::less CompareIntPair; +typedef std::pair StringPair; + +inline std::string first_string(const StringPair& x) +{ + return x.first; +} + +inline std::string second_string(const StringPair& x) +{ + return x.second; +} + +struct Range +{ + Range(int x) + : m_start(x), m_finish(x) {} + + Range(int start, int finish) + : m_start(start), m_finish(finish) {} + + std::size_t length() const + { return m_finish < m_start ? 0 : m_finish - m_start; } + + void length(std::size_t new_length) + { m_finish = m_start + new_length; } + + int operator[](std::size_t n) + { return m_start + n; } + + Range slice(std::size_t start, std::size_t end) + { + if (start > length()) + start = length(); + if (end > length()) + end = length(); + return Range(m_start + start, m_start + end); + } + + int m_start, m_finish; +}; + +//////////////////////////////////////////////////////////////////////// +// // +// Begin wrapping code. Usually this would live in a separate header. // +// // +//////////////////////////////////////////////////////////////////////// + +// Since Foo has virtual functions which we want overriden in Python, we must +// derive FooCallback. +class FooCallback : public Foo +{ + public: + // Note the additional constructor parameter "self", which is needed to + // allow function overriding from Python. + FooCallback(PyObject* self, int x); + + friend struct PythonClass; // give it access to the functions below + + private: // implementations of Foo virtual functions that are overridable in python. + int add_len(const char* x) const; + + // A function which Python can call in case bar is not overridden from + // Python. In true Python style, we use a free function taking an initial + // self parameter. You can put this function anywhere; it needn't be a + // static member of the wrapping class. + static int default_add_len(const Foo* self, const char* x); + + // Since Foo::pure() is pure virtual, we don't need a corresponding + // default_pure(). A failure to override it in Python will result in an + // exception at runtime when pure() is called. + std::string pure() const; + + private: // Required boilerplate if functions will be overridden + PyObject* m_self; // No, we don't want a boost::python::ref here, or we'd get an ownership cycle. +}; + +// Define the Python base class +struct Foo::PythonClass : boost::python::class_builder { PythonClass(boost::python::module_builder&); }; + +// No virtual functions on Bar or Baz which are actually supposed to behave +// virtually from C++, so we'll rely on the library to define a wrapper for +// us. Even so, Python class_t types for each type we're wrapping should be +// _defined_ here in a header where they can be seen by other extension class +// definitions, since it is the definition of the boost::python::class_builder<> that +// causes to_python/from_python conversion functions to be generated. +struct BarPythonClass : boost::python::class_builder { BarPythonClass(boost::python::module_builder&); }; +struct BazPythonClass : boost::python::class_builder { BazPythonClass(boost::python::module_builder&); }; + +struct StringMapPythonClass + : boost::python::class_builder +{ + StringMapPythonClass(boost::python::module_builder&); + + // These static functions implement the right argument protocols for + // implementing the Python "special member functions" for mapping on + // StringMap. Could just as easily be global functions. + static const std::string& get_item(const StringMap& m, std::size_t key); + static void set_item(StringMap& m, std::size_t key, const std::string& value); + static void del_item(StringMap& m, std::size_t key); +}; + +struct IntPairPythonClass + : boost::python::class_builder +{ + IntPairPythonClass(boost::python::module_builder&); + + // The following could just as well be a free function; it implements the + // getattr functionality for IntPair. + static int getattr(const IntPair&, const std::string& s); + static void setattr(IntPair&, const std::string& name, int value); + static void delattr(IntPair&, const char* name); +}; + +struct CompareIntPairPythonClass + : boost::python::class_builder +{ + CompareIntPairPythonClass(boost::python::module_builder&); +}; + +} // namespace extclass_demo + +#endif // EXTCLASS_DEMO_DWA052200_H_ diff --git a/test/comprehensive.py b/test/comprehensive.py new file mode 100644 index 00000000..578197f1 --- /dev/null +++ b/test/comprehensive.py @@ -0,0 +1,1087 @@ +r''' +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +Automatic checking of the number and type of arguments. Foo's constructor takes +a single long parameter. + + >>> ext = Foo() + Traceback (innermost last): + File "", line 1, in ? + TypeError: function requires exactly 1 argument; 0 given + + >>> try: ext = Foo('foo') + ... except TypeError, err: + ... assert re.match( + ... '(illegal argument type for built-in operation)|(an integer is required)', str(err)) + ... else: print 'no exception' + + >>> ext = Foo(1) + +Call a virtual function. This call takes a trip into C++ where +FooCallback::add_len() looks up the Python "add_len" attribute and finds the +wrapper for FooCallback::default_add_len(), which in turn calls Foo::add_len(). + + >>> ext.add_len('hello') + 6 + >>> ext.set(3) + >>> ext.add_len('hello') + 8 + +Call a pure virtual function which should have been overridden, but was not. + + >>> ext.call_pure() + Traceback (innermost last): + File "", line 1, in ? + AttributeError: pure + +We can subclass Foo. + + >>> class Subclass(Foo): + ... def __init__(self, seq): + ... Foo.__init__(self, len(seq)) + ... + ... def pure(self): + ... return 'not pure anymore!' + ... + ... def get(self): + ... return Foo.add_len(self, '') + ... + ... def add_len(self, s): + ... print 'called add_len()' + ... return self.get() + len(s) + ... + >>> b = Subclass('yippee') + >>> b.get() + 6 + >>> b.mumble() + 'mumble' + >>> b.call_pure() + 'not pure anymore!' + +If no __init__ function is defined, the one from the base class takes effect, just +like in a Python class. + + >>> class DemonstrateInitPassthru(Foo): pass + ... + >>> q = DemonstrateInitPassthru(1) + >>> q.add_len("x") + 2 + +If we don't initialize the base class, we'll get a RuntimeError when we try to +use its methods. The test illustrates the kind of error to expect. + + >>> class BadSubclass(Foo): + ... def __init__(self): pass + ... + >>> barf = BadSubclass() + >>> barf.set(4) + Traceback (innermost last): + ... + RuntimeError: __init__ function for extension class 'Foo' was never called. + +Here we are tesing that the simple definition procedure used in the C++ demo +file for classes without any virtual functions actually worked. + + >>> bar = Bar(3, 4) + >>> bar.first() + 3 + >>> bar.second() + 4 + >>> baz = Baz() + +We can actually return the wrapped classes by value + + >>> baz.pass_bar(bar).first() + 3 + >>> bar.pass_baz(baz) is baz # A copy of the return value is made. + 0 + >>> type(bar.pass_baz(baz)) is type(baz) + 1 + +And, yes, we can multiply inherit from these classes. + + >>> class MISubclass(Subclass, Bar): + ... def __init__(self, s): + ... Subclass.__init__(self, s) + ... Bar.__init__(self, 0, len(s)) + ... + >>> mi = MISubclass('xx') + >>> mi.first() + 0 + >>> mi.second() + 2 + >>> mi.mumble() + 'mumble' + +We can even mulitply inherit from built-in Python classes, even if they are +first in the list of bases + + >>> class RealPythonClass: + ... def real_python_method(self): + ... print 'RealPythonClass.real_python_method()' + ... def other_first(self, other): + ... return other.first() + + >>> class MISubclass2(RealPythonClass, Bar): + ... def new_method(self): + ... print 'MISubclass2.new_method()' + ... bound_function = RealPythonClass().other_first + ... + >>> mi2 = MISubclass2(7, 8) + >>> mi2.first() # we can call inherited member functions from Bar + 7 + >>> mi2.real_python_method() # we can call inherited member functions from RealPythonClass + RealPythonClass.real_python_method() + + >>> mi2.new_method() # we can call methods on the common derived class + MISubclass2.new_method() + + We can call unbound methods from the base class accessed through the derived class + >>> MISubclass2.real_python_method(mi2) + RealPythonClass.real_python_method() + + We have not interfered with ordinary python bound methods + >>> MISubclass2.bound_function(mi2) + 7 + >>> mi2.bound_function() + 7 + +Any object whose class is derived from Bar can be passed to a function expecting +a Bar parameter: + + >>> baz.pass_bar(mi).first() + 0 + +But objects not derived from Bar cannot: + + >>> baz.pass_bar(baz) + Traceback (innermost last): + ... + TypeError: extension class 'Baz' is not convertible into 'Bar'. + +The clone function on Baz returns a smart pointer; we wrap it into an +extension_instance and make it look just like any other Baz obj. + + >>> baz_clone = baz.clone() + >>> baz_clone.pass_bar(mi).first() + 0 + +Functions expecting an std::auto_ptr parameter will not accept a raw Baz + + >>> try: baz.eat_baz(Baz()) + ... except RuntimeError, err: + ... assert re.match("Object of extension class 'Baz' does not wrap <.*>.", + ... str(err)) + ... else: + ... print 'no exception' + +We can pass std::auto_ptr where it is expected + + >>> baz.eat_baz(baz_clone) + +And if the auto_ptr has given up ownership? + + # MSVC6 ships with an outdated auto_ptr that doesn't get zeroed out when it + # gives up ownership. If you are using MSVC6 without the new Dinkumware + # library, SGI STL or the STLport, expect this test to crash unless you put + # --broken-auto-ptr on the command line. + >>> if not '--broken-auto-ptr' in sys.argv: + ... try: baz_clone.clone() + ... except RuntimeError, err: + ... assert re.match('Converting from python, pointer or smart pointer to <.*> is NULL.', str(err)) + ... else: + ... print 'no exeption' + +Polymorphism also works: + + >>> polymorphic_foo = baz.create_foo() + >>> polymorphic_foo.call_pure() + 'this was never pure!' + >>> baz.get_foo_value(polymorphic_foo) + 1000 + +Pickling tests: + + >>> world.__module__ + 'demo' + >>> world.__safe_for_unpickling__ + 1 + >>> world.__reduce__() + 'world' + >>> reduced = world('Hello').__reduce__() + >>> reduced[0] == world + 1 + >>> reduced[1:] + (('Hello',), (0,)) + >>> import StringIO + >>> import cPickle + >>> pickle = cPickle + >>> for number in (24, 42): + ... wd = world('California') + ... wd.set_secret_number(number) + ... # Dump it out and read it back in. + ... f = StringIO.StringIO() + ... pickle.dump(wd, f) + ... f = StringIO.StringIO(f.getvalue()) + ... wl = pickle.load(f) + ... # + ... print wd.greet(), wd.get_secret_number() + ... print wl.greet(), wl.get_secret_number() + ... + Hello from California! 24 + Hello from California! 24 + Hello from California! 42 + Hello from California! 0 + +Special member attributes. Tests courtesy of Barry Scott + + >>> class DerivedFromFoo(Foo): + ... def __init__(self): + ... Foo.__init__( self, 1 ) + ... def fred(self): + ... 'Docs for DerivedFromFoo.fred' + ... print 'Barry.fred' + ... def __del__(self): + ... print 'Deleting DerivedFromFoo' + + >>> class Base: + ... i_am_base = 'yes' + ... def fred(self): + ... 'Docs for Base.fred' + ... pass + + + >>> class DerivedFromBase(Base): + ... i_am_derived_from_base = 'yes' + ... def fred(self): + ... 'Docs for DerivedFromBase.fred' + ... pass + + >>> df = DerivedFromFoo() + >>> dir(df) + [] + >>> dir(DerivedFromFoo) + ['__del__', '__doc__', '__init__', '__module__', 'fred'] + >>> df.__dict__ + {} + + >>> df.fred.__doc__ + 'Docs for DerivedFromFoo.fred' + >>> db = DerivedFromBase() + >>> dir(db) + [] + >>> dir(DerivedFromBase) + ['__doc__', '__module__', 'fred', 'i_am_derived_from_base'] + >>> db.__dict__ + {} + >>> db.fred.__doc__ + 'Docs for DerivedFromBase.fred' + +Special member functions in action + >>> del df + Deleting DerivedFromFoo + + # force method table sharing + >>> class DerivedFromStringMap(StringMap): pass + ... + + >>> m = StringMap() + +__getitem__() + >>> m[1] + Traceback (innermost last): + File "", line 1, in ? + KeyError: 1 + +__setitem__() + + >>> m[1] = 'hello' + +__getitem__() + >>> m[1] + 'hello' + +__delitem__() + >>> del m[1] + >>> m[1] # prove that it's gone + Traceback (innermost last): + File "", line 1, in ? + KeyError: 1 + +__delitem__() + >>> del m[2] + Traceback (innermost last): + File "", line 1, in ? + KeyError: 2 + +__length__() + >>> len(m) + 0 + >>> m[3] = 'farther' + >>> len(m) + 1 + +Check for sequence/mapping confusion: + >>> for x in m: + ... print x + ... + Traceback (innermost last): + File "", line 1, in ? + KeyError: 0 + +Check for the ability to pass a non-const reference as a constructor parameter + >>> x = Fubar(Foo(1)) + +Some simple overloading tests: + >>> r = Range(3) + >>> print str(r) + (3, 3) + >>> r.start + 3 + >>> r.finish + 3 + >>> r.__len__() + 0 + >>> r.__len__(4) + >>> r.finish + 7 + >>> try: r = Range('yikes') + ... except TypeError, e: + ... assert re.match( + ... 'No overloaded functions match [(]Range, string[)]\. Candidates are:\n.*\n.*', + ... str(e)) + ... else: print 'no exception' + +Sequence tests: + >>> len(Range(3, 10)) + 7 + + >>> map(lambda x:x, Range(3, 10)) + [3, 4, 5, 6, 7, 8, 9] + + >>> map(lambda x:x, Range(3, 10)[-2:]) + [8, 9] + + >>> map(lambda x:x, Range(3, 10)[:-4]) + [3, 4, 5] + + >>> map(lambda x:x, Range(3, 10)[4:]) + [7, 8, 9] + + >>> map(lambda x:x, Range(3, 10)[4:100]) + [7, 8, 9] + + >>> map(lambda x:x, Range(3, 10)[20:]) + [] + + >>> map(lambda x:x, Range(3, 10)[0:4]) + [3, 4, 5, 6] + +Numeric tests: + >>> x = Rational(2,3) + >>> y = Rational(1,4) + >>> print x + y + 11/12 + >>> print x - y + 5/12 + >>> print x * y + 1/6 + >>> print x / y + 8/3 + >>> print x + 1 # testing coercion + 5/3 + >>> print 1 + x # coercion the other way + 5/3 + +delete non-existent attribute: + del m.foobar + Traceback (innermost last): + File "", line 1, in ? + AttributeError: delete non-existing obj attribute + +Testing __getattr__ and __getattr__: + + >>> n = IntPair(1, 2) + >>> n.first + 1 + >>> n.second + 2 + >>> n.third + Traceback (innermost last): + File "", line 1, in ? + AttributeError: third + +Testing __setattr__ and __setattr__: + >>> n.first = 33 # N.B __setattr__first sets first to + >>> n.first # the negative of its argument. + -33 + >>> n.second = 66 + >>> n.second + 66 + +Testing __delattr__ and __delattr__: + >>> del n.first + Traceback (innermost last): + File "", line 1, in ? + AttributeError: first can't be deleted! + >>> del n.second + Traceback (innermost last): + File "", line 1, in ? + AttributeError: Attributes can't be deleted! + >>> del n.third + Traceback (innermost last): + File "", line 1, in ? + AttributeError: Attributes can't be deleted! + + # Now show that we can override it. + + >>> class IntTriple(IntPair): + ... def __getattr__(self, s): + ... if s in ['first', 'second']: + ... return IntPair.__getattr__(self, s) + ... elif s == 'third': + ... return 3 + ... else: + ... raise AttributeError(s) + ... + ... # Also show that __setattr__ is supported + ... def __setattr__(self, name, value): + ... raise AttributeError('no writable attributes') + ... + >>> p = IntTriple(0, 1) + >>> p.first + 0 + >>> p.second + 1 + >>> p.third + 3 + >>> p.bax + Traceback (innermost last): + File "", line 1, in ? + AttributeError: bax + >>> p.third = 'yes' + Traceback (innermost last): + File "", line 1, in ? + AttributeError: no writable attributes + >>> del p.third + Traceback (innermost last): + File "", line 1, in ? + AttributeError: Attributes can't be deleted! + +demonstrate def_readonly, def_read_write: + >>> sp = StringPair("hello", "world") + >>> sp.first # first is read-only + 'hello' + >>> first_string(sp) # prove that we're not just looking in sp's __dict__ + 'hello' + >>> sp.first = 'hi' # we're not allowed to change it + Traceback (innermost last): + File "", line 1, in ? + AttributeError: 'first' attribute is read-only + >>> first_string(sp) # prove that it hasn't changed + 'hello' + + >>> sp.second # second is read/write + 'world' + >>> second_string(sp) + 'world' + >>> sp.second = 'universe' # set the second attribute + >>> sp.second + 'universe' + >>> second_string(sp) # this proves we didn't just set it in sp's __dict__ + 'universe' + +some __str__ and __repr__ tests: + >>> sp + ('hello', 'universe') + >>> repr(sp) + "('hello', 'universe')" + >>> str(sp) + "('hello', 'universe')" + + Range has a __str__ function but not a __repr__ function + >>> range = Range(5, 20) + >>> str(range) + '(5, 20)' + >>> assert re.match('', repr(range)) + +__hash__ and __cmp__ tests: + # Range has both __hash__ and __cmp__, thus is hashable + >>> colors = { Range(3,4): 'blue', Range(7,9): 'red' } + >>> colors[Range(3,4)] + 'blue' + + # StringPair has only __cmp__ + >>> { StringPair('yo', 'eddy'): 1 } + Traceback (innermost last): + File "", line 1, in ? + TypeError: unhashable type + + # But it can be sorted + >>> stringpairs = [ StringPair('yo', 'eddy'), StringPair('yo', 'betty'), sp ] + >>> stringpairs.sort() + >>> stringpairs + [('hello', 'universe'), ('yo', 'betty'), ('yo', 'eddy')] + +make_pair is a global function in the module. + + >>> couple = make_pair(3,12) + >>> couple.first + 3 + >>> couple.second + 12 + +Testing __call__: + >>> couple2 = make_pair(3, 7) + >>> comparator = CompareIntPair() + >>> comparator(couple, couple) + 0 + >>> comparator(couple, couple2) + 0 + >>> comparator(couple2, couple) + 1 + +Testing overloaded free functions + >>> overloaded() + 'Hello world!' + >>> overloaded(1) + 1 + >>> overloaded('foo') + 'foo' + >>> overloaded(1,2) + 3 + >>> overloaded(1,2,3) + 6 + >>> overloaded(1,2,3,4) + 10 + >>> overloaded(1,2,3,4,5) + 15 + >>> try: overloaded(1, 'foo') + ... except TypeError, err: + ... assert re.match("No overloaded functions match \(int, string\)\. Candidates are:", + ... str(err)) + ... else: + ... print 'no exception' + +Testing overloaded constructors + + >>> over = OverloadTest() + >>> over.getX() + 1000 + >>> over = OverloadTest(1) + >>> over.getX() + 1 + >>> over = OverloadTest(1,1) + >>> over.getX() + 2 + >>> over = OverloadTest(1,1,1) + >>> over.getX() + 3 + >>> over = OverloadTest(1,1,1,1) + >>> over.getX() + 4 + >>> over = OverloadTest(1,1,1,1,1) + >>> over.getX() + 5 + >>> over = OverloadTest(over) + >>> over.getX() + 5 + >>> try: over = OverloadTest(1, 'foo') + ... except TypeError, err: + ... assert re.match("No overloaded functions match \(OverloadTest, int, string\)\. Candidates are:", + ... str(err)) + ... else: + ... print 'no exception' + +Testing overloaded methods + + >>> over.setX(3) + >>> over.overloaded() + 3 + >>> over.overloaded(1) + 1 + >>> over.overloaded(1,1) + 2 + >>> over.overloaded(1,1,1) + 3 + >>> over.overloaded(1,1,1,1) + 4 + >>> over.overloaded(1,1,1,1,1) + 5 + >>> try: over.overloaded(1,'foo') + ... except TypeError, err: + ... assert re.match("No overloaded functions match \(OverloadTest, int, string\)\. Candidates are:", + ... str(err)) + ... else: + ... print 'no exception' + +Testing base class conversions + + >>> testUpcast(over) + Traceback (innermost last): + TypeError: extension class 'OverloadTest' is not convertible into 'Base'. + >>> der1 = Derived1(333) + >>> der1.x() + 333 + >>> testUpcast(der1) + 333 + >>> der1 = derived1Factory(1000) + >>> testDowncast1(der1) + 1000 + >>> testDowncast2(der1) + Traceback (innermost last): + TypeError: extension class 'Base' is not convertible into 'Derived2'. + >>> der2 = Derived2(444) + >>> der2.x() + 444 + >>> testUpcast(der2) + 444 + >>> der2 = derived2Factory(1111) + >>> testDowncast2(der2) + Traceback (innermost last): + TypeError: extension class 'Base' is not convertible into 'Derived2'. + +Testing interaction between callbacks, base declarations, and overloading +- testCallback() calls callback() (within C++) +- callback() is overloaded (in the wrapped class CallbackTest) +- callback() is redefined in RedefineCallback (overloading is simulated by type casing) +- testCallback() should use the redefined callback() + + >>> c = CallbackTest() + >>> c.testCallback(1) + 2 + >>> c.testCallback('foo') + Traceback (innermost last): + File "", line 1, in ? + TypeError: illegal argument type for built-in operation + >>> c.callback(1) + 2 + >>> c.callback('foo') + 'foo 1' + + >>> import types + >>> class RedefineCallback(CallbackTest): + ... def callback(self, x): + ... if type(x) is types.IntType: + ... return x - 2 + ... else: + ... return CallbackTest.callback(self,x) + ... + >>> r = RedefineCallback() + >>> r.callback(1) + -1 + >>> r.callback('foo') + 'foo 1' + >>> r.testCallback('foo') + Traceback (innermost last): + File "", line 1, in ? + TypeError: illegal argument type for built-in operation + >>> r.testCallback(1) + -1 + >>> testCallback(r, 1) + -1 + +Regression test for a reference-counting bug thanks to Mark Evans +() + >>> sizelist([]) + 0.0 + >>> sizelist([1, 2, 4]) + 3.0 + +And another for doubles + >>> vector_double().push_back(3.0) + +Tests for method lookup in the context of inheritance +Set up the tests + + >>> a1 = A1() + >>> a2 = A2() + >>> b1 = B1() + >>> b2 = B2() + >>> pa1_a1 = factoryA1asA1() + >>> pb1_a1 = factoryB1asA1() + >>> pb2_a1 = factoryB2asA1() + >>> pc_a1 = factoryCasA1() + >>> pa2_a2 = factoryA2asA2() + >>> pb1_a2 = factoryB1asA2() + >>> pb1_b1 = factoryB1asB1() + >>> pc_b1 = factoryCasB1() + >>> class DA1(A1): + ... def overrideA1(self): + ... return 'DA1.overrideA1' + ... + >>> da1 = DA1() + >>> class DB1(B1): + ... def overrideA1(self): + ... return 'DB1.overrideA1' + ... def overrideB1(self): + ... return 'DB1.overrideB1' + ... + >>> db1 = DB1() + >>> class DB2(B2): pass + ... + >>> db2 = DB2() + +test overrideA1 + + >>> a1.overrideA1() + 'A1::overrideA1' + >>> b1.overrideA1() + 'B1::overrideA1' + >>> b2.overrideA1() + 'B2::overrideA1' + >>> da1.overrideA1() + 'DA1.overrideA1' + >>> db1.overrideA1() + 'DB1.overrideA1' + >>> pa1_a1.overrideA1() + 'A1::overrideA1' + >>> pb1_a1.overrideA1() + 'B1::overrideA1' + >>> pb2_a1.overrideA1() + 'B2::overrideA1' + >>> pb1_b1.overrideA1() + 'B1::overrideA1' + >>> pc_a1.overrideA1() + 'B1::overrideA1' + >>> pc_b1.overrideA1() + 'B1::overrideA1' + +test call_overrideA1 + + >>> call_overrideA1(a1) + 'A1::overrideA1' + >>> call_overrideA1(b1) + 'B1::overrideA1' + >>> call_overrideA1(b2) + 'B2::overrideA1' + >>> call_overrideA1(da1) + 'DA1.overrideA1' + >>> call_overrideA1(db1) + 'DB1.overrideA1' + >>> call_overrideA1(pa1_a1) + 'A1::overrideA1' + >>> call_overrideA1(pb1_a1) + 'B1::overrideA1' + >>> call_overrideA1(pb2_a1) + 'B2::overrideA1' + >>> call_overrideA1(pb1_b1) + 'B1::overrideA1' + >>> call_overrideA1(pc_a1) + 'B1::overrideA1' + >>> call_overrideA1(pc_b1) + 'B1::overrideA1' + +test inheritA1 + + >>> a1.inheritA1() + 'A1::inheritA1' + >>> b1.inheritA1() + 'A1::inheritA1' + >>> b2.inheritA1() + 'A1::inheritA1' + >>> da1.inheritA1() + 'A1::inheritA1' + >>> db1.inheritA1() + 'A1::inheritA1' + >>> pa1_a1.inheritA1() + 'A1::inheritA1' + >>> pb1_a1.inheritA1() + 'A1::inheritA1' + >>> pb2_a1.inheritA1() + 'A1::inheritA1' + >>> pb1_b1.inheritA1() + 'A1::inheritA1' + >>> pc_a1.inheritA1() + 'A1::inheritA1' + >>> pc_b1.inheritA1() + 'A1::inheritA1' + +test call_inheritA1 + + >>> call_inheritA1(a1) + 'A1::inheritA1' + >>> call_inheritA1(b1) + 'A1::inheritA1' + >>> call_inheritA1(b2) + 'A1::inheritA1' + >>> call_inheritA1(da1) + 'A1::inheritA1' + >>> call_inheritA1(db1) + 'A1::inheritA1' + >>> call_inheritA1(pa1_a1) + 'A1::inheritA1' + >>> call_inheritA1(pb1_a1) + 'A1::inheritA1' + >>> call_inheritA1(pb2_a1) + 'A1::inheritA1' + >>> call_inheritA1(pb1_b1) + 'A1::inheritA1' + >>> call_inheritA1(pc_a1) + 'A1::inheritA1' + >>> call_inheritA1(pc_b1) + 'A1::inheritA1' + +test inheritA2 + + >>> a2.inheritA2() + 'A2::inheritA2' + >>> b1.inheritA2() + 'A2::inheritA2' + >>> b2.inheritA2() + 'A2::inheritA2' + >>> db1.inheritA2() + 'A2::inheritA2' + >>> pa2_a2.inheritA2() + 'A2::inheritA2' + >>> pb1_a2.inheritA2() + 'A2::inheritA2' + >>> pb1_b1.inheritA2() + 'A2::inheritA2' + +test overrideB1 + + >>> b1.overrideB1() + 'B1::overrideB1' + >>> db1.overrideB1() + 'DB1.overrideB1' + >>> pb1_b1.overrideB1() + 'B1::overrideB1' + >>> pc_b1.overrideB1() + 'C::overrideB1' + +test call_overrideB1 + + >>> call_overrideB1(b1) + 'B1::overrideB1' + >>> call_overrideB1(db1) + 'DB1.overrideB1' + >>> call_overrideB1(pb1_a1) + 'B1::overrideB1' + >>> call_overrideB1(pc_a1) + 'C::overrideB1' + >>> call_overrideB1(pb1_b1) + 'B1::overrideB1' + >>> call_overrideB1(pc_b1) + 'C::overrideB1' + +test inheritB2 + + >>> b2.inheritB2() + 'B2::inheritB2' + >>> db2.inheritB2() + 'B2::inheritB2' + +========= test the new def_raw() feature ========== + + >>> r = RawTest(1) + >>> raw(r,1,third=1,fourth=1) + 4 + >>> r.raw(1,third=1,fourth=1) + 4 + >>> raw(r,1,third=1,f=1) + Traceback (innermost last): + KeyError: fourth + >>> raw(r,1,third=1) + Traceback (innermost last): + TypeError: wrong number of arguments + >>> raw(r,1) + Traceback (innermost last): + TypeError: wrong number of arguments + >>> raw() + Traceback (innermost last): + TypeError: wrong number of arguments + >>> raw1(1,second=1) + 2 + >>> raw1(1) + 1 + >>> raw1(second=1) + 1 + >>> raw1() + 0 + >>> raw2(1,second=1) + 2 + >>> raw2(1) + 1 + >>> raw2(second=1) + 1 + >>> raw2() + 0 + +========= test export of operators ========== + + >>> i = Int(2) + >>> j = i+i + >>> j.i() + 4 + >>> j = i-i + >>> j.i() + 0 + >>> j = i*i + >>> j.i() + 4 + >>> i>> cmp(i,i) + 0 + >>> k = Int(5) + >>> j = divmod(k, i) + >>> j[0].i() + 2 + >>> j[1].i() + 1 + >>> j = pow(i, k) + >>> j.i() + 32 + >>> j = pow(i, k, k) + >>> j.i() + 2 + >>> j = -i + >>> j.i() + -2 + >>> str(i) + '2' + >>> j = i/i + Traceback (innermost last): + TypeError: bad operand type(s) for / + >>> j = abs(i) + Traceback (innermost last): + TypeError: bad operand type for abs() + >>> j = i+1 + >>> j.i() + 3 + >>> j = i-1 + >>> j.i() + 1 + >>> j = i*1 + >>> j.i() + 2 + >>> i<1 + 0 + >>> cmp(i,1) + 1 + >>> j = pow(i, 5) + >>> j.i() + 32 + >>> j = pow(i, 5, k) + Traceback (innermost last): + TypeError: bad operand type(s) for pow() + >>> j = pow(i, 5, 5) + Traceback (innermost last): + TypeError: bad operand type(s) for pow() + >>> j = i/1 + Traceback (innermost last): + TypeError: bad operand type(s) for / + >>> j = 1+i + >>> j.i() + 3 + >>> j = 1-i + >>> j.i() + -1 + >>> j = 1*i + >>> j.i() + 2 + >>> 1>> cmp(1,i) + -1 + >>> j = 1/i + Traceback (innermost last): + TypeError: bad operand type(s) for / + >>> pow(1,i) + Traceback (innermost last): + TypeError: bad operand type(s) for pow() + +Test operator export to a subclass + + # force method table sharing + >>> class IntDerived1(Int): pass + ... + + >>> class IntDerived(Int): + ... def __init__(self, i): + ... Int.__init__(self, i) + ... def __str__(self): + ... return 'IntDerived: ' + str(self.i()) + ... + >>> f = IntDerived(3) + >>> str(f) + 'IntDerived: 3' + >>> j = f * f + >>> j.i() + 9 + >>> j = f * i + >>> j.i() + 6 + >>> j = f * 5 + >>> j.i() + 15 + >>> j = i * f + >>> j.i() + 6 + >>> j = 5 * f + >>> j.i() + 15 + + +========= Prove that the "phantom base class" issue is resolved ========== + + >>> assert pa1_a1.__class__ == A1 + >>> assert pb1_a1.__class__ == A1 + >>> assert pb2_a1.__class__ == A1 + >>> assert pc_a1.__class__ == A1 + >>> assert pa2_a2.__class__ == A2 + >>> assert pb1_a2.__class__ == A2 + >>> assert pb1_b1.__class__ == B1 + >>> assert pc_b1.__class__ == B1 + >>> assert A1 in B1.__bases__ + >>> assert A2 in B1.__bases__ + >>> assert A1 in B2.__bases__ + >>> assert A2 in B2.__bases__ + >>> assert A1 in DA1.__bases__ + >>> assert B1 in DB1.__bases__ + >>> assert B2 in DB2.__bases__ + +=============================================================== +test methodologies for wrapping functions that return a pointer + + >>> get_record().value + 1234 + + In this methodology, the referent is copied + >>> get_record() == get_record() + 0 + +======== Enums and non-method class attributes ============== + >>> eo = EnumOwner(EnumOwner.one, EnumOwner.two) + >>> eo.first + 1 + >>> eo.second + 2 + >>> eo.first = EnumOwner.three + >>> eo.second = EnumOwner.one + >>> eo.first + 3 + >>> eo.second + 1 +''' + +from demo import * +import string +import re +import sys + +def run(args = None): + if args is not None: + sys.argv = args + import doctest, test_extclass + doctest.testmod(test_extclass) + +if __name__ == '__main__': + run() From 8ab19a235463889701860a6efa18cb67f8668cf2 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 26 Nov 2000 16:42:51 +0000 Subject: [PATCH 002/154] Undo CVS mistake [SVN r8330] --- doc/#index.html# | 212 ----------------------------------------------- 1 file changed, 212 deletions(-) delete mode 100644 doc/#index.html# diff --git a/doc/#index.html# b/doc/#index.html# deleted file mode 100644 index ff5946a8..00000000 --- a/doc/#index.html# +++ /dev/null @@ -1,212 +0,0 @@ - - - - py_cpp Python/C++ binding documentation - -

- c++boost.gif (8819 bytes) py_cpp* -

- -

- The source code for py_cpp, including a MSVC demo project is available here. - -

Synopsis

-

- py_cpp is a system for quickly and easily interfacing C++ code with Python such that the Python interface is - very similar to the C++ interface. It is designed to be minimally - intrusive on your C++ design. In most cases, you should not have to alter - your C++ classes in any way in order to use them with py_cpp. The system - should simply “reflect” your C++ classes and functions into - Python. The major features of py_cpp include support for: -

-among others. - - -

Supported Platforms

-

py_cpp has been tested in the following configurations: - -

- -

Py_cpp requires the boost libraries, and is - has been accepted for inclusion into the boost libraries pending “boostification“ - (completion of the documentation, change in some naming conventions and - resolution of some namespace issues). - -

Credits

-
    -
  • David Abrahams originated - and wrote py_cpp. - -
  • Ullrich Koethe - had independently developed a similar system. When he discovered py_cpp, - he generously contributed countless hours of coding and much insight into - improving it. He is responsible for an early version of the support for function overloading and wrote the support for - reflecting C++ inheritance - relationships. He has helped to improve error-reporting from both - Python and C++, and has designed an extremely easy-to-use way of - exposing numeric operators, including - a way to avoid explicit coercion by means of overloading. - -
  • The members of the boost mailing list and the Python community supplied - invaluable early feedback. In particular, Ron Clarke, Mark Evans, Anton - Gluck, Ralf W. Grosse-Kunstleve, Prabhu Ramachandran, and Barry Scott took - the brave step of trying to use py_cpp while it was still in early stages - of development. - -
  • The development of py_cpp wouldn't have been - possible without the generous support of Dragon Systems/Lernout and - Hauspie, Inc who supported its development as an open-source project. -
- -

Table of Contents

- -
    -
  1. A Brief Introduction to writing Python - extension modules - -
  2. Comparisons between py_cpp and other - systems for extending Python - -
  3. A Simple Example Using py_cpp - -
  4. Overridable Virtual Functions - -
  5. Function Overloading - -
  6. Inheritance - -
  7. Special Method and Operator Support - -
  8. A Peek Under the Hood - -
  9. Building a Module with Py_cpp - -
  10. Advanced Topics - -
      -
    1. class_builder<> - -
    2. enums - -
    3. References - -
    4. Pointers and Smart Pointers - -
    5. Built-in Python Types - -
    6. Other Extension Types - -
    7. Templates -
    - -
- -

- More sophisticated examples are given in - extclass_demo.cpp, extclass_demo.h, and - test_extclass.py in the source code - archive. There's much more here, and much more documentation to - come... -

- Questions should be directed to the boost mailing list. - -

Naming Contest

- -

- Yes, I know py_cpp is a lousy name. Problem is, the best names my puny - imagination can muster (IDLE and GRAIL) are taken, so I'm holding a - naming contest. First prize? You get to pick the name<0.2wink> and - you will be credited in the documentation. Names that have been suggested - so far include: -

    -
  • - Py++ -
  • - Python++ -
  • - Coil -
  • - SnakeSkin -
  • - CCCP - Convert C++ - Classes to Python -
  • - C3PO - Convert C++ - Classes to Python - Objects -
  • - PALIN - Python - Augmented-Language - INtegration -
  • - CLEESE - C++ Language Extension Environment - Supremely Easy -
  • - JONES - Just Obscenely Neat Extension - System -
  • - C-thru -
  • - SeamlessC -
  • - BorderCrossing -
  • - Perseus (because he solved a hairy problem involving snakes by using - reflection and was invisible most of the time). -
- Please post or send me your suggestions!
-
- -

- © Copyright David Abrahams 2000. Permission to copy, use, modify, - sell and distribute this document is granted provided this copyright - notice appears in all copies. This document is provided “as is” without - express or implied warranty, and with no claim as to its suitability for - any purpose. -

- Updated: Nov 26, 2000 - - From 6691261130ec29a3ed929d6c8f5600fa0a422992 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 27 Nov 2000 06:57:31 +0000 Subject: [PATCH 003/154] This commit was generated by cvs2svn to compensate for changes in r715, which included commits to RCS files with non-trunk default branches. [SVN r8332] --- build/bpl_static.dsp | 216 ++++++++++++++++++++++++++++++++++++ build/build.dsw | 74 ++++++++++++ build/build.opt | 1 + build/example1/example1.dsp | 107 ++++++++++++++++++ build/rwgk1/rwgk1.dsp | 105 ++++++++++++++++++ build/test/test.dsp | 112 +++++++++++++++++++ 6 files changed, 615 insertions(+) create mode 100644 build/bpl_static.dsp create mode 100644 build/build.dsw create mode 100644 build/build.opt create mode 100644 build/example1/example1.dsp create mode 100644 build/rwgk1/rwgk1.dsp create mode 100644 build/test/test.dsp diff --git a/build/bpl_static.dsp b/build/bpl_static.dsp new file mode 100644 index 00000000..60f56070 --- /dev/null +++ b/build/bpl_static.dsp @@ -0,0 +1,216 @@ +# Microsoft Developer Studio Project File - Name="bpl_static" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=bpl_static - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "bpl_static.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "bpl_static.mak" CFG="bpl_static - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bpl_static - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "bpl_static - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bpl_static - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W4 /WX /GR /GX /O2 /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "bpl_static - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /WX /Gm /GR /GX /ZI /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "bpl_static - Win32 Release" +# Name "bpl_static - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\src\classes.cpp +# ADD CPP /W3 +# End Source File +# Begin Source File + +SOURCE=..\src\conversions.cpp +# ADD CPP /W3 +# End Source File +# Begin Source File + +SOURCE=..\src\extension_class.cpp +# ADD CPP /W3 +# End Source File +# Begin Source File + +SOURCE=..\src\functions.cpp +# ADD CPP /W3 +# End Source File +# Begin Source File + +SOURCE=..\src\init_function.cpp +# ADD CPP /W3 +# End Source File +# Begin Source File + +SOURCE=..\src\module_builder.cpp +# ADD CPP /W3 +# End Source File +# Begin Source File + +SOURCE=..\src\objects.cpp +# ADD CPP /W3 +# End Source File +# Begin Source File + +SOURCE=..\src\types.cpp +# ADD CPP /W3 +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\boost\python\detail\base_object.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\callback.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\caller.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\detail\cast.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\class_builder.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\classes.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\detail\config.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\conversions.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\errors.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\detail\extension_class.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\detail\functions.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\detail\init_function.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\module_builder.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\detail\none.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\objects.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\operators.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\reference.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\detail\signatures.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\detail\singleton.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\detail\types.hpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\boost\python\detail\wrap_python.hpp +# End Source File +# End Group +# End Target +# End Project diff --git a/build/build.dsw b/build/build.dsw new file mode 100644 index 00000000..f4ee1a11 --- /dev/null +++ b/build/build.dsw @@ -0,0 +1,74 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "bpl_static"=.\bpl_static.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "example1"=.\example1\example1.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name bpl_static + End Project Dependency +}}} + +############################################################################### + +Project: "rwgk1"=.\rwgk1\rwgk1.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name bpl_static + End Project Dependency +}}} + +############################################################################### + +Project: "test"=.\test\test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name bpl_static + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/build/build.opt b/build/build.opt new file mode 100644 index 00000000..3599f1b0 --- /dev/null +++ b/build/build.opt @@ -0,0 +1 @@ +ÐÏࡱ \ No newline at end of file diff --git a/build/example1/example1.dsp b/build/example1/example1.dsp new file mode 100644 index 00000000..78d1f0d8 --- /dev/null +++ b/build/example1/example1.dsp @@ -0,0 +1,107 @@ +# Microsoft Developer Studio Project File - Name="example1" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=example1 - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "example1.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "example1.mak" CFG="example1 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "example1 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "example1 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "example1 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/hello.dll" /libpath:"c:\tools\python\libs" + +!ELSEIF "$(CFG)" == "example1 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug/hello.dll" /pdbtype:sept /libpath:"c:\tools\python\libs" + +!ENDIF + +# Begin Target + +# Name "example1 - Win32 Release" +# Name "example1 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\example\example1.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/build/rwgk1/rwgk1.dsp b/build/rwgk1/rwgk1.dsp new file mode 100644 index 00000000..18526979 --- /dev/null +++ b/build/rwgk1/rwgk1.dsp @@ -0,0 +1,105 @@ +# Microsoft Developer Studio Project File - Name="rwgk1" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=rwgk1 - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "rwgk1.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "rwgk1.mak" CFG="rwgk1 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "rwgk1 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "rwgk1 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "rwgk1 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /libpath:"c:\tools\python\libs" + +!ELSEIF "$(CFG)" == "rwgk1 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs" + +!ENDIF + +# Begin Target + +# Name "rwgk1 - Win32 Release" +# Name "rwgk1 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\example\rwgk1.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/build/test/test.dsp b/build/test/test.dsp new file mode 100644 index 00000000..a29d011a --- /dev/null +++ b/build/test/test.dsp @@ -0,0 +1,112 @@ +# Microsoft Developer Studio Project File - Name="test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=test - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "test.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "test.mak" CFG="test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "test - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "test - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "test - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /Zm200 /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /libpath:"c:\tools\python\libs" + +!ELSEIF "$(CFG)" == "test - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /Zm200 /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "test - Win32 Release" +# Name "test - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\test\comprehensive.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\test\comprehensive.hpp +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project From 308f3acb46852db4429e07337ee6f64f46b83391 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 27 Nov 2000 07:02:14 +0000 Subject: [PATCH 004/154] boost-ification [SVN r8335] --- doc/building.html | 11 ++-- doc/comparisons.html | 64 +++++++++++------------ doc/enums.html | 23 ++++++--- doc/example1.html | 27 +++++----- doc/extending.html | 14 ++--- doc/index.html | 111 +++++++++++----------------------------- doc/inheritance.html | 42 ++++++++------- doc/overloading.html | 7 ++- doc/overriding.html | 16 +++--- doc/pointers.html | 21 ++++---- doc/special.html | 32 ++++++------ doc/under-the-hood.html | 6 +-- 12 files changed, 169 insertions(+), 205 deletions(-) diff --git a/doc/building.html b/doc/building.html index 9c0452e7..84657b7a 100644 --- a/doc/building.html +++ b/doc/building.html @@ -1,21 +1,21 @@ - Building a Module with Py_cpp + Building an Extension Module

c++boost.gif (8819 bytes)Building a Module with Py_cpp + src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">Building an Extension Module

- Right now, the only supported configuration is one in which the py_cpp + Right now, the only supported configuration is one in which the BPL source files are statically linked with the source for your extension module. You may first build them into a library and link it with your extension module source, but the effect is the same as compiling all the source files together. Some users have successfully built the - py_cpp sources into a shared library, and support for a shared library - build is planned, but not yet implemented. The py_cpp source files are: + sources into a shared library, and support for a shared library + build is planned, but not yet implemented. The BPL source files are:

 extclass.cpp
@@ -29,6 +29,7 @@
          

+ Next: Enums Previous: A Peek Under the Hood Up: Top

diff --git a/doc/comparisons.html b/doc/comparisons.html index d0c31d9f..2590dae2 100644 --- a/doc/comparisons.html +++ b/doc/comparisons.html @@ -12,14 +12,16 @@

CXX

- Like py_cpp, CXX attempts to - provide a C++-oriented interface to Python. In most cases, like py_cpp, - it relieves the user from worrying about reference-counts. As far as I - can tell, there is no support for subclassing C++ extension types in - Python. An even more-significant difference is that a user's C++ code is - still basically “dealing with Python objects”, though they are wrapped - in C++ classes. This means such jobs as argument parsing and conversion - are still left to be done explicitly by the user. + Like BPL, CXX attempts to + provide a C++-oriented interface to Python. In most cases, as with the + boost library, it relieves the user from worrying about + reference-counts. Both libraries automatically convert thrown C++ + exceptions into Python exceptions. As far as I can tell, CXX has no + support for subclassing C++ extension types in Python. An even + more significant difference is that a user's C++ code is still basically + “dealing with Python objects”, though they are wrapped in + C++ classes. This means such jobs as argument parsing and conversion are + still left to be done explicitly by the user.

CXX claims to interoperate well with the C++ Standard Library @@ -38,11 +40,9 @@

As far as I can tell, CXX enables one to write what is essentially idiomatic Python code in C++, manipulating Python objects through the - same fully-generic interfaces we use in Python. I think it would be fair - to say that while you're not programming directly to the “bare - metal” with CXX, in comparison to py_cpp, it presents a low-level - interface to Python. That use is also supported by the py_cpp object - wrappers. + same fully-generic interfaces we use in Python. While you're hardly programming directly to the “bare + metal” with CXX, it basically presents a “C++-ized” + version of the Python 'C' API.

Paul F. Dubois, the original @@ -65,7 +65,7 @@ that.”
-Paul Dubois languages. Swig relies on a parser to read your source code and produce additional source code files which can be compiled into a Python (or Perl or Tcl) extension module. It has been successfully used to create - many Python extension modules. Like py_cpp, SWIG is trying to allow an + many Python extension modules. Like BPL, SWIG is trying to allow an existing interface to be wrapped with little or no change to the existing code. The documentation says “SWIG parses a form of ANSI C syntax that has been extended with a number of special directives. As a @@ -78,15 +78,15 @@ that.”
-Paul Dubois couldnt handle templates, didnt do func overloading properly etc. For ANSI C libraries this was fine. But for usual C++ code this was a problem. Simple things work. But for anything very complicated (or - realistic), one had to write code by hand. I believe py_cpp doesn't have + realistic), one had to write code by hand. I believe BPL doesn't have this problem[sic]... IMHO overloaded functions are very important to wrap correctly.”
-Prabhu Ramachandran

- By contrast, py_cpp doesn't attempt to parse C++ - the problem is simply + By contrast, BPL doesn't attempt to parse C++ - the problem is simply too complex to do correctly. Technically, one does - write code by hand to use py_cpp. The goal, however, has been to make + write code by hand to use BPL. The goal, however, has been to make that code nearly as simple as listing the names of the classes and member functions you want to expose in Python. @@ -95,7 +95,7 @@ that.”
-Paul Dubois SIP is a system similar to SWIG, though seemingly more - C++-oriented. The author says that like py_cpp, SIP supports overriding + C++-oriented. The author says that like BPL, SIP supports overriding extension class member functions in Python subclasses. It appears to have been designed specifically to directly support some features of PyQt/PyKDE, which is its primary client. Documentation is almost @@ -113,7 +113,7 @@ that.”
-Paul Dubois to a wide range of computer languages, including Common Lisp, C++, C, Modula-3, and Python. ILU can parse the ISL to generate a C++ language header file describing the interface, of which the user is expected to - provide an implementation. Unlike py_cpp, this means that the system + provide an implementation. Unlike BPL, this means that the system imposes implementation details on your C++ code at the deepest level. It is worth noting that some of the C++ names generated by ILU are supposed to be reserved to the C++ implementation. It is unclear from the @@ -148,7 +148,7 @@ an inheritance relationship?

Zope ExtensionClasses

- ExtensionClasses in Zope use the same underlying mechanism as py_cpp + ExtensionClasses in Zope use the same underlying mechanism as BPL to support subclassing of extension types in Python, including multiple-inheritance. Both systems support pickling/unpickling of extension class instances in very similar ways. Both systems rely on the @@ -159,30 +159,30 @@ an inheritance relationship? The major differences are:

  • - py_cpp lifts the burden on the user to parse and convert function + BPL lifts the burden on the user to parse and convert function argument types. Zope provides no such facility.
  • - py_cpp lifts the burden on the user to maintain Python + BPL lifts the burden on the user to maintain Python reference-counts.
  • - py_cpp supports function overloading; Zope does not. + BPL supports function overloading; Zope does not.
  • - py_cpp supplies a simple mechanism for exposing read-only and + BPL supplies a simple mechanism for exposing read-only and read/write access to data members of the wrapped C++ type as Python attributes.
  • Writing a Zope ExtensionClass is significantly more complex than - exposing a C++ class to python using py_cpp (mostly a summary of the + exposing a C++ class to python using BPL (mostly a summary of the previous 4 items). A Zope Example illustrates the differences.
  • Zope's ExtensionClasses are specifically motivated by “the need for a - C-based persistence mechanism”. Py_cpp's are motivated by the desire + C-based persistence mechanism”. BPL's are motivated by the desire to simply reflect a C++ API into Python with as little modification as possible.
  • - The following Zope restriction does not apply to py_cpp: “At most one + The following Zope restriction does not apply to BPL: “At most one base extension direct or indirect super class may define C data members. If an extension subclass inherits from multiple base extension classes, then all but one must be mix-in classes that @@ -191,22 +191,22 @@ an inheritance relationship? Zope requires use of the somewhat funky inheritedAttribute (search for “inheritedAttribute” on this page) - method to access base class methods. In py_cpp, base class methods can + method to access base class methods. In BPL, base class methods can be accessed in the usual way by writing “BaseClass.method”.
  • Zope supplies some creative but esoteric idioms such as - Acquisition. No specific support for this is built into py_cpp. + Acquisition. No specific support for this is built into BPL.
  • Zope's ComputedAttribute support is designed to be used from Python. The analogous feature of - py_cpp can be used from C++ or Python. The feature is arguably - easier to use in py_cpp. + BPL can be used from C++ or Python. The feature is arguably + easier to use in BPL.

+ Next: A Simple Example Using BPL Previous: A Brief Introduction to writing Python Extension Modules - Next: A Simple Example Using py_cpp Up: Top

© Copyright David Abrahams 2000. Permission to copy, use, modify, diff --git a/doc/enums.html b/doc/enums.html index 57aef35f..16277b03 100644 --- a/doc/enums.html +++ b/doc/enums.html @@ -8,31 +8,36 @@ c++boost.gif (8819 bytes)Wrapping enums +

Because there is in general no way to deduce that a value of arbitrary type T -is an enumeration constant, py_cpp cannot automatically convert enum values to -and from Python. To handle this case, you need to decide how you want the enum -to show up in Python (since Python doesn't have enums). Once you have done that, -you can write some simple from_python() and -to_python() functions. +is an enumeration constant, the Boost Python Library cannot automatically +convert enum values to and from Python. To handle this case, you need to decide +how you want the enum to show up in Python (since Python doesn't have +enums). Once you have done that, you can write some simple +from_python() and to_python() functions.

If you are satisfied with a Python int as a way to represent your enum -values, py_cpp provides a shorthand for these functions. You just need to +values, we provide a shorthand for these functions. You just need to instantiate boost::python::enum_as_int_converters<EnumType> where EnumType is your enumerated type. There are two convenient ways to do this:

  1. +   ...
    +} // close my_namespace
     // drop into namespace python and explicitly instantiate
     BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
       template class enum_as_int_converters;
     BOOST_PYTHON_END_CONVERSION_NAMESPACE
    +namespace my_namespace { // re-open my_namespace
    +   ...
     
  2.  // instantiate as base class in any namespace
     struct EnumTypeConverters
    -    : boost::python::py_enum_as_int_converters
    +    : boost::python::enum_as_int_converters<EnumType>
     {
     };
     
    @@ -82,6 +87,10 @@ my_class.add(boost::python::to_python(enum_value_1), "enum_value_1"); my_class.add(boost::python::to_python(enum_value_2), "enum_value_2"); ... +

    + Next: Pointers + Previous: Building an Extension Module + Up: Top

    © Copyright David Abrahams 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright diff --git a/doc/example1.html b/doc/example1.html index 9bf9e280..e39c3801 100644 --- a/doc/example1.html +++ b/doc/example1.html @@ -1,7 +1,7 @@ - A Simple Example Using py_cpp + A Simple Example Using BPL

    @@ -9,7 +9,7 @@ "c++boost.gif (8819 bytes)">

    - A Simple Example Using py_cpp + A Simple Example Using BPL

    Suppose we have the following C++ API which we want to expose in @@ -24,20 +24,20 @@ namespace hello {    public:       world(int);       ~world(); -      std::string get() const { return "hi, world"; } +      std::string greet() const { return "hi, world"; }     ...   }; -  std::size_t length(const world& x) { return std::strlen(x.get()); } +  std::size_t length(const world& x) { return std::strlen(x.greet()); } }

    Here is the C++ code for a python module called hello - which exposes the API using py_cpp: + which exposes the API using BPL:

    -#include 
    +#include <boost/python/class_builder.hpp>
     // Python requires an exported function called init<module-name> in every
     // extension module. This is where we build the module contents.
     extern "C"
    @@ -49,15 +49,15 @@ void inithello()
         try
         {
            // create an object representing this extension module
    -       boost::python::module_builder hello("hello");
    +       boost::python::module_builder m("hello");
            // Create the Python type object for our extension class
    -       boost::python::class_builder<hello::world> world_class(hello, "world");
    +       boost::python::class_builder<hello::world> world_class(m, "world");
            // Add the __init__ function
            world_class.def(boost::python::constructor<int>());
            // Add a regular member function
            world_class.def(&hello::world::get, "get");
            // Add a regular function to the module
    -       hello.def(hello::length, "length");
    +       m.def(hello::length, "length");
         }
         catch(...)
         {
    @@ -82,7 +82,7 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID)
     
     >>> import hello
     >>> hi_world = hello.world(3)
    ->>> hi_world.get()
    +>>> hi_world.greet()
     'hi, world'
     >>> hello.length(hi_world)
     9
    @@ -93,11 +93,11 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID)
           
     >>> class my_subclass(hello.world):
    -...     def get(self):
    +...     def greet(self):
     ...         return 'hello, world'
     ...
     >>> y = my_subclass(4)
    ->>> y.get()
    +>>> y.greet()
     'hello, world'
     
    @@ -115,7 +115,8 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) to have a length() of 12? If so, read on...

    - Previous: Comparisons with other systems Next: Overridable virtual functions Up: + Next: Overridable virtual functions + Previous: Comparisons with other systems Up: Top

    © Copyright David Abrahams 2000. Permission to copy, use, modify, diff --git a/doc/extending.html b/doc/extending.html index 47341389..c4a3a5e4 100644 --- a/doc/extending.html +++ b/doc/extending.html @@ -38,11 +38,11 @@ This last item typically occupies a great deal of code in an extension module. Remember that Python is a completely dynamic language. A callable - object receives its arguments in a tuple; it is up to that object to - extract those arguments from the tuple, check their types, and raise - appropriate exceptions. There are numerous other tedious details that need - to be managed; too many to mention here. Py_cpp is designed to lift most of - that burden.
    + object receives its arguments in a tuple; it is up to that object to extract + those arguments from the tuple, check their types, and raise appropriate + exceptions. There are numerous other tedious details that need to be + managed; too many to mention here. The Boost Python Library is designed to + lift most of that burden.

    @@ -56,10 +56,10 @@ sublcassing the extension type. Aside from being tedious, it's not really the same as having a true class, because there's no way for the user to override a method of the extension type which is called from the - extension module. Py_cpp solves this problem by taking advantage of Python's metaclass feature to provide objects which look, walk, and hiss almost exactly - like regular Python classes. Py_cpp classes are actually cleaner than + like regular Python classes. BPL classes are actually cleaner than Python classes in some subtle ways; a more detailed discussion will follow (someday).

    Next: Comparisons with Other Systems Up: - py_cpp Python/C++ binding documentation + The Boost Python Library (BPL)

    c++boost.gif (8819 bytes) py_cpp* + align="center" height="86">The Boost Python Library (BPL)

    -

    - The source code for py_cpp, including a MSVC demo project is available here. -

    Synopsis

    - py_cpp is a system for quickly and easily interfacing C++ code with Python such that the Python interface is + Use the Boost Python Library to quickly and easily export a C++ library to Python such that the Python interface is very similar to the C++ interface. It is designed to be minimally intrusive on your C++ design. In most cases, you should not have to alter - your C++ classes in any way in order to use them with py_cpp. The system + your C++ classes in any way in order to use them with BPL. The system should simply “reflect” your C++ classes and functions into - Python. The major features of py_cpp include support for: + Python. The major features of BPL include support for:

    • Subclassing extension types in Python
    • Overriding virtual functions in Python @@ -32,7 +28,7 @@ among others.

      Supported Platforms

      -

      py_cpp has been tested in the following configurations: +

      BPL has been tested in the following configurations:

      • Against Python 1.5.2 using the following compiler/library: @@ -56,7 +52,7 @@ among others. href="mailto:rwgk@cci.lbl.gov">Ralf W. Grosse-Kunstleve]
      • An upcoming release of Metrowerks CodeWarrior - Pro6 for Windows (the first release has a bug that's fatal to py_cpp) + Pro6 for Windows (the first release has a bug that's fatal to BPL)

    • Against Python 2.0 using the following compiler/library combinations: @@ -67,18 +63,13 @@ among others.
    -

    Py_cpp requires the boost libraries, and is - has been accepted for inclusion into the boost libraries pending “boostification“ - (completion of the documentation, change in some naming conventions and - resolution of some namespace issues). -

    Credits

      -
    • David Abrahams originated - and wrote py_cpp. +
    • David Abrahams originated + and wrote the library.
    • Ullrich Koethe - had independently developed a similar system. When he discovered py_cpp, + had independently developed a similar system. When he discovered BPL, he generously contributed countless hours of coding and much insight into improving it. He is responsible for an early version of the support for function overloading and wrote the support for @@ -88,13 +79,13 @@ among others. exposing numeric operators, including a way to avoid explicit coercion by means of overloading. -
    • The members of the boost mailing list and the Python community supplied - invaluable early feedback. In particular, Ron Clarke, Mark Evans, Anton - Gluck, Ralf W. Grosse-Kunstleve, Prabhu Ramachandran, and Barry Scott took - the brave step of trying to use py_cpp while it was still in early stages - of development. +
    • The members of the boost mailing list and the Python community + supplied invaluable early feedback. In particular, Ron Clarke, Mark Evans, + Anton Gluck, Ralf W. Grosse-Kunstleve, Chuck Ingold, Prabhu Ramachandran, + and Barry Scott took the brave step of trying to use BPL while it was + still in early stages of development. -
    • The development of py_cpp wouldn't have been +
    • The development of BPL wouldn't have been possible without the generous support of Dragon Systems/Lernout and Hauspie, Inc who supported its development as an open-source project.
    @@ -105,10 +96,10 @@ among others.
  3. A Brief Introduction to writing Python extension modules -
  4. Comparisons between py_cpp and other +
  5. Comparisons between BPL and other systems for extending Python -
  6. A Simple Example Using py_cpp +
  7. A Simple Example Using BPL
  8. Overridable Virtual Functions @@ -120,11 +111,13 @@ among others.
  9. A Peek Under the Hood -
  10. Building a Module with Py_cpp +
  11. Building a Module with BPL
  12. Advanced Topics
      +
    1. Pickling +
    2. class_builder<>
    3. enums @@ -143,63 +136,17 @@ among others.

    - More sophisticated examples are given in - extclass_demo.cpp, extclass_demo.h, and - test_extclass.py in the source code - archive. There's much more here, and much more documentation to - come... + Documentation is a major ongoing project; assistance is greatly + appreciated! In the meantime, useful examples of every BPL feature should + be evident in the regression test files test/comprehensive.[py/hpp/cpp] +

    Questions should be directed to the boost mailing list. -

    Naming Contest

    - -

    - Yes, I know py_cpp is a lousy name. Problem is, the best names my puny - imagination can muster (IDLE and GRAIL) are taken, so I'm holding a - naming contest. First prize? You get to pick the name<0.2wink> and - you will be credited in the documentation. Names that have been suggested - so far include: -

      -
    • - Py++ -
    • - Python++ -
    • - Coil -
    • - SnakeSkin -
    • - CCCP - Convert C++ - Classes to Python -
    • - C3PO - Convert C++ - Classes to Python - Objects -
    • - PALIN - Python - Augmented-Language - INtegration -
    • - CLEESE - C++ Language Extension Environment - Supremely Easy -
    • - JONES - Just Obscenely Neat Extension - System -
    • - C-thru -
    • - SeamlessC -
    • - BorderCrossing -
    • - Perseus (because he solved a hairy problem involving snakes by using - reflection and was invisible most of the time). -
    - Please post or send me your suggestions!
    -
    -

    © Copyright David Abrahams 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright diff --git a/doc/inheritance.html b/doc/inheritance.html index 2dd8071b..d11899c8 100644 --- a/doc/inheritance.html +++ b/doc/inheritance.html @@ -12,11 +12,11 @@

    Inheritance in Python

    - Py_cpp extension classes support single and multiple-inheritance in - Python, just like regular Python classes. You can mix built-in Python - classes with py_cpp extension classes in a derived class' tuple of - bases. Whenever a py_cpp extension class is among the bases for a new - class in Python, the result is an extension class: + BPL extension classes support single and multiple-inheritance in + Python, just like regular Python classes. You can arbitrarily mix + built-in Python classes with extension classes in a derived class' + tuple of bases. Whenever a BPL extension class is among the bases for a + new class in Python, the result is an extension class:

     >>> class MyPythonClass:
    @@ -37,7 +37,7 @@
     
     

    Reflecting C++ Inheritance Relationships

    - Py_cpp also allows us to represent C++ inheritance relationships so that + BPL also allows us to represent C++ inheritance relationships so that wrapped derived classes may be passed where values, pointers, or references to a base class are expected as arguments. The declare_base member function of @@ -71,7 +71,11 @@ int get_derived_x(const Derived& d) { return d.x; }


    -#include +#include <boost/python/class_builder.hpp> + +// namespace alias for code brevity +namespace python = boost::python; + extern "C" #ifdef _WIN32 __declspec(dllexport) @@ -80,13 +84,13 @@ void initmy_module() {     try     { -       boost::python::module_builder my_module("my_module"); +       python::module_builder my_module("my_module"); -       boost::python::class_builder<Base> base_class(my_module, "Base"); -       base_class.def(boost::python::constructor<void>()); +       python::class_builder<Base> base_class(my_module, "Base"); +       base_class.def(python::constructor<void>()); -       boost::python::class_builder<Derived> derived_class(my_module, "Derived"); -       derived_class.def(boost::python::constructor<void>()); +       python::class_builder<Derived> derived_class(my_module, "Derived"); +       derived_class.def(python::constructor<void>()); // Establish the inheritance relationship between Base and Derived derived_class.declare_base(base_class); @@ -96,7 +100,7 @@ void initmy_module()     }     catch(...)     { -       boost::python::handle_exception();    // Deal with the exception for Python +       python::handle_exception();    // Deal with the exception for Python     } }
    @@ -135,12 +139,12 @@ struct Base2 {}; struct Derived2 { int f(); };
    ... -   boost::python::class_builder<Base> base2_class(my_module, "Base2"); -   base2_class.def(boost::python::constructor<void>()); +   python::class_builder<Base> base2_class(my_module, "Base2"); +   base2_class.def(python::constructor<void>()); -   boost::python::class_builder<Derived2> derived2_class(my_module, "Derived2"); -   derived2_class.def(boost::python::constructor<void>()); - derived_class.declare_base(base_class, boost::python::without_downcast); +   python::class_builder<Derived2> derived2_class(my_module, "Derived2"); +   derived2_class.def(python::constructor<void>()); + derived_class.declare_base(base_class, python::without_downcast);
  13. @@ -150,8 +154,8 @@ struct Derived2 { int f(); }; references, or values.

    + Next: Special Method and Operator Support Previous: Function Overloading - Next: Special Method Names Up: Top

    © Copyright David Abrahams 2000. Permission to copy, use, modify, diff --git a/doc/overloading.html b/doc/overloading.html index 6197b230..5c2c236d 100644 --- a/doc/overloading.html +++ b/doc/overloading.html @@ -113,8 +113,7 @@ namespace scope as Python member functions.

    Overload Resolution

    - The function overload resolution mechanism in py_cpp works as - follows: + The function overload resolution mechanism works as follows:

      @@ -141,8 +140,8 @@ namespace scope as Python member functions.

    - Prev: Overridable Virtual Functions - Next: Special Method Names + Next: Inheritance + Previous: Overridable Virtual Functions Up: Top

    © Copyright David Abrahams 2000. Permission to copy, use, modify, diff --git a/doc/overriding.html b/doc/overriding.html index f8810ca1..ae629580 100644 --- a/doc/overriding.html +++ b/doc/overriding.html @@ -17,7 +17,7 @@

    Example

    -

    In this example, it is assumed that world::get() is a virtual +

    In this example, it is assumed that world::greet() is a virtual member function:

    @@ -26,7 +26,7 @@ class world
      public:
         world(int);
         virtual ~world();
    -    virtual std::string get() const { return "hi, world"; }
    +    virtual std::string greet() const { return "hi, world"; }
     };
     
    @@ -65,11 +65,11 @@ struct world_callback : world : world(x), m_self(self) {} - std::string get() const // 3 + std::string greet() const // 3 { return boost::python::callback<std::string>::call_method(m_self, "get"); } static std::string default_get(const hello::world& self) const // 4 - { return self.world::get(); } + { return self.world::greet(); } private: PyObject* m_self; // 1 }; @@ -94,7 +94,7 @@ world_class.def(&world::get, "get", &world_callback::default_get)
     >>> class my_subclass(hello.world):
    -...     def get(self):
    +...     def greet(self):
     ...         return 'hello, world'
     ...
     >>> hello.length(my_subclass())
    @@ -181,9 +181,9 @@ break the ODR).
     
         

    - Prev: A Simple Example Using py_cpp Next: Function Overloading Up: Top + Next: Function Overloading + Previous: A Simple Example Using py_cpp + Up: Top

    © Copyright David Abrahams 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright diff --git a/doc/pointers.html b/doc/pointers.html index fe30af0b..0d0a92dc 100644 --- a/doc/pointers.html +++ b/doc/pointers.html @@ -13,7 +13,7 @@

    In general, raw pointers passed to or returned from functions are problematic -for py_cpp because pointers have too many potential meanings. Is it an iterator? +for BPL because pointers have too many potential meanings. Is it an iterator? A pointer to a single element? An array? When used as a return value, is the caller expected to manage (delete) the pointed-to object or is the pointer really just a reference? If the latter, what happens to Python references to the @@ -35,11 +35,9 @@ converted from/to Python strings.

    My first piece of advice to anyone with a case not covered above is “find a way to avoid the problem.” For example, if you have just one -or two functions returning a pointer to a single (not an array of) const -T* for some wrapped T, you may be able to write a “thin -converting wrapper” over those two functions as follows (Since py_cpp -converts const T& values to_python by copying the T -into a new extension instance, Foo must have a public copy constructor): +or two functions that return a pointer to an individual const +T, and T is a wrapped class, you may be able to write a “thin +converting wrapper” over those two functions as follows:

     const Foo* f(); // original function
    @@ -47,6 +45,10 @@ const Foo& f_wrapper() { return *f(); }
       ...
     my_module.def(f_wrapper, "f");
     
    +

    +Foo must have a public copy constructor for this technique to work, since BPL +converts const T& values to_python by copying the T +value into a new extension instance.

    Dealing with the problem

    @@ -118,7 +120,7 @@ return value. You can handle this case by returning a Python tuple: typedef unsigned ErrorCode; const char* f(int* in_out_x); // original function ... -#include +#include <boost/python/objects.hpp> const boost::python::tuple f_wrapper(int in_x) { const char* s = f(in_x); return boost::python::tuple(s, in_x); @@ -131,8 +133,9 @@ my_module.def(f_wrapper, "f"); >>> str,out_x = f(3)
    - - +

    + Previous: Enums + Up: Top

    © Copyright David Abrahams 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright diff --git a/doc/special.html b/doc/special.html index 4c314fcf..7dd210ba 100644 --- a/doc/special.html +++ b/doc/special.html @@ -13,7 +13,7 @@ Overview

    - Py_cpp supports all of the standard special method names supported by real Python class instances except __complex__ (more on the reasons - Note that py_cpp also supports automatic wrapping of + Note that BPL also supports automatic wrapping of __str__ and __cmp__. This is explained in the next section and the Table of Automatically Wrapped Methods. @@ -113,7 +113,7 @@ foo_class.def(&to_string, "__str__"); href="http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/numeric-types.html">numeric protocols. This is the basic same technique used to expose to_string() as __str__() above, and is covered in detail below. Py_cpp also supports + href="#numeric_manual">covered in detail below. BPL also supports automatic wrapping of numeric operators whenever they have already been defined in C++. @@ -170,7 +170,7 @@ a = i + b; bignum_class.def(boost::python::operators<boost::python::op_add>(), boost::python::right_operand<int>()); bignum_class.def(boost::python::operators<boost::python::op_add>(), boost::python::left_operand<int>()); - Py_cpp uses overloading to register several variants of the same + BPL uses overloading to register several variants of the same operation (more on this in the context of coercion). Again, several operators can be exported at once:

    @@ -276,13 +276,13 @@ bignum_class.def(&rmod,  "__rmod__");
           coercion functions can be difficult if many type combinations must be
           supported. 
           

    - Py_cpp solves this problem the same way that C++ does: with overloading. This technique drastically simplifies the code neccessary to support operators: you just register - operators for all desired type combinations, and py_cpp automatically + operators for all desired type combinations, and BPL automatically ensures that the correct function is called in each case; there is no need for user-defined coercion functions. To enable operator - overloading, py_cpp provides a standard coercion which is implicitly + overloading, BPL provides a standard coercion which is implicitly registered whenever automatic operator wrapping is used.

    If you wrap all operator functions manually, but still want to use @@ -354,7 +354,7 @@ bignum_class.def((ternary_function2)&power, "__pow__"); In the second variant, however, BigNum appears only as second argument, and in the last one it is the third argument. These functions - must be presented to py_cpp such that that the BigNum + must be presented to BPL such that that the BigNum argument appears in first position:

    @@ -381,7 +381,7 @@ Note that "__rrpow__" is an extension not present in plain Python.
     
     

    Table of Automatically Wrapped Methods

    - Py_cpp can automatically wrap the following special methods: @@ -755,13 +755,13 @@ KeyError: 2

    Customized Attribute Access

    - Just like built-in Python classes, py_cpp extension classes support special the usual attribute access methods __getattr__, __setattr__, and __delattr__. Because writing these functions can be tedious in the common case where the attributes being accessed are - known statically, py_cpp checks the special names + known statically, BPL checks the special names

    • @@ -777,7 +777,7 @@ KeyError: 2 following shows how we can implement a “computed attribute” in Python:
      ->>> class Range(AnyPy_cppExtensionClass):
      +>>> class Range(AnyBPLExtensionClass):
       ...    def __init__(self, start, end):
       ...        self.start = start
       ...        self.end = end
      @@ -793,7 +793,7 @@ KeyError: 2
                Direct Access to Data Members
             
             

      - Py_cpp uses the special + BPL uses the special __xxxattr__<name>__ functionality described above to allow direct access to data members through the following special functions on class_builder<> and @@ -873,9 +873,9 @@ if (PyInstance_Check(r)) { ...

      - Previous: Inheritance Next: A Peek Under the Hood Up: Top +Next: A Peek Under the Hood +Previous: Inheritance +Up: Top

      © Copyright David Abrahams and Ullrich Köthe 2000. Permission to copy, use, modify, sell and distribute this document is diff --git a/doc/under-the-hood.html b/doc/under-the-hood.html index 288021cf..902804d3 100644 --- a/doc/under-the-hood.html +++ b/doc/under-the-hood.html @@ -22,7 +22,7 @@ "example1.html#add_world_class">add it to the module it goes into the module's dictionary to be looked up under the name "world".

      - Py_cpp uses C++'s template argument deduction mechanism to determine the + BPL uses C++'s template argument deduction mechanism to determine the types of arguments to functions (except constructors, for which we must provide an argument list because they can't be named in C++). Then, it calls the appropriate @@ -48,8 +48,8 @@ the top of your module's init function, then def the member functions later to avoid problems with inter-class dependencies.

      - Previous: Function Overloading - Next: Building a Module with Py_cpp + Next: Building a Module with BPL + Previous: Special Method and Operator Support Up: Top

      © Copyright David Abrahams 2000. Permission to copy, use, modify, From 16c12f18309640e4229122f9832ec7ba96931cc4 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 27 Nov 2000 07:23:39 +0000 Subject: [PATCH 005/154] boost-ification [SVN r8336] --- example/rwgk1.cpp | 41 + example/{example1.py => test_example1.py} | 0 example/test_rwgk1.py | 17 + test/comprehensive.cpp | 34 +- test/comprehensive.hpp | 10 +- test/comprehensive.py | 8 +- test/doctest.py | 1112 +++++++++++++++++++++ 7 files changed, 1197 insertions(+), 25 deletions(-) create mode 100644 example/rwgk1.cpp rename example/{example1.py => test_example1.py} (100%) create mode 100644 example/test_rwgk1.py create mode 100644 test/doctest.py diff --git a/example/rwgk1.cpp b/example/rwgk1.cpp new file mode 100644 index 00000000..0577aded --- /dev/null +++ b/example/rwgk1.cpp @@ -0,0 +1,41 @@ +#include + +namespace { // Avoid cluttering the global namespace. + + // A couple of simple C++ functions that we want to expose to Python. + std::string greet() { return "hello, world"; } + int square(int number) { return number * number; } +} + +#include + +namespace python = boost::python; + +// Python requires an exported function called init in every +// extension module. This is where we build the module contents. +extern "C" +#ifdef _WIN32 +__declspec(dllexport) +#endif +initrwgk1() +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("rwgk1"); + + // Add regular functions to the module. + this_module.def(greet, "greet"); + this_module.def(square, "square"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} + +// Win32 DLL boilerplate +#if defined(_WIN32) +#include +extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) { return 1; } +#endif // _WIN32 diff --git a/example/example1.py b/example/test_example1.py similarity index 100% rename from example/example1.py rename to example/test_example1.py diff --git a/example/test_rwgk1.py b/example/test_rwgk1.py new file mode 100644 index 00000000..87298875 --- /dev/null +++ b/example/test_rwgk1.py @@ -0,0 +1,17 @@ +r'''>>> import rwgk1 + >>> print rwgk1.greet() + hello, world + >>> number = 11 + >>> print number, '*', number, '=', rwgk1.square(number) + 11 * 11 = 121 +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_rwgk1 + doctest.testmod(test_rwgk1) + +if __name__ == '__main__': + run() diff --git a/test/comprehensive.cpp b/test/comprehensive.cpp index cae924e6..7fad74bb 100644 --- a/test/comprehensive.cpp +++ b/test/comprehensive.cpp @@ -11,7 +11,7 @@ #include // for pow() #include -namespace extclass_demo { +namespace bpl_test { FooCallback::FooCallback(PyObject* self, int x) : Foo(x), m_self(self) @@ -714,12 +714,14 @@ const Record* get_record() return &v; } -template class boost::python::class_builder; // explicitly instantiate +} // namespace bpl_test -} // namespace extclass_demo +namespace boost { namespace python { + template class class_builder; // explicitly instantiate +}} // namespace boost::python BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE -inline PyObject* to_python(const extclass_demo::Record* p) +inline PyObject* to_python(const bpl_test::Record* p) { return to_python(*p); } @@ -731,7 +733,7 @@ BOOST_PYTHON_END_CONVERSION_NAMESPACE /* */ /************************************************************/ -namespace extclass_demo { +namespace bpl_test { struct EnumOwner { @@ -753,8 +755,8 @@ struct EnumOwner } namespace boost { namespace python { - template class enum_as_int_converters; - using extclass_demo::pow; + template class enum_as_int_converters; + using bpl_test::pow; }} // namespace boost::python // This is just a way of getting the converters instantiated @@ -763,7 +765,7 @@ namespace boost { namespace python { //{ //}; -namespace extclass_demo { +namespace bpl_test { /************************************************************/ /* */ @@ -1036,7 +1038,7 @@ void init_module(boost::python::module_builder& m) world_class.def(world_setstate, "__setstate__"); } -PyObject* raw(boost::python::tuple const& args, boost::python::dictionary const& keywords) +PyObject* raw(const boost::python::tuple& args, const boost::python::dictionary& keywords) { if(args.size() != 2 || keywords.size() != 2) { @@ -1055,21 +1057,21 @@ PyObject* raw(boost::python::tuple const& args, boost::python::dictionary const& void init_module() { - boost::python::module_builder demo("demo"); - init_module(demo); + boost::python::module_builder test("test"); + init_module(test); // Just for giggles, add a raw metaclass. - demo.add(new boost::python::meta_class); + test.add(new boost::python::meta_class); } extern "C" #ifdef _WIN32 __declspec(dllexport) #endif -void initdemo() +void inittest() { try { - extclass_demo::init_module(); + bpl_test::init_module(); } catch(...) { boost::python::handle_exception(); @@ -1083,7 +1085,7 @@ CompareIntPairPythonClass::CompareIntPairPythonClass(boost::python::module_build def(&CompareIntPair::operator(), "__call__"); } -} // namespace extclass_demo +} // namespace bpl_test #if defined(_WIN32) @@ -1124,7 +1126,7 @@ BOOL WINAPI DllMain( switch(fdwReason) { case DLL_PROCESS_DETACH: - assert(extclass_demo::total_Ints == 0); + assert(bpl_test::total_Ints == 0); } #endif diff --git a/test/comprehensive.hpp b/test/comprehensive.hpp index d8a8e8ea..ed90f061 100644 --- a/test/comprehensive.hpp +++ b/test/comprehensive.hpp @@ -6,8 +6,8 @@ // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. -#ifndef EXTCLASS_DEMO_DWA052200_H_ -# define EXTCLASS_DEMO_DWA052200_H_ +#ifndef BPL_TEST_DWA052200_H_ +# define BPL_TEST_DWA052200_H_ // // Example code demonstrating extension class usage // @@ -21,7 +21,7 @@ # include # include -namespace extclass_demo { +namespace bpl_test { // // example: Foo, Bar, and Baz are C++ classes we want to wrap. @@ -226,6 +226,6 @@ struct CompareIntPairPythonClass CompareIntPairPythonClass(boost::python::module_builder&); }; -} // namespace extclass_demo +} // namespace bpl_test -#endif // EXTCLASS_DEMO_DWA052200_H_ +#endif // BPL_TEST_DWA052200_H_ diff --git a/test/comprehensive.py b/test/comprehensive.py index 578197f1..a8e181d2 100644 --- a/test/comprehensive.py +++ b/test/comprehensive.py @@ -209,7 +209,7 @@ Polymorphism also works: Pickling tests: >>> world.__module__ - 'demo' + 'test' >>> world.__safe_for_unpickling__ 1 >>> world.__reduce__() @@ -1072,7 +1072,7 @@ test methodologies for wrapping functions that return a pointer 1 ''' -from demo import * +from test import * import string import re import sys @@ -1080,8 +1080,8 @@ import sys def run(args = None): if args is not None: sys.argv = args - import doctest, test_extclass - doctest.testmod(test_extclass) + import doctest, comprehensive + doctest.testmod(comprehensive) if __name__ == '__main__': run() diff --git a/test/doctest.py b/test/doctest.py new file mode 100644 index 00000000..248da82a --- /dev/null +++ b/test/doctest.py @@ -0,0 +1,1112 @@ +# Module doctest version 0.9.4 +# Released to the public domain 27-Mar-1999, +# by Tim Peters (tim_one@email.msn.com). + +# Provided as-is; use at your own risk; no warranty; no promises; enjoy! + +"""module_builder doctest -- a framework for running examples in docstrings. + +NORMAL USAGE + +In normal use, end each module M with: + +def _test(): + import doctest, M # replace M with your module's name + return doctest.testmod(M) # ditto + +if __name__ == "__main__": + _test() + +Then running the module as a script will cause the examples in the +docstrings to get executed and verified: + +python M.python + +This won't display anything unless an example fails, in which case +the failing example(s) and the cause(s) of the failure(s) are printed +to stdout (why not stderr? because stderr is a lame hack <0.2 wink>), +and the final line of output is "Test failed.". + +Run it with the -v switch instead: + +python M.python -v + +and a detailed report of all examples tried is printed to stdout, along +with assorted summaries at the end. + +You can force verbose mode by passing "verbose=1" to testmod, or prohibit +it by passing "verbose=0". In either of those cases, sys.argv is not +examined by testmod. + +In any case, testmod returns a 2-tuple of ints (f, t), where f is the +number of docstring examples that failed and t is the total number of +docstring examples attempted. + + +WHICH DOCSTRINGS ARE EXAMINED? + ++ M.__doc__. + ++ f.__doc__ for all functions f in M.__dict__.values(), except those + with private names. + ++ C.__doc__ for all classes C in M.__dict__.values(), except those with + private names. + ++ If M.__test__ exists and "is true", it must be a dict, and + each entry maps a (string) name to a function object, class object, or + string. function and class object docstrings found from M.__test__ + are searched even if the name is private, and strings are searched + directly as if they were docstrings. In output, a key K in M.__test__ + appears with name + .__test__.K + +Any classes found are recursively searched similarly, to test docstrings +in their contained methods and nested classes. Private names reached +from M's globals are skipped, but all names reached from M.__test__ are +searched. + +By default, a name is considered to be private if it begins with an +underscore (like "_my_func") but doesn't both begin and end with (at +least) two underscores (like "__init__"). You can change the default +by passing your own "isprivate" function to testmod. + +If you want to test docstrings in objects with private names too, stuff +them into an M.__test__ dict, or see ADVANCED USAGE below (e.g., pass your +own isprivate function to Tester's constructor, or call the rundoc method +of a Tester obj). + +Warning: imports can cause trouble; e.g., if you do + +from XYZ import XYZclass + +then XYZclass is a name in M.__dict__ too, and doctest has no way to +know that XYZclass wasn't *defined* in M. So it may try to execute the +examples in XYZclass's docstring, and those in turn may require a +different set of globals to work correctly. I prefer to do "import *"- +friendly imports, a la + +import XYY +_XYZclass = XYZ.XYZclass +del XYZ + +and then the leading underscore stops testmod from going nuts. You may +prefer the method in the next section. + + +WHAT'S THE EXECUTION CONTEXT? + +By default, each time testmod finds a docstring to test, it uses a +*copy* of M's globals (so that running tests on a module doesn't change +the module's real globals, and so that one test in M can't leave behind +crumbs that accidentally allow another test to work). This means +examples can freely use any names defined at top-level in M. It also +means that sloppy imports (see above) can cause examples in external +docstrings to use globals inappropriate for them. + +You can force use of your own dict as the execution context by passing +"globs=your_dict" to testmod instead. Presumably this would be a copy +of M.__dict__ merged with the globals from other imported modules. + + +WHAT IF I WANT TO TEST A WHOLE PACKAGE? + +Piece o' cake, provided the modules do their testing from docstrings. +Here's the test.python I use for the world's most elaborate Rational/ +floating-base-conversion pkg (which I'll distribute some day): + +from Rational import Cvt +from Rational import Format +from Rational import machprec +from Rational import Rat +from Rational import Round +from Rational import utils + +modules = (Cvt, + Format, + machprec, + Rat, + Round, + utils) + +def _test(): + import doctest + import sys + verbose = "-v" in sys.argv + for mod in modules: + doctest.testmod(mod, verbose=verbose, report=0) + doctest.master.summarize() + +if __name__ == "__main__": + _test() + +IOW, it just runs testmod on all the pkg modules. testmod remembers the +names and outcomes (# of failures, # of tries) for each item it's seen, +and passing "report=0" prevents it from printing a summary in verbose +mode. Instead, the summary is delayed until all modules have been +tested, and then "doctest.master.summarize()" forces the summary at the +end. + +So this is very nice in practice: each module can be tested individually +with almost no work beyond writing up docstring examples, and collections +of modules can be tested too as a unit with no more work than the above. + + +WHAT ABOUT EXCEPTIONS? + +No problem, as long as the only output generated by the example is the +traceback itself. For example: + + >>> 1/0 + Traceback (innermost last): + File "", line 1, in ? + ZeroDivisionError: integer division or modulo + >>> + +Note that only the exception type and value are compared (specifically, +only the last line in the traceback). + + +ADVANCED USAGE + +doctest.testmod() captures the testing policy I find most useful most +often. You may want other policies. + +testmod() actually creates a local obj of class doctest.Tester, +runs appropriate methods of that class, and merges the results into +global Tester obj doctest.master. + +You can create your own instances of doctest.Tester, and so build your +own policies, or even run methods of doctest.master directly. See +doctest.Tester.__doc__ for details. + + +SO WHAT DOES A DOCSTRING EXAMPLE LOOK LIKE ALREADY!? + +Oh ya. It's easy! In most cases a copy-and-paste of an interactive +console session works fine -- just make sure the leading whitespace +is rigidly consistent (you can mix tabs and spaces if you're too lazy +to do it right, but doctest is not in the business of guessing what +you think a tab means). + + >>> # comments are ignored + >>> x = 12 + >>> x + 12 + >>> if x == 13: + ... print "yes" + ... else: + ... print "no" + ... print "NO" + ... print "NO!!!" + ... + no + NO + NO!!! + >>> + +Any expected output must immediately follow the final ">>>" or "..." +line containing the code, and the expected output (if any) extends +to the next ">>>" or all-whitespace line. That's it. + +Bummers: + ++ Expected output cannot contain an all-whitespace line, since such a + line is taken to signal the end of expected output. + ++ Output to stdout is captured, but not output to stderr (exception + tracebacks are captured via a different means). + ++ If you continue a line via backslashing in an interactive session, + or for any other reason use a backslash, you need to double the + backslash in the docstring version. This is simply because you're + in a string, and so the backslash must be escaped for it to survive + intact. Like: + +>>> if "yes" == \\ +... "y" + \\ +... "es": # in the source code you'll see the doubled backslashes +... print 'yes' +yes + +The starting column doesn't matter: + +>>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1.0 + +and as many leading whitespace characters are stripped from the expected +output as appeared in the initial ">>>" line that triggered it. + +If you execute this very file, the examples above will be found and +executed, leading to this output in verbose mode: + +Running doctest.__doc__ +Trying: 1/0 +Expecting: +Traceback (innermost last): + File "", line 1, in ? +ZeroDivisionError: integer division or modulo +ok +Trying: x = 12 +Expecting: nothing +ok +Trying: x +Expecting: 12 +ok +Trying: +if x == 13: + print "yes" +else: + print "no" + print "NO" + print "NO!!!" +Expecting: +no +NO +NO!!! +ok +... and a bunch more like that, with this summary at the end: + +5 items had no tests: + doctest.Tester.__init__ + doctest.Tester.run__test__ + doctest.Tester.summarize + doctest.run_docstring_examples + doctest.testmod +12 items passed all tests: + 8 tests in doctest + 6 tests in doctest.Tester + 10 tests in doctest.Tester.merge + 7 tests in doctest.Tester.rundict + 3 tests in doctest.Tester.rundoc + 3 tests in doctest.Tester.runstring + 2 tests in doctest.__test__._TestClass + 2 tests in doctest.__test__._TestClass.__init__ + 2 tests in doctest.__test__._TestClass.get + 1 tests in doctest.__test__._TestClass.square + 2 tests in doctest.__test__.string + 7 tests in doctest.is_private +53 tests in 17 items. +53 passed and 0 failed. +Test passed. +""" + +# 0,0,1 06-Mar-1999 +# initial version posted +# 0,0,2 06-Mar-1999 +# loosened parsing: +# cater to stinkin' tabs +# don't insist on a blank after PS2 prefix +# so trailing "... " line from a compound stmt no longer +# breaks if the file gets whitespace-trimmed +# better error msgs for inconsistent leading whitespace +# 0,9,1 08-Mar-1999 +# exposed the Tester class and added client methods +# plus docstring examples of their use (eww - head-twisting!) +# fixed logic error in reporting total # of tests & failures +# added __test__ support to testmod (a pale reflection of Christian +# Tismer's vision ...) +# removed the "deep" argument; fiddle __test__ instead +# simplified endcase logic for extracting tests, and running them. +# before, if no output was expected but some was produced +# anyway via an eval'ed result, the discrepancy wasn't caught +# made TestClass private and used __test__ to get at it +# many doc updates +# speed _SpoofOut for long expected outputs +# 0,9,2 09-Mar-1999 +# throw out comments from examples, enabling use of the much simpler +# exec compile(... "single") ... +# for simulating the runtime; that barfs on comment-only lines +# used the traceback module to do a much better job of reporting +# exceptions +# run __doc__ values thru str(), "just in case" +# privateness of names now determined by an overridable "isprivate" +# function +# by default a name now considered to be private iff it begins with +# an underscore but doesn't both begin & end with two of 'em; so +# e.g. class_t.__init__ etc are searched now -- as they always +# should have been +# 0,9,3 18-Mar-1999 +# added .flush stub to _SpoofOut (JPython buglet diagnosed by +# Hugh Emberson) +# repaired ridiculous docs about backslashes in examples +# minor internal changes +# changed source to Unix line-end conventions +# moved __test__ logic into new Tester.run__test__ method +# 0,9,4 27-Mar-1999 +# report item name and line # in failing examples +# 0,9,5 29-Jun-1999 +# allow straightforward exceptions in examples - thanks to Mark Hammond! +# 0,9,5,1 31-Mar-2000 +# break cyclic references to functions which are defined in docstrings, +# avoiding cyclic trash +# 0,9,5,2 11-Apr-2000 +# made module argument to testmod optional; it runs testmod on the __main__ +# module in that case. + +__version__ = 0, 9, 5 + +import types +_FunctionType = types.FunctionType +_ClassType = types.ClassType +_ModuleType = types.ModuleType +_StringType = types.StringType +del types + +import string +_string_find = string.find +_string_join = string.join +_string_split = string.split +_string_rindex = string.rindex +del string + +import re +PS1 = ">>>" +PS2 = "..." +_isPS1 = re.compile(r"(\s*)" + re.escape(PS1)).match +_isPS2 = re.compile(r"(\s*)" + re.escape(PS2)).match +_isEmpty = re.compile(r"\s*$").match +_isComment = re.compile(r"\s*#").match +del re + +# Extract interactive examples from a string. Return a list of triples, +# (source, outcome, lineno). "source" is the source code, and ends +# with a newline iff the source spans more than one line. "outcome" is +# the expected output if any, else an empty string. When not empty, +# outcome always ends with a newline. "lineno" is the line number, +# 0-based wrt the start of the string, of the first source line. + +def _extract_examples(s): + isPS1, isPS2 = _isPS1, _isPS2 + isEmpty, isComment = _isEmpty, _isComment + examples = [] + lines = _string_split(s, "\n") + i, n = 0, len(lines) + while i < n: + line = lines[i] + i = i + 1 + m = isPS1(line) + if m is None: + continue + j = m.end(0) # beyond the prompt + if isEmpty(line, j) or isComment(line, j): + # a bare prompt or comment -- not interesting + continue + lineno = i - 1 + if line[j] != " ": + raise ValueError("line " + `lineno` + " of docstring lacks " + "blank after " + PS1 + ": " + line) + j = j + 1 + blanks = m.group(1) + nblanks = len(blanks) + # suck up this and following PS2 lines + source = [] + while 1: + source.append(line[j:]) + line = lines[i] + m = isPS2(line) + if m: + if m.group(1) != blanks: + raise ValueError("inconsistent leading whitespace " + "in line " + `i` + " of docstring: " + line) + i = i + 1 + else: + break + if len(source) == 1: + source = source[0] + else: + # get rid of useless null line from trailing empty "..." + if source[-1] == "": + del source[-1] + source = _string_join(source, "\n") + "\n" + # suck up response + if isPS1(line) or isEmpty(line): + expect = "" + else: + expect = [] + while 1: + if line[:nblanks] != blanks: + raise ValueError("inconsistent leading whitespace " + "in line " + `i` + " of docstring: " + line) + expect.append(line[nblanks:]) + i = i + 1 + line = lines[i] + if isPS1(line) or isEmpty(line): + break + expect = _string_join(expect, "\n") + "\n" + examples.append( (source, expect, lineno) ) + return examples + +# Capture stdout when running examples. + +class _SpoofOut: + def __init__(self): + self.clear() + def write(self, s): + self.buf.append(s) + def get(self): + return _string_join(self.buf, "") + def clear(self): + self.buf = [] + def flush(self): + # JPython calls flush + pass + +# Display some tag-and-msg pairs nicely, keeping the tag and its msg +# on the same line when that makes sense. + +def _tag_out(printer, *tag_msg_pairs): + for tag, msg in tag_msg_pairs: + printer(tag + ":") + msg_has_nl = msg[-1:] == "\n" + msg_has_two_nl = msg_has_nl and \ + _string_find(msg, "\n") < len(msg) - 1 + if len(tag) + len(msg) < 76 and not msg_has_two_nl: + printer(" ") + else: + printer("\n") + printer(msg) + if not msg_has_nl: + printer("\n") + +# Run list of examples, in context globs. "out" can be used to display +# stuff to "the real" stdout, and fakeout is an obj of _SpoofOut +# that captures the examples' std output. Return (#failures, #tries). + +def _run_examples_inner(out, fakeout, examples, globs, verbose, name): + import sys, traceback + OK, BOOM, FAIL = range(3) + NADA = "nothing" + stderr = _SpoofOut() + failures = 0 + for source, want, lineno in examples: + if verbose: + _tag_out(out, ("Trying", source), + ("Expecting", want or NADA)) + fakeout.clear() + try: + exec compile(source, "", "single") in globs + got = fakeout.get() + state = OK + except: + # See whether the exception was expected. + if _string_find(want, "Traceback (innermost last):\n") == 0: + # Only compare exception type and value - the rest of + # the traceback isn't necessary. + want = _string_split(want, '\n')[-2] + '\n' + exc_type, exc_val, exc_tb = sys.exc_info() + got = traceback.format_exception_only(exc_type, exc_val)[0] + state = OK + else: + # unexpected exception + stderr.clear() + traceback.print_exc(file=stderr) + state = BOOM + + if state == OK: + if got == want: + if verbose: + out("ok\n") + continue + state = FAIL + + assert state in (FAIL, BOOM) + failures = failures + 1 + out("*" * 65 + "\n") + _tag_out(out, ("Failure in example", source)) + out("from line #" + `lineno` + " of " + name + "\n") + if state == FAIL: + _tag_out(out, ("Expected", want or NADA), ("Got", got)) + else: + assert state == BOOM + _tag_out(out, ("Exception raised", stderr.get())) + return failures, len(examples) + +# Run list of examples, in context globs. Return (#failures, #tries). + +def _run_examples(examples, globs, verbose, name): + import sys + saveout = sys.stdout + try: + sys.stdout = fakeout = _SpoofOut() + x = _run_examples_inner(saveout.write, fakeout, examples, + globs, verbose, name) + finally: + sys.stdout = saveout + return x + +def run_docstring_examples(f, globs, verbose=0, name="NoName"): + """f, globs, verbose=0, name="NoName" -> run examples from f.__doc__. + + Use dict globs as the globals for execution. + Return (#failures, #tries). + + If optional arg verbose is true, print stuff even if there are no + failures. + Use string name in failure msgs. + """ + + try: + doc = f.__doc__ + if not doc: + # docstring empty or None + return 0, 0 + # just in case CT invents a doc object that has to be forced + # to look like a string <0.9 wink> + doc = str(doc) + except: + return 0, 0 + + e = _extract_examples(doc) + if not e: + return 0, 0 + return _run_examples(e, globs, verbose, name) + +def is_private(prefix, base): + """prefix, base -> true iff name prefix + "." + base is "private". + + Prefix may be an empty string, and base does not contain a period. + Prefix is ignored (although functions you write conforming to this + protocol may make use of it). + Return true iff base begins with an (at least one) underscore, but + does not both begin and end with (at least) two underscores. + + >>> is_private("a.b", "my_func") + 0 + >>> is_private("____", "_my_func") + 1 + >>> is_private("someclass", "__init__") + 0 + >>> is_private("sometypo", "__init_") + 1 + >>> is_private("x.y.z", "_") + 1 + >>> is_private("_x.y.z", "__") + 0 + >>> is_private("", "") # senseless but consistent + 0 + """ + + return base[:1] == "_" and not base[:2] == "__" == base[-2:] + +class Tester: + """class_t Tester -- runs docstring examples and accumulates stats. + +In normal use, function doctest.testmod() hides all this from you, +so use that if you can. Create your own instances of Tester to do +fancier things. + +Methods: + runstring(s, name) + Search string s for examples to run; use name for logging. + Return (#failures, #tries). + + rundoc(object, name=None) + Search object.__doc__ for examples to run; use name (or + object.__name__) for logging. Return (#failures, #tries). + + rundict(d, name) + Search for examples in docstrings in all of d.values(); use name + for logging. Return (#failures, #tries). + + run__test__(d, name) + Treat dict d like module.__test__. Return (#failures, #tries). + + summarize(verbose=None) + Display summary of testing results, to stdout. Return + (#failures, #tries). + + merge(other) + Merge in the test results from Tester obj "other". + +>>> from doctest import Tester +>>> t = Tester(globs={'x': 42}, verbose=0) +>>> t.runstring(r''' +... >>> x = x * 2 +... >>> print x +... 42 +... ''', 'XYZ') +***************************************************************** +Failure in example: print x +from line #2 of XYZ +Expected: 42 +Got: 84 +(1, 2) +>>> t.runstring(">>> x = x * 2\\n>>> print x\\n84\\n", 'example2') +(0, 2) +>>> t.summarize() +1 items had failures: + 1 of 2 in XYZ +***Test Failed*** 1 failures. +(1, 4) +>>> t.summarize(verbose=1) +1 items passed all tests: + 2 tests in example2 +1 items had failures: + 1 of 2 in XYZ +4 tests in 2 items. +3 passed and 1 failed. +***Test Failed*** 1 failures. +(1, 4) +>>> +""" + + def __init__(self, mod=None, globs=None, verbose=None, + isprivate=None): + """mod=None, globs=None, verbose=None, isprivate=None + +See doctest.__doc__ for an overview. + +Optional keyword arg "mod" is a module, whose globals are used for +executing examples. If not specified, globs must be specified. + +Optional keyword arg "globs" gives a dict to be used as the globals +when executing examples; if not specified, use the globals from +module mod. + +In either case, a copy of the dict is used for each docstring +examined. + +Optional keyword arg "verbose" prints lots of stuff if true, only +failures if false; by default, it's true iff "-v" is in sys.argv. + +Optional keyword arg "isprivate" specifies a function used to determine +whether a name is private. The default function is doctest.is_private; +see its docs for details. +""" + + if mod is None and globs is None: + raise TypeError("Tester.__init__: must specify mod or globs") + if mod is not None and type(mod) is not _ModuleType: + raise TypeError("Tester.__init__: mod must be a module; " + + `mod`) + if globs is None: + globs = mod.__dict__ + self.globs = globs + + if verbose is None: + import sys + verbose = "-v" in sys.argv + self.verbose = verbose + + if isprivate is None: + isprivate = is_private + self.isprivate = isprivate + + self.name2ft = {} # map name to (#failures, #trials) pair + + def runstring(self, s, name): + """ + s, name -> search string s for examples to run, logging as name. + + Use string name as the key for logging the outcome. + Return (#failures, #examples). + + >>> t = Tester(globs={}, verbose=1) + >>> test = r''' + ... # just an example + ... >>> x = 1 + 2 + ... >>> x + ... 3 + ... ''' + >>> t.runstring(test, "Example") + Running string Example + Trying: x = 1 + 2 + Expecting: nothing + ok + Trying: x + Expecting: 3 + ok + 0 of 2 examples failed in string Example + (0, 2) + """ + + if self.verbose: + print "Running string", name + f = t = 0 + e = _extract_examples(s) + if e: + globs = self.globs.copy() + f, t = _run_examples(e, globs, self.verbose, name) + globs.clear() # DWA - break cyclic references to functions defined in docstrings + if self.verbose: + print f, "of", t, "examples failed in string", name + self.__record_outcome(name, f, t) + return f, t + + def rundoc(self, object, name=None): + """ + object, name=None -> search object.__doc__ for examples to run. + + Use optional string name as the key for logging the outcome; + by default use object.__name__. + Return (#failures, #examples). + If object is a class object, search recursively for method + docstrings too. + object.__doc__ is examined regardless of name, but if object is + a class, whether private names reached from object are searched + depends on the constructor's "isprivate" argument. + + >>> t = Tester(globs={}, verbose=0) + >>> def _f(): + ... '''Trivial docstring example. + ... >>> assert 2 == 2 + ... ''' + ... return 32 + ... + >>> t.rundoc(_f) # expect 0 failures in 1 example + (0, 1) + """ + + if name is None: + try: + name = object.__name__ + except AttributeError: + raise ValueError("Tester.rundoc: name must be given " + "when object.__name__ doesn't exist; " + `object`) + if self.verbose: + print "Running", name + ".__doc__" + globs = self.globs.copy() + f, t = run_docstring_examples(object, globs, + self.verbose, name) + globs.clear() # DWA - break cyclic references to functions defined in docstrings + + if self.verbose: + print f, "of", t, "examples failed in", name + ".__doc__" + self.__record_outcome(name, f, t) + if type(object) is _ClassType: + f2, t2 = self.rundict(object.__dict__, name) + f = f + f2 + t = t + t2 + return f, t + + def rundict(self, d, name): + """ + d. name -> search for docstring examples in all of d.values(). + + For k, v in d.items() such that v is a function or class, + do self.rundoc(v, name + "." + k). Whether this includes + objects with private names depends on the constructor's + "isprivate" argument. + Return aggregate (#failures, #examples). + + >>> def _f(): + ... '''>>> assert 1 == 1 + ... ''' + >>> def g(): + ... '''>>> assert 2 != 1 + ... ''' + >>> d = {"_f": _f, "g": g} + >>> t = Tester(globs={}, verbose=0) + >>> t.rundict(d, "rundict_test") # _f is skipped + (0, 1) + >>> t = Tester(globs={}, verbose=0, isprivate=lambda x,y: 0) + >>> t.rundict(d, "rundict_test_pvt") # both are searched + (0, 2) + """ + + if not hasattr(d, "items"): + raise TypeError("Tester.rundict: d must support .items(); " + + `d`) + f = t = 0 + for thisname, value in d.items(): + if type(value) in (_FunctionType, _ClassType): + f2, t2 = self.__runone(value, name + "." + thisname) + f = f + f2 + t = t + t2 + return f, t + + def run__test__(self, d, name): + """d, name -> Treat dict d like module.__test__. + + Return (#failures, #tries). + See testmod.__doc__ for details. + """ + + failures = tries = 0 + prefix = name + "." + savepvt = self.isprivate + try: + self.isprivate = lambda *args: 0 + for k, v in d.items(): + thisname = prefix + k + if type(v) is _StringType: + f, t = self.runstring(v, thisname) + elif type(v) in (_FunctionType, _ClassType): + f, t = self.rundoc(v, thisname) + else: + raise TypeError("Tester.run__test__: values in " + "dict must be strings, functions " + "or classes; " + `v`) + failures = failures + f + tries = tries + t + finally: + self.isprivate = savepvt + return failures, tries + + def summarize(self, verbose=None): + """ + verbose=None -> summarize results, return (#failures, #tests). + + Print summary of test results to stdout. + Optional arg 'verbose' controls how wordy this is. By + default, use the verbose setting established by the + constructor. + """ + + if verbose is None: + verbose = self.verbose + notests = [] + passed = [] + failed = [] + totalt = totalf = 0 + for x in self.name2ft.items(): + name, (f, t) = x + assert f <= t + totalt = totalt + t + totalf = totalf + f + if t == 0: + notests.append(name) + elif f == 0: + passed.append( (name, t) ) + else: + failed.append(x) + if verbose: + if notests: + print len(notests), "items had no tests:" + notests.sort() + for thing in notests: + print " ", thing + if passed: + print len(passed), "items passed all tests:" + passed.sort() + for thing, count in passed: + print " %3d tests in %s" % (count, thing) + if failed: + print len(failed), "items had failures:" + failed.sort() + for thing, (f, t) in failed: + print " %3d of %3d in %s" % (f, t, thing) + if verbose: + print totalt, "tests in", len(self.name2ft), "items." + print totalt - totalf, "passed and", totalf, "failed." + if totalf: + print "***Test Failed***", totalf, "failures." + elif verbose: + print "Test passed." + return totalf, totalt + + def merge(self, other): + """ + other -> merge in test results from the other Tester obj. + + If self and other both have a test result for something + with the same name, the (#failures, #tests) results are + summed, and a warning is printed to stdout. + + >>> from doctest import Tester + >>> t1 = Tester(globs={}, verbose=0) + >>> t1.runstring(''' + ... >>> x = 12 + ... >>> print x + ... 12 + ... ''', "t1example") + (0, 2) + >>> + >>> t2 = Tester(globs={}, verbose=0) + >>> t2.runstring(''' + ... >>> x = 13 + ... >>> print x + ... 13 + ... ''', "t2example") + (0, 2) + >>> common = ">>> assert 1 + 2 == 3\\n" + >>> t1.runstring(common, "common") + (0, 1) + >>> t2.runstring(common, "common") + (0, 1) + >>> t1.merge(t2) + *** Tester.merge: 'common' in both testers; summing outcomes. + >>> t1.summarize(1) + 3 items passed all tests: + 2 tests in common + 2 tests in t1example + 2 tests in t2example + 6 tests in 3 items. + 6 passed and 0 failed. + Test passed. + (0, 6) + >>> + """ + + d = self.name2ft + for name, (f, t) in other.name2ft.items(): + if d.has_key(name): + print "*** Tester.merge: '" + name + "' in both" \ + " testers; summing outcomes." + f2, t2 = d[name] + f = f + f2 + t = t + t2 + d[name] = f, t + + def __record_outcome(self, name, f, t): + if self.name2ft.has_key(name): + print "*** Warning: '" + name + "' was tested before;", \ + "summing outcomes." + f2, t2 = self.name2ft[name] + f = f + f2 + t = t + t2 + self.name2ft[name] = f, t + + def __runone(self, target, name): + if "." in name: + i = _string_rindex(name, ".") + prefix, base = name[:i], name[i+1:] + else: + prefix, base = "", base + if self.isprivate(prefix, base): + return 0, 0 + return self.rundoc(target, name) + +master = None + +def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None, + report=1): + """m=None, name=None, globs=None, verbose=None, isprivate=None, report=1 + + Test examples in docstrings in functions and classes reachable from + module m, starting with m.__doc__. Private names are skipped. + + Also test examples reachable from dict m.__test__ if it exists and is + not None. m.__dict__ maps names to functions, classes and strings; + function and class docstrings are tested even if the name is private; + strings are tested directly, as if they were docstrings. + + Return (#failures, #tests). + + See doctest.__doc__ for an overview. + + Optional keyword arg "name" gives the name of the module; by default + use m.__name__. + + Optional keyword arg "globs" gives a dict to be used as the globals + when executing examples; by default, use m.__dict__. A copy of this + dict is actually used for each docstring, so that each docstring's + examples start with a clean slate. + + Optional keyword arg "verbose" prints lots of stuff if true, prints + only failures if false; by default, it's true iff "-v" is in sys.argv. + + Optional keyword arg "isprivate" specifies a function used to + determine whether a name is private. The default function is + doctest.is_private; see its docs for details. + + Optional keyword arg "report" prints a summary at the end when true, + else prints nothing at the end. In verbose mode, the summary is + detailed, else very brief (in fact, empty if all tests passed). + + Advanced tomfoolery: testmod runs methods of a local obj of + class doctest.Tester, then merges the results into (or creates) + global Tester obj doctest.master. Methods of doctest.master + can be called directly too, if you want to do something unusual. + Passing report=0 to testmod is especially useful then, to delay + displaying a summary. Invoke doctest.master.summarize(verbose) + when you're done fiddling. + """ + + global master + + if m is None: + import sys + # DWA - m will still be None if this wasn't invoked from the command + # line, in which case the following TypeError is about as good an error + # as we should expect + m = sys.modules.get('__main__') + + if type(m) is not _ModuleType: + raise TypeError("testmod: module required; " + `m`) + if name is None: + name = m.__name__ + tester = Tester(m, globs=globs, verbose=verbose, isprivate=isprivate) + failures, tries = tester.rundoc(m, name) + f, t = tester.rundict(m.__dict__, name) + failures = failures + f + tries = tries + t + if hasattr(m, "__test__"): + testdict = m.__test__ + if testdict: + if not hasattr(testdict, "items"): + raise TypeError("testmod: module.__test__ must support " + ".items(); " + `testdict`) + f, t = tester.run__test__(testdict, name + ".__test__") + failures = failures + f + tries = tries + t + if report: + tester.summarize() + if master is None: + master = tester + else: + master.merge(tester) + return failures, tries + +class _TestClass: + """ + A pointless class, for sanity-checking of docstring testing. + + Methods: + square() + get() + + >>> _TestClass(13).get() + _TestClass(-12).get() + 1 + >>> hex(_TestClass(13).square().get()) + '0xa9' + """ + + def __init__(self, val): + """val -> _TestClass object with associated value val. + + >>> t = _TestClass(123) + >>> print t.get() + 123 + """ + + self.val = val + + def square(self): + """square() -> square TestClass's associated value + + >>> _TestClass(13).square().get() + 169 + """ + + self.val = self.val ** 2 + return self + + def get(self): + """get() -> return TestClass's associated value. + + >>> x = _TestClass(-42) + >>> print x.get() + -42 + """ + + return self.val + +__test__ = {"_TestClass": _TestClass, + "string": r""" + Example of a string object, searched as-is. + >>> x = 1; y = 2 + >>> x + y, x * y + (3, 2) + """ + } + +def _test(): + import doctest + return doctest.testmod(doctest) + +if __name__ == "__main__": + _test() From c44498ea69f5a4cf08afb69371ead10677dc061b Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 27 Nov 2000 07:53:09 +0000 Subject: [PATCH 006/154] boost-ification [SVN r8337] --- build/build.opt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 build/build.opt diff --git a/build/build.opt b/build/build.opt deleted file mode 100644 index 3599f1b0..00000000 --- a/build/build.opt +++ /dev/null @@ -1 +0,0 @@ -ÐÏࡱ \ No newline at end of file From 89760f95f1720f9485da834f57e4544c3d1d5343 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 27 Nov 2000 07:54:02 +0000 Subject: [PATCH 007/154] boost-ification [SVN r8338] --- build/build.opt | Bin 0 -> 84480 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 build/build.opt diff --git a/build/build.opt b/build/build.opt new file mode 100644 index 0000000000000000000000000000000000000000..a650cf1f83e6ca05cbe1a0fccd96f89b59f47f31 GIT binary patch literal 84480 zcmca`Uhu)fjZzO8(10BSGsD0CoD6J8;!F$-42&?o00YCn|NsAkxG);TZeU(z@W##z@X2-z+k|@z+lM0z+l9{z+lY4z+l3_z+lS2z+lF}z+le6z+l0^z+lP1 zz+lC|z+lb5z+l6`z+lV3z+eY8&w+t~!I6Q1!HI!^!I^=9!G(c=!Igo5!Ht1|!JUDD z!GnQ;!IOc3!Ha=`!JC1B!H0o?!Iy!7!HA_D_M5(5K6 zG6Mrc3RM4e1_p+71_p)<1_p*q1_p*K1_p*~1_p*41_p*)1_p*a1_p+F1_p)#1_p*g z1_p*A1_p*=1_p)_1_p*ws2Sx93=9-r@+9(2uib{v&|p z81fm)8HyQF!Qn_qFS@({0}~@C?|{llV(sSv83M{I;PjTlkjYR24h4`fshE#}i4l}X zL3V>MG5WaGA%G0wAwVZL=1y&FPCSjU5QY#X33vyBo z4e;0nQxgMYz;x@y=pmt!{QMla?=tg}b4pWEW0G?ci;MGv^fHuUc)2*0koD;4 z#bDP)juwzdD#+28mzJ4MitAD`lS@dqCoMB4l?+`u`HAFMR+^Vgx@DQU1^GoJMO0=U z8IH@$D=A9ONKMWrCD3y+i^;GmCqFNp^l->cEy>7FAwyq&N^xlcsbQF#pHfOr(#WmM zP0Y#3PbMW4b1Msq@=Nkb(L#DKtz%aU{+&LW%-bb1h`R!VpKx|Hz~0=H6B*T5%eWgQ*vT)3BE9fdKIRc zV9G#MpIT9png{YmJh=TtyhUlHdC4WDc|S8Rvm_p-k9eE%^7B%OS6!T$o|jlsT0~SV zLIbThGcP?SwIn}}cxynJgoKzcFG?(khlD&4cEIWlf=L8Ybdiw2A&HL|hm(?Zi&E24 zi&FEF@kUc|ZemeMd_f7`d4 zYCsrf9!w30KEc4iFbz8G08#_OXP6imG{9rCAQcb{QwK5@qy~g>nFrDV(hgDs!uZsI z)Pl^+iy0mN!x#!39sh$RiqY{u(8vuuk3jkhkWK(810JK}e+8rCf1~4nuu^4o{I9qq zW_0{-bo_60{14|4J!G&i20FqxI{p_kI{pXhvy9@=5Eu=C(GVC7fzc44N(gW;Ff;i2 zc=<3faE7E7mpGRem8B}WSj7|U6fOpG9VVHm$^h^#h<0v#>@-roiwhEyQx(*~+o{y8 z6igHfit<6*tu=}@A*Rt^6~taN$C9+In2f#4pxq-msiXV9A^Yw@8@fmz3LoA74GF!` z{onbBCETPZqtWr-(eYpK=^vxxzu?`C@X?mh@n6tv8Mv)8I{u3?Gk`iUIlBKlGbd(r z|2MesKpD6m-Tw{hWR2p{5Eu=C(GVC7fzc2coFS0#3Ua2e1kwu=K#pS9Zo$`2t5ig!-7(CQWJ|)!DE%6LxLGVtXHg{aZ3>EH<$$qBb=s! zlriGf%EloQ9PAXtz{tSO;2e@zl%87RS(2KI$2oW{1W7`TOmQt{rY=>;;e$=5VXvEPxFu;8w$n zGMSG@9m=6+xYhBa4XNT*$%ndy8Mi`iq?6rntKtWpI)-%M5N?&+NSi+Ks6tw$idz*2 zY#}giCA=u@Z`|s5kQajDR>lcGjS;sR9^`W`aVrzTTvLWyF%R*}o{Svn#KGe}~+zQ!~Q_B)_^fGX(0HsQzeZhl#Kn89zIpL$r zxYh6_m8PYo77-3(uEeBbP!Ups≶XgBEaG$pNWX@R`G#hJ2PUZlkzh1yMl(Zbclh z69{oDfz+Ku)QNPi?WkFo5w1CTM{7HHV+g5*L(STbxGIW@l_IEIA-at)THArz!N^fh zxLh2q?I67eq);2YwH*;v&j3`2RITlZ>$Op{PNa4pgxG3`lbBv5aor0dThhce^NDJd z5Z_~@MF~zsKHw#`6GB{-1`0aDg()$80%AK+RPQ?wIYL2H&w;r9EYgh(xZAEoRzQRc zWnu?Ki0TP|QZ3Q_8KQe-M0R|LXt5E|k0q)zLtJr7d`FSs@D|ba6H#3iB6^6#^g)Ol ztRl9aBX;bFxDgAYN8E_66Cu4t2niaZ9mS&|Fd71*Aut*OqaiRF0;3@?8UiGQ02dP@ z3ut1U&crRJ&bu$%olNFR8 z%T*LWc3CSxIr+ub3i-u)$r&k`MH=dQdioFqQlqX3R|Q%e2EVP%S^lCN7(QluWMsRU{qAr>cM@jgfaWLYA}!9@6v6&$)C#e>6l z*cM?zR~MqMq{JH4pk$9FTtLE5W2n7)k}oK=n7H+rNSBl|G6+FdZKfudAXZ&MT}Z^* z6QahW`B3kV#64|5+~6rub6LEgMRM@FG;v!=^hhl6lVe29MG!ODLd+<)5M=Ep@_szr zo+Z58hKTWIA{S(EfmV1xE{MhLAYxY^5-~GEW}DYCr;4Cww=m~7?; z1u)Xh!ni$5%%ndT;{I9O1`(bQC4N;YF;i_s&K?uH_<^|jbbhpB9&rZ;ar2mh;G9KV z0SHQSM9%;dw>q7Od0igj7CRHUR-6NNcQc-VBWj&KPf;SMf&{Gr# zTu6;uEwRfvxWO?DIYJblX~;KD<5oxH+5}KyE=tZw1zkvw+c2WnClIrAn-i2Y3Diu) zHGYV!zKEUtCVHs=52!$gT{w?B)QDJ81DVMtrUgn=$b!mpf|X@{ZUNE}M7W(#OxukJ zFB0E)AT0|LmtBa={Y2GUyeOOfaR(exy#*rLdPFzciEUpJlk?VL33ZSx#sKzPLTY`vg`4H2hB%d{rJ1jR0axPaN9}W z0A}W-LZ?KDt%iuIXGiw|V%^#fUHX9MU<#s(<){Xz=YA)0pn0F0aFh*2D+FR zb(Jh)kuOLbvH%sdAeP|j*_W)7QP%@!q~_%0!P#LSQ!oNHKMN=#t|%_ z5QFL%7K?+48IUHnBSBi;X;zwWu3%MiVz;=g^XJvlLT)BAgbaeCSs{uITKOe5?_asRv{2qOCtW>ptS@DWjFkM3S04#E-2I+rp#j7z}a4D#Z45h#gd+W{-%JE(O&Gb4VFX0OfANYxam39wMq^ zL2OS3xfKdwkFNhkUQ0sEcmc7c5aG(5*bMZ{8$!RR%} zS`^SS4oED4SOgbzU<(6K*bJxD97L7yL=1ZqRqYU8ZWG;%C#FS8T=$!(kRY~+N!;uv zs8K?6Q<nT|`b@5qH%rk;B2njI|Rx`ao>(5i{RJxTiuykAavGWl)!y@JIuZ z!vn+)h!WQoAb!S#+AB7QADt#j=EIP3rUy|lLh#sZ@`(ve9*H;yB#g|J80e*`-P zk(P3atVD@B{gJ392(b%=h-&&1(dZ<)%};D2oS6EUnA*0WvbZF%Bo*I@9Yl2=h-$$T z-$x>{kxq2uo2Vuyv4?(-uK!5IxUHI)HYpJ`Bh{PzME0pj=r9r2lm}IZL^M%}n}s2w z)j@1~pKu$Uq>d6Xt#u+BbHrBpL^kV*Yp#>j79zfdO>D1=H3hLsX}O*r6y$`xBXjOmPz1F(9gZsMi{i0CH~S=A9SX+!LYHSsM!qB|Qz4N4F_utMb) z+vxfa=oBYWwHY>BPC3SlpIb(RYKGt zAo2N@=w=)-Et1jsf0W|_iD_bh?%5;UP9?U}MRcoxaF2n=u__{J8{!)^L^h6zZA}q1 z_)gSdY*J}jT51sy@kHbi1)!$;==?v%xGk}LEn?;y2)9&;nUP2)9Os}e6Jb?Eb`Oai z5F@TBI6D8&&)|%>mlf2?gx1ER^Z$r5nMddU^YC9~LF_ObQC)4~N7x`Em&oMk{6A6_ zCVpAm==?wGG1f%4`H3CpL#vPfGcqzU2{16MkpIffk-)$K>(Y+WqhK@yhJOhB{r~@e z69WT7GXn!d3j+f~D+2>V8v_GFI|Bnl2Ll5`Cj$dR7Xt&szyJUL_b@Op^fE9o^f53n z^fNFpOkiMOn8?7uFo}VIVKM^)!xRPvhN%n;4AY?ML3(B~FfhzwU|^Wdz`!tvfq`Kz z0|Uc61_p-t3=9kl7#J89GB7YKVqjoc4Alb~S{udm3jsz3RtC`U<^TVT4BQOP&N;~jgfQWwnh-8zs1w9aMT`!UF-8kBXLS5mPfuS@Paia7jdUC_ zNyipL2be)d#Dm#bwziFq|BjCT61aYmsJSj;o1Vl?_JYRSh@L7ZYV{~F%Qr^He?@|W zoq|Tke=!C+LFsXH{1+owM#q0g$A7WiX-3?VuhIQq(545{AQ>?W+(yTLN5_AQit%l_ zA!d&z@#EUWtRx^}A;jqTFV>kYA{w2eBDt^kSy38j1HWj)p$kuIl9gu)u45u91M&O zyf9IxqSVA}m<$sGLxZSGVo4&XgQnn{S)7=YnVy%MnpXl-!OFmJK)^9MIkmW0AuKaL zC$S_mKMy9!#=vlZ*E3HcATd2v!L_I;AAJ56$VyoTh6BQ$IXS86i8%_MdBr6~rOC)T zdl(oFh&mP(B~~gp<(KBA6f3w^B&VjPq^7{k?qy&&Am)~npID;clA4!al$)5N;9rnh zl$Zxs(#ODXKm@8Jvn(?uRUxTTAu6>fA7+Lc*cEwYi8+}m3ND$&1^LC9$gb!|7~q+g zT9KGsq7al?T$%&-{R9Sv1L6=HJfX&b-GFS!L?!5+vi9msygTn3Gur zPL2w0iJ3WwlvBr$dqBW9KczG$71M}%hTH?f0Y&-AsVSvJSmZfC?t;a&M`B(|PAbgy z==dMNXx3=9kkWtSNk)ENSKwlD;;L-iHxa>z00y$eIj1xwH73H>)z?2L zQmxw9#KO$X(!xd8#M0GC*U-?}P1niI#7x(~z|qmbz{J_m$knKpfk6jqD#&@TsQdH( z|Noc&|NlS6z`y{)Dl7~PFPIn@ml&K7nd%xEx)|s>x*0lw5{!YfrGcBJ zi>n!d1oMf3fdPa=pn=0Uz<~n_kPQqB43-QG3@{oNI0o>*fdmmWbW&1F5;JpRQY%V8 zVUwR1pPZ9e3|<#bmE;4nJ&75Td>95egh1}$0uc-h3@{qXWl(d*mVBV+9K}HPQIMK) zKnE6q=Gf7T8Ycz@1`rlvVPMz-DvNOKe;+;nBNciQ!07oOIF3jdo&RwPBIZoc(epnF zFxMRue>yQSYfDGhe`B4<9i9KdRlR}oBoW7$j^6(fMAVrj#N^S@`Jd7Gp907!<)i0+ cz}o(!^k@i-ybu_j{~394KI-Gq5P*dM06)EQvH$=8 literal 0 HcmV?d00001 From 01e60ac7118f80b6a608f8512223557887777d6f Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 27 Nov 2000 07:59:10 +0000 Subject: [PATCH 008/154] Comeau Compatibility [SVN r8339] --- include/boost/python/class_builder.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/python/class_builder.hpp b/include/boost/python/class_builder.hpp index 9e88f049..7ef843c4 100644 --- a/include/boost/python/class_builder.hpp +++ b/include/boost/python/class_builder.hpp @@ -27,8 +27,8 @@ class class_builder // define constructors template - void def(const signature& signature) - { m_class->def(signature); } + void def(const signature& s) + { m_class->def(s); } // export heterogeneous reverse-argument operators // (type of lhs: 'left', of rhs: 'right') From 57dd8ff5357c1a0f1cb887f79dc382747dc4a7e5 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 27 Nov 2000 08:04:05 +0000 Subject: [PATCH 009/154] boost-ification [SVN r8340] --- build/gcc.mak | 48 ++++++ build/tru64.mak | 51 ++++++ release_notes.txt | 217 +++++++++++++++++++++++ todo.txt | 426 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 742 insertions(+) create mode 100644 build/gcc.mak create mode 100644 build/tru64.mak create mode 100644 release_notes.txt create mode 100644 todo.txt diff --git a/build/gcc.mak b/build/gcc.mak new file mode 100644 index 00000000..cec872cf --- /dev/null +++ b/build/gcc.mak @@ -0,0 +1,48 @@ +LIBSRC = \ + extclass.cpp \ + init_function.cpp \ + py.cpp \ + module.cpp \ + subclass.cpp \ + functions.cpp \ + newtypes.cpp \ + objects.cpp + +LIBOBJ = $(LIBSRC:.cpp=.o) +OBJ = $(LIBOBJ) extclass_demo.o + + +ifeq "$(OS)" "Windows_NT" +PYTHON_LIB=c:/tools/python/libs/python15.lib +INC = -Ic:/cygnus/usr/include/g++-3 -Ic:/cygnus/usr/include -Ic:/boost -Ic:/tools/python/include +MODULE_EXTENSION=dll +else +INC = -I/home/koethe/include -I/home/koethe/C++/boost -I/home/koethe/python/include/python1.5 +MODULE_EXTENSION=so +endif + +%.o: %.cpp + g++ -fPIC $(INC) -c $*.cpp + +%.d: %.cpp + @echo creating $@ + @set -e; g++ -M $(INC) -c $*.cpp \ + | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \ + [ -s $@ ] || rm -f $@ + +demo: extclass_demo.o libpycpp.a + g++ -shared -o demomodule.$(MODULE_EXTENSION) $(PYTHON_LIB) extclass_demo.o -L. -lpycpp + python test_extclass.py + +clean: + rm -rf *.o *.$(MODULE_EXTENSION) *.a *.d *.pyc *.bak a.out + +libpycpp.a: $(LIBOBJ) + rm -f libpycpp.a + ar cq libpycpp.a $(LIBOBJ) + +DEP = $(OBJ:.o=.d) + +ifneq "$(MAKECMDGOALS)" "clean" +include $(DEP) +endif diff --git a/build/tru64.mak b/build/tru64.mak new file mode 100644 index 00000000..6631615c --- /dev/null +++ b/build/tru64.mak @@ -0,0 +1,51 @@ +# +# Tested with: +# Compaq C++ V6.2-024 for Digital UNIX V5.0 (Rev. 910) +# +# Python 1.5.2 was installed without any customizations. +# boost_all.zip vers. 1.18.1 was unpacked using unzip -aa and not modified. +# STLport-4.1b3 was unpacked using unzip -aa and not modified. +# +# Initial version 2000-10-20: Ralf W. Grosse-Kunstleve, rwgk@cci.lbl.gov +# + +PYINC= /usr/local/include/python1.5 +BOOSTINC= /usr/local/boost_1_18_1 +STLPORTINC= /usr/local/STLport-4.1b3/stlport +STLPORTOPTS= \ + -D__USE_STD_IOSTREAM \ + -D__STL_NO_SGI_IOSTREAMS \ + -D__STL_NO_NEW_C_HEADERS \ + -D_RWSTD_COMPILE_INSTANTIATE=1 + +STDOPTS= -std strict_ansi +WARNOPTS= -msg_disable 186,450,1115 +# use -msg_display_number to obtain integer tags for -msg_disable + +CPP= cxx +CPPOPTS= -I$(STLPORTINC) $(STLPORTOPTS) -I$(BOOSTINC) -I$(PYINC) \ + $(STDOPTS) $(WARNOPTS) + +LD= cxx +LDOPTS= -shared -expect_unresolved '*' + +OBJ = extclass.o functions.o init_function.o module.o newtypes.o \ + objects.o py.o subclass.o + +.SUFFIXES: .o .cpp + +all: demo.so hello.so + +demo.so: $(OBJ) extclass_demo.o + $(LD) $(LDOPTS) $(OBJ) extclass_demo.o -o demo.so + +hello.so: $(OBJ) example1.o + $(LD) $(LDOPTS) $(OBJ) example1.o -o hello.so + +.cpp.o: + -$(CPP) $(CPPOPTS) $(INC) -c $*.cpp + +clean: + rm -f $(OBJ) extclass_demo.o example1.o demo.so hello.so so_locations + rm -rf cxx_repository + rm -f *.pyc diff --git a/release_notes.txt b/release_notes.txt new file mode 100644 index 00000000..8932a0aa --- /dev/null +++ b/release_notes.txt @@ -0,0 +1,217 @@ +2000-11-22 10:00 + Ullrich fixed bug in operator_dispatcher. + +2000-11-21 10:00 + Changed all class and function names into lower_case. + + Ullrich updated documentation for operator wrapping. + +2000-11-20 10:00 + Ullrich renamed ExtensionClass:register_coerce() into + ExtensionClass:def_standard_coerce() and made it public + + Ullrich improved shared_pod_manager. + +2000-11-17 15:04 + Changed allocation strategy of shared_pod_manager to make it portable. + + Added pickling support + tests thanks to "Ralf W. Grosse-Kunstleve" + + + Added a specialization of Callback to prevent unsafe usage. + + Fixed Ullrich's operator_dispatcher refcount bug + + Removed const char* return values from virtual functions in tests; that + usage was unsafe. + + Ullrich changed Module::add() so that it steals a reference (fix of refcount bug) + + Ullrich added operator_dispatcher::create() optimization + + Ullrich changed design and implementation of TypeObjectBase::enable() (to eliminate low-level + code) and added shared_pod_manager optimization. + + +2000-11-15 12:01 + Fixed refcount bugs in operator calls. + + Added callback_adjust_refcount(PyObject*, Type) to account for different ownership + semantics of Callback's return types and Caller's arguments (which both use from_python()) + This bug caused refcount errors during operator calls. + + Moved operator_dispatcher into extclass.cpp + Gave it shared ownership of the objects it wraps + + Introduced sequence points in extension_class_coerce for exception-safety + + UPPER_CASE_MACRO_NAMES + + MixedCase template type argument names + + Changed internal error reporting to use Python exceptions so we don't force the + user to link in iostreams code + + Changed error return value of call_cmp to -1 + + Moved unwrap_* functions out of operator_dispatcher. This was transitional: when + I realized they didn't need to be declared in extclass.h I moved them out, but + now that operator_dispatcher itself is in extclass.cpp they could go back in. + + Numerous formatting tweaks + + Updated the BoundFunction::create() optimization and enabled it so it could actually be used! + +2000-11-15 00:26 + + Made Ullrich's operators support work with MSVC + + Cleaned up operators.h such that invalid define_operator<0> is no longer needed. + + Ullrich created operators.h to support wrapping of C++ operators (including the "__r*__" forms). + He added several auxiliary classes to extclass.h and extclass.cpp (most importantly, + py::detail::operator_dispatcher and py::operators) + +2000-11-13 22:29 + + removed obsolete ExtensionClassFromPython for good. + + removed unused class ExtensionType forward declaration + +2000-11-12 13:08 + + Added enum_as_int_converters for easier enum wrapping + + Introduced new conversion namespace macros: + PY_BEGIN_CONVERSION_NAMESPACE, + PY_END_CONVERSION_NAMESPACE, + PY_CONVERSION + + callback.h, gen_callback.py: + Added call() function so that a regular python function (as opposed to + method or other function-as-attribute) can be called. + + Added newlines for readability. + + class_wrapper.h: + Fixed a bug in add(), which allows non-method class attributes + + Ullrich has added def_raw for simple varargs and keyword support. + + Fixed version number check for __MWERKS__ + + Added tests for enums and non-method class attributes + + objects.h/objects.cpp: + Added py::String operator*= and operator* for repetition + + Change Dict::items(), keys(), and values() to return a List + + Added template versions of set_item, etc., methods so that users can optionally + use C++ types that have to_python() functions as parameters. + + Changed various Ptr by-value parameters to const Ptr& + + +======= Release ======= +2000-11-06 0:22 + Lots of documentation updates + + added 4-argument template constructor to py::Tuple + + added "add" member function to ClassWrapper<> to allow arbitrary Python + objects to be added to an extension class. + + gen_all.py now generates support for n argument member functions and n+1 + argument member functions at the suggestion of "Ralf W. Grosse-Kunstleve" + + + Added regression tests and re-ordered declare_base calls to verify that the + phantom base class issue is resolved. + +2000-11-04 17:35 + + Integrated Ullrich Koethe's brilliant from_python_experiment for better + error-reporting in many cases. + + extclass.h, gen_extclass.py: + removed special-case MSVC code + added much commentary + removed unused py_copy_to_new_value_holder + + init_function.h, gen_init_function.py: + added missing 'template' keyword on type-dependent template member usage + removed special-case MSVC code + added much commentary + +2000-11-04 0:36 + + Removed the need for the phantom base class that screwed up inheritance + hierarchies, introduced error-prone ordering dependencies, and complexified + logic in many places! + + extclass.h: Added some explanatory comments, removed wasteful m_self member + of HeldInstance + + extclass_demo.cpp: Added #pragmas which allow compilation in ansi strict + mode under Metrowerks + + functions.h: Added virtual_function as part of phantom base class removal; + expanded commentary + + pyptr.h: Added some missing 'typename's and a GCC workaround fix + + subclass.cpp: Added missing string literal const_cast<>s. + +2000-11-03 10:58 + + Fix friend function instantiation bug caught by Metrowerks (thanks + Metrowerks!) + + Add proof-of-concept for one technique of wrapping function that return a + pointer + + Worked around MSVC optimizer bug by writing to_python(double) and + to_python(float) out-of-line + +2000-11-02 23:25 + + Add /Zm200 option to vc6_prj to deal with MSVC resource limitations + + Remove conflicting /Ot option from vc6_prj release build + +======= Release ======= +2000-11-02 17:42 + + Added a fix for interactions between default virtual function + implementations and declare_base(). You still need to write your + declare_base() /after/ all member functions have been def()d for the two + classes concerned. Many, many thanks to Ullrich Koethe + for all his work on this. + + Added missing conversions: + to_python(float) + from_python(const char* const&) + from_python(const double&) + from_python(const float&) + + Added a Regression test for a reference-counting bug thanks to Mark Evans + () + + const-ify ClassBase::getattr() + + Add repr() function to Class + + Add to_python/from_python conversions for PyPtr + + Standardize set_item/get_item interfaces (instead of proxies) for Dict and List + + Add Reprable<> template to newtypes.h + + Fix a bug wherein the __module__ attribute would be lost for classes that have a + default virtual function implementation. + + Remove extra ';' in module.cpp thanks to "Ralf W. Grosse-Kunstleve" + + + Fix a bug in the code of example1.html diff --git a/todo.txt b/todo.txt new file mode 100644 index 00000000..d97eade5 --- /dev/null +++ b/todo.txt @@ -0,0 +1,426 @@ +Check for const reference parameters in all from_python functions in py.h, including implementations. +Better python and C++ exception handling/error reporting. +long long support +use Python generic numeric coercion in from_python() for C++ numeric types +Rename PyPtr to Reference. +Report Cygwin linker memory issues +__init__ stuff + Make abstract classes non-instantiable (?) + Call default __init__ functions automatically where applicable (?) +Support for Python LONG types in Objects.h +Throw TypeError after asserting when objects from objects.cpp detect a type mismatch. +Figure out how to package everything as a shared library. +Unicode string support +Add read-only wrapper for __dict__ attribute +Objects.h support for generic objects, Sequence objects, etc. +empty() member functions for objects.hpp + +Testing + Python 2.0 + object revival in __del__ + More thorough tests of objects.h/cpp classes + Better reference-count checking + +Optimizations + Remove one level of indirection on type objects (no vtbl?). + Specializations of Caller<> for commmon combinations of argument types (?) + Replace uses of XXXable classes + Don't allocate instance __dict__ unless used. + + +Documentation: + + differences between Python classes and ExtensionClasses + additional capabilities of ExtensionClasses + slice adjustment + + Why special attributes other than __doc__ and __name__ are immutable. + + An example of the problems with the built-in Python classes. + + >>> class A: + ... def __getattr__(self, name): + ... return 'A.__getattr__' + ... + >>> class B(A): pass + ... + >>> class C(B): pass + ... + >>> C().x + 'A.__getattr__' + >>> B.__bases__ = () + >>> C().x + 'A.__getattr__' + + Smart pointers + #ifndef PY_NO_INLINE_FRIENDS_IN_NAMESPACE + namespace py { + #endif + + template + struct VtkConverters + { + typedef py::PyExtensionClassConverters Converters; + + friend vtk_ptr& from_python(PyObject* p, py::Type&>) + { return Converters::ptr_from_python(p, py::Type >()); } + + friend vtk_ptr& from_python(PyObject* p, py::Type >) + { return Converters::ptr_from_python(p, py::Type >()); } + + friend const vtk_ptr& from_python(PyObject* p, py::Type&>) + { return Converters::ptr_from_python(p, py::Type >()); } + + friend PyObject* to_python(vtk_ptr x) + { return Converters::ptr_to_python(x); } + }; + + #ifndef PY_NO_INLINE_FRIENDS_IN_NAMESPACE + } + #endif + + template + struct VtkWrapper : py::ClassWrapper, py::VtkConverters + { + typedef py::ClassWrapper Base; + VtkWrapper(Module& module, const char* name) + : Base(module, name) {} + }; + + exception handling + + Advanced Topics: + Advanced Type Conversion + adding conversions for fundamental types + generic conversions for template types (with partial spec). + + Interacting with built-in Python objects and types from C++ + + dealing with non-const reference/pointer parameters + + extending multiple-argument support using gen_all.py + + + Fancy wrapping tricks + templates + Yes. If you look at the examples in extclass_demo.cpp you'll see that I have + exposed several template instantiations (e.g. std::pair) in Python. + Keep in mind, however, that you can only expose a template instantiation, + not a template. In other words, MyTemplate can be exposed. MyTemplate + itself cannot. + + Well, that's not strictly true. Wow, this is more complicated to explain + than I thought. + You can't make an ExtensionClass, since after all MyTemplate is + not a type. You can only expose a concrete type to Python. + + What you *can* do (if your compiler supports partial ordering of function + templates - MSVC is broken and does not) is to write appropriate + from_python() and to_python() functions for converting a whole class of + template instantiations to/from Python. That won't let you create an + instance of MyTemplate from Python, but it will let you + pass/return arbitrary MyTemplate instances to/from your + wrapped C++ functions. + + template + MyTemplate from_python(PyObject* x, py::Type >) + { + // code to convert x into a MyTemplate... that part is up to you + } + + template + PyObject* from_python(const MyTemplate&) + { + // code to convert MyTemplate into a PyObject*... that part is up to + you + } + + For example, you could use this to convert Python lists to/from + std::vector automatically. + + Pointer return values + + Case 1: + + > I am now also able to wrap the problematic TextRecordIterator for Python. + > However, one of its function compiles with this warning: + > + > d:\py_cpp/caller.h(33) : warning C4800: 'const class Record *const ' + > : forcing value to bool 'true' or 'false' (performance warning) + > d:\py_cpp/functions.h(54) : see reference to function template + > instantiation 'struct _object *__cdecl py::Caller::call(const class Record + > *const (__thiscall TextRecordIterator::*)(void),struct _object *,struct + > _object *)' being compiled + > + > If you look at the offending code, you'll see that we really do need to + > get back that pointer: + > + > const Record* const TextRecordIterator::Next() { + > if (fStatus != RecordIterator::SUCCESS) { + > return 0; + > } else { + > return &fData; + > } + > } + > + > The point of the TextRecordIterator is to hand over one reord after + > another. A bool wouldn't do us much good here :-) + > + > Do you have any suggestions for fixing this? + + In general, py_cpp doesn't automatically convert pointer return values + to_python because pointers have too many potential meanings. Is it an + iterator? A pointer to a single element? An array? Is ownership being passed + to Python or is the pointer really just a reference? If the latter, what + happens when some C++ code deletes the referent. The only exception to this + rule is const char*, since it has a generally accepted interpretation (could + be trouble with some generic code, though!) + + If you have wrapped the Record class, you could add this to namespace py: + + PyObject* to_python(const Record* p) { + return to_python(*p); + } + + Of course, this will cause the Record class to be copied. If you can't live + with that (Record would have to be /really/ heavyweight to make this + worthwhile), you can follow one of these dangerous approaches: + + 1. Use the technique I described with dangerous_array in + http://www.egroups.com/message/boost/6196. You do not have to expose Record + explicitly in this case. Instead the class you expose will be more of a + Record_proxy + + 2. Wrap Record in the usual way, then add the following to namespace py: + + PyObject* to_python(const Record* p) + { + return ExtensionClass::ptr_to_python(const_cast(p)); + } + + This will cause the Record* to be treated as though it were an owning smart + pointer, even though it's not. Be sure you don't use the reference for + anything from Python once the pointer becomes invalid, though. Don't worry + too much about the const-correctness issue: Const-correctness is completely + lost to Python anyway! + + 3. As above, but instead wrap const Record rather than plain Record. Then + you can avoid the const_cast, but you obviously can't def() any non-const + member functions of Record. + + Case 2: + + > I have yet another question. This is more a general wrapper question. + > Let me say that there is a function that returns a float* which most + > probably is an array. Similarly if I have a function that takes a + > float* as an argument, what is the best way of wrapping this? + + I think you have correctly perceived that it doesn't make sense for me to + automatically convert all pointers, since the ownership semantics are so + blurry. + + > 1) If the array is small it makes sense to convert it to either a + > tuple or list. What is the easiest way to do this?? I am looking + > for a way that makes one write the least code. :) + + How can you tell the length of the array from a single pointer? + Once you've answered that question, you can expose a wrapper function which + returns an instance of the py::Tuple or py::List class from objects.h. If + you are using a List, for example, you could write something like this: + + py::List wrap_f() + { + T* start = f(); + py::List x; + for (T* p = start; p != start + length_constant; ++p) + x.push_back(py::to_python(*p)); + return x; + } + + > 2) If the array is large it may not make sense to use a list/tuple + > esp. if the values are used for computationally intense programs. + + In this case you can do one of several somewhat dangerous things. Why + dangerous? Because python can not control the lifetime of the data, so the + data in the array may be destroyed or become invalid before the last + reference to it disappears. The basic approach is to make a small C++ class + which contains the pointer, and expose that: + + // UNTESTED + template + struct dangerous_array + { + dangerous_array(T* start, T* end) + : m_start(start), m_end(end) {} + + // exposed as "__len__" + std::size_t length() { + return m_end - m_start; + } + + // exposed as "__getitem__" + T get_item(std::size_t n) { + check_range(n); + return start[n]; + } + + // exposed as "__setitem__" if the array is mutable + void set_item(std::size_t n, const T& x) { + check_range(n); + start[n] = x; + } + private: + void check_range(std::size_t n) { + if (n >= m_end - m_start) { + PyErr_SetString(PyExc_IndexError, "array index out of range"); + throw py::ErrorAlreadySet; + } + } + T* m_start; + T* m_end; + }; + + A reasonably safe approach would be to make a wrapper function for each + function that returns a T*, and expose that instead. If you're too lazy and + you really like to live on the edge, though, you can write to_python(T*) in + terms of to_python(const dangerous_array&), and you'll automatically + convert all T* return values to a wrapped dangerous_array. + + > 3) For an arbitrary class "class_A", say, can py_cpp handle + > references to class_A &instance, or class_A *instance?? i.e. will it + > wrap function calls to such objects? This question is obviously + > related to the earlier questions. + + Yes, iff class_A has been exposed to python with a ClassWrapper. + See http://people.ne.mediaone.net/abrahams/downloads/under-the-hood.html for + a few details. + + raw C++ arrays + You could expose a function like this one to get the desired effect: + + #include + void set_len(UnitCell& x, py::Tuple tuple) + { + double len[3]; + for (std::size_t i =0; i < 3; ++i) + len[i] = py::from_python(tuple[i].get(), py::Type()); + x.set_len(len); + } + + Types that are already wrapped by other libraries + + It's not documented yet, but you should be able to use a raw PyObject* or a + py::Ptr as one parameter to your C++ function. Then you can manipulate it as + any other generic Python object. + + Alternatively, If the NTL gives you a C/C++ interface, you can also write + your own converter function: + + some_ntl_type& from_python(PyObject* p, py::Type) + { + // an Example implementation. Basically, you need + // to extract the NTL type from the PyObject*. + if (p->ob_type != NTL_long_type) { + PyErr_SetString(PyExc_TypeErr, "NTL long required"); + throw py::ArgumentError(); + } + return *static_cast(p); + } + + then the C++ functions you're wrapping can take a some_NTL_type& parameter + directly. + + "Thin converting wrappers" for constructors + + hijack some of the functionality + described in the section on Overridable Virtual Functions (even though you + don't have any virtual functions). I suggest this workaround: + + struct UnitCellWrapper : UnitCell + { + UnitCellWrapper(PyObject* self, py::Tuple x, py::Tuple y) + : UnitCell(from_python(x[1], py::Type()), + from_python(x[2], py::Type()), + from_python(x[3], py::Type()), + from_python(y[1], py::Type()), + from_python(y[2], py::Type()), + from_python(y[3], py::Type())) + {} + } + + py::ClassWrapper unit_cell_class; + unit_cell_class.def(py::Constructor()); + ... + + returning references to wrapped objects + + the importance of declaration order of ClassWrappers/ExtensionInstances + + out parameters and non-const pointers + + Calling back into Python: + // caveat: UNTESTED! + #include + #include + #include + #include + int main() + { + try { + py::Ptr module(PyImport_ImportModule("weapons")); + const int strength = 10; + const char* manufacturer = "Vordon Empire"; + py::Ptr a_blaster(py::Callback::call_method( + module.get(), "Blaster", strength, manufacturer)); + py::Callback::call_method(a_blaster.get(), "Fire"); + int old_strength = py::Callback::call_method(a_blaster.get(), "get_strength"); + py::Callback::call_method(a_blaster.get(), "set_strength", 5); + } + catch(...) + { + } + } + + Miscellaneous + About the vc6 project and the debug build + About doctest.py + +Boost remarks: + + > > One of us is completely nuts ;->. How can I move the test + > > (is_prefix(enablers[i].name + 2, name + 2)) outside the loop if it + depends + > > on the loop index, i? + > > + > name += 2; + > for() + > { + > if (is_prefix(enablers[i].name + 2, name)) + > } + + I see now. I guess I should stop pussyfooting and either go for optimization + or clarity here, eh? + + ------ + + > Re: Dict + > Why abbreviate this? Code is read 5 or 6 times for every time its + > written. The few extra characters don't affect compile time or program + > speed. It's part of my personal goal of write what you mean, name them + what + > they are. + + I completely agree. Abbrevs rub me the wrong way, 2 ;-> + + ------- + + + + +Later: + keyword and varargs? + Put explicit Type<> arguments at the beginnings of overloads, to make them look more like template instance specifications. + +Known bugs + can't handle 'const void' return values + Who returns 'const void'? I did it once, by mistake ;) From 23441191c3ced215d6f0ea1c9550fa5e10200f0f Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 27 Nov 2000 12:57:10 +0000 Subject: [PATCH 010/154] boost-ification [SVN r8342] --- include/boost/python/detail/config.hpp | 2 +- include/boost/python/detail/wrap_python.hpp | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/boost/python/detail/config.hpp b/include/boost/python/detail/config.hpp index 2488bd8e..faf52ee4 100644 --- a/include/boost/python/detail/config.hpp +++ b/include/boost/python/detail/config.hpp @@ -21,7 +21,7 @@ # else # define BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE namespace boost { namespace python { # define BOOST_PYTHON_END_CONVERSION_NAMESPACE }} // namespace boost::python -# define BOOST_PYTHON_CONVERSION python +# define BOOST_PYTHON_CONVERSION boost::python # define BOOST_PYTHON_IMPORT_CONVERSION(x) void never_defined() // so we can follow the macro with a ';' # endif diff --git a/include/boost/python/detail/wrap_python.hpp b/include/boost/python/detail/wrap_python.hpp index 7c6dd5be..eb831b68 100644 --- a/include/boost/python/detail/wrap_python.hpp +++ b/include/boost/python/detail/wrap_python.hpp @@ -1,5 +1,22 @@ +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +// This file serves as a wrapper around which allows it to be +// compiled with GCC 2.95.2 under Win32 and which disables the default MSVC +// behavior so that a program may be compiled in debug mode without requiring a +// special debugging build of the Python library. + + +// To use the Python debugging library, #define BOOST_DEBUG_PYTHON on the +// compiler command-line. + #ifdef _DEBUG -# ifndef DEBUG_PYTHON +# ifndef BOOST_DEBUG_PYTHON # undef _DEBUG // Don't let Python force the debug library just because we're debugging. # define DEBUG_UNDEFINED_FROM_WRAP_PYTHON_H # endif From 445b0438a2da659c6bff6c1ca29771345d639365 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 28 Nov 2000 04:42:46 +0000 Subject: [PATCH 011/154] bug fix [SVN r8345] --- example/rwgk1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/rwgk1.cpp b/example/rwgk1.cpp index 0577aded..b21ae4d1 100644 --- a/example/rwgk1.cpp +++ b/example/rwgk1.cpp @@ -17,7 +17,7 @@ extern "C" #ifdef _WIN32 __declspec(dllexport) #endif -initrwgk1() +void initrwgk1() { try { From 4e27f8de274fd8f76ea227200b6c2a0d3352ec21 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 28 Nov 2000 05:17:07 +0000 Subject: [PATCH 012/154] boost-ification [SVN r8347] --- build/como.mak | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ build/gcc.mak | 39 +++++++++++++++++++++----------------- 2 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 build/como.mak diff --git a/build/como.mak b/build/como.mak new file mode 100644 index 00000000..5a9920d8 --- /dev/null +++ b/build/como.mak @@ -0,0 +1,51 @@ +LIBSRC = \ + classes.cpp \ + conversions.cpp \ + extension_class.cpp \ + functions.cpp \ + init_function.cpp \ + module_builder.cpp \ + objects.cpp \ + types.cpp + +LIBOBJ = $(LIBSRC:.cpp=.o) +OBJ = $(LIBOBJ) + + +ifeq "$(OS)" "Windows_NT" +PYTHON_LIB=c:/tools/python/libs/python15.lib +INC = -Ic:/cygnus/usr/include/g++-3 -Ic:/cygnus/usr/include -Ic:/boost -Ic:/tools/python/include +MODULE_EXTENSION=dll +else +INC = -I/usr/local/include/python1.5 +MODULE_EXTENSION=so +endif + +%.o: ../src/%.cpp + como --pic $(INC) -o $*.o -c $< + +%.d: ../src/%.cpp + @echo creating $@ + @set -e; como -M $(INC) -c $< \ + | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \ + [ -s $@ ] || rm -f $@ + +example1: example1.o libpycpp.a + como-dyn-link -o ../example/hellomodule.$(MODULE_EXTENSION) $(PYHTON_LIB) example1.o -L. -lpycpp + python ../example/test_example1.py + +example1.o: ../example/example1.cpp + como --pic $(INC) -o $*.o -c $< + +clean: + rm -rf *.o *.$(MODULE_EXTENSION) *.a *.d *.pyc *.bak a.out + +libpycpp.a: $(LIBOBJ) + rm -f libpycpp.a + ar cq libpycpp.a $(LIBOBJ) + +DEP = $(OBJ:.o=.d) + +ifneq "$(MAKECMDGOALS)" "clean" +include $(DEP) +endif diff --git a/build/gcc.mak b/build/gcc.mak index cec872cf..d0b42548 100644 --- a/build/gcc.mak +++ b/build/gcc.mak @@ -1,15 +1,15 @@ LIBSRC = \ - extclass.cpp \ - init_function.cpp \ - py.cpp \ - module.cpp \ - subclass.cpp \ + classes.cpp \ + conversions.cpp \ + extension_class.cpp \ functions.cpp \ - newtypes.cpp \ - objects.cpp - + init_function.cpp \ + module_builder.cpp \ + objects.cpp \ + types.cpp + LIBOBJ = $(LIBSRC:.cpp=.o) -OBJ = $(LIBOBJ) extclass_demo.o +OBJ = $(LIBOBJ) ifeq "$(OS)" "Windows_NT" @@ -17,22 +17,27 @@ PYTHON_LIB=c:/tools/python/libs/python15.lib INC = -Ic:/cygnus/usr/include/g++-3 -Ic:/cygnus/usr/include -Ic:/boost -Ic:/tools/python/include MODULE_EXTENSION=dll else -INC = -I/home/koethe/include -I/home/koethe/C++/boost -I/home/koethe/python/include/python1.5 +INC = -I/usr/local/include/python1.5 MODULE_EXTENSION=so endif -%.o: %.cpp - g++ -fPIC $(INC) -c $*.cpp +%.o: ../src/%.cpp + g++ -fPIC -Wall -W $(INC) -o $*.o -c $< -%.d: %.cpp +%.d: ../src/%.cpp @echo creating $@ - @set -e; g++ -M $(INC) -c $*.cpp \ + @set -e; g++ -M $(INC) -c $< \ | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \ [ -s $@ ] || rm -f $@ -demo: extclass_demo.o libpycpp.a - g++ -shared -o demomodule.$(MODULE_EXTENSION) $(PYTHON_LIB) extclass_demo.o -L. -lpycpp - python test_extclass.py + +example1: example1.o libpycpp.a + g++ -shared -o ../example/hellomodule.$(MODULE_EXTENSION) $(PYHTON_LIB) example1.o -L. -lpycpp + python ../example/test_example1.py + +example1.o: ../example/example1.cpp + g++ -fPIC -Wall -W $(INC) -o $*.o -c $< + clean: rm -rf *.o *.$(MODULE_EXTENSION) *.a *.d *.pyc *.bak a.out From 7f58e66754067b1852b7a66aa515d83afc7c25a5 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 28 Nov 2000 05:17:55 +0000 Subject: [PATCH 013/154] removed non-portable but beautiful “/” [SVN r8349] --- doc/building.html | 4 +- doc/comparisons.html | 38 ++++---- doc/data_structures.txt | 192 ++++++++++++++++++++++++++++++++++++++++ doc/enums.html | 4 +- doc/example1.html | 6 +- doc/index.html | 10 ++- doc/overloading.html | 14 +-- doc/pointers.html | 6 +- doc/special.html | 20 ++--- 9 files changed, 244 insertions(+), 50 deletions(-) create mode 100644 doc/data_structures.txt diff --git a/doc/building.html b/doc/building.html index 84657b7a..4ac2343c 100644 --- a/doc/building.html +++ b/doc/building.html @@ -35,8 +35,8 @@

      © Copyright David Abrahams 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright - notice appears in all copies. This document is provided “as - is” without express or implied warranty, and with no claim as to + notice appears in all copies. This document is provided ``as + is'' without express or implied warranty, and with no claim as to its suitability for any purpose.

      Updated: Nov 26, 2000 diff --git a/doc/comparisons.html b/doc/comparisons.html index 2590dae2..336220fb 100644 --- a/doc/comparisons.html +++ b/doc/comparisons.html @@ -19,7 +19,7 @@ exceptions into Python exceptions. As far as I can tell, CXX has no support for subclassing C++ extension types in Python. An even more significant difference is that a user's C++ code is still basically - “dealing with Python objects”, though they are wrapped in + ``dealing with Python objects'', though they are wrapped in C++ classes. This means such jobs as argument parsing and conversion are still left to be done explicitly by the user. @@ -40,8 +40,8 @@

      As far as I can tell, CXX enables one to write what is essentially idiomatic Python code in C++, manipulating Python objects through the - same fully-generic interfaces we use in Python. While you're hardly programming directly to the “bare - metal” with CXX, it basically presents a “C++-ized” + same fully-generic interfaces we use in Python. While you're hardly programming directly to the ``bare + metal'' with CXX, it basically presents a ``C++-ized'' version of the Python 'C' API.

      @@ -51,11 +51,11 @@ fill in the other half. Here is his response to the commentary above:

      -“My intention with CXX was not to do what you are doing. It was to enable a +``My intention with CXX was not to do what you are doing. It was to enable a person to write an extension directly in C++ rather than C. I figured others had the wrapping business covered. I thought maybe CXX would provide an easier target language for those making wrappers, but I never explored -that.”
      -Paul Dubois +that.''
      -Paul Dubois

      SWIG

      @@ -67,20 +67,20 @@ that.”
      -Paul Dubois Perl or Tcl) extension module. It has been successfully used to create many Python extension modules. Like BPL, SWIG is trying to allow an existing interface to be wrapped with little or no change to the - existing code. The documentation says “SWIG parses a form of ANSI C + existing code. The documentation says ``SWIG parses a form of ANSI C syntax that has been extended with a number of special directives. As a result, interfaces are usually built by grabbing a header file and - tweaking it a little bit.” For C++ interfaces, the tweaking has often + tweaking it a little bit.'' For C++ interfaces, the tweaking has often proven to amount to more than just a little bit. One user writes: -
      “The problem with swig (when I used it) is that it +
      ``The problem with swig (when I used it) is that it couldnt handle templates, didnt do func overloading properly etc. For ANSI C libraries this was fine. But for usual C++ code this was a problem. Simple things work. But for anything very complicated (or realistic), one had to write code by hand. I believe BPL doesn't have this problem[sic]... IMHO overloaded functions are very important to - wrap correctly.”
      -Prabhu Ramachandran + wrap correctly.''
      -Prabhu Ramachandran

      @@ -124,7 +124,7 @@ that.”
      -Paul Dubois GRAD is another very ambitious project aimed at generating Python wrappers for - interfaces written in “legacy languages”, among which C++ is the first one + interfaces written in ``legacy languages'', among which C++ is the first one implemented. Like SWIG, it aims to parse source code and automatically generate wrappers, though it appears to take a more sophisticated approach to parsing in general and C++ in particular, so it should do a much better @@ -152,9 +152,9 @@ an inheritance relationship? to support subclassing of extension types in Python, including multiple-inheritance. Both systems support pickling/unpickling of extension class instances in very similar ways. Both systems rely on the - same “Don - Beaudry Hack” that also inspired Don's MESS System. + Beaudry Hack'' that also inspired Don's MESS System.

      The major differences are:

      Here is the C++ code for a python module called hello - which exposes the API using BPL: + which exposes the API using:

       #include <boost/python/class_builder.hpp>
      diff --git a/doc/index.html b/doc/index.html
      index 43a971bf..1167f637 100644
      --- a/doc/index.html
      +++ b/doc/index.html
      @@ -16,7 +16,7 @@
             very similar to the C++ interface. It is designed to be minimally
             intrusive on your C++ design. In most cases, you should not have to alter
             your C++ classes in any way in order to use them with BPL. The system
      -      should simply “reflect” your C++ classes and functions into
      +      should simply ``reflect'' your C++ classes and functions into
             Python. The major features of BPL include support for:
       
@@ -150,7 +152,7 @@ among others.

© Copyright David Abrahams 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright - notice appears in all copies. This document is provided “as is” without + notice appears in all copies. This document is provided ``as is'' without express or implied warranty, and with no claim as to its suitability for any purpose.

diff --git a/doc/overloading.html b/doc/overloading.html index 5c2c236d..995b3a40 100644 --- a/doc/overloading.html +++ b/doc/overloading.html @@ -123,7 +123,7 @@ namespace scope as Python member functions. class is found which has a matching attribute, only functions overloaded in the context of that class are candidates for overload resolution. In this sense, overload resolution mirrors the C++ mechanism, where a name - in a derived class “hides” all functions with the same name from a base + in a derived class ``hides'' all functions with the same name from a base class.

@@ -132,11 +132,11 @@ namespace scope as Python member functions. def()ed. The first function whose signature can be made to match each argument passed is the one which is ultimately called. This means in particular that you cannot overload the same function on - both “int” and “float” because Python + both ``int'' and ``float'' because Python automatically converts either of the two types into the other one. - If the “float” overload is found first, it is used - also used for arguments of type “int” as well, and the - “int” version of the function is never invoked. + If the ``float'' overload is found first, it is used + also used for arguments of type ``int'' as well, and the + ``int'' version of the function is never invoked.

@@ -146,8 +146,8 @@ namespace scope as Python member functions.

© Copyright David Abrahams 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright - notice appears in all copies. This document is provided “as - is” without express or implied warranty, and with no claim as to + notice appears in all copies. This document is provided ``as + is'' without express or implied warranty, and with no claim as to its suitability for any purpose.

Updated: Nov 26, 2000 diff --git a/doc/pointers.html b/doc/pointers.html index 0d0a92dc..26f96f0d 100644 --- a/doc/pointers.html +++ b/doc/pointers.html @@ -34,10 +34,10 @@ converted from/to Python strings.

Can you avoid the problem?

My first piece of advice to anyone with a case not covered above is -“find a way to avoid the problem.” For example, if you have just one +``find a way to avoid the problem.'' For example, if you have just one or two functions that return a pointer to an individual const -T, and T is a wrapped class, you may be able to write a “thin -converting wrapper” over those two functions as follows: +T, and T is a wrapped class, you may be able to write a ``thin +converting wrapper'' over those two functions as follows:

 const Foo* f(); // original function
diff --git a/doc/special.html b/doc/special.html
index 7dd210ba..286dc396 100644
--- a/doc/special.html
+++ b/doc/special.html
@@ -78,7 +78,7 @@
         
__call__ (self[, args...])
-Called when the instance is “called” as a function; if this method +Called when the instance is ``called'' as a function; if this method is defined, x(arg1, arg2, ...) is a shorthand for x.__call__(arg1, arg2, ...). @@ -143,7 +143,7 @@ bignum_class.def(boost::python::operators<boost::python::op_add>()); Since BigNum also supports subtraction, multiplication, and division, we want to export those also. This can be done in a single command by - “or”ing the operator identifiers together (a complete list of these + ``or''ing the operator identifiers together (a complete list of these identifiers and the corresponding operators can be found in the Table of Automatically Wrapped Methods):
@@ -181,7 +181,7 @@ bignum_class.def(boost::python::operators<(boost::python::op_sub | boost::pyt
 
The type of the operand not mentioned is taken from the class being wrapped. In our example, the class object is bignum_class, and thus the - other operand's type is “BigNum const&”. You can override + other operand's type is ``BigNum const&''. You can override this default by explicitly specifying a type in the operators template:
@@ -189,7 +189,7 @@ bignum_class.def(boost::python::operators<boost::python::op_add, BigNum>()
 

Note that automatic wrapping uses the expression - “left + right” and can be used uniformly + ``left + right'' and can be used uniformly regardless of whether the C++ operators are supplied as free functions

 BigNum operator+(BigNum, BigNum)
@@ -261,9 +261,9 @@ bignum_class.def(&rmod,  "__rmod__");
       

Automatic and manual wrapping can be mixed arbitrarily. Note that you cannot overload the same operator for a given extension class on both - “int” and “float”, because Python implicitly + ``int'' and ``float'', because Python implicitly converts these types into each other. Thus, the overloaded variant - found first (be it “int“ or “float”) will be + found first (be it ``int`` or ``float'') will be used for either of the two types.

Coercion

@@ -315,7 +315,7 @@ some_class.def(&custom_coerce, "__coerce__"); Note that the later use of automatic operator wrapping on a class_builder or a call to - “some_class.def_standard_coerce()” will cause any + ``some_class.def_standard_coerce()'' will cause any custom coercion function to be replaced by the standard one.

The Ternary pow() Operator

@@ -689,7 +689,7 @@ void throw_key_error_if_end( // Define some simple wrapper functions which match the Python protocol // for __getitem__, __setitem__, and __delitem__. Just as in Python, a -// free function with a “self” first parameter makes a fine class method. +// free function with a ``self'' first parameter makes a fine class method. const std::string& get_item(const StringMap& self, std::size_t key) { @@ -774,7 +774,7 @@ KeyError: 2 to provide functional access to the attribute <name>. This facility can be used from C++ or entirely from Python. For example, the - following shows how we can implement a “computed attribute” in Python: + following shows how we can implement a ``computed attribute'' in Python:
 >>> class Range(AnyBPLExtensionClass):
@@ -880,7 +880,7 @@ Up: Top
          © Copyright David Abrahams and Ullrich Köthe 2000.
         Permission to copy, use, modify, sell and distribute this document is
         granted provided this copyright notice appears in all copies. This
-        document is provided “as is” without express or implied
+        document is provided ``as is'' without express or implied
         warranty, and with no claim as to its suitability for any purpose.
       

Updated: Nov 26, 2000 From c278310d1b6b2bbe25d6a2fec944bde3ce07c231 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 28 Nov 2000 05:19:10 +0000 Subject: [PATCH 014/154] Fix for compatibility with STLport using native iostreams [SVN r8351] --- include/boost/python/operators.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/boost/python/operators.hpp b/include/boost/python/operators.hpp index d0c06895..e76943e8 100644 --- a/include/boost/python/operators.hpp +++ b/include/boost/python/operators.hpp @@ -2,7 +2,9 @@ #define OPERATORS_UK112000_H_ #include -#if !defined(__GNUC__) || defined(__SGI_STL_PORT) +// When STLport is used with native streams, _STL::ostringstream().str() is not +// _STL::string, but std::string. +#if defined(__SGI_STL_PORT) ? __SGI_STL_OWN_IOSTREAMS : !defined(__GNUC__) # include #else # include @@ -473,17 +475,15 @@ namespace detail { tuple args(ref(arguments, ref::increment_count)); -#if !defined(__GNUC__) || defined(__SGI_STL_PORT) +// When STLport is used with native streams, _STL::ostringstream().str() is not +// _STL::string, but std::string. +#if defined(__SGI_STL_PORT) ? __SGI_STL_OWN_IOSTREAMS : !defined(__GNUC__) std::ostringstream s; s << BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()); + return BOOST_PYTHON_CONVERSION::to_python(s.str()); #else std::ostrstream s; s << BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) << char(); -#endif - -#if !defined(__GNUC__) || defined(__SGI_STL_PORT) - return BOOST_PYTHON_CONVERSION::to_python(s.str()); -#else return BOOST_PYTHON_CONVERSION::to_python(const_cast(s.str())); #endif } From 8637e270a90a8cbb60e674375d67b6dd09356910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20K=C3=B6the?= Date: Tue, 28 Nov 2000 21:22:21 +0000 Subject: [PATCH 015/154] minor improvements, fix of typos [SVN r8352] --- doc/special.html | 62 +++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/doc/special.html b/doc/special.html index 286dc396..525b0a56 100644 --- a/doc/special.html +++ b/doc/special.html @@ -41,12 +41,17 @@ __init__(self)

Initialize the class instance. For extension classes not subclassed in - Python, this is provided by the - boost::python::constructor<...>() construct and should not be explicitly defed. + Python, __init__ is defined by + +
    my_class.def(boost::python::constructor<...>())
+ + (see section "A Simple Example Using BPL").

__del__(self)
- Called when the extension instance is about to be destroyed. + Called when the extension instance is about to be destroyed. For extension classes + not subclassed in Python, __del__ is always defined automatically by + means of the class' destructor.
__repr__(self)
@@ -111,7 +116,7 @@ foo_class.def(&to_string, "__str__"); Numeric operators can be exposed manually, by defing C++ [member] functions that support the standard Python numeric - protocols. This is the basic same technique used to expose + protocols. This is the same basic technique used to expose to_string() as __str__() above, and is covered in detail below. BPL also supports automatic wrapping of numeric operators whenever they have already @@ -121,7 +126,7 @@ foo_class.def(&to_string, "__str__");

Supose we wanted to expose a C++ class - BigNum which supports addition, so that we can write (in C++): + BigNum which supports addition. That is, in C++ we can write:

 BigNum a, b, c;
 ...
@@ -196,7 +201,7 @@ BigNum operator+(BigNum, BigNum)
 
or as member functions
-BigNum::operator+(BigNum).
+BigNum BigNum::operator+(BigNum).
 

@@ -218,8 +223,7 @@ namespace boost { namespace python {

In some cases, automatic wrapping of operators may be impossible or undesirable. Suppose, for example, that the modulo operation for BigNums - is defined by a set of functions mod() (for automatic - wrapping, we would need operator%()): + is defined by a set of functions called mod():

 BigNum mod(BigNum const& left, BigNum const& right);
@@ -228,8 +232,9 @@ BigNum mod(int left, BigNum const& right);
 

- In order to create the Python operator "__mod__" from these functions, we - have to wrap them manually: + For automatic wrapping of the modulo function, operator%() would be needed. + Therefore, the mod()-functions must be wrapped manually. That is, we have + to export them explicitly with the Python special name "__mod__":

 bignum_class.def((BigNum (*)(BigNum const&, BigNum const&))&mod, "__mod__");
@@ -237,8 +242,8 @@ bignum_class.def((BigNum (*)(BigNum const&, int))&mod, "__mod__");
 

- The third form (with int as left operand) cannot be wrapped - this way. We must first create a function rmod() with the + The third form of mod() (with int as left operand) cannot + be wrapped directly. We must first create a function rmod() with the operands reversed:

@@ -248,7 +253,7 @@ BigNum rmod(BigNum const& right, int left)
 }
 
- This function must be wrapped under the name "__rmod__": + This function must be wrapped under the name "__rmod__" (standing for "reverse mod"):
 bignum_class.def(&rmod,  "__rmod__");
@@ -271,7 +276,7 @@ bignum_class.def(&rmod,  "__rmod__");
 
       Plain Python can only execute operators with identical types on the left
       and right hand side. If it encounters an expression where the types of
-      the left and right operand differ, it tries to coerce these type to a
+      the left and right operand differ, it tries to coerce these types to a
       common type before invoking the actual operator. Implementing good
       coercion functions can be difficult if many type combinations must be
       supported. 
@@ -295,7 +300,7 @@ bignum_class.def_standard_coerce();
 
If you encounter a situation where you absolutely need a customized - coercion, you can overload the "__coerce__" operator itself. The signature + coercion, you can still define the "__coerce__" operator manually. The signature of a coercion function should look like one of the following (the first is the safest): @@ -310,13 +315,22 @@ PyObject* custom_coerce(PyObject* left, PyObject* right); converted to the same type. Such a function is wrapped as usual:
+// this must be called before any use of automatic operator  
+// wrapping or a call to some_class.def_standard_coerce()
 some_class.def(&custom_coerce, "__coerce__");
 
- Note that the later use of automatic operator wrapping on a + Note that the standard coercion (defined by use of automatic operator wrapping on a class_builder or a call to - ``some_class.def_standard_coerce()'' will cause any - custom coercion function to be replaced by the standard one. + “some_class.def_standard_coerce()”) will never be applied + if a custom coercion function has been registered. Therefore, in your coercion function + you should call + +
+boost::python::detail::extension_class_coerce(left, right);
+
+ + for all cases that you don't want to handle yourself.

The Ternary pow() Operator

@@ -330,7 +344,7 @@ some_class.def(&custom_coerce, "__coerce__"); this is done as usual:
-BigNum power(BigNum const& first, BigNum const& second, BigNum const& module);
+BigNum power(BigNum const& first, BigNum const& second, BigNum const& modulus);
 typedef BigNum (ternary_function1)(const BigNum&, const BigNum&, const BigNum&);
 ...
 bignum_class.def((ternary_function1)&power,  "__pow__");
@@ -353,19 +367,19 @@ bignum_class.def((ternary_function2)&power,  "__pow__");
 
In the second variant, however, BigNum appears only as second - argument, and in the last one it is the third argument. These functions + argument, and in the last one it's the third argument. These functions must be presented to BPL such that that the BigNum argument appears in first position:
 BigNum rpower(BigNum const& second, int first, int modulus)
 {
-    return power(first, second, third);
+    return power(first, second, modulus);
 }
 
-BigNum rrpower(BigNum const& third, int first, int second)
+BigNum rrpower(BigNum const& modulus, int first, int second)
 {
-    return power(first, second, third);
+    return power(first, second, modulus);
 }
 
@@ -637,7 +651,7 @@ for i in S: while in C++ one writes
-for (iterator i = S.begin(), end = S.end(); i != end)
+for (iterator i = S.begin(), end = S.end(); i != end; ++i)
 

One could try to wrap C++ iterators in order to carry the C++ idiom into From 8a5de60b33218a6c66354945f43bbff65e4ab176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20K=C3=B6the?= Date: Tue, 28 Nov 2000 21:38:21 +0000 Subject: [PATCH 016/154] fixed html bugs recovered by "validator.w3.org" [SVN r8353] --- doc/special.html | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/doc/special.html b/doc/special.html index 525b0a56..1f35b01d 100644 --- a/doc/special.html +++ b/doc/special.html @@ -1,11 +1,10 @@ - + Special Method and Operator Support

- c++boost.gif (8819 bytes)Special Method and Operator Support

@@ -202,7 +201,7 @@ BigNum operator+(BigNum, BigNum) or as member functions
 BigNum BigNum::operator+(BigNum).
-
+

For the Python built-in functions pow() and @@ -646,13 +645,13 @@ Note that "__rrpow__" is an extension not present in plain Python. iteration idiom looks like

 for i in S:
-
+ while in C++ one writes
 for (iterator i = S.begin(), end = S.end(); i != end; ++i)
-
+

One could try to wrap C++ iterators in order to carry the C++ idiom into Python. However, this does not work very well because From ecdf8e1591508c33e1c303aa145d94918a260369 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 29 Nov 2000 13:41:18 +0000 Subject: [PATCH 017/154] changed name of extension_class_coerce to standard_coerce, applied Ullrich's documentation fix for standard_coerce. [SVN r8356] --- doc/special.html | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/doc/special.html b/doc/special.html index 1f35b01d..7debc7c1 100644 --- a/doc/special.html +++ b/doc/special.html @@ -195,12 +195,15 @@ bignum_class.def(boost::python::operators<boost::python::op_add, BigNum>() Note that automatic wrapping uses the expression ``left + right'' and can be used uniformly regardless of whether the C++ operators are supplied as free functions -

+
+ 
 BigNum operator+(BigNum, BigNum)
 
- or as member - functions
-BigNum BigNum::operator+(BigNum).
+
+        or as member functions
+
+
+BigNum::operator+(BigNum).
 

@@ -319,17 +322,17 @@ PyObject* custom_coerce(PyObject* left, PyObject* right); some_class.def(&custom_coerce, "__coerce__");

- Note that the standard coercion (defined by use of automatic operator wrapping on a - class_builder or a call to - “some_class.def_standard_coerce()”) will never be applied - if a custom coercion function has been registered. Therefore, in your coercion function - you should call + Note that the standard coercion (defined by use of automatic + operator wrapping on a class_builder or a call to + class_builder::def_standard_coerce()) will never be applied if + a custom coercion function has been registered. Therefore, in + your coercion function you should call
-boost::python::detail::extension_class_coerce(left, right);
+boost::python::standard_coerce(left, right);
 
- for all cases that you don't want to handle yourself. + for all cases that you don't want to handle yourself.

The Ternary pow() Operator

@@ -643,11 +646,12 @@ Note that "__rrpow__" is an extension not present in plain Python. to Python's iteration and access protocols. These protocols differ considerably from the ones found in C++. For example, Python's typical iteration idiom looks like +
 for i in S:
 
-while in C++ one writes + while in C++ one writes
 for (iterator i = S.begin(), end = S.end(); i != end; ++i)

From 0f43a2fe9bd01b818db9519c754476572f3f5ae1 Mon Sep 17 00:00:00 2001
From: Dave Abrahams 
Date: Wed, 29 Nov 2000 13:42:45 +0000
Subject: [PATCH 018/154] changed name of extension_class_coerce to
 standard_coerce.

[SVN r8357]
---
 .../boost/python/detail/extension_class.hpp   |  4 +--
 include/boost/python/operators.hpp            | 19 +++++++-----
 src/extension_class.cpp                       | 29 ++++++++-----------
 3 files changed, 25 insertions(+), 27 deletions(-)

diff --git a/include/boost/python/detail/extension_class.hpp b/include/boost/python/detail/extension_class.hpp
index 20d48796..0e2e3427 100644
--- a/include/boost/python/detail/extension_class.hpp
+++ b/include/boost/python/detail/extension_class.hpp
@@ -721,8 +721,6 @@ class extension_instance : public instance
 // Template function implementations
 //
 
-tuple extension_class_coerce(ref l, ref r);
-
 template 
 extension_class::extension_class()
     : extension_class_base(typeid(T).name())
@@ -743,7 +741,7 @@ void extension_class::def_standard_coerce()
     ref coerce_fct = dict().get_item(string("__coerce__"));
     
     if(coerce_fct.get() == 0) // not yet defined
-        this->def(&extension_class_coerce, "__coerce__");
+        this->def(&standard_coerce, "__coerce__");
 }
 
 template 
diff --git a/include/boost/python/operators.hpp b/include/boost/python/operators.hpp
index e76943e8..40400f47 100644
--- a/include/boost/python/operators.hpp
+++ b/include/boost/python/operators.hpp
@@ -1,17 +1,22 @@
 #ifndef OPERATORS_UK112000_H_
 #define OPERATORS_UK112000_H_
 
-#include 
+# include 
+# include 
+
 // When STLport is used with native streams, _STL::ostringstream().str() is not
-// _STL::string, but std::string.
-#if defined(__SGI_STL_PORT) ? __SGI_STL_OWN_IOSTREAMS : !defined(__GNUC__)
-# include 
-#else
-# include 
-#endif
+// _STL::string, but std::string. This confuses to_python(), so we'll use
+// strstream instead. Also, GCC 2.95.2 doesn't have sstream.
+# if defined(__SGI_STL_PORT) ? __SGI_STL_OWN_IOSTREAMS : !defined(__GNUC__) || __GNUC__ > 2
+#  include 
+# else
+#  include 
+# endif
 
 namespace boost { namespace python {
 
+tuple standard_coerce(ref l, ref r);
+
 namespace detail {
   
   // helper class for automatic operand type detection
diff --git a/src/extension_class.cpp b/src/extension_class.cpp
index cde3d836..c15e538b 100644
--- a/src/extension_class.cpp
+++ b/src/extension_class.cpp
@@ -46,24 +46,19 @@ BOOST_PYTHON_END_CONVERSION_NAMESPACE
 
 namespace boost { namespace python { 
 
-namespace detail {
+tuple standard_coerce(ref l, ref r)
+{
+    // Introduced sequence points for exception-safety.
+    ref first(detail::operator_dispatcher::create(l, l));
+    
+    ref second(r->ob_type == &detail::operator_dispatcher::type_obj
+               ? r
+               : ref(detail::operator_dispatcher::create(r, ref())));
 
-  tuple extension_class_coerce(ref l, ref r)
-  {
-      // Introduced sequence points for exception-safety.
-      ref first(operator_dispatcher::create(l, l));
-      ref second;
-      
-      if(r->ob_type == &operator_dispatcher::type_obj)
-      {
-           second = r;
-      }
-      else
-      {
-           second = ref(operator_dispatcher::create(r, ref()));
-      }
-      return boost::python::tuple(first, second);
-  }
+    return tuple(first, second);
+}
+
+namespace detail {
 
   enum { unwrap_exception_code = -1000 };
 

From 9dca983e3336107c5865149821f5fbbc953dd2d6 Mon Sep 17 00:00:00 2001
From: Dave Abrahams 
Date: Wed, 29 Nov 2000 14:18:37 +0000
Subject: [PATCH 019/154] changed name of extension_class_coerce to
 standard_coerce.

[SVN r8358]
---
 src/gen_extclass.py | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/gen_extclass.py b/src/gen_extclass.py
index 5180a3de..f8906970 100644
--- a/src/gen_extclass.py
+++ b/src/gen_extclass.py
@@ -707,8 +707,6 @@ class extension_instance : public instance
 // Template function implementations
 //
 
-tuple extension_class_coerce(ref l, ref r);
-
 template 
 extension_class::extension_class()
     : extension_class_base(typeid(T).name())
@@ -729,7 +727,7 @@ void extension_class::def_standard_coerce()
     ref coerce_fct = dict().get_item(string("__coerce__"));
     
     if(coerce_fct.get() == 0) // not yet defined
-        this->def(&extension_class_coerce, "__coerce__");
+        this->def(&standard_coerce, "__coerce__");
 }
 
 template 

From 81cf5333c3318e45b40318435e9159582f7f8261 Mon Sep 17 00:00:00 2001
From: Dave Abrahams 
Date: Thu, 30 Nov 2000 04:51:05 +0000
Subject: [PATCH 020/154] Added module() function to get the module being built
 Added initializing() function to distinguish whether a module is initializing
 Changed logic so that multiple non-overlapping module_builders() may be
 constructed. This fixes a bug when BPL is built as a shared lib.

[SVN r8361]
---
 include/boost/python/module_builder.hpp | 21 ++++++++++++++++++---
 src/module_builder.cpp                  | 12 +++++++++++-
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/include/boost/python/module_builder.hpp b/include/boost/python/module_builder.hpp
index 57507e59..6a8a9b4b 100644
--- a/include/boost/python/module_builder.hpp
+++ b/include/boost/python/module_builder.hpp
@@ -18,11 +18,10 @@ namespace boost { namespace python {
 
 class module_builder
 {
-    typedef PyObject * (*raw_function_ptr)(boost::python::tuple const &, boost::python::dictionary const &);
-    
  public:
     // Create a module. REQUIRES: only one module_builder is created per module.
     module_builder(const char* name);
+    ~module_builder();
 
     // Add elements to the module
     void add(detail::function* x, const char* name);
@@ -41,13 +40,29 @@ class module_builder
         add(detail::new_wrapped_function(fn), name);
     }
 
-    static string name();
+    // Return true iff a module is currently being built.
+    static bool initializing();
     
+    // Return the name of the module currently being built.
+    // REQUIRES: initializing() == true
+    static string name();
+
+    // Return a pointer to the Python module object being built
+    PyObject* module() const;
+
  private:
     PyObject* m_module;
     static PyMethodDef initial_methods[1];
 };
 
+//
+// inline implementations
+//
+inline PyObject* module_builder::module() const
+{
+    return m_module;
+}
+
 }} // namespace boost::python
 
 #endif
diff --git a/src/module_builder.cpp b/src/module_builder.cpp
index ea00b71c..57eec75f 100644
--- a/src/module_builder.cpp
+++ b/src/module_builder.cpp
@@ -14,10 +14,15 @@ namespace {
   ref name_holder;
 }
 
+bool module_builder::initializing()
+{
+    return name_holder.get() != 0;
+}
+
 string module_builder::name()
 {
     // If this fails, you haven't created a module_builder object
-    assert(name_holder.get() != 0);
+    assert(initializing());
     return string(name_holder);
 }
 
@@ -29,6 +34,11 @@ module_builder::module_builder(const char* name)
     name_holder = ref(PyObject_GetAttrString(m_module, const_cast("__name__")));
 }
 
+module_builder::~module_builder()
+{
+    name_holder.reset();
+}
+
 void
 module_builder::add(detail::function* x, const char* name)
 {

From ff31b16285688a7852382fee42041e69f37f8f80 Mon Sep 17 00:00:00 2001
From: Dave Abrahams 
Date: Thu, 30 Nov 2000 04:53:31 +0000
Subject: [PATCH 021/154] Fixed __module__ name extraction logic so that when a
 module is not initializing the module name comes from the global __name__.

[SVN r8362]
---
 src/classes.cpp | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/classes.cpp b/src/classes.cpp
index 34b42c22..2901aa81 100644
--- a/src/classes.cpp
+++ b/src/classes.cpp
@@ -840,7 +840,27 @@ namespace {
   void add_current_module_name(dictionary& name_space)
   {
       static string module_key("__module__", string::interned);
-      name_space.set_item(module_key, module_builder::name());
+
+      // If the user didn't specify a __module__ attribute already
+      if (name_space.get_item(module_key).get() == 0)
+      {
+          if (module_builder::initializing())
+          {
+              // The global __name__ is not properly set in this case
+              name_space.set_item(module_key, module_builder::name());
+          }
+          else
+          {
+              // Get the module name from the global __name__
+              PyObject *globals = PyEval_GetGlobals();
+              if (globals != NULL)
+              {
+                  PyObject *module_name = PyDict_GetItemString(globals, "__name__");
+                  if (module_name != NULL)
+                      name_space.set_item(module_key, module_name);
+              }
+          }
+      }
   }
 }
 

From b91d11431d1af462023bbd7623514e7cdb656e4c Mon Sep 17 00:00:00 2001
From: Dave Abrahams 
Date: Fri, 1 Dec 2000 02:27:06 +0000
Subject: [PATCH 022/154] Applied fixes for como courtesy of Jens Maurer.

[SVN r8375]
---
 include/boost/python/operators.hpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/boost/python/operators.hpp b/include/boost/python/operators.hpp
index 40400f47..100c62aa 100644
--- a/include/boost/python/operators.hpp
+++ b/include/boost/python/operators.hpp
@@ -7,7 +7,7 @@
 // When STLport is used with native streams, _STL::ostringstream().str() is not
 // _STL::string, but std::string. This confuses to_python(), so we'll use
 // strstream instead. Also, GCC 2.95.2 doesn't have sstream.
-# if defined(__SGI_STL_PORT) ? __SGI_STL_OWN_IOSTREAMS : !defined(__GNUC__) || __GNUC__ > 2
+# if defined(__SGI_STL_PORT) ? defined(__SGI_STL_OWN_IOSTREAMS) : (!defined(__GNUC__) || __GNUC__ > 2)
 #  include 
 # else
 #  include 
@@ -482,7 +482,7 @@ namespace detail
 
 // When STLport is used with native streams, _STL::ostringstream().str() is not
 // _STL::string, but std::string.
-#if defined(__SGI_STL_PORT) ? __SGI_STL_OWN_IOSTREAMS : !defined(__GNUC__)
+#if defined(__SGI_STL_PORT) ? defined(__SGI_STL_OWN_IOSTREAMS) : (!defined(__GNUC__) || __GNUC__ > 2)
               std::ostringstream s;
               s << BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type());
               return BOOST_PYTHON_CONVERSION::to_python(s.str()); 

From 7ea7f87a9fd9dbc96b1c942257a9076aa057640c Mon Sep 17 00:00:00 2001
From: Beman Dawes 
Date: Fri, 8 Dec 2000 15:12:31 +0000
Subject: [PATCH 023/154] Fixed broken link

[SVN r8401]
---
 doc/index.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/index.html b/doc/index.html
index 1167f637..0f5f3e04 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -19,7 +19,7 @@
       should simply ``reflect'' your C++ classes and functions into
       Python. The major features of BPL include support for:
 
    -
  • Subclassing extension types in Python +
  • Subclassing extension types in Python
  • Overriding virtual functions in Python
  • [Member] function Overloading
  • Automatic wrapping of numeric operators From 826c1bd894280d6980aa540662b60eebf6939434 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 10 Dec 2000 03:41:32 +0000 Subject: [PATCH 024/154] Correct asynchrony with python generator [SVN r8442] --- .../boost/python/detail/extension_class.hpp | 39 ++++++++++++++++--- include/boost/python/detail/init_function.hpp | 30 +++++++------- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/include/boost/python/detail/extension_class.hpp b/include/boost/python/detail/extension_class.hpp index 0e2e3427..94d9bf6b 100644 --- a/include/boost/python/detail/extension_class.hpp +++ b/include/boost/python/detail/extension_class.hpp @@ -6,7 +6,7 @@ // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. // -// This file automatically generated for 5-argument constructors by +// This file automatically generated for 10-argument constructors by // gen_extclass.python #ifndef EXTENSION_CLASS_DWA052000_H_ @@ -363,8 +363,8 @@ class extension_class ~extension_class(); // define constructors - template - inline void def(constructor) + template + inline void def(constructor) // The following incantation builds a signature1, signature2,... object. It // should _all_ get optimized away. { add_constructor( @@ -373,7 +373,12 @@ class extension_class prepend(type::id(), prepend(type::id(), prepend(type::id(), - signature0())))))); + prepend(type::id(), + prepend(type::id(), + prepend(type::id(), + prepend(type::id(), + prepend(type::id(), + signature0()))))))))))); } @@ -625,6 +630,16 @@ public: held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4) : T(a1, a2, a3, a4) {} template held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : T(a1, a2, a3, a4, a5) {} + template + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : T(a1, a2, a3, a4, a5, a6) {} + template + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) : T(a1, a2, a3, a4, a5, a6, a7) {} + template + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) : T(a1, a2, a3, a4, a5, a6, a7, a8) {} + template + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) : T(a1, a2, a3, a4, a5, a6, a7, a8, a9) {} + template + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) : T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {} }; // Abstract base class for all obj holders. Base for template class @@ -676,6 +691,21 @@ public: template instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : m_held(p, a1, a2, a3, a4, a5) {} + template + instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : + m_held(p, a1, a2, a3, a4, a5, a6) {} + template + instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) : + m_held(p, a1, a2, a3, a4, a5, a6, a7) {} + template + instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) : + m_held(p, a1, a2, a3, a4, a5, a6, a7, a8) {} + template + instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) : + m_held(p, a1, a2, a3, a4, a5, a6, a7, a8, a9) {} + template + instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) : + m_held(p, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {} public: // implementation of instance_holder_base required interface bool held_by_value() { return true; } @@ -829,4 +859,3 @@ std::vector class_registry::static_derived_class_info; }}} // namespace boost::python::detail #endif // EXTENSION_CLASS_DWA052000_H_ - diff --git a/include/boost/python/detail/init_function.hpp b/include/boost/python/detail/init_function.hpp index e53f8aa9..f4b24fa6 100644 --- a/include/boost/python/detail/init_function.hpp +++ b/include/boost/python/detail/init_function.hpp @@ -110,11 +110,11 @@ template struct init2; template struct init3; template struct init4; template struct init5; -template struct Init6; -template struct Init7; -template struct Init8; -template struct Init9; -template struct Init10; +template struct init6; +template struct init7; +template struct init8; +template struct init9; +template struct init10; template struct init_function @@ -165,7 +165,7 @@ struct init_function template static init* create(signature6) { - return new Init6::const_reference, detail::parameter_traits::const_reference, detail::parameter_traits::const_reference, @@ -176,7 +176,7 @@ struct init_function template static init* create(signature7) { - return new Init7::const_reference, detail::parameter_traits::const_reference, detail::parameter_traits::const_reference, @@ -188,7 +188,7 @@ struct init_function template static init* create(signature8) { - return new Init8::const_reference, detail::parameter_traits::const_reference, detail::parameter_traits::const_reference, @@ -201,7 +201,7 @@ struct init_function template static init* create(signature9) { - return new Init9::const_reference, detail::parameter_traits::const_reference, detail::parameter_traits::const_reference, @@ -215,7 +215,7 @@ struct init_function template static init* create(signature10) { - return new Init10::const_reference, detail::parameter_traits::const_reference, detail::parameter_traits::const_reference, @@ -353,7 +353,7 @@ struct init5 : init }; template -struct Init6 : init +struct init6 : init { virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const { @@ -379,7 +379,7 @@ struct Init6 : init }; template -struct Init7 : init +struct init7 : init { virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const { @@ -407,7 +407,7 @@ struct Init7 : init }; template -struct Init8 : init +struct init8 : init { virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const { @@ -437,7 +437,7 @@ struct Init8 : init }; template -struct Init9 : init +struct init9 : init { virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const { @@ -469,7 +469,7 @@ struct Init9 : init }; template -struct Init10 : init +struct init10 : init { virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const { From e5670d5e3c625f5e5a850fa4a706e89536594995 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 10 Dec 2000 03:42:28 +0000 Subject: [PATCH 025/154] Correct the generated filenames [SVN r8444] --- src/gen_all.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gen_all.py b/src/gen_all.py index fd8d78cc..416c66f1 100644 --- a/src/gen_all.py +++ b/src/gen_all.py @@ -6,12 +6,12 @@ from gen_singleton import * from gen_extclass import * def gen_all(args): - open('callback.h', 'w').write(gen_callback(args)) - open('caller.h', 'w').write(gen_caller(args)) - open('init_function.h', 'w').write(gen_init_function(args)) - open('signatures.h', 'w').write(gen_signatures(args)) - open('instance.h', 'w').write(gen_singleton(args)) - open('extclass.h', 'w').write(gen_extclass(args)) + open('callback.hpp', 'w').write(gen_callback(args)) + open('caller.hpp', 'w').write(gen_caller(args)) + open('init_function.hpp', 'w').write(gen_init_function(args)) + open('signatures.hpp', 'w').write(gen_signatures(args)) + open('instance.hpp', 'w').write(gen_singleton(args)) + open('extension_class.hpp', 'w').write(gen_extclass(args)) if __name__ == '__main__': import sys From 7ca17b7bd9deff152b80f5571f1ba45805e2d346 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 12 Dec 2000 03:37:33 +0000 Subject: [PATCH 026/154] Fixed links to avoid www.pythonlabs.com [SVN r8455] --- doc/index.html | 2 +- doc/overloading.html | 2 +- doc/special.html | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/index.html b/doc/index.html index 0f5f3e04..9ddd65d3 100644 --- a/doc/index.html +++ b/doc/index.html @@ -12,7 +12,7 @@

    Synopsis

    Use the Boost Python Library to quickly and easily export a C++ library to Python such that the Python interface is + href="http://www.python.org">Python such that the Python interface is very similar to the C++ interface. It is designed to be minimally intrusive on your C++ design. In most cases, you should not have to alter your C++ classes in any way in order to use them with BPL. The system diff --git a/doc/overloading.html b/doc/overloading.html index 995b3a40..6979efd0 100644 --- a/doc/overloading.html +++ b/doc/overloading.html @@ -118,7 +118,7 @@ namespace scope as Python member functions.

    • Attribute lookup for extension classes proceeds in the + href="http://www.python.org/doc/current/tut/node11.html#SECTION0011510000000000000000">the usual Python way using a depth-first, left-to-right search. When a class is found which has a matching attribute, only functions overloaded in the context of that class are candidates for overload resolution. In diff --git a/doc/special.html b/doc/special.html index 7debc7c1..50cee505 100644 --- a/doc/special.html +++ b/doc/special.html @@ -13,7 +13,7 @@

      BPL supports all of the standard + "http://www.python.org/doc/current/ref/specialnames.html"> special method names supported by real Python class instances except __complex__ (more on the reasons below). In addition, it can quickly and easily expose @@ -33,7 +33,7 @@ Python provides a number of special operators for basic customization of a class. Only a brief description is provided below; more complete documentation can be found here. + href="http://www.python.org/doc/current/ref/customization.html">here.

      @@ -114,7 +114,7 @@ foo_class.def(&to_string, "__str__");

      Numeric operators can be exposed manually, by defing C++ [member] functions that support the standard Python numeric + href="http://www.python.org/doc/current/ref/numeric-types.html">numeric protocols. This is the same basic technique used to expose to_string() as __str__() above, and is covered in detail below. BPL also supports @@ -398,7 +398,7 @@ Note that "__rrpow__" is an extension not present in plain Python.

      Table of Automatically Wrapped Methods

      BPL can automatically wrap the following + "http://www.python.org/doc/current/ref/specialnames.html"> special methods:

      @@ -672,12 +672,12 @@ for (iterator i = S.begin(), end = S.end(); i != end; ++i)

      It is a better idea to support the standard Python + href="http://www.python.org/doc/current/ref/sequence-types.html">Python sequence and mapping protocols for your wrapped containers. These operators have to be wrapped manually because there are no corresponding C++ operators that could be used for automatic wrapping. The Python documentation lists the relevant + "http://www.python.org/doc/current/ref/sequence-types.html"> container operators. In particular, expose __getitem__, __setitem__ and remember to raise the appropriate Python exceptions (PyExc_IndexError for sequences, @@ -773,7 +773,7 @@ KeyError: 2

      Just like built-in Python classes, BPL extension classes support special + href="http://www.python.org/doc/current/ref/attribute-access.html">special the usual attribute access methods __getattr__, __setattr__, and __delattr__. Because writing these functions can From 7d9332e94f2ae6980527fe29f064ce1dfff5e97d Mon Sep 17 00:00:00 2001 From: John Maddock Date: Sat, 30 Dec 2000 11:28:30 +0000 Subject: [PATCH 027/154] added directure structure proposal [SVN r8504] --- build/bpl_static.dsp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/bpl_static.dsp b/build/bpl_static.dsp index 60f56070..701dd309 100644 --- a/build/bpl_static.dsp +++ b/build/bpl_static.dsp @@ -63,8 +63,8 @@ LIB32=link.exe -lib # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W4 /WX /Gm /GR /GX /ZI /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /WX /Gm /GR /GX /ZI /Od /I "d:\boost\type_traits" /I "..\..\.." /I "c:\progra~1\python20\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe From a8641c69cc3cad4d3b662c85396b0ef925740b5e Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 21 Jan 2001 05:29:26 +0000 Subject: [PATCH 028/154] A bug fix that I failed to check in long ago for the use of strstream [SVN r8666] --- include/boost/python/operators.hpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/include/boost/python/operators.hpp b/include/boost/python/operators.hpp index 100c62aa..41b1bf5c 100644 --- a/include/boost/python/operators.hpp +++ b/include/boost/python/operators.hpp @@ -8,6 +8,10 @@ // _STL::string, but std::string. This confuses to_python(), so we'll use // strstream instead. Also, GCC 2.95.2 doesn't have sstream. # if defined(__SGI_STL_PORT) ? defined(__SGI_STL_OWN_IOSTREAMS) : (!defined(__GNUC__) || __GNUC__ > 2) +# define BOOST_PYTHON_USE_SSTREAM +# endif + +#if BOOST_PYTHON_USE_SSTREAM # include # else # include @@ -468,6 +472,16 @@ namespace detail static const char * rname() { return "__rcmp__"; } }; +# ifndef BOOST_PYTHON_USE_SSTREAM + class unfreezer { + public: + unfreezer(std::ostrstream& s) : m_stream(s) {} + ~unfreezer() { m_stream.freeze(false); } + private: + std::ostrstream& m_stream; + }; +# endif + // str(): Manual specialization needed because the string conversion does not follow // the standard pattern relized by the macros. template <> @@ -482,15 +496,16 @@ namespace detail // When STLport is used with native streams, _STL::ostringstream().str() is not // _STL::string, but std::string. -#if defined(__SGI_STL_PORT) ? defined(__SGI_STL_OWN_IOSTREAMS) : (!defined(__GNUC__) || __GNUC__ > 2) +# ifdef BOOST_PYTHON_USE_SSTREAM std::ostringstream s; s << BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()); return BOOST_PYTHON_CONVERSION::to_python(s.str()); -#else +# else std::ostrstream s; s << BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type()) << char(); + auto unfreezer unfreeze(s); return BOOST_PYTHON_CONVERSION::to_python(const_cast(s.str())); -#endif +# endif } const char* description() const @@ -506,4 +521,5 @@ namespace detail }} // namespace boost::python +# undef BOOST_PYTHON_USE_SSTREAM #endif /* OPERATORS_UK112000_H_ */ From 6238770324f697c5d2256b32f591c4584b2df5ff Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 22 Jan 2001 22:58:37 +0000 Subject: [PATCH 029/154] Added a fix from Ralf W. Grosse-Kunstleve [SVN r8724] --- include/boost/python/operators.hpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/include/boost/python/operators.hpp b/include/boost/python/operators.hpp index 41b1bf5c..f7017355 100644 --- a/include/boost/python/operators.hpp +++ b/include/boost/python/operators.hpp @@ -1,3 +1,14 @@ +// (C) Copyright Ullrich Koethe and David Abrahams 2000-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. +// +// The authors gratefully acknowlege the support of Dragon Systems, Inc., in +// producing this work. +// +// Revision History: +// 20 Jan 2001 - Added a fix from Ralf W. Grosse-Kunstleve (David Abrahams) #ifndef OPERATORS_UK112000_H_ #define OPERATORS_UK112000_H_ @@ -9,9 +20,9 @@ // strstream instead. Also, GCC 2.95.2 doesn't have sstream. # if defined(__SGI_STL_PORT) ? defined(__SGI_STL_OWN_IOSTREAMS) : (!defined(__GNUC__) || __GNUC__ > 2) # define BOOST_PYTHON_USE_SSTREAM -# endif +# endi -#if BOOST_PYTHON_USE_SSTREAM +#if defined(BOOST_PYTHON_USE_SSTREAM) # include # else # include From b0d9bbc0b15b787d15aeaf378d2614b0eeae5365 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 23 Jan 2001 22:41:46 +0000 Subject: [PATCH 030/154] Another stupid typo fix by Ralf W. Grosse-Kunstleve [SVN r8745] --- include/boost/python/operators.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/python/operators.hpp b/include/boost/python/operators.hpp index f7017355..da88ec6c 100644 --- a/include/boost/python/operators.hpp +++ b/include/boost/python/operators.hpp @@ -8,6 +8,7 @@ // producing this work. // // Revision History: +// 23 Jan 2001 - Another stupid typo fix by Ralf W. Grosse-Kunstleve (David Abrahams) // 20 Jan 2001 - Added a fix from Ralf W. Grosse-Kunstleve (David Abrahams) #ifndef OPERATORS_UK112000_H_ #define OPERATORS_UK112000_H_ @@ -20,7 +21,7 @@ // strstream instead. Also, GCC 2.95.2 doesn't have sstream. # if defined(__SGI_STL_PORT) ? defined(__SGI_STL_OWN_IOSTREAMS) : (!defined(__GNUC__) || __GNUC__ > 2) # define BOOST_PYTHON_USE_SSTREAM -# endi +# endif #if defined(BOOST_PYTHON_USE_SSTREAM) # include From e508842da672b5f8865fb93718b4e6048fa0d02d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 27 Jan 2001 17:35:02 +0000 Subject: [PATCH 031/154] BPL support for exporting/importing class wrappers. [SVN r8788] --- example/abstract.cpp | 34 ++++++ example/dvect.cpp | 69 +++++++++++ example/dvect.h | 32 +++++ example/example1.cpp | 54 --------- example/{rwgk1.cpp => getting_started1.cpp} | 15 +-- example/getting_started2.cpp | 51 ++++++++ example/getting_started3.cpp | 122 +++++++++++++++++++ example/getting_started4.cpp | 104 ++++++++++++++++ example/getting_started5.cpp | 127 ++++++++++++++++++++ example/ivect.cpp | 69 +++++++++++ example/ivect.h | 32 +++++ example/noncopyable_export.cpp | 24 ++++ example/noncopyable_import.cpp | 42 +++++++ example/store.h | 14 +++ example/test_abstract.py | 23 ++++ example/test_example1.py | 50 -------- example/test_getting_started1.py | 17 +++ example/test_getting_started2.py | 19 +++ example/test_getting_started3.py | 56 +++++++++ example/test_getting_started4.py | 35 ++++++ example/test_getting_started5.py | 22 ++++ example/test_rwgk1.py | 17 --- example/tst_dvect.py | 16 +++ example/tst_ivect.py | 16 +++ example/tst_noncopyable.py | 8 ++ 25 files changed, 935 insertions(+), 133 deletions(-) create mode 100644 example/abstract.cpp create mode 100644 example/dvect.cpp create mode 100644 example/dvect.h delete mode 100644 example/example1.cpp rename example/{rwgk1.cpp => getting_started1.cpp} (74%) create mode 100644 example/getting_started2.cpp create mode 100644 example/getting_started3.cpp create mode 100644 example/getting_started4.cpp create mode 100644 example/getting_started5.cpp create mode 100644 example/ivect.cpp create mode 100644 example/ivect.h create mode 100644 example/noncopyable_export.cpp create mode 100644 example/noncopyable_import.cpp create mode 100644 example/store.h create mode 100644 example/test_abstract.py delete mode 100644 example/test_example1.py create mode 100644 example/test_getting_started1.py create mode 100644 example/test_getting_started2.py create mode 100644 example/test_getting_started3.py create mode 100644 example/test_getting_started4.py create mode 100644 example/test_getting_started5.py delete mode 100644 example/test_rwgk1.py create mode 100644 example/tst_dvect.py create mode 100644 example/tst_ivect.py create mode 100644 example/tst_noncopyable.py diff --git a/example/abstract.cpp b/example/abstract.cpp new file mode 100644 index 00000000..41d34def --- /dev/null +++ b/example/abstract.cpp @@ -0,0 +1,34 @@ +// Example by Ullrich Koethe +#include "boost/python/class_builder.hpp" +#include + +struct Abstract +{ + virtual std::string test() = 0; +}; + +struct Abstract_callback: Abstract +{ + Abstract_callback(PyObject * self) + : m_self(self) + {} + + std::string test() + { + return boost::python::callback::call_method(m_self, "test"); + } + + PyObject * m_self; +}; + +extern "C" +DL_EXPORT(void) +initabstract() +{ + boost::python::module_builder a("abstract"); + + boost::python::class_builder + a_class(a, "Abstract"); + a_class.def(boost::python::constructor<>()); // wrap a constructor + a_class.def(&Abstract::test, "test"); +} diff --git a/example/dvect.cpp b/example/dvect.cpp new file mode 100644 index 00000000..3228010c --- /dev/null +++ b/example/dvect.cpp @@ -0,0 +1,69 @@ +#include "ivect.h" +#include "dvect.h" +#include +#include +namespace python = boost::python; + +namespace { + + vects::ivect dvect_as_ivect(const vects::dvect& dv) + { + vects::ivect iv(dv.size()); + vects::ivect::iterator iviter = iv.begin(); + for (int i = 0; i < dv.size(); i++) iviter[i] = static_cast(dv[i]); + return iv; + } + + boost::python::tuple ivect_as_tuple(const vects::ivect& iv) + { + return iv.as_tuple(); + } + + std::auto_ptr auto_ptr_ivect(const vects::dvect& dv) + { + return std::auto_ptr(new vects::ivect(dvect_as_ivect(dv))); + } + + boost::shared_ptr shared_ptr_ivect(const vects::dvect& dv) + { + return boost::shared_ptr(new vects::ivect(dvect_as_ivect(dv))); + } + + boost::python::tuple auto_ptr_ivect_as_tuple(std::auto_ptr& iv) + { + return iv->as_tuple(); + } + + boost::python::tuple shared_ptr_ivect_as_tuple(boost::shared_ptr& iv) + { + return iv->as_tuple(); + } +} + +extern "C" +DL_EXPORT(void) +initdvect() +{ + try + { + python::module_builder this_module("dvect"); + + python::x_class_builder dvect_class(this_module, "dvect"); + + python::import_class_builder ivect_class("ivect", "ivect"); + + dvect_class.def(python::constructor()); + dvect_class.def(&vects::dvect::as_tuple, "as_tuple"); + dvect_class.def(dvect_as_ivect, "as_ivect"); + + this_module.def(ivect_as_tuple, "ivect_as_tuple"); + dvect_class.def(auto_ptr_ivect, "auto_ptr_ivect"); + dvect_class.def(shared_ptr_ivect, "shared_ptr_ivect"); + this_module.def(auto_ptr_ivect_as_tuple, "auto_ptr_ivect_as_tuple"); + this_module.def(shared_ptr_ivect_as_tuple, "shared_ptr_ivect_as_tuple"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/dvect.h b/example/dvect.h new file mode 100644 index 00000000..8ffe7b50 --- /dev/null +++ b/example/dvect.h @@ -0,0 +1,32 @@ +#ifndef DVECT_H +#define DVECT_H + +#include +#include + +namespace vects { + + struct dvect : public std::vector + { + dvect() : std::vector() {} + dvect(size_t n) : std::vector(n) {} + dvect(boost::python::tuple tuple) : std::vector(tuple.size()) + { + std::vector::iterator v_it = begin(); + for (int i = 0; i < tuple.size(); i++) + v_it[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), + boost::python::type()); + } + + boost::python::tuple as_tuple() const + { + boost::python::tuple t(size()); + for (int i = 0; i < size(); i++) + t.set_item(i, + boost::python::ref(BOOST_PYTHON_CONVERSION::to_python((*this)[i]))); + return t; + } + }; +} + +#endif // DVECT_H diff --git a/example/example1.cpp b/example/example1.cpp deleted file mode 100644 index 467ac0dc..00000000 --- a/example/example1.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include - -namespace hello { - class world - { - public: - world(int) {} - ~world() {} - const char* get() const { return "hi, world"; } - }; - - size_t length(const world& x) { return strlen(x.get()); } -} - -#include - -// Python requires an exported function called init in every -// extension module. This is where we build the module contents. -extern "C" -#ifdef _WIN32 -__declspec(dllexport) -#endif -void inithello() -{ - try - { - // create an object representing this extension module - boost::python::module_builder hello("hello"); - - // Create the Python type object for our extension class - boost::python::class_builder world_class(hello, "world"); - - // Add the __init__ function - world_class.def(boost::python::constructor()); - // Add a regular member function - world_class.def(&hello::world::get, "get"); - - // Add a regular function to the module - hello.def(hello::length, "length"); - } - catch(...) - { - boost::python::handle_exception(); // Deal with the exception for Python - } -} - -// Win32 DLL boilerplate -#if defined(_WIN32) -#include -extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) -{ - return 1; -} -#endif // _WIN32 diff --git a/example/rwgk1.cpp b/example/getting_started1.cpp similarity index 74% rename from example/rwgk1.cpp rename to example/getting_started1.cpp index b21ae4d1..9679a2a4 100644 --- a/example/rwgk1.cpp +++ b/example/getting_started1.cpp @@ -8,21 +8,18 @@ namespace { // Avoid cluttering the global namespace. } #include - namespace python = boost::python; // Python requires an exported function called init in every // extension module. This is where we build the module contents. extern "C" -#ifdef _WIN32 -__declspec(dllexport) -#endif -void initrwgk1() +DL_EXPORT(void) +initgetting_started1() { try { // Create an object representing this extension module. - python::module_builder this_module("rwgk1"); + python::module_builder this_module("getting_started1"); // Add regular functions to the module. this_module.def(greet, "greet"); @@ -33,9 +30,3 @@ void initrwgk1() python::handle_exception(); // Deal with the exception for Python } } - -// Win32 DLL boilerplate -#if defined(_WIN32) -#include -extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) { return 1; } -#endif // _WIN32 diff --git a/example/getting_started2.cpp b/example/getting_started2.cpp new file mode 100644 index 00000000..82b4a6df --- /dev/null +++ b/example/getting_started2.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class world + { + private: + std::string country; + public: + world(const std::string& country) { this->country = country; } + std::string greet() const { return "Hello from " + country + "!"; } + }; + + // A function taking a world object as an argument. + std::string invite(const world& w) { + return w.greet() + " Please come soon!"; + } +} + +extern "C" +DL_EXPORT(void) +initgetting_started2() +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("getting_started2"); + + // Create the Python type object for our extension class. + python::class_builder world_class(this_module, "world"); + + // Add the __init__ function. + world_class.def(python::constructor()); + // Add a regular member function. + world_class.def(&world::greet, "greet"); + + // Add invite() as a regular function to the module. + this_module.def(invite, "invite"); + + // Even better, invite() can also be made a member of world_class!!! + world_class.def(invite, "invite"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/getting_started3.cpp b/example/getting_started3.cpp new file mode 100644 index 00000000..7e827249 --- /dev/null +++ b/example/getting_started3.cpp @@ -0,0 +1,122 @@ +/* + This example shows how to make an Extension Class "pickleable". + + Python's pickle module implements a basic but powerful algorithm + for "pickling" (a.k.a. serializing, marshalling or flattening) + nearly arbitrary Python objects. + + The user can influence how an Extension Class instance is pickled + by defining three special methods: __getinitargs__(), + __getstate__(), and __setstate(). This interface is similar to + that for regular Python classes as described in detail in the + Python Library Reference for pickle: + + http://www.python.org/doc/current/lib/module-pickle.html + + When an Extension Class instance is pickled, __getinitargs__() is + called, if implemented. This method should return a tuple + containing the arguments to be passed to the class constructor when + the object is restored. + + If there is no __getstate__() method, the instance's __dict__ is + pickled if it is not empty. If __getstate__() is defined, it should + return an object representing the state of the instance. + + If there is no __setstate__() method, __getstate__() must return a + dictionary. When the instance is restored, the items in this dictionary + are added to the instance's __dict__. + + If the Extension Class defines __setstate__(), the pickle loader + calls it with the result of __getstate__() as arguments. In this + case, the state object need not be a dictionary. The + __getstate__() and __setstate__() methods can do what they want. + + If both __getinitargs__() and __getstate__() are defined, the + instance is restored by first calling the constructor with + the result of __getinitargs__() as argument. After the instance + is reconstructed, the __dict__ is updated or __setstate__() is + called if implemented. + + The mechanism described here is an exact replication of that one + implemented by Jim Fulton's ExtensionClass (included in Zope 2.2.2). + */ + +#include +#include + +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class world + { + private: + std::string country; + int secret_number; + public: + world(const std::string& country) : secret_number(0) { + this->country = country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + void set_secret_number(int number) { secret_number = number; } + int get_secret_number() const { return secret_number; } + }; + + // Support for pickle. + python::tuple world_getinitargs(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_country()); + return result; + } + + python::tuple world_getstate(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_secret_number()); + return result; + } + + void world_setstate(world& w, python::tuple state) { + if (state.size() != 1) { + PyErr_SetString(PyExc_ValueError, + "Unexpected argument in call to __setstate__."); + throw python::error_already_set(); + } + int number = BOOST_PYTHON_CONVERSION::from_python(state[0].get(), + python::type()); + if (number != 42) + w.set_secret_number(number); + } +} + +extern "C" +DL_EXPORT(void) +initgetting_started3() +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("getting_started3"); + + // Create the Python type object for our extension class. + python::class_builder world_class(this_module, "world"); + + // Add the __init__ function. + world_class.def(python::constructor()); + // Add a regular member function. + world_class.def(&world::greet, "greet"); + world_class.def(&world::get_secret_number, "get_secret_number"); + world_class.def(&world::set_secret_number, "set_secret_number"); + + // Support for pickle. + world_class.def(world_getinitargs, "__getinitargs__"); + world_class.def(world_getstate, "__getstate__"); + world_class.def(world_setstate, "__setstate__"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/getting_started4.cpp b/example/getting_started4.cpp new file mode 100644 index 00000000..0c7bd7ee --- /dev/null +++ b/example/getting_started4.cpp @@ -0,0 +1,104 @@ +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // A wrapper is used to define additional constructors. + // + struct vector_double_wrapper: std::vector + { + // Tell the compiler how to convert a base class object to + // this wrapper object. + vector_double_wrapper(PyObject*, const std::vector& vd) + : std::vector(vd) {} + + vector_double_wrapper(PyObject* self) + : std::vector() {} + + vector_double_wrapper(PyObject* self, const int n) + : std::vector(n) {} + + vector_double_wrapper(PyObject* self, python::tuple tuple) + : std::vector(tuple.size()) + { + std::vector::iterator vd = begin(); + for (int i = 0; i < tuple.size(); i++) + vd[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), + python::type()); + } + }; + + double getitem(const std::vector& vd, const std::size_t key) { + return vd[key]; + } + + void setitem(std::vector& vd, const std::size_t key, + const double &d) { + std::vector::iterator vditer = vd.begin(); + vditer[key] = d; + } + + void delitem(std::vector& vd, const std::size_t key) { + std::vector::iterator vditer = vd.begin(); + vd.erase(&vditer[key]); + } + + // Convert vector_double to a regular Python tuple. + // + python::tuple as_tuple(const std::vector& vd) + { + python::tuple t(vd.size()); + for (int i = 0; i < vd.size(); i++) t.set_item(i, + python::ref(BOOST_PYTHON_CONVERSION::to_python(vd[i]))); + return t; + } + + // Function returning a vector_double object to Python. + // + std::vector foo(const int n) + { + std::vector vd(n); + std::vector::iterator vditer = vd.begin(); + for (int i = 0; i < n; i++) vditer[i] = double(i); + return vd; + } + + // Same as foo(), but avoid copying on return. + // + std::auto_ptr > bar(const int n) + { + std::auto_ptr > vdptr(new std::vector(n)); + std::vector::iterator vditer = vdptr->begin(); + for (int i = 0; i < n; i++) vditer[i] = double(10 * i); + return vdptr; + } +} + +extern "C" +DL_EXPORT(void) +initgetting_started4() +{ + try + { + python::module_builder this_module("getting_started4"); + + python::class_builder, vector_double_wrapper> + vector_double(this_module, "vector_double"); + + 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__"); + vector_double.def(setitem, "__setitem__"); + vector_double.def(delitem, "__delitem__"); + vector_double.def(as_tuple, "as_tuple"); + + this_module.def(foo, "foo"); + this_module.def(bar, "bar"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/getting_started5.cpp b/example/getting_started5.cpp new file mode 100644 index 00000000..e82fec30 --- /dev/null +++ b/example/getting_started5.cpp @@ -0,0 +1,127 @@ +/* + This example shows how to convert a class from and to native + Python objects, such as tuples. + + We do not want to expose the helper class MillerIndex as an + Extension Class. However, in order to simplify the wrapper code, + we want to define from_python() and to_python() functions for + class MillerIndex. + + Consider the alternatives: + + - Expose MillerIndex as an Extension Class. + We need a constructor MillerIndex(python::tuple). + Python function calls become more complex: + foo(MillerIndex((1,2,3)) instead of foo((1,2,3)) + We need a method such as MillerIndex().as_tuple(). + + - Define a wrapper function for each function that we + want to expose, e.g.: + void add(const IndexingSet& ixset, const python::tuple PyMIx) + + The first alternative introduces a new type that the user has to + deal with. Other modules using Miller indices might organize them in + different ways, for example to increase runtime efficiency for + important procedures. This means, the user has to know how to + convert between the different kinds of Miller index representations. + This can quickly become a nuisance. Relying on native Python data + structures minimizes the number of special types the user has to + learn and convert. Of course, this argument is only valid for + small and relatively simply classes. + + If there are many member functions with MillerIndex arguments, the + second alternative is impractical, and concentrating the conversion + mechanism in one central place is essential for code + maintainability. An added benefit is that more convenient (smarter) + conversion functions can be provided without cluttering the rest of + the wrapper code. + + */ + +#include +#include +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // The helper class. + // + class MillerIndex { + public: + int v[3]; + }; + + // The main class. Imagine that there are MANY member functions + // like add() and get(). + // + class IndexingSet { + private: + std::vector VMIx; + public: + void add(const MillerIndex& MIx) { VMIx.push_back(MIx); } + MillerIndex get(const std::size_t i) const { return VMIx[i]; } + }; +} + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + + // Convert a Python tuple to a MillerIndex object. + // + MillerIndex from_python(PyObject* p, python::type) + { + python::tuple tup = python::tuple(python::ref(p)); + if (tup.size() != 3) { + PyErr_SetString(PyExc_ValueError, + "expecting exactly 3 values in tuple."); + throw python::error_already_set(); + } + MillerIndex result; + for (int i = 0; i < 3; i++) + result.v[i] = from_python(tup[i].get(), python::type()); + return result; + } + + // Similar conversion for MillerIndex objects passed by value. + // Not actually used, but included to show the principle. + // + MillerIndex from_python(PyObject* p, python::type) + { + return from_python(p, python::type()); + } + + // Convert a MillerIndex object to a Python tuple. + // + PyObject* to_python(const MillerIndex& hkl) + { + python::tuple result(3); + for (int i = 0; i < 3; i++) + result.set_item(i, to_python(hkl.v[i])); + return result.reference().release(); + } + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +extern "C" +DL_EXPORT(void) +initgetting_started5() +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("getting_started5"); + + // Create the Python type object for our extension class. + python::class_builder ixset_class(this_module, "IndexingSet"); + + // Add the __init__ function. + ixset_class.def(python::constructor<>()); + // Add the member functions. + ixset_class.def(&IndexingSet::add, "add"); + ixset_class.def(&IndexingSet::get, "get"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/ivect.cpp b/example/ivect.cpp new file mode 100644 index 00000000..f8ca8707 --- /dev/null +++ b/example/ivect.cpp @@ -0,0 +1,69 @@ +#include "ivect.h" +#include "dvect.h" +#include +#include +namespace python = boost::python; + +namespace { + + vects::dvect ivect_as_dvect(const vects::ivect& iv) + { + vects::dvect dv(iv.size()); + vects::dvect::iterator dviter = dv.begin(); + for (int i = 0; i < iv.size(); i++) dviter[i] = static_cast(iv[i]); + return dv; + } + + boost::python::tuple dvect_as_tuple(const vects::dvect& dv) + { + return dv.as_tuple(); + } + + std::auto_ptr auto_ptr_dvect(const vects::ivect& iv) + { + return std::auto_ptr(new vects::dvect(ivect_as_dvect(iv))); + } + + boost::shared_ptr shared_ptr_dvect(const vects::ivect& iv) + { + return boost::shared_ptr(new vects::dvect(ivect_as_dvect(iv))); + } + + boost::python::tuple auto_ptr_dvect_as_tuple(std::auto_ptr& dv) + { + return dv->as_tuple(); + } + + boost::python::tuple shared_ptr_dvect_as_tuple(boost::shared_ptr& dv) + { + return dv->as_tuple(); + } +} + +extern "C" +DL_EXPORT(void) +initivect() +{ + try + { + python::module_builder this_module("ivect"); + + python::x_class_builder ivect_class(this_module, "ivect"); + + python::import_class_builder dvect_class("dvect", "dvect"); + + ivect_class.def(python::constructor()); + ivect_class.def(&vects::ivect::as_tuple, "as_tuple"); + ivect_class.def(ivect_as_dvect, "as_dvect"); + + this_module.def(dvect_as_tuple, "dvect_as_tuple"); + ivect_class.def(auto_ptr_dvect, "auto_ptr_dvect"); + ivect_class.def(shared_ptr_dvect, "shared_ptr_dvect"); + this_module.def(auto_ptr_dvect_as_tuple, "auto_ptr_dvect_as_tuple"); + this_module.def(shared_ptr_dvect_as_tuple, "shared_ptr_dvect_as_tuple"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/ivect.h b/example/ivect.h new file mode 100644 index 00000000..a0187307 --- /dev/null +++ b/example/ivect.h @@ -0,0 +1,32 @@ +#ifndef IVECT_H +#define IVECT_H + +#include +#include + +namespace vects { + + struct ivect : public std::vector + { + ivect() : std::vector() {} + ivect(size_t n) : std::vector(n) {} + ivect(boost::python::tuple tuple) : std::vector(tuple.size()) + { + std::vector::iterator v_it = begin(); + for (int i = 0; i < tuple.size(); i++) + v_it[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), + boost::python::type()); + } + + boost::python::tuple as_tuple() const + { + boost::python::tuple t(size()); + for (int i = 0; i < size(); i++) + t.set_item(i, + boost::python::ref(BOOST_PYTHON_CONVERSION::to_python((*this)[i]))); + return t; + } + }; +} + +#endif // IVECT_H diff --git a/example/noncopyable_export.cpp b/example/noncopyable_export.cpp new file mode 100644 index 00000000..82c3f049 --- /dev/null +++ b/example/noncopyable_export.cpp @@ -0,0 +1,24 @@ +#include +#include +namespace python = boost::python; + +#include "store.h" + +extern "C" +DL_EXPORT(void) +initnoncopyable_export() +{ + try + { + python::module_builder this_module("noncopyable_export"); + + python::xptr_class_builder store_class(this_module, "store"); + + store_class.def(python::constructor()); + store_class.def(&store::recall, "recall"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/noncopyable_import.cpp b/example/noncopyable_import.cpp new file mode 100644 index 00000000..529c9f42 --- /dev/null +++ b/example/noncopyable_import.cpp @@ -0,0 +1,42 @@ +#include +#include +namespace python = boost::python; + +#include "store.h" + +namespace { // Avoid cluttering the global namespace. + + // A function with store objects as both input and output parameters. + // Because the copy constructor is disabled, we cannot pass a store + // object by value. Instead, we pass a smart pointer. + std::auto_ptr add_stores(const store& s1, const store& s2) + { + int sum = s1.recall() + s2.recall(); + std::auto_ptr ss = std::auto_ptr(new store(sum)); + return ss; + } +} + +extern "C" +DL_EXPORT(void) +initnoncopyable_import() +{ + try + { + python::module_builder this_module("noncopyable_import"); + + python::import_class_builder + dvect_class("noncopyable_export", "store"); + + // Imagine all the additional classes with member functions + // that have store objects as input and output parameters. + // Lots and lots of them. + // However, to keep this example simple, we only define a + // module-level function. + this_module.def(add_stores, "add_stores"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/store.h b/example/store.h new file mode 100644 index 00000000..74ef0477 --- /dev/null +++ b/example/store.h @@ -0,0 +1,14 @@ +#ifndef STORE_H +#define STORE_H + +class store +{ + private: + store(const store&) { } // Disable the copy constructor. + int number; + public: + store(const int i) : number(i) { } + int recall() const { return number; } +}; + +#endif // STORE_H diff --git a/example/test_abstract.py b/example/test_abstract.py new file mode 100644 index 00000000..dda8aaa7 --- /dev/null +++ b/example/test_abstract.py @@ -0,0 +1,23 @@ +# Example by Ullrich Koethe +r'''>>> from abstract import * + >>> class A(Abstract): + ... def __init__(self, text): + ... Abstract.__init__(self) # call the base class constructor + ... self.text = text + ... def test(self): # implement abstract function + ... return self.text + ... + >>> a = A("Hello") + >>> a.test() + 'Hello' +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_abstract + doctest.testmod(test_abstract) + +if __name__ == '__main__': + run() diff --git a/example/test_example1.py b/example/test_example1.py deleted file mode 100644 index 0e3a9a18..00000000 --- a/example/test_example1.py +++ /dev/null @@ -1,50 +0,0 @@ -r''' -// (C) Copyright David Abrahams 2000. 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. -// -// The author gratefully acknowleges the support of Dragon Systems, Inc., in -// producing this work. - -That's it! If we build this shared library and put it on our PYTHONPATH we can -now access our C++ class and function from Python. - - >>> import hello - >>> hi_world = hello.world(3) - >>> hi_world.get() - 'hi, world' - >>> hello.length(hi_world) - 9 - -We can even make a subclass of hello.world: - - - >>> class my_subclass(hello.world): - ... def get(self): - ... return 'hello, world' - ... - >>> y = my_subclass(2) - >>> y.get() - 'hello, world' - -Pretty cool! You can't do that with an ordinary Python extension type! - - >>> hello.length(y) - 9 - -Of course, you may now have a slightly empty feeling in the pit of your little -pythonic stomach. Perhaps you feel your subclass deserves to have a length() of -12? If so, read on... -''' -from hello import * - -def run(args = None): - if args is not None: - import sys - sys.argv = args - import doctest, test_example1 - doctest.testmod(test_example1) - -if __name__ == '__main__': - run() diff --git a/example/test_getting_started1.py b/example/test_getting_started1.py new file mode 100644 index 00000000..7daf65af --- /dev/null +++ b/example/test_getting_started1.py @@ -0,0 +1,17 @@ +r'''>>> import getting_started1 + >>> print getting_started1.greet() + hello, world + >>> number = 11 + >>> print number, '*', number, '=', getting_started1.square(number) + 11 * 11 = 121 +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_getting_started1 + doctest.testmod(test_getting_started1) + +if __name__ == '__main__': + run() diff --git a/example/test_getting_started2.py b/example/test_getting_started2.py new file mode 100644 index 00000000..09215816 --- /dev/null +++ b/example/test_getting_started2.py @@ -0,0 +1,19 @@ +r'''>>> import getting_started2 + >>> w = getting_started2.world('California') + >>> print w.greet() + Hello from California! + >>> print getting_started2.invite(w) + Hello from California! Please come soon! + >>> print w.invite() + Hello from California! Please come soon! +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_getting_started2 + doctest.testmod(test_getting_started2) + +if __name__ == '__main__': + run() diff --git a/example/test_getting_started3.py b/example/test_getting_started3.py new file mode 100644 index 00000000..d62cf5a2 --- /dev/null +++ b/example/test_getting_started3.py @@ -0,0 +1,56 @@ +r'''>>> import getting_started3 + >>> import re + >>> import pickle + >>> getting_started3.world.__module__ + 'getting_started3' + >>> getting_started3.world.__safe_for_unpickling__ + 1 + >>> getting_started3.world.__reduce__() + 'world' + >>> assert re.match( + ... "\(, \('Hello',\), \(0,\)\)", + ... repr(getting_started3.world('Hello').__reduce__())) + >>> + >>> for number in (24, 42): + ... wd = getting_started3.world('California') + ... wd.set_secret_number(number) + ... pstr = pickle.dumps(wd) + ... print pstr + ... wl = pickle.loads(pstr) + ... print wd.greet(), wd.get_secret_number() + ... print wl.greet(), wl.get_secret_number() + cgetting_started3 + world + p0 + (S'California' + p1 + tp2 + R(I24 + tp3 + bp4 + . + Hello from California! 24 + Hello from California! 24 + cgetting_started3 + world + p0 + (S'California' + p1 + tp2 + R(I42 + tp3 + bp4 + . + Hello from California! 42 + Hello from California! 0 +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_getting_started3 + doctest.testmod(test_getting_started3) + +if __name__ == '__main__': + run() diff --git a/example/test_getting_started4.py b/example/test_getting_started4.py new file mode 100644 index 00000000..82b5c794 --- /dev/null +++ b/example/test_getting_started4.py @@ -0,0 +1,35 @@ +r'''>>> import getting_started4 + >>> v=getting_started4.vector_double() + >>> print v.as_tuple() + () + >>> v=getting_started4.vector_double(5) + >>> print v.as_tuple() + (0.0, 0.0, 0.0, 0.0, 0.0) + >>> print len(v) + 5 + >>> v=getting_started4.vector_double((3,4,5)) + >>> print v.as_tuple() + (3.0, 4.0, 5.0) + >>> print v[1] + 4.0 + >>> v[1] = 40 + >>> print v.as_tuple() + (3.0, 40.0, 5.0) + >>> del v[1] + >>> print v.as_tuple() + (3.0, 5.0) + >>> print getting_started4.foo(11).as_tuple() + (0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0) + >>> print getting_started4.bar(12).as_tuple() + (0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0) +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_getting_started4 + doctest.testmod(test_getting_started4) + +if __name__ == '__main__': + run() diff --git a/example/test_getting_started5.py b/example/test_getting_started5.py new file mode 100644 index 00000000..8eeba1e2 --- /dev/null +++ b/example/test_getting_started5.py @@ -0,0 +1,22 @@ +r'''>>> import getting_started5 + >>> ixset = getting_started5.IndexingSet() + >>> ixset.add((1,2,3)) + >>> ixset.add((4,5,6)) + >>> ixset.add((7,8,9)) + >>> print ixset.get(0) + (1, 2, 3) + >>> print ixset.get(1) + (4, 5, 6) + >>> print ixset.get(2) + (7, 8, 9) +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_getting_started5 + doctest.testmod(test_getting_started5) + +if __name__ == '__main__': + run() diff --git a/example/test_rwgk1.py b/example/test_rwgk1.py deleted file mode 100644 index 87298875..00000000 --- a/example/test_rwgk1.py +++ /dev/null @@ -1,17 +0,0 @@ -r'''>>> import rwgk1 - >>> print rwgk1.greet() - hello, world - >>> number = 11 - >>> print number, '*', number, '=', rwgk1.square(number) - 11 * 11 = 121 -''' - -def run(args = None): - if args is not None: - import sys - sys.argv = args - import doctest, test_rwgk1 - doctest.testmod(test_rwgk1) - -if __name__ == '__main__': - run() diff --git a/example/tst_dvect.py b/example/tst_dvect.py new file mode 100644 index 00000000..563f0ad5 --- /dev/null +++ b/example/tst_dvect.py @@ -0,0 +1,16 @@ +import dvect +print dvect.dvect.__converters__ +dv = dvect.dvect((1,2,3,4,5)) +print dv +print dv.as_tuple() +iv = dv.as_ivect() +print iv +print iv.as_tuple() +print dvect.ivect_as_tuple(iv) +aiv = dv.auto_ptr_ivect() +print aiv +siv = dv.shared_ptr_ivect() +print dvect.auto_ptr_ivect_as_tuple(aiv) +print dvect.ivect_as_tuple(aiv) +print dvect.shared_ptr_ivect_as_tuple(siv) +print dvect.ivect_as_tuple(siv) diff --git a/example/tst_ivect.py b/example/tst_ivect.py new file mode 100644 index 00000000..58bc323f --- /dev/null +++ b/example/tst_ivect.py @@ -0,0 +1,16 @@ +import ivect +print ivect.ivect.__converters__ +iv = ivect.ivect((1,2,3,4,5)) +print iv +print iv.as_tuple() +dv = iv.as_dvect() +print dv +print dv.as_tuple() +print ivect.dvect_as_tuple(dv) +adv = iv.auto_ptr_dvect() +print adv +sdv = iv.shared_ptr_dvect() +print ivect.auto_ptr_dvect_as_tuple(adv) +print ivect.dvect_as_tuple(adv) +print ivect.shared_ptr_dvect_as_tuple(sdv) +print ivect.dvect_as_tuple(sdv) diff --git a/example/tst_noncopyable.py b/example/tst_noncopyable.py new file mode 100644 index 00000000..913df039 --- /dev/null +++ b/example/tst_noncopyable.py @@ -0,0 +1,8 @@ +import noncopyable_export +import noncopyable_import +s1 = noncopyable_export.store(1) +print s1.recall() +s2 = noncopyable_export.store(2) +print s2.recall() +s3 = noncopyable_import.add_stores(s1, s2) +print s3.recall() From f24a95c9172769d78a3695392464cfab08b4e7cd Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 31 Jan 2001 19:27:17 +0000 Subject: [PATCH 032/154] fix for reference count bug. [SVN r8835] --- example/getting_started5.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/getting_started5.cpp b/example/getting_started5.cpp index e82fec30..bbe4725a 100644 --- a/example/getting_started5.cpp +++ b/example/getting_started5.cpp @@ -70,7 +70,7 @@ BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // MillerIndex from_python(PyObject* p, python::type) { - python::tuple tup = python::tuple(python::ref(p)); + python::tuple tup = python::tuple(python::ref(p, ref::increment_count)); if (tup.size() != 3) { PyErr_SetString(PyExc_ValueError, "expecting exactly 3 values in tuple."); From 1d4dfdf271155f94ed4684b92bf426de8445aa4c Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 5 Feb 2001 23:28:01 +0000 Subject: [PATCH 033/154] converted <> to <> [SVN r8954] --- doc/pointers.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/pointers.html b/doc/pointers.html index 26f96f0d..bf8ec8ae 100644 --- a/doc/pointers.html +++ b/doc/pointers.html @@ -90,7 +90,7 @@ BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround PyObject* to_python(const Foo* p) { - return to_python(const_cast(p)); + return to_python(const_cast<Foo*>(p)); } BOOST_PYTHON_END_CONVERSION_NAMESPACE

From 4d19be8ea477d05df16c979032326175d088d299 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 6 Feb 2001 03:08:00 +0000 Subject: [PATCH 034/154] PyExtensionClassConverters -> python_extension_class_converters<Foo> [SVN r8968] --- doc/pointers.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/pointers.html b/doc/pointers.html index bf8ec8ae..e26cea02 100644 --- a/doc/pointers.html +++ b/doc/pointers.html @@ -85,7 +85,7 @@ code before the last Python reference to it disappears: BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround PyObject* to_python(Foo* p) { - return boost::python::PyExtensionClassConverters::ptr_to_python(p); + return boost::python::python_extension_class_converters<Foo>::ptr_to_python(p); } PyObject* to_python(const Foo* p) From 1d17690f694f72b7b663f048f93b4f356905a404 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 7 Feb 2001 23:50:41 +0000 Subject: [PATCH 035/154] Add back old example files that were accidentally removed from the main branch. [SVN r9016] --- example/example1.cpp | 54 ++++++++++++++++++++++++++++++++++++++++ example/rwgk1.cpp | 41 ++++++++++++++++++++++++++++++ example/test_example1.py | 50 +++++++++++++++++++++++++++++++++++++ example/test_rwgk1.py | 17 +++++++++++++ 4 files changed, 162 insertions(+) create mode 100644 example/example1.cpp create mode 100644 example/rwgk1.cpp create mode 100644 example/test_example1.py create mode 100644 example/test_rwgk1.py diff --git a/example/example1.cpp b/example/example1.cpp new file mode 100644 index 00000000..467ac0dc --- /dev/null +++ b/example/example1.cpp @@ -0,0 +1,54 @@ +#include + +namespace hello { + class world + { + public: + world(int) {} + ~world() {} + const char* get() const { return "hi, world"; } + }; + + size_t length(const world& x) { return strlen(x.get()); } +} + +#include + +// Python requires an exported function called init in every +// extension module. This is where we build the module contents. +extern "C" +#ifdef _WIN32 +__declspec(dllexport) +#endif +void inithello() +{ + try + { + // create an object representing this extension module + boost::python::module_builder hello("hello"); + + // Create the Python type object for our extension class + boost::python::class_builder world_class(hello, "world"); + + // Add the __init__ function + world_class.def(boost::python::constructor()); + // Add a regular member function + world_class.def(&hello::world::get, "get"); + + // Add a regular function to the module + hello.def(hello::length, "length"); + } + catch(...) + { + boost::python::handle_exception(); // Deal with the exception for Python + } +} + +// Win32 DLL boilerplate +#if defined(_WIN32) +#include +extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) +{ + return 1; +} +#endif // _WIN32 diff --git a/example/rwgk1.cpp b/example/rwgk1.cpp new file mode 100644 index 00000000..b21ae4d1 --- /dev/null +++ b/example/rwgk1.cpp @@ -0,0 +1,41 @@ +#include + +namespace { // Avoid cluttering the global namespace. + + // A couple of simple C++ functions that we want to expose to Python. + std::string greet() { return "hello, world"; } + int square(int number) { return number * number; } +} + +#include + +namespace python = boost::python; + +// Python requires an exported function called init in every +// extension module. This is where we build the module contents. +extern "C" +#ifdef _WIN32 +__declspec(dllexport) +#endif +void initrwgk1() +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("rwgk1"); + + // Add regular functions to the module. + this_module.def(greet, "greet"); + this_module.def(square, "square"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} + +// Win32 DLL boilerplate +#if defined(_WIN32) +#include +extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) { return 1; } +#endif // _WIN32 diff --git a/example/test_example1.py b/example/test_example1.py new file mode 100644 index 00000000..0e3a9a18 --- /dev/null +++ b/example/test_example1.py @@ -0,0 +1,50 @@ +r''' +// (C) Copyright David Abrahams 2000. 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. +// +// The author gratefully acknowleges the support of Dragon Systems, Inc., in +// producing this work. + +That's it! If we build this shared library and put it on our PYTHONPATH we can +now access our C++ class and function from Python. + + >>> import hello + >>> hi_world = hello.world(3) + >>> hi_world.get() + 'hi, world' + >>> hello.length(hi_world) + 9 + +We can even make a subclass of hello.world: + + + >>> class my_subclass(hello.world): + ... def get(self): + ... return 'hello, world' + ... + >>> y = my_subclass(2) + >>> y.get() + 'hello, world' + +Pretty cool! You can't do that with an ordinary Python extension type! + + >>> hello.length(y) + 9 + +Of course, you may now have a slightly empty feeling in the pit of your little +pythonic stomach. Perhaps you feel your subclass deserves to have a length() of +12? If so, read on... +''' +from hello import * + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_example1 + doctest.testmod(test_example1) + +if __name__ == '__main__': + run() diff --git a/example/test_rwgk1.py b/example/test_rwgk1.py new file mode 100644 index 00000000..87298875 --- /dev/null +++ b/example/test_rwgk1.py @@ -0,0 +1,17 @@ +r'''>>> import rwgk1 + >>> print rwgk1.greet() + hello, world + >>> number = 11 + >>> print number, '*', number, '=', rwgk1.square(number) + 11 * 11 = 121 +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_rwgk1 + doctest.testmod(test_rwgk1) + +if __name__ == '__main__': + run() From 0d04bf8e34031d7413bce85c4eeabf73e5024445 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 7 Feb 2001 23:58:44 +0000 Subject: [PATCH 036/154] Remove example files that were accidentally added to the main branch. [SVN r9017] --- example/README | 6 +++ example/dvect.cpp | 69 ---------------------------------- example/dvect.h | 32 ---------------- example/ivect.cpp | 69 ---------------------------------- example/ivect.h | 32 ---------------- example/noncopyable_export.cpp | 24 ------------ example/noncopyable_import.cpp | 42 --------------------- example/store.h | 14 ------- example/tst_dvect.py | 16 -------- example/tst_ivect.py | 16 -------- example/tst_noncopyable.py | 8 ---- 11 files changed, 6 insertions(+), 322 deletions(-) create mode 100644 example/README delete mode 100644 example/dvect.cpp delete mode 100644 example/dvect.h delete mode 100644 example/ivect.cpp delete mode 100644 example/ivect.h delete mode 100644 example/noncopyable_export.cpp delete mode 100644 example/noncopyable_import.cpp delete mode 100644 example/store.h delete mode 100644 example/tst_dvect.py delete mode 100644 example/tst_ivect.py delete mode 100644 example/tst_noncopyable.py diff --git a/example/README b/example/README new file mode 100644 index 00000000..34b50d61 --- /dev/null +++ b/example/README @@ -0,0 +1,6 @@ +To get started with the Boost Python Library, use the examples +getting_started?.cpp and abstract.cpp. + +The files example1.cpp and rwgk1.cpp are obsolete. They are only +included because the makefiles in the build directory still refer to +them. This will be fixed later. diff --git a/example/dvect.cpp b/example/dvect.cpp deleted file mode 100644 index 3228010c..00000000 --- a/example/dvect.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "ivect.h" -#include "dvect.h" -#include -#include -namespace python = boost::python; - -namespace { - - vects::ivect dvect_as_ivect(const vects::dvect& dv) - { - vects::ivect iv(dv.size()); - vects::ivect::iterator iviter = iv.begin(); - for (int i = 0; i < dv.size(); i++) iviter[i] = static_cast(dv[i]); - return iv; - } - - boost::python::tuple ivect_as_tuple(const vects::ivect& iv) - { - return iv.as_tuple(); - } - - std::auto_ptr auto_ptr_ivect(const vects::dvect& dv) - { - return std::auto_ptr(new vects::ivect(dvect_as_ivect(dv))); - } - - boost::shared_ptr shared_ptr_ivect(const vects::dvect& dv) - { - return boost::shared_ptr(new vects::ivect(dvect_as_ivect(dv))); - } - - boost::python::tuple auto_ptr_ivect_as_tuple(std::auto_ptr& iv) - { - return iv->as_tuple(); - } - - boost::python::tuple shared_ptr_ivect_as_tuple(boost::shared_ptr& iv) - { - return iv->as_tuple(); - } -} - -extern "C" -DL_EXPORT(void) -initdvect() -{ - try - { - python::module_builder this_module("dvect"); - - python::x_class_builder dvect_class(this_module, "dvect"); - - python::import_class_builder ivect_class("ivect", "ivect"); - - dvect_class.def(python::constructor()); - dvect_class.def(&vects::dvect::as_tuple, "as_tuple"); - dvect_class.def(dvect_as_ivect, "as_ivect"); - - this_module.def(ivect_as_tuple, "ivect_as_tuple"); - dvect_class.def(auto_ptr_ivect, "auto_ptr_ivect"); - dvect_class.def(shared_ptr_ivect, "shared_ptr_ivect"); - this_module.def(auto_ptr_ivect_as_tuple, "auto_ptr_ivect_as_tuple"); - this_module.def(shared_ptr_ivect_as_tuple, "shared_ptr_ivect_as_tuple"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/dvect.h b/example/dvect.h deleted file mode 100644 index 8ffe7b50..00000000 --- a/example/dvect.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef DVECT_H -#define DVECT_H - -#include -#include - -namespace vects { - - struct dvect : public std::vector - { - dvect() : std::vector() {} - dvect(size_t n) : std::vector(n) {} - dvect(boost::python::tuple tuple) : std::vector(tuple.size()) - { - std::vector::iterator v_it = begin(); - for (int i = 0; i < tuple.size(); i++) - v_it[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), - boost::python::type()); - } - - boost::python::tuple as_tuple() const - { - boost::python::tuple t(size()); - for (int i = 0; i < size(); i++) - t.set_item(i, - boost::python::ref(BOOST_PYTHON_CONVERSION::to_python((*this)[i]))); - return t; - } - }; -} - -#endif // DVECT_H diff --git a/example/ivect.cpp b/example/ivect.cpp deleted file mode 100644 index f8ca8707..00000000 --- a/example/ivect.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "ivect.h" -#include "dvect.h" -#include -#include -namespace python = boost::python; - -namespace { - - vects::dvect ivect_as_dvect(const vects::ivect& iv) - { - vects::dvect dv(iv.size()); - vects::dvect::iterator dviter = dv.begin(); - for (int i = 0; i < iv.size(); i++) dviter[i] = static_cast(iv[i]); - return dv; - } - - boost::python::tuple dvect_as_tuple(const vects::dvect& dv) - { - return dv.as_tuple(); - } - - std::auto_ptr auto_ptr_dvect(const vects::ivect& iv) - { - return std::auto_ptr(new vects::dvect(ivect_as_dvect(iv))); - } - - boost::shared_ptr shared_ptr_dvect(const vects::ivect& iv) - { - return boost::shared_ptr(new vects::dvect(ivect_as_dvect(iv))); - } - - boost::python::tuple auto_ptr_dvect_as_tuple(std::auto_ptr& dv) - { - return dv->as_tuple(); - } - - boost::python::tuple shared_ptr_dvect_as_tuple(boost::shared_ptr& dv) - { - return dv->as_tuple(); - } -} - -extern "C" -DL_EXPORT(void) -initivect() -{ - try - { - python::module_builder this_module("ivect"); - - python::x_class_builder ivect_class(this_module, "ivect"); - - python::import_class_builder dvect_class("dvect", "dvect"); - - ivect_class.def(python::constructor()); - ivect_class.def(&vects::ivect::as_tuple, "as_tuple"); - ivect_class.def(ivect_as_dvect, "as_dvect"); - - this_module.def(dvect_as_tuple, "dvect_as_tuple"); - ivect_class.def(auto_ptr_dvect, "auto_ptr_dvect"); - ivect_class.def(shared_ptr_dvect, "shared_ptr_dvect"); - this_module.def(auto_ptr_dvect_as_tuple, "auto_ptr_dvect_as_tuple"); - this_module.def(shared_ptr_dvect_as_tuple, "shared_ptr_dvect_as_tuple"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/ivect.h b/example/ivect.h deleted file mode 100644 index a0187307..00000000 --- a/example/ivect.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef IVECT_H -#define IVECT_H - -#include -#include - -namespace vects { - - struct ivect : public std::vector - { - ivect() : std::vector() {} - ivect(size_t n) : std::vector(n) {} - ivect(boost::python::tuple tuple) : std::vector(tuple.size()) - { - std::vector::iterator v_it = begin(); - for (int i = 0; i < tuple.size(); i++) - v_it[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), - boost::python::type()); - } - - boost::python::tuple as_tuple() const - { - boost::python::tuple t(size()); - for (int i = 0; i < size(); i++) - t.set_item(i, - boost::python::ref(BOOST_PYTHON_CONVERSION::to_python((*this)[i]))); - return t; - } - }; -} - -#endif // IVECT_H diff --git a/example/noncopyable_export.cpp b/example/noncopyable_export.cpp deleted file mode 100644 index 82c3f049..00000000 --- a/example/noncopyable_export.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -namespace python = boost::python; - -#include "store.h" - -extern "C" -DL_EXPORT(void) -initnoncopyable_export() -{ - try - { - python::module_builder this_module("noncopyable_export"); - - python::xptr_class_builder store_class(this_module, "store"); - - store_class.def(python::constructor()); - store_class.def(&store::recall, "recall"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/noncopyable_import.cpp b/example/noncopyable_import.cpp deleted file mode 100644 index 529c9f42..00000000 --- a/example/noncopyable_import.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -namespace python = boost::python; - -#include "store.h" - -namespace { // Avoid cluttering the global namespace. - - // A function with store objects as both input and output parameters. - // Because the copy constructor is disabled, we cannot pass a store - // object by value. Instead, we pass a smart pointer. - std::auto_ptr add_stores(const store& s1, const store& s2) - { - int sum = s1.recall() + s2.recall(); - std::auto_ptr ss = std::auto_ptr(new store(sum)); - return ss; - } -} - -extern "C" -DL_EXPORT(void) -initnoncopyable_import() -{ - try - { - python::module_builder this_module("noncopyable_import"); - - python::import_class_builder - dvect_class("noncopyable_export", "store"); - - // Imagine all the additional classes with member functions - // that have store objects as input and output parameters. - // Lots and lots of them. - // However, to keep this example simple, we only define a - // module-level function. - this_module.def(add_stores, "add_stores"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/store.h b/example/store.h deleted file mode 100644 index 74ef0477..00000000 --- a/example/store.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef STORE_H -#define STORE_H - -class store -{ - private: - store(const store&) { } // Disable the copy constructor. - int number; - public: - store(const int i) : number(i) { } - int recall() const { return number; } -}; - -#endif // STORE_H diff --git a/example/tst_dvect.py b/example/tst_dvect.py deleted file mode 100644 index 563f0ad5..00000000 --- a/example/tst_dvect.py +++ /dev/null @@ -1,16 +0,0 @@ -import dvect -print dvect.dvect.__converters__ -dv = dvect.dvect((1,2,3,4,5)) -print dv -print dv.as_tuple() -iv = dv.as_ivect() -print iv -print iv.as_tuple() -print dvect.ivect_as_tuple(iv) -aiv = dv.auto_ptr_ivect() -print aiv -siv = dv.shared_ptr_ivect() -print dvect.auto_ptr_ivect_as_tuple(aiv) -print dvect.ivect_as_tuple(aiv) -print dvect.shared_ptr_ivect_as_tuple(siv) -print dvect.ivect_as_tuple(siv) diff --git a/example/tst_ivect.py b/example/tst_ivect.py deleted file mode 100644 index 58bc323f..00000000 --- a/example/tst_ivect.py +++ /dev/null @@ -1,16 +0,0 @@ -import ivect -print ivect.ivect.__converters__ -iv = ivect.ivect((1,2,3,4,5)) -print iv -print iv.as_tuple() -dv = iv.as_dvect() -print dv -print dv.as_tuple() -print ivect.dvect_as_tuple(dv) -adv = iv.auto_ptr_dvect() -print adv -sdv = iv.shared_ptr_dvect() -print ivect.auto_ptr_dvect_as_tuple(adv) -print ivect.dvect_as_tuple(adv) -print ivect.shared_ptr_dvect_as_tuple(sdv) -print ivect.dvect_as_tuple(sdv) diff --git a/example/tst_noncopyable.py b/example/tst_noncopyable.py deleted file mode 100644 index 913df039..00000000 --- a/example/tst_noncopyable.py +++ /dev/null @@ -1,8 +0,0 @@ -import noncopyable_export -import noncopyable_import -s1 = noncopyable_export.store(1) -print s1.recall() -s2 = noncopyable_export.store(2) -print s2.recall() -s3 = noncopyable_import.add_stores(s1, s2) -print s3.recall() From f3d9193743d8635a46b53c7d36a3c77d8c61c83c Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 8 Feb 2001 01:54:59 +0000 Subject: [PATCH 037/154] Fix for linux gcc-2.95.2 [SVN r9023] --- example/getting_started5.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/example/getting_started5.cpp b/example/getting_started5.cpp index bbe4725a..4b64e4b8 100644 --- a/example/getting_started5.cpp +++ b/example/getting_started5.cpp @@ -70,7 +70,8 @@ BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // MillerIndex from_python(PyObject* p, python::type) { - python::tuple tup = python::tuple(python::ref(p, ref::increment_count)); + python::tuple tup + = python::tuple(python::ref(p, python::ref::increment_count)); if (tup.size() != 3) { PyErr_SetString(PyExc_ValueError, "expecting exactly 3 values in tuple."); From b000c759477dc3cdaaa6ced47accf92e890fc7f3 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 23 Feb 2001 08:58:32 +0000 Subject: [PATCH 038/154] Fix for python::tuple.set_item() memory leak. [SVN r9316] --- example/getting_started5.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/getting_started5.cpp b/example/getting_started5.cpp index 4b64e4b8..c9f1ce36 100644 --- a/example/getting_started5.cpp +++ b/example/getting_started5.cpp @@ -97,7 +97,7 @@ BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE { python::tuple result(3); for (int i = 0; i < 3; i++) - result.set_item(i, to_python(hkl.v[i])); + result.set_item(i, python::ref(to_python(hkl.v[i]))); return result.reference().release(); } From 977841a7f383115244b27fdf58a4af6429852ff8 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Fri, 2 Mar 2001 01:48:30 +0000 Subject: [PATCH 039/154] Use PyObject_INIT() instead of hand-initializing objects [SVN r9375] --- include/boost/python/detail/base_object.hpp | 6 ++-- include/boost/python/detail/wrap_python.hpp | 7 +++++ src/extension_class.cpp | 7 +++-- src/functions.cpp | 31 ++++++++++++--------- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/include/boost/python/detail/base_object.hpp b/include/boost/python/detail/base_object.hpp index f8ed665b..bf0faa7b 100644 --- a/include/boost/python/detail/base_object.hpp +++ b/include/boost/python/detail/base_object.hpp @@ -5,6 +5,9 @@ // // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. +// +// Revision History: +// Mar 01 01 Use PyObject_INIT() instead of trying to hand-initialize (David Abrahams) #ifndef BASE_OBJECT_DWA051600_H_ # define BASE_OBJECT_DWA051600_H_ @@ -46,9 +49,8 @@ base_object::base_object(PyTypeObject* type_obj) std:: #endif memset(bp, 0, sizeof(base_python_type)); - ob_refcnt = 1; - ob_type = type_obj; Py_INCREF(type_obj); + PyObject_INIT(bp, type_obj); } template diff --git a/include/boost/python/detail/wrap_python.hpp b/include/boost/python/detail/wrap_python.hpp index eb831b68..9e57c287 100644 --- a/include/boost/python/detail/wrap_python.hpp +++ b/include/boost/python/detail/wrap_python.hpp @@ -15,6 +15,9 @@ // To use the Python debugging library, #define BOOST_DEBUG_PYTHON on the // compiler command-line. +// Revision History: +// 01 Mar 01 define PyObject_INIT() for Python 1.x + #ifdef _DEBUG # ifndef BOOST_DEBUG_PYTHON # undef _DEBUG // Don't let Python force the debug library just because we're debugging. @@ -76,3 +79,7 @@ typedef int pid_t; # define _DEBUG #endif +#if !defined(PY_MAJOR_VERSION) || PY_MAJOR_VERSION < 2 +# define PyObject_INIT(op, typeobj) \ + ( (op)->ob_type = (typeobj), _Py_NewReference((PyObject *)(op)), (op) ) +#endif diff --git a/src/extension_class.cpp b/src/extension_class.cpp index c15e538b..47862ec7 100644 --- a/src/extension_class.cpp +++ b/src/extension_class.cpp @@ -5,6 +5,9 @@ // // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. +// +// Revision History: +// Mar 01 01 Use PyObject_INIT() instead of trying to hand-initialize (David Abrahams) #include #include @@ -446,8 +449,8 @@ operator_dispatcher::operator_dispatcher(const ref& o, const ref& s) : m_object(o), m_self(s), m_free_list_link(0) { - ob_refcnt = 1; - ob_type = &type_obj; + PyObject* self = this; + PyObject_INIT(self, &type_obj); } operator_dispatcher* diff --git a/src/functions.cpp b/src/functions.cpp index e166c91c..71b59136 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -5,6 +5,9 @@ // // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. +// +// Revision History: +// Mar 01 01 Use PyObject_INIT() instead of trying to hand-initialize (David Abrahams) #include #include @@ -97,19 +100,6 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const return 0; } -bound_function* bound_function::create(const ref& target, const ref& fn) -{ - bound_function* const result = free_list; - if (result == 0) - return new bound_function(target, fn); - - free_list = result->m_free_list_link; - result->m_target = target; - result->m_unbound_function = fn; - Py_INCREF(result); - return result; -} - // The instance class whose obj represents the type of bound_function // objects in Python. bound_functions must be GetAttrable so the __doc__ // attribute of built-in Python functions can be accessed when bound. @@ -123,6 +113,21 @@ private: // type_object hook override void dealloc(bound_function*) const; }; +bound_function* bound_function::create(const ref& target, const ref& fn) +{ + bound_function* const result = free_list; + if (result == 0) + return new bound_function(target, fn); + + free_list = result->m_free_list_link; + result->m_target = target; + result->m_unbound_function = fn; + + PyObject* self = result; + PyObject_INIT(self, type_object::instance()); + return result; +} + bound_function::bound_function(const ref& target, const ref& fn) : python_object(type_object::instance()), m_target(target), From f5fa4a460a27afdfb53b5054c6a9550c009b1817 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 3 Mar 2001 10:22:35 +0000 Subject: [PATCH 040/154] Wrong file name replaced (instance.hpp -> singleton.hpp). [SVN r9390] --- src/gen_all.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gen_all.py b/src/gen_all.py index 416c66f1..3877d181 100644 --- a/src/gen_all.py +++ b/src/gen_all.py @@ -10,7 +10,7 @@ def gen_all(args): open('caller.hpp', 'w').write(gen_caller(args)) open('init_function.hpp', 'w').write(gen_init_function(args)) open('signatures.hpp', 'w').write(gen_signatures(args)) - open('instance.hpp', 'w').write(gen_singleton(args)) + open('singleton.hpp', 'w').write(gen_singleton(args)) open('extension_class.hpp', 'w').write(gen_extclass(args)) if __name__ == '__main__': From 51d60a603590d559647283bbf3d9c33ebf866002 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 3 Mar 2001 11:48:52 +0000 Subject: [PATCH 041/154] added: converters for [plain] char and std::complex [SVN r9397] --- include/boost/python/conversions.hpp | 39 ++++++++++++++++++++++++++++ src/conversions.cpp | 21 +++++++++++++++ test/comprehensive.cpp | 34 ++++++++++++++++++++++++ test/comprehensive.py | 33 +++++++++++++++++++++++ 4 files changed, 127 insertions(+) diff --git a/include/boost/python/conversions.hpp b/include/boost/python/conversions.hpp index d11f7f14..b633c0ee 100644 --- a/include/boost/python/conversions.hpp +++ b/include/boost/python/conversions.hpp @@ -5,6 +5,9 @@ // // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. +// +// Revision History: +// Mar 03 01 added: converters for [plain] char and std::complex (Ralf W. Grosse-Kunstleve) #ifndef METHOD_DWA122899_H_ # define METHOD_DWA122899_H_ @@ -16,6 +19,7 @@ # include # include # include +# include BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround @@ -100,6 +104,10 @@ PyObject* to_python(unsigned short); 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); +char from_python(PyObject*, boost::python::type); + PyObject* to_python(signed char); signed char from_python(PyObject*, boost::python::type); signed char from_python(PyObject*, boost::python::type); @@ -130,6 +138,32 @@ PyObject* to_python(const std::string& s); std::string from_python(PyObject*, boost::python::type); std::string from_python(PyObject*, boost::python::type); +template +PyObject* to_python(const std::complex& sc) { + Py_complex pcc; + pcc.real = sc.real(); + pcc.imag = sc.imag(); + return PyComplex_FromCComplex(pcc); +} + +template +std::complex from_python(PyObject* p, + boost::python::type&>) { + if (! PyComplex_Check(p)) { + PyErr_SetString(PyExc_TypeError, "expected a complex number"); + throw boost::python::argument_error(); + } + return std::complex( + static_cast(PyComplex_RealAsDouble(p)), + static_cast(PyComplex_ImagAsDouble(p))); +} + +template +inline std::complex from_python(PyObject* p, + boost::python::type >) { + return from_python(p, boost::python::type&>()); +} + // For when your C++ function really wants to pass/return a PyObject* PyObject* to_python(PyObject*); PyObject* from_python(PyObject*, boost::python::type); @@ -304,6 +338,11 @@ inline unsigned short from_python(PyObject* p, boost::python::type()); } +inline char from_python(PyObject* p, boost::python::type) +{ + return from_python(p, boost::python::type()); +} + inline signed char from_python(PyObject* p, boost::python::type) { return from_python(p, boost::python::type()); diff --git a/src/conversions.cpp b/src/conversions.cpp index ded01e0e..369f197a 100644 --- a/src/conversions.cpp +++ b/src/conversions.cpp @@ -5,6 +5,9 @@ // // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. +// +// Revision History: +// Mar 03 01 added: converters for [plain] char (Ralf W. Grosse-Kunstleve) #include #include @@ -160,6 +163,24 @@ unsigned short from_python(PyObject* p, boost::python::type type return integer_from_python(p, type); } +PyObject* to_python(char c) +{ + if (c == '\0') return PyString_FromString(""); + return PyString_FromStringAndSize(&c, 1); +} + +char from_python(PyObject* p, boost::python::type) +{ + int l = -1; + if (PyString_Check(p)) l = PyString_Size(p); + if (l < 0 || l > 1) { + PyErr_SetString(PyExc_TypeError, "expected string of length 0 or 1"); + throw boost::python::argument_error(); + } + if (l == 0) return '\0'; + return PyString_AsString(p)[0]; +} + PyObject* to_python(unsigned char i) { return integer_to_python(i); diff --git a/test/comprehensive.cpp b/test/comprehensive.cpp index 7fad74bb..592b0ebd 100644 --- a/test/comprehensive.cpp +++ b/test/comprehensive.cpp @@ -815,6 +815,25 @@ namespace bpl_test { w.set_secret_number(number); } + // Test plain char converters. + char get_plain_char() { return 'x'; } + std::string use_plain_char(char c) { return std::string(3, c); } + std::string use_const_plain_char(const char c) { return std::string(5, c); } + + // Test std::complex converters. + std::complex dpolar(double rho, double theta) { + return std::polar(rho, theta); + } + double dreal(const std::complex& c) { return c.real(); } + double dimag(std::complex c) { return c.imag(); } + + // Test std::complex converters. + std::complex fpolar(float rho, float theta) { + return std::polar(rho, theta); + } + double freal(const std::complex& c) { return c.real(); } + double fimag(std::complex c) { return c.imag(); } + /************************************************************/ /* */ /* init the module */ @@ -1036,6 +1055,21 @@ void init_module(boost::python::module_builder& m) world_class.def(world_getinitargs, "__getinitargs__"); world_class.def(world_getstate, "__getstate__"); world_class.def(world_setstate, "__setstate__"); + + // Test plain char converters. + m.def(get_plain_char, "get_plain_char"); + m.def(use_plain_char, "use_plain_char"); + m.def(use_const_plain_char, "use_const_plain_char"); + + // Test std::complex converters. + m.def(dpolar, "dpolar"); + m.def(dreal, "dreal"); + m.def(dimag, "dimag"); + + // Test std::complex converters. + m.def(fpolar, "fpolar"); + m.def(freal, "freal"); + m.def(fimag, "fimag"); } PyObject* raw(const boost::python::tuple& args, const boost::python::dictionary& keywords) diff --git a/test/comprehensive.py b/test/comprehensive.py index a8e181d2..8bc8021c 100644 --- a/test/comprehensive.py +++ b/test/comprehensive.py @@ -1070,6 +1070,39 @@ test methodologies for wrapping functions that return a pointer 3 >>> eo.second 1 + +======== test [plain] char converters ============== + >>> get_plain_char() + 'x' + >>> use_plain_char('a') + 'aaa' + >>> use_const_plain_char('b') + 'bbbbb' + +======== test std::complex converters ============== + >>> c = dpolar(3, 5) + >>> type(c) + + >>> '%.3g' % (dreal(c)) + '0.851' + >>> '%.3g' % (dimag(c)) + '-2.88' + >>> '%.3g' % (freal(c)) + '0.851' + >>> '%.3g' % (fimag(c)) + '-2.88' + >>> c = fpolar(7, 13) + >>> type(c) + + >>> '%.3g' % (fimag(c)) + '2.94' + >>> '%.3g' % (freal(c)) + '6.35' + >>> '%.3g' % (dimag(c)) + '2.94' + >>> '%.3g' % (dreal(c)) + '6.35' + ''' from test import * From 1d4427c056ef90b36aaaecc9babc86a778b82e95 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 3 Mar 2001 12:05:15 +0000 Subject: [PATCH 042/154] "T" replaced by "Held" to reduce chances of name clashes. [SVN r9398] --- .../boost/python/detail/extension_class.hpp | 30 +++++++++---------- src/gen_extclass.py | 10 +++---- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/boost/python/detail/extension_class.hpp b/include/boost/python/detail/extension_class.hpp index 94d9bf6b..bf43ec5c 100644 --- a/include/boost/python/detail/extension_class.hpp +++ b/include/boost/python/detail/extension_class.hpp @@ -61,7 +61,7 @@ T* check_non_null(T* p) return p; } -template class held_instance; +template class held_instance; typedef void* (*conversion_function_ptr)(void*); @@ -613,33 +613,33 @@ class extension_class // A simple wrapper over a T which allows us to use extension_class with a // single template parameter only. See extension_class, above. -template -class held_instance : public T +template +class held_instance : public Held { // There are no member functions: we want to avoid inadvertently overriding - // any virtual functions in T. + // any virtual functions in Held. public: - held_instance(PyObject*) : T() {} + held_instance(PyObject*) : Held() {} template - held_instance(PyObject*, A1 a1) : T(a1) {} + held_instance(PyObject*, A1 a1) : Held(a1) {} template - held_instance(PyObject*, A1 a1, A2 a2) : T(a1, a2) {} + held_instance(PyObject*, A1 a1, A2 a2) : Held(a1, a2) {} template - held_instance(PyObject*, A1 a1, A2 a2, A3 a3) : T(a1, a2, a3) {} + held_instance(PyObject*, A1 a1, A2 a2, A3 a3) : Held(a1, a2, a3) {} template - held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4) : T(a1, a2, a3, a4) {} + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4) : Held(a1, a2, a3, a4) {} template - held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : T(a1, a2, a3, a4, a5) {} + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : Held(a1, a2, a3, a4, a5) {} template - held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : T(a1, a2, a3, a4, a5, a6) {} + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : Held(a1, a2, a3, a4, a5, a6) {} template - held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) : T(a1, a2, a3, a4, a5, a6, a7) {} + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) : Held(a1, a2, a3, a4, a5, a6, a7) {} template - held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) : T(a1, a2, a3, a4, a5, a6, a7, a8) {} + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) : Held(a1, a2, a3, a4, a5, a6, a7, a8) {} template - held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) : T(a1, a2, a3, a4, a5, a6, a7, a8, a9) {} + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) : Held(a1, a2, a3, a4, a5, a6, a7, a8, a9) {} template - held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) : T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {} + held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) : Held(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {} }; // Abstract base class for all obj holders. Base for template class diff --git a/src/gen_extclass.py b/src/gen_extclass.py index f8906970..7c378d45 100644 --- a/src/gen_extclass.py +++ b/src/gen_extclass.py @@ -66,7 +66,7 @@ T* check_non_null(T* p) return p; } -template class held_instance; +template class held_instance; typedef void* (*conversion_function_ptr)(void*); @@ -613,15 +613,15 @@ class extension_class // A simple wrapper over a T which allows us to use extension_class with a // single template parameter only. See extension_class, above. -template -class held_instance : public T +template +class held_instance : public Held { // There are no member functions: we want to avoid inadvertently overriding - // any virtual functions in T. + // any virtual functions in Held. public:""" + gen_functions("""%{ template <%(class A%n%:, %)>%} - held_instance(PyObject*%(, A%n% a%n%)) : T(%(a%n%:, %)) {}""", args) + held_instance(PyObject*%(, A%n% a%n%)) : Held(%(a%n%:, %)) {}""", args) + """ }; From b06d9e50ebf64969d198ab03430d21eb40cb8442 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 3 Mar 2001 12:55:53 +0000 Subject: [PATCH 043/154] added: pickle safety measures; bug fix: use bound_function::create() [SVN r9399] --- include/boost/python/class_builder.hpp | 10 ++++++ src/classes.cpp | 46 ++++++++++++++++++++------ test/comprehensive.py | 41 +++++++++++++++++++++++ 3 files changed, 87 insertions(+), 10 deletions(-) diff --git a/include/boost/python/class_builder.hpp b/include/boost/python/class_builder.hpp index 7ef843c4..4a9ec1b2 100644 --- a/include/boost/python/class_builder.hpp +++ b/include/boost/python/class_builder.hpp @@ -1,3 +1,6 @@ +// Revision History: +// Mar 03 01 added: pickle safety measures (Ralf W. Grosse-Kunstleve) + #ifndef CLASS_WRAPPER_DWA101000_H_ # define CLASS_WRAPPER_DWA101000_H_ @@ -24,6 +27,13 @@ class class_builder ~class_builder() {} + + inline void dict_defines_state() { + add(ref(BOOST_PYTHON_CONVERSION::to_python(1)), "__dict_defines_state__"); + } + inline void getstate_manages_dict() { + add(ref(BOOST_PYTHON_CONVERSION::to_python(1)), "__getstate_manages_dict__"); + } // define constructors template diff --git a/src/classes.cpp b/src/classes.cpp index 2901aa81..625d67b7 100644 --- a/src/classes.cpp +++ b/src/classes.cpp @@ -5,6 +5,10 @@ // // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. +// +// Revision History: +// Mar 03 01 added: pickle safety measures (Ralf W. Grosse-Kunstleve) +// Mar 03 01 bug fix: use bound_function::create() (instead of new bound_function) #include #include @@ -67,8 +71,7 @@ namespace { ref global_class_reduce() { - static ref result(detail::new_wrapped_function(class_reduce)); - return result; + return ref(detail::new_wrapped_function(class_reduce)); } @@ -93,17 +96,41 @@ namespace { ref getstate(PyObject_GetAttrString(obj, const_cast("__getstate__")), ref::null_ok); PyErr_Clear(); + + ref dict(PyObject_GetAttrString(obj, const_cast("__dict__")), ref::null_ok); + PyErr_Clear(); + if (getstate.get() != 0) { + if (dict.get() != 0 && dictionary(dict).size() > 0) + { + ref getstate_manages_dict(PyObject_GetAttrString(instance_class.get(), const_cast("__getstate_manages_dict__")), ref::null_ok); + PyErr_Clear(); + if (getstate_manages_dict.get() == 0) + { + PyErr_SetString(PyExc_RuntimeError, "Incomplete pickle support (__getstate_manages_dict__ not set)"); + throw error_already_set(); + } + } + ref state = ref(PyEval_CallObject(getstate.get(), NULL)); return tuple(instance_class, initargs, state); } - ref state(PyObject_GetAttrString(obj, const_cast("__dict__")), ref::null_ok); - PyErr_Clear(); - if (state.get() != 0 && dictionary(state).size() > 0) + if (getinitargs.get() == 0) { - return tuple(instance_class, initargs, state); + ref dict_defines_state(PyObject_GetAttrString(instance_class.get(), const_cast("__dict_defines_state__")), ref::null_ok); + PyErr_Clear(); + if (dict_defines_state.get() == 0) + { + PyErr_SetString(PyExc_RuntimeError, "Incomplete pickle support (__dict_defines_state__ not set)"); + throw error_already_set(); + } + } + + if (dict.get() != 0 && dictionary(dict).size() > 0) + { + return tuple(instance_class, initargs, dict); } return tuple(instance_class, initargs); @@ -111,8 +138,7 @@ namespace { ref global_instance_reduce() { - static ref result(detail::new_wrapped_function(instance_reduce)); - return result; + return ref(detail::new_wrapped_function(instance_reduce)); } } @@ -177,7 +203,7 @@ namespace detail { if (!BOOST_CSTD_::strcmp(name, "__reduce__")) { ref target(as_object(this), ref::increment_count); - return new bound_function(target, global_class_reduce()); + return bound_function::create(target, global_class_reduce()); } ref local_attribute = m_name_space.get_item(string(name).reference()); @@ -348,7 +374,7 @@ PyObject* instance::getattr(const char* name, bool use_special_function) if (!BOOST_CSTD_::strcmp(name, "__reduce__")) { - return new detail::bound_function(ref(this, ref::increment_count), global_instance_reduce()); + return detail::bound_function::create(ref(this, ref::increment_count), global_instance_reduce()); } ref local_attribute = m_name_space.get_item(string(name).reference()); diff --git a/test/comprehensive.py b/test/comprehensive.py index 8bc8021c..3c7f3c61 100644 --- a/test/comprehensive.py +++ b/test/comprehensive.py @@ -239,6 +239,47 @@ Pickling tests: Hello from California! 42 Hello from California! 0 +Pickle safety measures: + >>> r=Rational(3, 4) + >>> r + Rational(3, 4) + >>> try: s=pickle.dumps(r) + ... except RuntimeError, err: print err[0] + ... + Incomplete pickle support (__dict_defines_state__ not set) + >>> class myrational(Rational): + ... __dict_defines_state__ = 1 # this is a lie but good enough for testing. + ... + >>> r=myrational(3, 4) + >>> r + Rational(3, 4) + >>> s=pickle.dumps(r) + + >>> class myworld(world): + ... def __init__(self): + ... world.__init__(self, 'anywhere') + ... self.x = 1 + ... + >>> w = myworld() + >>> w.greet() + 'Hello from anywhere!' + >>> w.__dict__ + {'x': 1} + >>> try: s=pickle.dumps(w) + ... except RuntimeError, err: print err[0] + ... + Incomplete pickle support (__getstate_manages_dict__ not set) + + >>> class myunsafeworld(myworld): + ... __getstate_manages_dict__ = 1 # this is a lie but good enough for testing. + ... + >>> w = myunsafeworld() + >>> w.greet() + 'Hello from anywhere!' + >>> w.__dict__ + {'x': 1} + >>> s=pickle.dumps(w) + Special member attributes. Tests courtesy of Barry Scott >>> class DerivedFromFoo(Foo): From fc62d3b44ec404cb470746c3c681764b846b88a8 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 3 Mar 2001 14:46:26 +0000 Subject: [PATCH 044/154] New Makefiles for tru64_cxx, linux_gcc, mingw32. [SVN r9400] --- build/Makefile.linux_gcc | 166 +++++++++++++++++++++++++++++++ build/Makefile.mingw32 | 210 +++++++++++++++++++++++++++++++++++++++ build/Makefile.tru64_cxx | 170 +++++++++++++++++++++++++++++++ build/tru64.mak | 51 ---------- 4 files changed, 546 insertions(+), 51 deletions(-) create mode 100644 build/Makefile.linux_gcc create mode 100644 build/Makefile.mingw32 create mode 100644 build/Makefile.tru64_cxx delete mode 100644 build/tru64.mak diff --git a/build/Makefile.linux_gcc b/build/Makefile.linux_gcc new file mode 100644 index 00000000..3e8f1041 --- /dev/null +++ b/build/Makefile.linux_gcc @@ -0,0 +1,166 @@ +# Usage: +# +# Create a new empty directory anywhere (preferably not in the boost tree). +# Copy this Makefile to that new directory and rename it to "Makefile" +# Set the BOOST pathname below. +# +# make softlinks Create softlinks to source code and tests +# make Compile all sources +# make test Run doctest tests +# make clean Remove all object files +# make unlink Remove softlinks + +BOOST= /net/cci/rwgk/boost + +PYEXE= /usr/local/Python-1.5.2/bin/python +PYINC= -I/usr/local/Python-1.5.2/include/python1.5 +#PYEXE= /usr/local/Python-2.0/bin/python +#PYINC= -I/usr/local/Python-2.0/include/python2.0 +#STLPORTINC= -I/usr/local/STLport-4.1b3/stlport +#STLPORTOPTS= \ +# -D__USE_STD_IOSTREAM \ +# -D__STL_NO_SGI_IOSTREAMS \ +# -D__STL_USE_NATIVE_STRING \ +# -D__STL_NO_NEW_C_HEADERS \ +# -D_RWSTD_COMPILE_INSTANTIATE=1 +#STLPORTINC= -I/usr/local/STLport-4.1b4/stlport +#STLPORTOPTS= -D__NO_USE_STD_IOSTREAM -D__STL_NO_SGI_IOSTREAMS +#STLPORTINC= -I/net/cci/xp/C++_C_headers + +STDOPTS= -ftemplate-depth-21 +WARNOPTS= +# use -msg_display_number to obtain integer tags for -msg_disable + +CPP= g++ +CPPOPTS= $(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \ + $(STDOPTS) $(WARNOPTS) -g +MAKEDEP= -M + +LD= g++ +LDOPTS= -shared + +#HIDDEN= -hidden + +BPL_SRC = $(BOOST)/libs/python/src +BPL_TST = $(BOOST)/libs/python/test +BPL_EXA = $(BOOST)/libs/python/example +SOFTLINKS = \ +$(BPL_SRC)/classes.cpp \ +$(BPL_SRC)/conversions.cpp \ +$(BPL_SRC)/extension_class.cpp \ +$(BPL_SRC)/functions.cpp \ +$(BPL_SRC)/init_function.cpp \ +$(BPL_SRC)/module_builder.cpp \ +$(BPL_SRC)/objects.cpp \ +$(BPL_SRC)/types.cpp \ +$(BPL_TST)/comprehensive.cpp \ +$(BPL_TST)/comprehensive.hpp \ +$(BPL_TST)/comprehensive.py \ +$(BPL_TST)/doctest.py \ +$(BPL_EXA)/abstract.cpp \ +$(BPL_EXA)/getting_started1.cpp \ +$(BPL_EXA)/getting_started2.cpp \ +$(BPL_EXA)/getting_started3.cpp \ +$(BPL_EXA)/getting_started4.cpp \ +$(BPL_EXA)/getting_started5.cpp \ +$(BPL_EXA)/test_abstract.py \ +$(BPL_EXA)/test_getting_started1.py \ +$(BPL_EXA)/test_getting_started2.py \ +$(BPL_EXA)/test_getting_started3.py \ +$(BPL_EXA)/test_getting_started4.py \ +$(BPL_EXA)/test_getting_started5.py + +OBJ = classes.o conversions.o extension_class.o functions.o \ + init_function.o module_builder.o \ + objects.o types.o +DEPOBJ= $(OBJ) comprehensive.o abstract.o \ + getting_started1.o getting_started2.o getting_started3.o \ + getting_started4.o getting_started5.o + +.SUFFIXES: .o .cpp + +all: libbpl.a test.so abstract.so \ + getting_started1.so getting_started2.so getting_started3.so \ + getting_started4.so getting_started5.so + +softlinks: + @ for pn in $(SOFTLINKS); \ + do \ + bn=`basename "$$pn"`; \ + if [ ! -e "$$bn" ]; then \ + echo "ln -s $$pn ."; \ + ln -s "$$pn" .; \ + else \ + echo "info: no softlink created (file exists): $$bn"; \ + fi; \ + done + +unlink: + @ for pn in $(SOFTLINKS); \ + do \ + bn=`basename "$$pn"`; \ + if [ -L "$$bn" ]; then \ + echo "rm $$bn"; \ + rm "$$bn"; \ + elif [ -e "$$bn" ]; then \ + echo "info: not a softlink: $$bn"; \ + fi; \ + done + +libbpl.a: $(OBJ) + rm -f libbpl.a + ar r libbpl.a $(OBJ) + +test.so: $(OBJ) comprehensive.o + $(LD) $(LDOPTS) $(OBJ) comprehensive.o -o test.so -lm + +abstract.so: $(OBJ) abstract.o + $(LD) $(LDOPTS) $(OBJ) abstract.o -o abstract.so + +getting_started1.so: $(OBJ) getting_started1.o + $(LD) $(LDOPTS) $(OBJ) getting_started1.o -o getting_started1.so + +getting_started2.so: $(OBJ) getting_started2.o + $(LD) $(LDOPTS) $(OBJ) getting_started2.o -o getting_started2.so + +getting_started3.so: $(OBJ) getting_started3.o + $(LD) $(LDOPTS) $(OBJ) getting_started3.o -o getting_started3.so + +getting_started4.so: $(OBJ) getting_started4.o + $(LD) $(LDOPTS) $(OBJ) getting_started4.o -o getting_started4.so + +getting_started5.so: $(OBJ) getting_started5.o + $(LD) $(LDOPTS) $(OBJ) getting_started5.o -o getting_started5.so + +.cpp.o: + $(CPP) $(CPPOPTS) -c $*.cpp + +test: + $(PYEXE) comprehensive.py + $(PYEXE) test_abstract.py + $(PYEXE) test_getting_started1.py + $(PYEXE) test_getting_started2.py + $(PYEXE) test_getting_started3.py + $(PYEXE) test_getting_started4.py + $(PYEXE) test_getting_started5.py + +clean: + rm -f $(OBJ) libbpl.a libbpl.a.input + rm -f comprehensive.o test.so + rm -f abstract.o abstract.so + rm -f getting_started1.o getting_started1.so + rm -f getting_started2.o getting_started2.so + rm -f getting_started3.o getting_started3.so + rm -f getting_started4.o getting_started4.so + rm -f getting_started5.o getting_started5.so + rm -f so_locations *.pyc + rm -rf cxx_repository + +depend: + @ cat Makefile.nodepend; \ + for obj in $(DEPOBJ); \ + do \ + bn=`echo "$$obj" | cut -d. -f1`; \ + $(CPP) $(CPPOPTS) $(MAKEDEP) "$$bn".cpp; \ + done + diff --git a/build/Makefile.mingw32 b/build/Makefile.mingw32 new file mode 100644 index 00000000..2d86efcd --- /dev/null +++ b/build/Makefile.mingw32 @@ -0,0 +1,210 @@ +# Usage: +# +# Create a new empty directory anywhere (preferably not in the boost tree). +# Copy this Makefile to that new directory and rename it to "Makefile" +# Set the BOOST_* pathnames below. +# +# The idea is that the build directory is on a Unix filesystem that +# is mounted on a PC using SAMBA. Use this makefile under both Unix +# and Windows: +# +# Unix: make softlinks Create softlinks to source code and tests +# Win: make Compile all sources +# Win: make test Run doctest tests +# Unix: make clean Remove all object files +# Unix: make unlink Remove softlinks + +# To install mingw32, follow instructions at: +# http://starship.python.net/crew/kernr/mingw32/Notes.html +# In particular, install: +# ftp://ftp.xraylith.wisc.edu/pub/khan/gnu-win32/mingw32/gcc-2.95.2/gcc-2.95.2-msvcrt.exe +# ftp://ftp.xraylith.wisc.edu/pub/khan/gnu-win32/mingw32/gcc-2.95.2/fixes/quote-fix-msvcrt.exe +# http://starship.python.net/crew/kernr/mingw32/Python-1.5.2-mingw32.zip +# Unpack the first two archives in the default locations and update your PATH. +# Unpack the third archive in \usr. + +# Note: comprehensive.cpp generates compiler errors and later crashes. +# L:\boost\boost\python\detail\extension_class.hpp:643: warning: +# alignment of `vtable for class +# boost::python::detail::held_instance' +# is greater than maximum object file alignment. Using 16. +# Could this be fixed with compiler options? +# -fhuge-objects looks interesting, but requires recompiling the C++ library. +# (what exactly does that mean?) +# -fvtable-thunks eliminates the compiler warning, but "import test" still +# causes a crash. + +BOOST_UNIX= /net/cci/rwgk/boost +BOOST_WIN= "L:\boost" + +PYEXE= "C:\Program files\Python\python.exe" +PYINC= -I"C:\usr\include\python1.5" +PYLIB= "C:\usr\lib\libpython15.a" + +STDOPTS= -ftemplate-depth-21 +WARNOPTS= + +CPP= g++ +CPPOPTS= $(STLPORTINC) $(STLPORTOPTS) -I$(BOOST_WIN) $(PYINC) \ + $(STDOPTS) $(WARNOPTS) -g + +LD= g++ +LDOPTS= -shared + +BPL_SRC = $(BOOST_UNIX)/libs/python/src +BPL_TST = $(BOOST_UNIX)/libs/python/test +BPL_EXA = $(BOOST_UNIX)/libs/python/example +SOFTLINKS = \ +$(BPL_SRC)/classes.cpp \ +$(BPL_SRC)/conversions.cpp \ +$(BPL_SRC)/extension_class.cpp \ +$(BPL_SRC)/functions.cpp \ +$(BPL_SRC)/init_function.cpp \ +$(BPL_SRC)/module_builder.cpp \ +$(BPL_SRC)/objects.cpp \ +$(BPL_SRC)/types.cpp \ +$(BPL_TST)/comprehensive.cpp \ +$(BPL_TST)/comprehensive.hpp \ +$(BPL_TST)/comprehensive.py \ +$(BPL_TST)/doctest.py \ +$(BPL_EXA)/abstract.cpp \ +$(BPL_EXA)/getting_started1.cpp \ +$(BPL_EXA)/getting_started2.cpp \ +$(BPL_EXA)/getting_started3.cpp \ +$(BPL_EXA)/getting_started4.cpp \ +$(BPL_EXA)/getting_started5.cpp \ +$(BPL_EXA)/passing_char.cpp \ +$(BPL_EXA)/test_abstract.py \ +$(BPL_EXA)/test_getting_started1.py \ +$(BPL_EXA)/test_getting_started2.py \ +$(BPL_EXA)/test_getting_started3.py \ +$(BPL_EXA)/test_getting_started4.py \ +$(BPL_EXA)/test_getting_started5.py + +DEFS= \ +test \ +abstract \ +getting_started1 \ +getting_started2 \ +getting_started3 \ +getting_started4 \ +getting_started5 + +OBJ = classes.o conversions.o extension_class.o functions.o \ + init_function.o module_builder.o \ + objects.o types.o + +.SUFFIXES: .o .cpp + +all: libbpl.a test.pyd abstract.pyd \ + getting_started1.pyd getting_started2.pyd getting_started3.pyd \ + getting_started4.pyd getting_started5.pyd + +softlinks: defs + @ for pn in $(SOFTLINKS); \ + do \ + bn=`basename "$$pn"`; \ + if [ ! -e "$$bn" ]; then \ + echo "ln -s $$pn ."; \ + ln -s "$$pn" .; \ + else \ + echo "info: no softlink created (file exists): $$bn"; \ + fi; \ + done + +unlink: rmdefs + @ for pn in $(SOFTLINKS); \ + do \ + bn=`basename "$$pn"`; \ + if [ -L "$$bn" ]; then \ + echo "rm $$bn"; \ + rm "$$bn"; \ + elif [ -e "$$bn" ]; then \ + echo "info: not a softlink: $$bn"; \ + fi; \ + done + +defs: + @ for def in $(DEFS); \ + do \ + echo "EXPORTS\n\tinit$$def" > $$def.def; \ + done + +rmdefs: + @ for def in $(DEFS); \ + do \ + rm $$def.def; \ + done + +libbpl.a: $(OBJ) + del libbpl.a + ar r libbpl.a $(OBJ) + +DLLWRAPOPTS= -s --driver-name g++ -s + --entry _DllMainCRTStartup@12 --target=i386-mingw32 + +test.pyd: $(OBJ) comprehensive.o + dllwrap $(DLLWRAPOPTS) \ + --dllname test.pyd \ + --def test.def \ + $(OBJ) comprehensive.o $(PYLIB) + +abstract.pyd: $(OBJ) abstract.o + dllwrap $(DLLWRAPOPTS) \ + --dllname abstract.pyd \ + --def abstract.def \ + $(OBJ) abstract.o $(PYLIB) + +getting_started1.pyd: $(OBJ) getting_started1.o + dllwrap $(DLLWRAPOPTS) \ + --dllname getting_started1.pyd \ + --def getting_started1.def \ + $(OBJ) getting_started1.o $(PYLIB) + +getting_started2.pyd: $(OBJ) getting_started2.o + dllwrap $(DLLWRAPOPTS) \ + --dllname getting_started2.pyd \ + --def getting_started2.def \ + $(OBJ) getting_started2.o $(PYLIB) + +getting_started3.pyd: $(OBJ) getting_started3.o + dllwrap $(DLLWRAPOPTS) \ + --dllname getting_started3.pyd \ + --def getting_started3.def \ + $(OBJ) getting_started3.o $(PYLIB) + +getting_started4.pyd: $(OBJ) getting_started4.o + dllwrap $(DLLWRAPOPTS) \ + --dllname getting_started4.pyd \ + --def getting_started4.def \ + $(OBJ) getting_started4.o $(PYLIB) + +getting_started5.pyd: $(OBJ) getting_started5.o + dllwrap $(DLLWRAPOPTS) \ + --dllname getting_started5.pyd \ + --def getting_started5.def \ + $(OBJ) getting_started5.o $(PYLIB) + +.cpp.o: + $(CPP) $(CPPOPTS) -c $*.cpp + +test: + $(PYEXE) comprehensive.py + $(PYEXE) test_abstract.py + $(PYEXE) test_getting_started1.py + $(PYEXE) test_getting_started2.py + $(PYEXE) test_getting_started3.py + $(PYEXE) test_getting_started4.py + $(PYEXE) test_getting_started5.py + +clean: + rm -f $(OBJ) libbpl.a libbpl.a.input + rm -f comprehensive.o test.pyd + rm -f abstract.o abstract.pyd + rm -f getting_started1.o getting_started1.pyd + rm -f getting_started2.o getting_started2.pyd + rm -f getting_started3.o getting_started3.pyd + rm -f getting_started4.o getting_started4.pyd + rm -f getting_started5.o getting_started5.pyd + rm -f so_locations *.pyc + rm -rf cxx_repository diff --git a/build/Makefile.tru64_cxx b/build/Makefile.tru64_cxx new file mode 100644 index 00000000..7b932bd3 --- /dev/null +++ b/build/Makefile.tru64_cxx @@ -0,0 +1,170 @@ +# Usage: +# +# Create a new empty directory anywhere (preferably not in the boost tree). +# Copy this Makefile to that new directory and rename it to "Makefile" +# Set the BOOST pathname below. +# +# make softlinks Create softlinks to source code and tests +# make Compile all sources +# make test Run doctest tests +# make clean Remove all object files +# make unlink Remove softlinks + +BOOST= /net/cci/rwgk/boost + +PYEXE= /usr/local/Python-1.5.2/bin/python +PYINC= -I/usr/local/Python-1.5.2/include/python1.5 +#PYEXE= /usr/local/Python-2.0/bin/python +#PYINC= -I/usr/local/Python-2.0/include/python2.0 +#STLPORTINC= -I/usr/local/STLport-4.1b3/stlport +#STLPORTOPTS= \ +# -D__USE_STD_IOSTREAM \ +# -D__STL_NO_SGI_IOSTREAMS \ +# -D__STL_USE_NATIVE_STRING \ +# -D__STL_NO_NEW_C_HEADERS \ +# -D_RWSTD_COMPILE_INSTANTIATE=1 +#STLPORTINC= -I/usr/local/STLport-4.1b4/stlport +#STLPORTOPTS= -D__NO_USE_STD_IOSTREAM -D__STL_NO_SGI_IOSTREAMS +STLPORTINC= -I/net/cci/xp/C++_C_headers + +STDOPTS= -std strict_ansi +WARNOPTS= -msg_disable 186,450,1115 +# use -msg_display_number to obtain integer tags for -msg_disable + +CPP= cxx +CPPOPTS= $(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \ + $(STDOPTS) $(WARNOPTS) -g +MAKEDEP= -Em + +LD= cxx +LDOPTS= -shared -expect_unresolved 'Py*' -expect_unresolved '_Py*' + +#HIDDEN= -hidden + +BPL_SRC = $(BOOST)/libs/python/src +BPL_TST = $(BOOST)/libs/python/test +BPL_EXA = $(BOOST)/libs/python/example +SOFTLINKS = \ +$(BPL_SRC)/classes.cpp \ +$(BPL_SRC)/conversions.cpp \ +$(BPL_SRC)/extension_class.cpp \ +$(BPL_SRC)/functions.cpp \ +$(BPL_SRC)/init_function.cpp \ +$(BPL_SRC)/module_builder.cpp \ +$(BPL_SRC)/objects.cpp \ +$(BPL_SRC)/types.cpp \ +$(BPL_TST)/comprehensive.cpp \ +$(BPL_TST)/comprehensive.hpp \ +$(BPL_TST)/comprehensive.py \ +$(BPL_TST)/doctest.py \ +$(BPL_EXA)/abstract.cpp \ +$(BPL_EXA)/getting_started1.cpp \ +$(BPL_EXA)/getting_started2.cpp \ +$(BPL_EXA)/getting_started3.cpp \ +$(BPL_EXA)/getting_started4.cpp \ +$(BPL_EXA)/getting_started5.cpp \ +$(BPL_EXA)/test_abstract.py \ +$(BPL_EXA)/test_getting_started1.py \ +$(BPL_EXA)/test_getting_started2.py \ +$(BPL_EXA)/test_getting_started3.py \ +$(BPL_EXA)/test_getting_started4.py \ +$(BPL_EXA)/test_getting_started5.py + +OBJ = classes.o conversions.o extension_class.o functions.o \ + init_function.o module_builder.o \ + objects.o types.o +DEPOBJ= $(OBJ) comprehensive.o abstract.o \ + getting_started1.o getting_started2.o getting_started3.o \ + getting_started4.o getting_started5.o + +.SUFFIXES: .o .cpp + +all: libbpl.a test.so abstract.so \ + getting_started1.so getting_started2.so getting_started3.so \ + getting_started4.so getting_started5.so + +softlinks: + @ for pn in $(SOFTLINKS); \ + do \ + bn=`basename "$$pn"`; \ + if [ ! -e "$$bn" ]; then \ + echo "ln -s $$pn ."; \ + ln -s "$$pn" .; \ + else \ + echo "info: no softlink created (file exists): $$bn"; \ + fi; \ + done + +unlink: + @ for pn in $(SOFTLINKS); \ + do \ + bn=`basename "$$pn"`; \ + if [ -L "$$bn" ]; then \ + echo "rm $$bn"; \ + rm "$$bn"; \ + elif [ -e "$$bn" ]; then \ + echo "info: not a softlink: $$bn"; \ + fi; \ + done + +libbpl.a: $(OBJ) + rm -f libbpl.a + cd cxx_repository; \ + ls -1 > ../libbpl.a.input; \ + ar r ../libbpl.a -input ../libbpl.a.input + rm -f libbpl.a.input + ar r libbpl.a $(OBJ) + +test.so: $(OBJ) comprehensive.o + $(LD) $(LDOPTS) $(OBJ) comprehensive.o -o test.so -lm + +abstract.so: $(OBJ) abstract.o + $(LD) $(LDOPTS) $(OBJ) abstract.o -o abstract.so + +getting_started1.so: $(OBJ) getting_started1.o + $(LD) $(LDOPTS) $(OBJ) getting_started1.o -o getting_started1.so + +getting_started2.so: $(OBJ) getting_started2.o + $(LD) $(LDOPTS) $(OBJ) getting_started2.o -o getting_started2.so + +getting_started3.so: $(OBJ) getting_started3.o + $(LD) $(LDOPTS) $(OBJ) getting_started3.o -o getting_started3.so + +getting_started4.so: $(OBJ) getting_started4.o + $(LD) $(LDOPTS) $(OBJ) getting_started4.o -o getting_started4.so + +getting_started5.so: $(OBJ) getting_started5.o + $(LD) $(LDOPTS) $(OBJ) getting_started5.o -o getting_started5.so + +.cpp.o: + $(CPP) $(CPPOPTS) -c $*.cpp + +test: + $(PYEXE) comprehensive.py + $(PYEXE) test_abstract.py + $(PYEXE) test_getting_started1.py + $(PYEXE) test_getting_started2.py + $(PYEXE) test_getting_started3.py + $(PYEXE) test_getting_started4.py + $(PYEXE) test_getting_started5.py + +clean: + rm -f $(OBJ) libbpl.a libbpl.a.input + rm -f comprehensive.o test.so + rm -f abstract.o abstract.so + rm -f getting_started1.o getting_started1.so + rm -f getting_started2.o getting_started2.so + rm -f getting_started3.o getting_started3.so + rm -f getting_started4.o getting_started4.so + rm -f getting_started5.o getting_started5.so + rm -f so_locations *.pyc + rm -rf cxx_repository + +depend: + @ cat Makefile.nodepend; \ + for obj in $(DEPOBJ); \ + do \ + bn=`echo "$$obj" | cut -d. -f1`; \ + $(CPP) $(CPPOPTS) $(MAKEDEP) "$$bn".cpp; \ + done + diff --git a/build/tru64.mak b/build/tru64.mak deleted file mode 100644 index 6631615c..00000000 --- a/build/tru64.mak +++ /dev/null @@ -1,51 +0,0 @@ -# -# Tested with: -# Compaq C++ V6.2-024 for Digital UNIX V5.0 (Rev. 910) -# -# Python 1.5.2 was installed without any customizations. -# boost_all.zip vers. 1.18.1 was unpacked using unzip -aa and not modified. -# STLport-4.1b3 was unpacked using unzip -aa and not modified. -# -# Initial version 2000-10-20: Ralf W. Grosse-Kunstleve, rwgk@cci.lbl.gov -# - -PYINC= /usr/local/include/python1.5 -BOOSTINC= /usr/local/boost_1_18_1 -STLPORTINC= /usr/local/STLport-4.1b3/stlport -STLPORTOPTS= \ - -D__USE_STD_IOSTREAM \ - -D__STL_NO_SGI_IOSTREAMS \ - -D__STL_NO_NEW_C_HEADERS \ - -D_RWSTD_COMPILE_INSTANTIATE=1 - -STDOPTS= -std strict_ansi -WARNOPTS= -msg_disable 186,450,1115 -# use -msg_display_number to obtain integer tags for -msg_disable - -CPP= cxx -CPPOPTS= -I$(STLPORTINC) $(STLPORTOPTS) -I$(BOOSTINC) -I$(PYINC) \ - $(STDOPTS) $(WARNOPTS) - -LD= cxx -LDOPTS= -shared -expect_unresolved '*' - -OBJ = extclass.o functions.o init_function.o module.o newtypes.o \ - objects.o py.o subclass.o - -.SUFFIXES: .o .cpp - -all: demo.so hello.so - -demo.so: $(OBJ) extclass_demo.o - $(LD) $(LDOPTS) $(OBJ) extclass_demo.o -o demo.so - -hello.so: $(OBJ) example1.o - $(LD) $(LDOPTS) $(OBJ) example1.o -o hello.so - -.cpp.o: - -$(CPP) $(CPPOPTS) $(INC) -c $*.cpp - -clean: - rm -f $(OBJ) extclass_demo.o example1.o demo.so hello.so so_locations - rm -rf cxx_repository - rm -f *.pyc From 28e6a84acbf5c2fe893d5ca74b49dc78764588e9 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 4 Mar 2001 15:10:16 +0000 Subject: [PATCH 045/154] Fixed std::complex<> stuff to work with MSVC [SVN r9408] --- include/boost/python/conversions.hpp | 82 +++++++++++++++++++++------- 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/include/boost/python/conversions.hpp b/include/boost/python/conversions.hpp index b633c0ee..47f80989 100644 --- a/include/boost/python/conversions.hpp +++ b/include/boost/python/conversions.hpp @@ -7,7 +7,9 @@ // producing this work. // // Revision History: -// Mar 03 01 added: converters for [plain] char and std::complex (Ralf W. Grosse-Kunstleve) +// 04 Mar 01 Fixed std::complex<> stuff to work with MSVC (David Abrahams) +// 03 Mar 01 added: converters for [plain] char and std::complex +// (Ralf W. Grosse-Kunstleve) #ifndef METHOD_DWA122899_H_ # define METHOD_DWA122899_H_ @@ -19,8 +21,18 @@ # include # include # include + +# ifdef BOOST_MSVC6_OR_EARLIER +# pragma warning(push) +# pragma warning(disable:4275) // disable a bogus warning caused by +# endif + # include +# ifdef BOOST_MSVC6_OR_EARLIER +# pragma warning(pop) +# endif + BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround // This can be instantiated on an enum to provide the to_python/from_python @@ -74,6 +86,30 @@ inline void xdecref(T* p) xdecref_impl(reinterpret_cast(p_base)); } +namespace detail { + + void expect_complex(PyObject*); + + template + std::complex complex_from_python(PyObject* p, boost::python::type) + { + expect_complex(p); + + return std::complex( + static_cast(PyComplex_RealAsDouble(p)), + static_cast(PyComplex_ImagAsDouble(p))); + } + + template + PyObject* complex_to_python(const std::complex& sc) { + Py_complex pcc; + pcc.real = sc.real(); + pcc.imag = sc.imag(); + return PyComplex_FromCComplex(pcc); + } + +} + }} // namespace boost::python BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE @@ -138,30 +174,34 @@ PyObject* to_python(const std::string& s); std::string from_python(PyObject*, boost::python::type); std::string from_python(PyObject*, boost::python::type); -template -PyObject* to_python(const std::complex& sc) { - Py_complex pcc; - pcc.real = sc.real(); - pcc.imag = sc.imag(); - return PyComplex_FromCComplex(pcc); +inline PyObject* to_python(const std::complex& x) +{ + return boost::python::detail::complex_to_python(x); } -template -std::complex from_python(PyObject* p, - boost::python::type&>) { - if (! PyComplex_Check(p)) { - PyErr_SetString(PyExc_TypeError, "expected a complex number"); - throw boost::python::argument_error(); - } - return std::complex( - static_cast(PyComplex_RealAsDouble(p)), - static_cast(PyComplex_ImagAsDouble(p))); +inline PyObject* to_python(const std::complex& x) +{ + return boost::python::detail::complex_to_python(x); } -template -inline std::complex from_python(PyObject* p, - boost::python::type >) { - return from_python(p, boost::python::type&>()); +inline std::complex from_python(PyObject* p, + boost::python::type >) { + return boost::python::detail::complex_from_python(p, boost::python::type()); +} + +inline std::complex from_python(PyObject* p, + boost::python::type&>) { + return boost::python::detail::complex_from_python(p, boost::python::type()); +} + +inline std::complex from_python(PyObject* p, + boost::python::type >) { + return boost::python::detail::complex_from_python(p, boost::python::type()); +} + +inline std::complex from_python(PyObject* p, + boost::python::type&>) { + return boost::python::detail::complex_from_python(p, boost::python::type()); } // For when your C++ function really wants to pass/return a PyObject* From 0b97d9bae58d79e4c834f9e5a809a4fe36116368 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 4 Mar 2001 15:12:30 +0000 Subject: [PATCH 046/154] Some fixes so it will compile with Intel C++ [SVN r9409] --- include/boost/python/detail/config.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/boost/python/detail/config.hpp b/include/boost/python/detail/config.hpp index faf52ee4..3207f7c6 100644 --- a/include/boost/python/detail/config.hpp +++ b/include/boost/python/detail/config.hpp @@ -6,6 +6,9 @@ // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. +// Revision History: +// 04 Mar 01 Some fixes so it will compile with Intel C++ (Dave Abrahams) + #ifndef CONFIG_DWA052200_H_ # define CONFIG_DWA052200_H_ @@ -46,8 +49,9 @@ # endif // The STLport puts all of the standard 'C' library names in std (as far as the -// user is concerned), but without it you need a fix if you're using MSVC. -# if defined(BOOST_MSVC6_OR_EARLIER) && !defined(__STLPORT) +// user is concerned), but without it you need a fix if you're using MSVC or +// Intel C++ +# if defined(BOOST_MSVC_STD_ITERATOR) # define BOOST_CSTD_ # else # define BOOST_CSTD_ std From a40daca9ef899a340608ee22b729a53160bb46b1 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 4 Mar 2001 15:14:04 +0000 Subject: [PATCH 047/154] *** empty log message *** [SVN r9410] --- include/boost/python/detail/wrap_python.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/boost/python/detail/wrap_python.hpp b/include/boost/python/detail/wrap_python.hpp index 9e57c287..d5b75374 100644 --- a/include/boost/python/detail/wrap_python.hpp +++ b/include/boost/python/detail/wrap_python.hpp @@ -16,7 +16,8 @@ // compiler command-line. // Revision History: -// 01 Mar 01 define PyObject_INIT() for Python 1.x +// 04 Mar 01 Rolled in some changes from the Dragon fork (Dave Abrahams) +// 01 Mar 01 define PyObject_INIT() for Python 1.x (Dave Abrahams) #ifdef _DEBUG # ifndef BOOST_DEBUG_PYTHON @@ -64,6 +65,8 @@ typedef int pid_t; # define _MSC_VER 900 # endif +# elif defined(_MSC_VER) +# include // prevents Python.h from defining LONGLONG_MAX, LONGLONG_MIN, and ULONGLONG_MAX # endif #endif // _WIN32 From 71aff9f0e8fce2dda850f08f861dc9fcbbc3f39b Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 4 Mar 2001 15:41:47 +0000 Subject: [PATCH 048/154] Changed library name to libboost_python.a [SVN r9411] --- build/como.mak | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/build/como.mak b/build/como.mak index 5a9920d8..c6f340a5 100644 --- a/build/como.mak +++ b/build/como.mak @@ -1,3 +1,5 @@ +# Revision History: +# 04 Mar 01 Changed library name to libboost_python.a (David Abrahams) LIBSRC = \ classes.cpp \ conversions.cpp \ @@ -30,8 +32,8 @@ endif | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \ [ -s $@ ] || rm -f $@ -example1: example1.o libpycpp.a - como-dyn-link -o ../example/hellomodule.$(MODULE_EXTENSION) $(PYHTON_LIB) example1.o -L. -lpycpp +example1: example1.o libboost_python.a + como-dyn-link -o ../example/hellomodule.$(MODULE_EXTENSION) $(PYHTON_LIB) example1.o -L. -lboost_python python ../example/test_example1.py example1.o: ../example/example1.cpp @@ -40,9 +42,9 @@ example1.o: ../example/example1.cpp clean: rm -rf *.o *.$(MODULE_EXTENSION) *.a *.d *.pyc *.bak a.out -libpycpp.a: $(LIBOBJ) - rm -f libpycpp.a - ar cq libpycpp.a $(LIBOBJ) +libboost_python.a: $(LIBOBJ) + rm -f libboost_python.a + ar cq libboost_python.a $(LIBOBJ) DEP = $(OBJ:.o=.d) From 4aa4f1c3b3b625450c1875548a49731db8bd6f3d Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 4 Mar 2001 15:45:02 +0000 Subject: [PATCH 049/154] Added DebugPython target; cleaned up some mess introduced by others [SVN r9412] --- build/bpl_static.dsp | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/build/bpl_static.dsp b/build/bpl_static.dsp index 701dd309..92af59c7 100644 --- a/build/bpl_static.dsp +++ b/build/bpl_static.dsp @@ -4,7 +4,7 @@ # TARGTYPE "Win32 (x86) Static Library" 0x0104 -CFG=bpl_static - Win32 Debug +CFG=bpl_static - Win32 DebugPython !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE @@ -13,12 +13,13 @@ CFG=bpl_static - Win32 Debug !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f "bpl_static.mak" CFG="bpl_static - Win32 Debug" +!MESSAGE NMAKE /f "bpl_static.mak" CFG="bpl_static - Win32 DebugPython" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "bpl_static - Win32 Release" (based on "Win32 (x86) Static Library") !MESSAGE "bpl_static - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "bpl_static - Win32 DebugPython" (based on "Win32 (x86) Static Library") !MESSAGE # Begin Project @@ -64,7 +65,30 @@ LIB32=link.exe -lib # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W4 /WX /Gm /GR /GX /ZI /Od /I "d:\boost\type_traits" /I "..\..\.." /I "c:\progra~1\python20\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /WX /Gm /GR /GX /Zi /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "bpl_static - Win32 DebugPython" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "bpl_static___Win32_DebugPython" +# PROP BASE Intermediate_Dir "bpl_static___Win32_DebugPython" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugPython" +# PROP Intermediate_Dir "DebugPython" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W4 /WX /Gm /GR /GX /Zi /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /WX /Gm /GR /GX /Zi /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "BOOST_DEBUG_PYTHON" /FR /YX /FD /GZ /EHs /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe @@ -80,6 +104,7 @@ LIB32=link.exe -lib # Name "bpl_static - Win32 Release" # Name "bpl_static - Win32 Debug" +# Name "bpl_static - Win32 DebugPython" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" From 4b926b7c7fa3aaf563745281034ed2405cf8b36b Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 4 Mar 2001 15:48:50 +0000 Subject: [PATCH 050/154] Changed library name to libboost_python.a, various cleanups, attempted Cygwin compatibility. Still needs testing on Linux. [SVN r9413] --- build/gcc.mak | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/build/gcc.mak b/build/gcc.mak index d0b42548..f71185e0 100644 --- a/build/gcc.mak +++ b/build/gcc.mak @@ -1,3 +1,10 @@ +# Revision History + +# 04 Mar 01 Changed library name to libboost_python.a, various cleanups, +# attempted Cygwin compatibility. Still needs testing on Linux +# (David Abrahams) + + LIBSRC = \ classes.cpp \ conversions.cpp \ @@ -11,13 +18,16 @@ LIBSRC = \ LIBOBJ = $(LIBSRC:.cpp=.o) OBJ = $(LIBOBJ) +PYTHON_INC=$(ROOT)/usr/local/include/python2.0 +# libpython2.0.dll ifeq "$(OS)" "Windows_NT" -PYTHON_LIB=c:/tools/python/libs/python15.lib -INC = -Ic:/cygnus/usr/include/g++-3 -Ic:/cygnus/usr/include -Ic:/boost -Ic:/tools/python/include +ROOT=c:/cygnus +INC = -Ic:/cygnus/usr/include/g++-3 -Ic:/cygnus/usr/include -Ic:/boost -I$(PYTHON_INC) MODULE_EXTENSION=dll +PYTHON_LIB=c:/cygnus/usr/local/lib/python2.0/config/libpython2.0.dll.a else -INC = -I/usr/local/include/python1.5 +INC = -I$(PYTHON_INC) MODULE_EXTENSION=so endif @@ -31,20 +41,30 @@ endif [ -s $@ ] || rm -f $@ -example1: example1.o libpycpp.a - g++ -shared -o ../example/hellomodule.$(MODULE_EXTENSION) $(PYHTON_LIB) example1.o -L. -lpycpp - python ../example/test_example1.py +PYTHON = python + +test: comprehensive.o libboost_python.a + g++ $(CXXFLAGS) -shared -o ../test/boost_python_test.$(MODULE_EXTENSION) comprehensive.o -L. -lboost_python $(PYTHON_LIB) + $(PYTHON) ../test/comprehensive.py + +comprehensive.o: ../test/comprehensive.cpp + g++ $(CXXFLAGS) --template-depth-32 -fPIC -Wall -W $(INC) -o $*.o -c $< + + +example1: example1.o libboost_python.a + g++ $(CXXFLAGS) -shared -o ../example/hellomodule.$(MODULE_EXTENSION) example1.o -L. -lboost_python $(PYTHON_LIB) + $(PYTHON) ../example/test_example1.py example1.o: ../example/example1.cpp - g++ -fPIC -Wall -W $(INC) -o $*.o -c $< + g++ $(CXXFLAGS) --template-depth-32 -fPIC -Wall -W $(INC) -o $*.o -c $< clean: rm -rf *.o *.$(MODULE_EXTENSION) *.a *.d *.pyc *.bak a.out -libpycpp.a: $(LIBOBJ) - rm -f libpycpp.a - ar cq libpycpp.a $(LIBOBJ) +libboost_python.a: $(LIBOBJ) + rm -f libboost_python.a + ar cq libboost_python.a $(LIBOBJ) DEP = $(OBJ:.o=.d) From f82151f925a3481ea05dd1b095069d5b5401f3ab Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 4 Mar 2001 15:48:55 +0000 Subject: [PATCH 051/154] no message [SVN r9414] --- build/build.opt | Bin 84480 -> 80384 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/build/build.opt b/build/build.opt index a650cf1f83e6ca05cbe1a0fccd96f89b59f47f31..9cdea95b7eef30bf876fd69fc7e9971cd8f4a6f9 100644 GIT binary patch literal 80384 zcmca`Uhu)fjZzO8(10BSGsD0CoD6J8;!F$-42&?o00YCn|NsAkxG);Tu3%tb_&*AU zObGn_|Np-N0|Nsy0|NsK0|Nsq0|PkD*%=rZI2afhI2jlixEL51xEUbv&C9^Rz{kMA zz|X+IAi%)DAjrVLAjH7HAk4tPAi}`FAPQ9{&cMJR!N9;E$-uxM#lXNI&A`AQ!@$5G z%fP@O$H2fK4^`*Sz`&ryz`&r)z`&rwz`&r&z`&r!z`&r+z`&rvz`&r%z`&pdRjb3m zz@W>(z@W##z@X2-z+k|@z+lM0z+l9{z+lY4z+eJZXU4$5V9vn6V8Ot^V9CJ1V8y_| zV9mh5V8g(`V9UV3V8_6~V9&t7;K0DZ;K;zh-~`p@!oa}b%D}+j#=yYf&cMLn!N9=a z$-uzi#lXPe&A`Cm!@$7c%fP_k2UXw9z`zj5z`zj1z`zj9z`zi~z`zj7z`zj3z`zjB zz`zi}z`zj6z`zj2z`zg<)f3CWz!1m4z!1;Cz>vVez>vtmz>vhiz>v(qz>vbgz>vzo zz>vnkz>vvYfz>vwnz>vkjz>v+rz>vehz>o_yC!c|Vp@4ybp^$-rp@@Njp_qYz zp@e~fp_GAvp^Slnp&Y6X6u(sr3=Gu_3=B043=Fjl3=DM)3=H)Q3=9omx92nDGn6nW zFt{@0F_bVAF;s%GG0|9zffb(Lk;@8f1~eopN*q~ofDyU82xrJ=C}PNFC}t>NNMuN6 zNM%r92xcf@NMtAhhXposki`@jm>5Bs4U|4XG_o8nHmDo}CsuIW7ct~Blrt1Fq=Lf{ zmmXZ=0t`%ypu7XhE5zE*12PPhS-|Nng&~un1RM$=VNx+40}~@Ce}e1=VPf=)ffPaQ zXJlXn=X;it)Z!8iXRDZ`{QTmQn4HX{;+TTUl8pSkn55FooRk=lJebf+DJ}rj0$fQ2 zIq}6Mi6xoInt1dfRKYZ|7L})G8*1Uv16B|NCSjU5QY#X33vyBo4e;oLsfmFxV7fKp z^OLetlS>q|bQIuBO&zR86&EGPWaed-#HW?!C6{F8=jkOE6o8aE`TGZl#Q1nR1;+$L zhIsh<#W;m}`nbe|xCV#BxVSony2FG)3gaQ1c#v$oi=K;*PpyKUktrzXVHiEWW>kah zwX#adk55j_$r&t;HU^cmFgJrUJDkJ7z%c4)>Lm|j15i;S0m^C$x(eZ$dB#QxE~!bS z=>g!J2+DOJtd(pPQ<9&b1J9wLBwLUS$)}J^Yh)0gqL-4B!ytrd7%28cP=te0b5awF zK~)d9er9E0bl`N(&nqd)&(U=TDF@lg!NBOi3lnuJN=*b+N#OP%69Yqos7qo=Vo7B| zs)BE3abiwpdR}g79;iYBt6*hdI3VDdoSa%*tPqx&pOXm6S1^Ow7#I%ldgdtvB&Me- zxE2-VgX%M|HdzLS1Hzs;IjQN1ISQV6#U(|h;2a6l*~7qaK-96QD6vw(DZex?rC7nW zA~`iRB^6YYf=%dUU^pP=mXn`YqTrI6mtT~dn4{odkXn?O2UpU^z;HkWswA^4GbL3a zsZt>-wFp$hg3V9^yCSbFF()%c!6mb}Aip>h+5PtCm&RUgYBQhz;HkiA{AVcn4GQPoROLg5B$jt z3vd2>sxmMfknqdTOU}NFOv*_Ghg$)% zdkA@Y3MgPb^GZ_FQ;QT_u!b8EN~VI+118l7@H05Oq!y&+ zrKIMesNyLAS&)-jmYRc48GBlJie5%R0d9l%lM;(lp_MXzl^l8bd8zo7aF-M%CZ{GP zCTHVw6fdl5FUD`0aB4+KYF=?>eqMZXPGT_u)x7zjf~6$Ch=4ktocz3WNP7gIBe}s= zrV=oWzq}~1ARZE9_&vjul9^mWgtf($#kt^QkI!)&$@zI{nd$hH@FthVmlP#tmJsj( zZ*gv7QAvD3NfCbc^A_i1CZ`hi0DD1YZfY(*mvMsXDMGGF163M?ZQ}y9)KUpJT@ci+ zL$oLHW(U69)RK(+6k=?KMghLe#hsZ~Qj`p;FYpBj2VvXziZj#m5=%;p2qwtnd{8^R zg0PXi#hH2OIjJT2dH5rqBQv)kzo-PC2e=`&5r|VRSfa%nVx=XSIhiGu_}#=+P?-v9 zsTAXL6(^`Q-Ta=oXT9lfXOrVq$f>;_4ZZQ%{ zy!@aPPFzkdO3X_qB8PG%CKZFqX}nR&Sx^b;T&Cg+6CO}GPB`d<@{_tS3>rfOVVGH<@h%XS`!5d~ax`P`bBPC815z`J85l;x zU^EQqod%deT}(Fcus^6r48jpi3=E(w3mVo3Wn&Q50p(NZ)Bs2g2n#baFl>j4gVccV zA1EKx1p%o6VVHR!c^E#yz`!sKT3mqCfbbb61_llA*epyH0|QJQ$XJjX5XNO5NEb*u zNDT<%QwLHDG84;iC#aK!+FqmH0MF?7AM(I5Ekk;U4qA?m|AAW7u-rL1{s$_fM#uj~ z$N%#4K!bar0uwUSGdliqGxpc z4|DQsbo_60{BLxuir!;YqxMlh&2ca=Gx+*=`7kkXhNKpkIF}Zcr7F5uftMO278jHy zo5ds+7lf8%=D=vsa=5La<&L10zX7R5X`od#dC92?MhXG>MJ0qa>w*S3M#ujk>*PU0 z9WXq)l#Y5Mt)t_AqwD_|7#K#^|BbHy8(sgGoH4ro4|#>-==wk0%Q3k}*Z+YQ!Sar- z|3euC8eRW~5*(xJ|FA3x=N(=DhqR1-bp0P}yau$G2-L>~t^EVx(e;1SAIE`(^(Z|W zwxpy1Z2Pan88R927*fFdqCxoW0ZCw3>?2t(w@NQA)ek5cG z4p4oE&?6t7UzA;3keHmRpbp+!pl+pLqEJwj588XJQLHJD1m7~Qkd~Q~TFeuiUs{x$ zssJ*km=CsV8zRRI-v13@bAcUzsfEWQH8CZ%2%;b2FeIfo1PHkjq76c#d2n?9_vrp_ z8XgZYy8nB0|96Q3`cCH2^`E2bKS$Sp20I0f?*GPIi8Q+Z8~tE{(f!|`)--gf>*)S( zq`(;6{|!wQqx-*c&wq{X{{{~&z{YGx_kWL$Cz3LrII4DNr5DFJkaJ%JZ1VC;6hKFU z73JsTq^8($Bty@FWMDu#=@CPj2uvCBk&z4x@Z%bZ)c`pZl33N?5lhhc;pq4u_&6}| za$Q<&S|6fIDZ$kklt3SuAG9lNK}(}Y&wm8P8fa2!bpJOf6h_DYM#uj~$Nxsh|F9mz zIXeC~I{t^}aMjWAztQnO%t?dM@xRgWztQs_N6%Yi7+PahqhpKIkFSJRkUPEPke23Q zxq5;RAq}}xg@eI40J5%+fKDldPWYV`(EBDp>n0gNmk=?4Sg%+?om~*?H<$$)1dza@ z8GIoINEv>u1e`_K0O(v910w@BgL6n?QF>~LXGv-<9{=EVF-Vetn?OpSwxTSIWMtri zgtmK8erW+z1*H5&SpbPg9dk-*0V9J5@>%|%t2`1j^HPgY45X$)!e{^UWR|2BC6?q9 zI6s}Yq_iN1h=Zkx+q*{8G%yF`oHcw0JPVO@tTZtPh7-H#jHt7~!OL|CACApU)Okll z-uA$glUYo}9RtK(4M1G)MKrM}vm_%owInl{s1v@4Ia!>a=u_-@K&z4o2Qx7z1`%LTvu6@IOrA5Duk3Q;5jI90iqxjyV?r#SQ2Vo>Zcuo7i1x z#9zEX%<=Wa9YiRaoS#>gS_HmfgqXWBsJN$$Jvp@ubW%L-o)9tD7Z6@-MeMa5L|=pe zDijE(IKHIPw6xSB!U~DKwT0MgN{G8XhlmsRh(C9Y$O~nNye)wvIkC6|{|y2hpbJ#+ zE0HWIO3W(;oec!dr18ZCsmb{D2tr~DssX=RevlK0QYnJ&68r{>z%MT&%5?tX#9ZRa zAxMJ_nZ!DvOMEdz)NLlC_rD;Hb|k9dM_hYobpQA0{_mtxy!T&Gv92bvtwzrMFW|di zKpoFfJQ@O{Aut*OqaiRF0;3@?VnV=+nUNVZ7GA-q&+tN|9yA0$V*Ebp(a{hX=^+4{ z|C50qzJX=-j|V1+KKF-Lmjp}~?s-2p1_p+gtdn&!6?Bsolpy!KDrBVQddV3nnME4vdV2a01Ue8zT@$VxFMe$H!Lu&;Tu3k}To<_8~ zZkc+lrV_|yFIc6}F5!-W&I+Ygq=E`f$dn~W=^Ivdq)AQ01g03wE_fK=oW2AZGepAz z4+8*D%Tct-3sQga3xGTKVCi4f%wlGt0UN9X@W=l`&bg^teuL9_Gd{9h`T zGA}(`cKoTk-f`I{MKZHj*$;H3~J`x+` zcMvAVgglTU==t-`3^@#m48;t^3}FnJ45iM9Cnkv8_5t!0VnA334QTMu@z*Hg&D|y zuRvE`gHJ9*1PF9g41HPvYpwtlF<4R!NEm0hf+V4KjLr#w#|h9!{CSBy_Kx@y$#{|z zb8?arle6(JE+zF8I%3bABKjaJA~&KCdE_FghpZ8KLL=en1j6T%5pgslKjK_90&9W= z!RaL)d|P=cfnz9%Iq8m=)3XR4aYx)4XGEU1Na`VT#EoDRc_Jj?GeG&15{pygAq%+i zXR*=yUonqzAHDwpTn!)%pc9^w;sl)?N1$9F_9#{^Q0+jd;1EQ;nk%EA0QdOg==eW+ zgpQ8?kB{-g(GVC7fzc2c4S~@R z7YR_m0jD`T2A+U$}2RPq? z&TZY$MgF<1UQCQEpxI1N-j}d#9L@h^#>c3((GVDlApl$dBg24nJ|pN#NVN3@j11i1 znbOo^z2t%dP>F#u#|jk_POT^bt;5OBiwCQQspU;8%}XxH%+G`CMw=3W>PKIg4i$zU z?*!#TCvc!Vv^x+P7&u^ut}-w%GNSo|fdNA~#u1hb$YB905m~`Ie6fTIS*EdomI`4p zjFCYQb?p*%|6wT0fW!x3Z=ml_XJKGq06PXL>LFf*hv5JJ3=DbDlU70Jtb!sQvD^jc zIu($z(e*!xuscIX*Z)8#uF+TPKsF%|y+4--g`?|#Qj<&Y-C8=j{wKK-X|=%U`X7w_ z&7L1y8Z{LcmpjYEK1Hu1+8Aiz2=CB z(}?+sGt=`DOG=AU2`r5u{^n%f;>^7CoYa#1JOa!9AU8qatJL5f1iX1=^!!)o+Hv%5 z7T!=J{vKLlZ(8Oe<^T<1Zs{If|AW$&A?Nc0@1_ov( zMnj*{n3N2;o8o3L$LpAR>r~(P4rPVUCXf#ut|)mSiS_ zsyk?CF*2YHO=Aq~LIV$Nz#2o@==d*aK%K6ehC$=oqx(NW$$79{#A6fPH@vMso&lQW_oqMH!9YO)iTsDN4*NAuwRbTb!F%R1#lMLSXkb zu@}jWj{lC1|67LW}xAcBFxg(06InW2;+mm!rQkD-L27$QtG3A%p>c{G(6jgvr% zp!e^9n3Q5t?Wfc}bp4dr&&9yZ06xeJZYan!I0rO}Uky6F#L6lqKOS_}i3aqj9tABO z1vpbv$Jr_de2!mCPG(Xubirs$aZz#%NOL@F`7dZaFi5GBzkhH@jE|>Na7;jCh=;#l zj8mwmk4sF5Yj8-6i>p(pJ4_g)Fdo8*2g$~}=(+g#)GFv1nIb!K)X}sHX=8&S7}7)3 z(V*#boU5uqlLsKIm24GLlAoW0lFtf~!DpC3v!0Pbe2QL5P7VW(69#dvNS0+_U|?ln zbl?On)h)`;(RBtzKFC%M21W;7n5a`xYGO7_hKYfpLDVI&BoTD3l7eq$abiwpdR}g7 zUI|PED+9v;0mtOz)Z$`=u+03NM9^LUm?Rqm!vS8;JcWS7^i%~`(CI5M8CeE~1Hzs; zIjQN1ISQV6#U(|h;9UeT`5p#_1EP*aMTwOPPWh#IDa8t|70IcoDXA$i6}=1$2gKZR z@)JuGTvGG$i*gfl6#NTPixTtTO8OWW4v0XNWR_*7q$(s;Dnz9g<-^QS1G^%xEHNiD zMZqPrxFEkc6WRU!2m?IxQY#XZOB8}qi%WChzMsIra6lYlgD2D&up5vKnaIF!fDfX^ zzbv&VEhoPmX8$Axh692Sso;{t|_Rp1N;!#(7Y5>o#G4(2RQxm6?{{3 z^NYZ@zJVfAm4V@agkOGMa(-S(W?pGxQcfy3+zOE0L&(!pKmqHSSCX2ZTBP8DHQb0$ zG8L3AV5Xq^dm6}!fTGN@%$(Hp)D&z9;4diDAc2Ce+mw;v0I!RWkAh!*iGmv_b-+T* ziIL%eBuK_HFS8^wF(|;O~ zxEo#nJG%ZCl{7OBUK@H@ve5qv!vjFX$dU|8MmCKkNhg zqw9ZBDsFPt|8j`9c!h)7CZl*X1V%$(Gz3ONU^E0qLtw;&!07pZBPOaxJvtf!7$LyM z02%;9KKE;MDvfqiX+v_-a)?f)At&`AlBSIfM(6)V=l{@WvPS3sM(6+X^FWh(p!GDP z^MCkmPvR~qN=#0L+}4MC_6lh`D&D!6(fuE|cE)gw&i`?UfTm?e@Bd28Lz#paJ^u$j z?aK+e*|4NI1>Y<=UoLow3GDhq++`MLeo|IuZb1${!+48Q(^894^O95XpQto?{txbO d9^L-|?l{5D>=`}(XK=3DAKgze8ZXpH0|0G)Qbqs( literal 84480 zcmca`Uhu)fjZzO8(10BSGsD0CoD6J8;!F$-42&?o00YCn|NsAkxG);TZeU(z@W##z@X2-z+k|@z+lM0z+l9{z+lY4z+l3_z+lS2z+lF}z+le6z+l0^z+lP1 zz+lC|z+lb5z+l6`z+lV3z+eY8&w+t~!I6Q1!HI!^!I^=9!G(c=!Igo5!Ht1|!JUDD z!GnQ;!IOc3!Ha=`!JC1B!H0o?!Iy!7!HA_D_M5(5K6 zG6Mrc3RM4e1_p+71_p)<1_p*q1_p*K1_p*~1_p*41_p*)1_p*a1_p+F1_p)#1_p*g z1_p*A1_p*=1_p)_1_p*ws2Sx93=9-r@+9(2uib{v&|p z81fm)8HyQF!Qn_qFS@({0}~@C?|{llV(sSv83M{I;PjTlkjYR24h4`fshE#}i4l}X zL3V>MG5WaGA%G0wAwVZL=1y&FPCSjU5QY#X33vyBo z4e;0nQxgMYz;x@y=pmt!{QMla?=tg}b4pWEW0G?ci;MGv^fHuUc)2*0koD;4 z#bDP)juwzdD#+28mzJ4MitAD`lS@dqCoMB4l?+`u`HAFMR+^Vgx@DQU1^GoJMO0=U z8IH@$D=A9ONKMWrCD3y+i^;GmCqFNp^l->cEy>7FAwyq&N^xlcsbQF#pHfOr(#WmM zP0Y#3PbMW4b1Msq@=Nkb(L#DKtz%aU{+&LW%-bb1h`R!VpKx|Hz~0=H6B*T5%eWgQ*vT)3BE9fdKIRc zV9G#MpIT9png{YmJh=TtyhUlHdC4WDc|S8Rvm_p-k9eE%^7B%OS6!T$o|jlsT0~SV zLIbThGcP?SwIn}}cxynJgoKzcFG?(khlD&4cEIWlf=L8Ybdiw2A&HL|hm(?Zi&E24 zi&FEF@kUc|ZemeMd_f7`d4 zYCsrf9!w30KEc4iFbz8G08#_OXP6imG{9rCAQcb{QwK5@qy~g>nFrDV(hgDs!uZsI z)Pl^+iy0mN!x#!39sh$RiqY{u(8vuuk3jkhkWK(810JK}e+8rCf1~4nuu^4o{I9qq zW_0{-bo_60{14|4J!G&i20FqxI{p_kI{pXhvy9@=5Eu=C(GVC7fzc44N(gW;Ff;i2 zc=<3faE7E7mpGRem8B}WSj7|U6fOpG9VVHm$^h^#h<0v#>@-roiwhEyQx(*~+o{y8 z6igHfit<6*tu=}@A*Rt^6~taN$C9+In2f#4pxq-msiXV9A^Yw@8@fmz3LoA74GF!` z{onbBCETPZqtWr-(eYpK=^vxxzu?`C@X?mh@n6tv8Mv)8I{u3?Gk`iUIlBKlGbd(r z|2MesKpD6m-Tw{hWR2p{5Eu=C(GVC7fzc2coFS0#3Ua2e1kwu=K#pS9Zo$`2t5ig!-7(CQWJ|)!DE%6LxLGVtXHg{aZ3>EH<$$qBb=s! zlriGf%EloQ9PAXtz{tSO;2e@zl%87RS(2KI$2oW{1W7`TOmQt{rY=>;;e$=5VXvEPxFu;8w$n zGMSG@9m=6+xYhBa4XNT*$%ndy8Mi`iq?6rntKtWpI)-%M5N?&+NSi+Ks6tw$idz*2 zY#}giCA=u@Z`|s5kQajDR>lcGjS;sR9^`W`aVrzTTvLWyF%R*}o{Svn#KGe}~+zQ!~Q_B)_^fGX(0HsQzeZhl#Kn89zIpL$r zxYh6_m8PYo77-3(uEeBbP!Ups≶XgBEaG$pNWX@R`G#hJ2PUZlkzh1yMl(Zbclh z69{oDfz+Ku)QNPi?WkFo5w1CTM{7HHV+g5*L(STbxGIW@l_IEIA-at)THArz!N^fh zxLh2q?I67eq);2YwH*;v&j3`2RITlZ>$Op{PNa4pgxG3`lbBv5aor0dThhce^NDJd z5Z_~@MF~zsKHw#`6GB{-1`0aDg()$80%AK+RPQ?wIYL2H&w;r9EYgh(xZAEoRzQRc zWnu?Ki0TP|QZ3Q_8KQe-M0R|LXt5E|k0q)zLtJr7d`FSs@D|ba6H#3iB6^6#^g)Ol ztRl9aBX;bFxDgAYN8E_66Cu4t2niaZ9mS&|Fd71*Aut*OqaiRF0;3@?8UiGQ02dP@ z3ut1U&crRJ&bu$%olNFR8 z%T*LWc3CSxIr+ub3i-u)$r&k`MH=dQdioFqQlqX3R|Q%e2EVP%S^lCN7(QluWMsRU{qAr>cM@jgfaWLYA}!9@6v6&$)C#e>6l z*cM?zR~MqMq{JH4pk$9FTtLE5W2n7)k}oK=n7H+rNSBl|G6+FdZKfudAXZ&MT}Z^* z6QahW`B3kV#64|5+~6rub6LEgMRM@FG;v!=^hhl6lVe29MG!ODLd+<)5M=Ep@_szr zo+Z58hKTWIA{S(EfmV1xE{MhLAYxY^5-~GEW}DYCr;4Cww=m~7?; z1u)Xh!ni$5%%ndT;{I9O1`(bQC4N;YF;i_s&K?uH_<^|jbbhpB9&rZ;ar2mh;G9KV z0SHQSM9%;dw>q7Od0igj7CRHUR-6NNcQc-VBWj&KPf;SMf&{Gr# zTu6;uEwRfvxWO?DIYJblX~;KD<5oxH+5}KyE=tZw1zkvw+c2WnClIrAn-i2Y3Diu) zHGYV!zKEUtCVHs=52!$gT{w?B)QDJ81DVMtrUgn=$b!mpf|X@{ZUNE}M7W(#OxukJ zFB0E)AT0|LmtBa={Y2GUyeOOfaR(exy#*rLdPFzciEUpJlk?VL33ZSx#sKzPLTY`vg`4H2hB%d{rJ1jR0axPaN9}W z0A}W-LZ?KDt%iuIXGiw|V%^#fUHX9MU<#s(<){Xz=YA)0pn0F0aFh*2D+FR zb(Jh)kuOLbvH%sdAeP|j*_W)7QP%@!q~_%0!P#LSQ!oNHKMN=#t|%_ z5QFL%7K?+48IUHnBSBi;X;zwWu3%MiVz;=g^XJvlLT)BAgbaeCSs{uITKOe5?_asRv{2qOCtW>ptS@DWjFkM3S04#E-2I+rp#j7z}a4D#Z45h#gd+W{-%JE(O&Gb4VFX0OfANYxam39wMq^ zL2OS3xfKdwkFNhkUQ0sEcmc7c5aG(5*bMZ{8$!RR%} zS`^SS4oED4SOgbzU<(6K*bJxD97L7yL=1ZqRqYU8ZWG;%C#FS8T=$!(kRY~+N!;uv zs8K?6Q<nT|`b@5qH%rk;B2njI|Rx`ao>(5i{RJxTiuykAavGWl)!y@JIuZ z!vn+)h!WQoAb!S#+AB7QADt#j=EIP3rUy|lLh#sZ@`(ve9*H;yB#g|J80e*`-P zk(P3atVD@B{gJ392(b%=h-&&1(dZ<)%};D2oS6EUnA*0WvbZF%Bo*I@9Yl2=h-$$T z-$x>{kxq2uo2Vuyv4?(-uK!5IxUHI)HYpJ`Bh{PzME0pj=r9r2lm}IZL^M%}n}s2w z)j@1~pKu$Uq>d6Xt#u+BbHrBpL^kV*Yp#>j79zfdO>D1=H3hLsX}O*r6y$`xBXjOmPz1F(9gZsMi{i0CH~S=A9SX+!LYHSsM!qB|Qz4N4F_utMb) z+vxfa=oBYWwHY>BPC3SlpIb(RYKGt zAo2N@=w=)-Et1jsf0W|_iD_bh?%5;UP9?U}MRcoxaF2n=u__{J8{!)^L^h6zZA}q1 z_)gSdY*J}jT51sy@kHbi1)!$;==?v%xGk}LEn?;y2)9&;nUP2)9Os}e6Jb?Eb`Oai z5F@TBI6D8&&)|%>mlf2?gx1ER^Z$r5nMddU^YC9~LF_ObQC)4~N7x`Em&oMk{6A6_ zCVpAm==?wGG1f%4`H3CpL#vPfGcqzU2{16MkpIffk-)$K>(Y+WqhK@yhJOhB{r~@e z69WT7GXn!d3j+f~D+2>V8v_GFI|Bnl2Ll5`Cj$dR7Xt&szyJUL_b@Op^fE9o^f53n z^fNFpOkiMOn8?7uFo}VIVKM^)!xRPvhN%n;4AY?ML3(B~FfhzwU|^Wdz`!tvfq`Kz z0|Uc61_p-t3=9kl7#J89GB7YKVqjoc4Alb~S{udm3jsz3RtC`U<^TVT4BQOP&N;~jgfQWwnh-8zs1w9aMT`!UF-8kBXLS5mPfuS@Paia7jdUC_ zNyipL2be)d#Dm#bwziFq|BjCT61aYmsJSj;o1Vl?_JYRSh@L7ZYV{~F%Qr^He?@|W zoq|Tke=!C+LFsXH{1+owM#q0g$A7WiX-3?VuhIQq(545{AQ>?W+(yTLN5_AQit%l_ zA!d&z@#EUWtRx^}A;jqTFV>kYA{w2eBDt^kSy38j1HWj)p$kuIl9gu)u45u91M&O zyf9IxqSVA}m<$sGLxZSGVo4&XgQnn{S)7=YnVy%MnpXl-!OFmJK)^9MIkmW0AuKaL zC$S_mKMy9!#=vlZ*E3HcATd2v!L_I;AAJ56$VyoTh6BQ$IXS86i8%_MdBr6~rOC)T zdl(oFh&mP(B~~gp<(KBA6f3w^B&VjPq^7{k?qy&&Am)~npID;clA4!al$)5N;9rnh zl$Zxs(#ODXKm@8Jvn(?uRUxTTAu6>fA7+Lc*cEwYi8+}m3ND$&1^LC9$gb!|7~q+g zT9KGsq7al?T$%&-{R9Sv1L6=HJfX&b-GFS!L?!5+vi9msygTn3Gur zPL2w0iJ3WwlvBr$dqBW9KczG$71M}%hTH?f0Y&-AsVSvJSmZfC?t;a&M`B(|PAbgy z==dMNXx3=9kkWtSNk)ENSKwlD;;L-iHxa>z00y$eIj1xwH73H>)z?2L zQmxw9#KO$X(!xd8#M0GC*U-?}P1niI#7x(~z|qmbz{J_m$knKpfk6jqD#&@TsQdH( z|Noc&|NlS6z`y{)Dl7~PFPIn@ml&K7nd%xEx)|s>x*0lw5{!YfrGcBJ zi>n!d1oMf3fdPa=pn=0Uz<~n_kPQqB43-QG3@{oNI0o>*fdmmWbW&1F5;JpRQY%V8 zVUwR1pPZ9e3|<#bmE;4nJ&75Td>95egh1}$0uc-h3@{qXWl(d*mVBV+9K}HPQIMK) zKnE6q=Gf7T8Ycz@1`rlvVPMz-DvNOKe;+;nBNciQ!07oOIF3jdo&RwPBIZoc(epnF zFxMRue>yQSYfDGhe`B4<9i9KdRlR}oBoW7$j^6(fMAVrj#N^S@`Jd7Gp907!<)i0+ cz}o(!^k@i-ybu_j{~394KI-Gq5P*dM06)EQvH$=8 From bf5eec727e06ee5fbeaa19a2a8ff9870f66c2ff0 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 4 Mar 2001 15:53:00 +0000 Subject: [PATCH 052/154] Added DebugPython target [SVN r9415] --- build/example1/example1.dsp | 39 +++++++++++++++++++++++++++----- build/rwgk1/rwgk1.dsp | 38 +++++++++++++++++++++++++++---- build/test/test.dsp | 45 ++++++++++++++++++++++++++++++++----- 3 files changed, 107 insertions(+), 15 deletions(-) diff --git a/build/example1/example1.dsp b/build/example1/example1.dsp index 78d1f0d8..dcff3f55 100644 --- a/build/example1/example1.dsp +++ b/build/example1/example1.dsp @@ -4,7 +4,7 @@ # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 -CFG=example1 - Win32 Debug +CFG=example1 - Win32 DebugPython !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE @@ -13,12 +13,13 @@ CFG=example1 - Win32 Debug !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f "example1.mak" CFG="example1 - Win32 Debug" +!MESSAGE NMAKE /f "example1.mak" CFG="example1 - Win32 DebugPython" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "example1 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "example1 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "example1 - Win32 DebugPython" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project @@ -68,8 +69,8 @@ LINK32=link.exe # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" @@ -79,7 +80,34 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug/hello.dll" /pdbtype:sept /libpath:"c:\tools\python\libs" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"Debug/hello.dll" /pdbtype:sept /libpath:"c:\tools\python\libs" + +!ELSEIF "$(CFG)" == "example1 - Win32 DebugPython" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "example1___Win32_DebugPython" +# PROP BASE Intermediate_Dir "example1___Win32_DebugPython" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugPython" +# PROP Intermediate_Dir "DebugPython" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /EHs /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"Debug/hello.dll" /pdbtype:sept /libpath:"c:\tools\python\libs" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"DebugPython/hello_d.dll" /pdbtype:sept /libpath:"c:\tools\python\src\PCbuild" !ENDIF @@ -87,6 +115,7 @@ LINK32=link.exe # Name "example1 - Win32 Release" # Name "example1 - Win32 Debug" +# Name "example1 - Win32 DebugPython" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" diff --git a/build/rwgk1/rwgk1.dsp b/build/rwgk1/rwgk1.dsp index 18526979..daf736b3 100644 --- a/build/rwgk1/rwgk1.dsp +++ b/build/rwgk1/rwgk1.dsp @@ -4,7 +4,7 @@ # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 -CFG=rwgk1 - Win32 Debug +CFG=rwgk1 - Win32 DebugPython !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE @@ -13,12 +13,13 @@ CFG=rwgk1 - Win32 Debug !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f "rwgk1.mak" CFG="rwgk1 - Win32 Debug" +!MESSAGE NMAKE /f "rwgk1.mak" CFG="rwgk1 - Win32 DebugPython" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "rwgk1 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "rwgk1 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "rwgk1 - Win32 DebugPython" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project @@ -65,9 +66,10 @@ LINK32=link.exe # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" @@ -77,7 +79,34 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs" + +!ELSEIF "$(CFG)" == "rwgk1 - Win32 DebugPython" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "rwgk1___Win32_DebugPython" +# PROP BASE Intermediate_Dir "rwgk1___Win32_DebugPython" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugPython" +# PROP Intermediate_Dir "DebugPython" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"DebugPython/rwgk1_d.dll" /pdbtype:sept /libpath:"C:\tools\python\src\PCbuild" !ENDIF @@ -85,6 +114,7 @@ LINK32=link.exe # Name "rwgk1 - Win32 Release" # Name "rwgk1 - Win32 Debug" +# Name "rwgk1 - Win32 DebugPython" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" diff --git a/build/test/test.dsp b/build/test/test.dsp index a29d011a..0816bf1e 100644 --- a/build/test/test.dsp +++ b/build/test/test.dsp @@ -4,7 +4,7 @@ # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 -CFG=test - Win32 Debug +CFG=test - Win32 DebugPython !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE @@ -13,12 +13,13 @@ CFG=test - Win32 Debug !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f "test.mak" CFG="test - Win32 Debug" +!MESSAGE NMAKE /f "test.mak" CFG="test - Win32 DebugPython" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "test - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "test - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "test - Win32 DebugPython" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project @@ -44,6 +45,7 @@ RSC=rc.exe # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /c # ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /Zm200 /c +# SUBTRACT CPP /Fr # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -53,7 +55,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /libpath:"c:\tools\python\libs" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/boost_python_test.dll" /libpath:"c:\tools\python\libs" !ELSEIF "$(CFG)" == "test - Win32 Debug" @@ -68,8 +70,9 @@ LINK32=link.exe # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /Zm200 /c +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /Zm200 /c +# SUBTRACT CPP /Fr # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" @@ -79,7 +82,36 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"Debug/boost_python_test.dll" /pdbtype:sept /libpath:"c:\tools\python\libs" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "test - Win32 DebugPython" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "test___Win32_DebugPython" +# PROP BASE Intermediate_Dir "test___Win32_DebugPython" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugPython" +# PROP Intermediate_Dir "DebugPython" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /Zm200 /c +# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /Zm200 /EHs /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs" +# SUBTRACT BASE LINK32 /pdb:none +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /debug /machine:I386 /out:"DebugPython/boost_python_test_d.dll" /pdbtype:sept /libpath:"c:\tools\python\src\PCbuild" # SUBTRACT LINK32 /pdb:none !ENDIF @@ -88,6 +120,7 @@ LINK32=link.exe # Name "test - Win32 Release" # Name "test - Win32 Debug" +# Name "test - Win32 DebugPython" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" From afdaa4d0d848ec7242cf5b5f1d4d8a00e1639e20 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 4 Mar 2001 15:55:35 +0000 Subject: [PATCH 053/154] Rolled in const_cast from Dragon fork [SVN r9416] --- src/classes.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/classes.cpp b/src/classes.cpp index 625d67b7..c609eeef 100644 --- a/src/classes.cpp +++ b/src/classes.cpp @@ -7,8 +7,9 @@ // producing this work. // // Revision History: -// Mar 03 01 added: pickle safety measures (Ralf W. Grosse-Kunstleve) -// Mar 03 01 bug fix: use bound_function::create() (instead of new bound_function) +// 04 Mar 01 Rolled in const_cast from Dragon fork (Dave Abrahams) +// 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) #include #include @@ -881,7 +882,7 @@ namespace { PyObject *globals = PyEval_GetGlobals(); if (globals != NULL) { - PyObject *module_name = PyDict_GetItemString(globals, "__name__"); + PyObject *module_name = PyDict_GetItemString(globals, const_cast("__name__")); if (module_name != NULL) name_space.set_item(module_key, module_name); } From a3f822b7d3b24fa9d179e68bfe7cc93093fe368d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 4 Mar 2001 15:56:07 +0000 Subject: [PATCH 054/154] Documentation for pickle support. [SVN r9417] --- doc/index.html | 2 +- doc/pickle.html | 223 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 doc/pickle.html diff --git a/doc/index.html b/doc/index.html index 9ddd65d3..4550be5c 100644 --- a/doc/index.html +++ b/doc/index.html @@ -116,7 +116,7 @@ among others.
  • Advanced Topics
      -
    1. Pickling +
    2. Pickle Support
    3. class_builder<> diff --git a/doc/pickle.html b/doc/pickle.html new file mode 100644 index 00000000..0e64d6fc --- /dev/null +++ b/doc/pickle.html @@ -0,0 +1,223 @@ + + + BPL Pickle Support + + + +c++boost.gif (8819 bytes) + + +
      +

      BPL Pickle Support

      + +Pickle is a Python module for object serialization, also known +as persistence, marshalling, or flattening. + +

      +It is often necessary to save and restore the contents of an object to +a file. One approach to this problem is to write a pair of functions +that read and write data from a file in a special format. A powerful +alternative approach is to use Python's pickle module. Exploiting +Python's ability for introspection, the pickle module recursively +converts nearly arbitrary Python objects into a stream of bytes that +can be written to a file. + +

      +The Boost Python Library supports the pickle module by emulating the +interface implemented by Jim Fulton's ExtensionClass module that is +included in the ZOPE distribution +(http://www.zope.org/). +This interface is similar to that for regular Python classes as +described in detail in the Python Library Reference for pickle: + +

      + http://www.python.org/doc/current/lib/module-pickle.html +
      + +
      +

      The BPL Pickle Interface

      + +At the user level, the BPL pickle interface involves three special +methods: + +
      +
      +__getinitargs__ +
      + When an instance of a BPL extension class is pickled, the pickler + tests if the instance has a __getinitargs__ method. This method must + return a Python tuple. When the instance is restored by the + unpickler, the contents of this tuple are used as the arguments for + the class constructor. + +

      + If __getinitargs__ is not defined, the class constructor will be + called without arguments. + +

      +

      +__getstate__ + +
      + When an instance of a BPL extension class is pickled, the pickler + tests if the instance has a __getstate__ method. This method should + return a Python object representing the state of the instance. + +

      + If __getstate__ is not defined, the instance's __dict__ is pickled + (if it is not empty). + +

      +

      +__setstate__ + +
      + When an instance of a BPL extension class is restored by the + unpickler, it is first constructed using the result of + __getinitargs__ as arguments (see above). Subsequently the unpickler + tests if the new instance has a __setstate__ method. If so, this + method is called with the result of __getstate__ (a Python object) as + the argument. + +

      + If __setstate__ is not defined, the result of __getstate__ must be + a Python dictionary. The items of this dictionary are added to + the instance's __dict__. +

      + +If both __getstate__ and __setstate__ are defined, the Python object +returned by __getstate__ need not be a dictionary. The __getstate__ and +__setstate__ methods can do what they want. + +
      +

      Pitfalls and Safety Guards

      + +In BPL extension modules with many extension classes, providing +complete pickle support for all classes would be a significant +overhead. In general complete pickle support should only be implemented +for extension classes that will eventually be pickled. However, the +author of a BPL extension module might not anticipate correctly which +classes need support for pickle. Unfortunately, the pickle protocol +described above has two important pitfalls that the end user of a BPL +extension module might not be aware of: + +
      +
      +Pitfall 1: +Both __getinitargs__ and __getstate__ are not defined. + +
      + In this situation the unpickler calls the class constructor without + arguments and then adds the __dict__ that was pickled by default to + that of the new instance. + +

      + However, most C++ classes wrapped with the BPL will have member data + that are not restored correctly by this procedure. To alert the user + to this problem, a safety guard is provided. If both __getinitargs__ + and __getstate__ are not defined, the BPL tests if the class has an + attribute __dict_defines_state__. An exception is raised if this + attribute is not defined: + +

      +    RuntimeError: Incomplete pickle support (__dict_defines_state__ not set)
      +
      + + In the rare cases where this is not the desired behavior, the safety + guard can deliberately be disabled. The corresponding C++ code for + this is, e.g.: + +
      +    class_builder py_your_class(your_module, "your_class");
      +    py_your_class.dict_defines_state();
      +
      + + It is also possible to override the safety guard at the Python level. + E.g.: + +
      +    import your_bpl_module
      +    class your_class(your_bpl_module.your_class):
      +      __dict_defines_state__ = 1
      +
      + +

      +

      +Pitfall 2: +__getstate__ is defined and the instance's __dict__ is not empty. + +
      + The author of a BPL extension class might provide a __getstate__ + method without considering the possibilities that: + +

      +

        +
      • + his class is used as a base class. Most likely the __dict__ of + instances of the derived class needs to be pickled in order to + restore the instances correctly. + +

        +

      • + the user adds items to the instance's __dict__ directly. Again, + the __dict__ of the instance then needs to be pickled. +
      +

      + + To alert the user to this highly unobvious problem, a safety guard is + provided. If __getstate__ is defined and the instance's __dict__ is + not empty, the BPL tests if the class has an attribute + __getstate_manages_dict__. An exception is raised if this attribute + is not defined: + +

      +    RuntimeError: Incomplete pickle support (__getstate_manages_dict__ not set)
      +
      + + To resolve this problem, it should first be established that the + __getstate__ and __setstate__ methods manage the instances's __dict__ + correctly. Note that this can be done both at the C++ and the Python + level. Finally, the safety guard should intentionally be overridden. + E.g. in C++: + +
      +    class_builder py_your_class(your_module, "your_class");
      +    py_your_class.getstate_manages_dict();
      +
      + + In Python: + +
      +    import your_bpl_module
      +    class your_class(your_bpl_module.your_class):
      +      __getstate_manages_dict__ = 1
      +      def __getstate__(self):
      +        # your code here
      +      def __setstate__(self, state):
      +        # your code here
      +
      +
      + +
      +

      Practical Advice

      + +
        +
      • + Avoid using __getstate__ if the instance can also be reconstructed + by way of __getinitargs__. This automatically avoids Pitfall 2. + +

        +

      • + If __getstate__ is required, include the instance's __dict__ in the + Python object that is returned. +
      + +
      +
      +Author: Ralf W. Grosse-Kunstleve, March 2001 +
      + From af6cfd0ea8b5c854e66ecc8540f8c3fb54860e54 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 4 Mar 2001 15:56:38 +0000 Subject: [PATCH 055/154] std::complex<> fixes for MSVC [SVN r9418] --- src/conversions.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/conversions.cpp b/src/conversions.cpp index 369f197a..88e30048 100644 --- a/src/conversions.cpp +++ b/src/conversions.cpp @@ -7,7 +7,8 @@ // producing this work. // // Revision History: -// Mar 03 01 added: converters for [plain] char (Ralf W. Grosse-Kunstleve) +// 04 Mar 01 std::complex<> fixes for MSVC (Dave Abrahams) +// 03 Mar 01 added: converters for [plain] char (Ralf W. Grosse-Kunstleve) #include #include @@ -47,6 +48,19 @@ void handle_exception() } } +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 From f6ba5a41da56aabcd0c337b1bd3fcaf36923d889 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 4 Mar 2001 15:57:47 +0000 Subject: [PATCH 056/154] Use PyObject_INIT() instead of trying to hand-initialize [SVN r9419] --- src/extension_class.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/extension_class.cpp b/src/extension_class.cpp index 47862ec7..f71976b9 100644 --- a/src/extension_class.cpp +++ b/src/extension_class.cpp @@ -7,7 +7,7 @@ // producing this work. // // Revision History: -// Mar 01 01 Use PyObject_INIT() instead of trying to hand-initialize (David Abrahams) +// 04 Mar 01 Use PyObject_INIT() instead of trying to hand-initialize (David Abrahams) #include #include @@ -463,7 +463,9 @@ operator_dispatcher::create(const ref& object, const ref& self) free_list = result->m_free_list_link; result->m_object = object; result->m_self = self; - Py_INCREF(result); + + PyObject* result_as_pyobject = result; + PyObject_INIT(result_as_pyobject, &type_obj); return result; } From 405710e635cce91ce42a0bd82ba4925cc82dc4dc Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 4 Mar 2001 15:59:52 +0000 Subject: [PATCH 057/154] Changed name of extension module so it would work with DebugPython, eliminated useless test that aggravated MSVC [SVN r9420] --- test/comprehensive.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/test/comprehensive.cpp b/test/comprehensive.cpp index 592b0ebd..57edd687 100644 --- a/test/comprehensive.cpp +++ b/test/comprehensive.cpp @@ -5,6 +5,10 @@ // // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. + +// Revision History: +// 04 Mar 01 Changed name of extension module so it would work with DebugPython, +// eliminated useless test that aggravated MSVC (David Abrahams) #include "comprehensive.hpp" #include #include // used for portability on broken compilers @@ -818,7 +822,14 @@ namespace bpl_test { // Test plain char converters. char get_plain_char() { return 'x'; } std::string use_plain_char(char c) { return std::string(3, c); } - std::string use_const_plain_char(const char c) { return std::string(5, c); } + + // This doesn't test anything but the compiler, since it has the same signature as the above. + // Since MSVC is broken and gets the signature wrong, we'll skip it. + std::string use_const_plain_char( +#ifndef BOOST_MSVC6_OR_EARLIER + const +#endif + char c) { return std::string(5, c); } // Test std::complex converters. std::complex dpolar(double rho, double theta) { @@ -1091,18 +1102,18 @@ PyObject* raw(const boost::python::tuple& args, const boost::python::dictionary& void init_module() { - boost::python::module_builder test("test"); - init_module(test); + boost::python::module_builder boost_python_test("boost_python_test"); + init_module(boost_python_test); // Just for giggles, add a raw metaclass. - test.add(new boost::python::meta_class); + boost_python_test.add(new boost::python::meta_class); } extern "C" #ifdef _WIN32 __declspec(dllexport) #endif -void inittest() +void initboost_python_test() { try { bpl_test::init_module(); From 7208104122237e24eafd16f471ebc6eedf289e6b Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 4 Mar 2001 16:02:46 +0000 Subject: [PATCH 058/154] Changed name of extension module so it would work with DebugPython, fixed exception message checking to work with Python 2.0 [SVN r9421] --- test/comprehensive.py | 44 ++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/test/comprehensive.py b/test/comprehensive.py index 3c7f3c61..c8033575 100644 --- a/test/comprehensive.py +++ b/test/comprehensive.py @@ -7,6 +7,15 @@ r''' // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. +// Revision History: +// 04 Mar 01 Changed name of extension module so it would work with DebugPython, +// fixed exception message checking to work with Python 2.0 +// (Dave Abrahams) + +Load up the extension module + + >>> from boost_python_test import * + Automatic checking of the number and type of arguments. Foo's constructor takes a single long parameter. @@ -17,9 +26,9 @@ a single long parameter. >>> try: ext = Foo('foo') ... except TypeError, err: - ... assert re.match( - ... '(illegal argument type for built-in operation)|(an integer is required)', str(err)) - ... else: print 'no exception' + ... assert_integer_expected(err) + ... else: + ... print 'no exception' >>> ext = Foo(1) @@ -209,7 +218,7 @@ Polymorphism also works: Pickling tests: >>> world.__module__ - 'test' + 'boost_python_test' >>> world.__safe_for_unpickling__ 1 >>> world.__reduce__() @@ -697,10 +706,11 @@ Testing interaction between callbacks, base declarations, and overloading >>> c = CallbackTest() >>> c.testCallback(1) 2 - >>> c.testCallback('foo') - Traceback (innermost last): - File "", line 1, in ? - TypeError: illegal argument type for built-in operation + + >>> try: c.testCallback('foo') + ... except TypeError, err: assert_integer_expected(err) + ... else: print 'no exception' + >>> c.callback(1) 2 >>> c.callback('foo') @@ -719,10 +729,11 @@ Testing interaction between callbacks, base declarations, and overloading -1 >>> r.callback('foo') 'foo 1' - >>> r.testCallback('foo') - Traceback (innermost last): - File "", line 1, in ? - TypeError: illegal argument type for built-in operation + + >>> try: r.testCallback('foo') + ... except TypeError, err: assert_integer_expected(err) + ... else: print 'no exception' + >>> r.testCallback(1) -1 >>> testCallback(r, 1) @@ -1145,8 +1156,15 @@ test methodologies for wrapping functions that return a pointer '6.35' ''' +#' + +def assert_integer_expected(err): + """Handle a common error report which appears differently in Python 1.5.x and 2.0""" + assert isinstance(err, TypeError) + message = str(err) + assert (message == "illegal argument type for built-in operation" + or message == "an integer is required") -from test import * import string import re import sys From 03dd2883f71fd8753148a3493ff4a70f909bd4f4 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 4 Mar 2001 17:39:14 +0000 Subject: [PATCH 059/154] file name change: test.so -> boost_python_test.so [SVN r9426] --- build/Makefile.linux_gcc | 8 ++++---- build/Makefile.mingw32 | 16 ++++++++-------- build/Makefile.tru64_cxx | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/build/Makefile.linux_gcc b/build/Makefile.linux_gcc index 3e8f1041..7021e221 100644 --- a/build/Makefile.linux_gcc +++ b/build/Makefile.linux_gcc @@ -79,7 +79,7 @@ DEPOBJ= $(OBJ) comprehensive.o abstract.o \ .SUFFIXES: .o .cpp -all: libbpl.a test.so abstract.so \ +all: libbpl.a boost_python_test.so abstract.so \ getting_started1.so getting_started2.so getting_started3.so \ getting_started4.so getting_started5.so @@ -111,8 +111,8 @@ libbpl.a: $(OBJ) rm -f libbpl.a ar r libbpl.a $(OBJ) -test.so: $(OBJ) comprehensive.o - $(LD) $(LDOPTS) $(OBJ) comprehensive.o -o test.so -lm +boost_python_test.so: $(OBJ) comprehensive.o + $(LD) $(LDOPTS) $(OBJ) comprehensive.o -o boost_python_test.so -lm abstract.so: $(OBJ) abstract.o $(LD) $(LDOPTS) $(OBJ) abstract.o -o abstract.so @@ -146,7 +146,7 @@ test: clean: rm -f $(OBJ) libbpl.a libbpl.a.input - rm -f comprehensive.o test.so + rm -f comprehensive.o boost_python_test.so rm -f abstract.o abstract.so rm -f getting_started1.o getting_started1.so rm -f getting_started2.o getting_started2.so diff --git a/build/Makefile.mingw32 b/build/Makefile.mingw32 index 2d86efcd..7c5f2c52 100644 --- a/build/Makefile.mingw32 +++ b/build/Makefile.mingw32 @@ -31,8 +31,8 @@ # Could this be fixed with compiler options? # -fhuge-objects looks interesting, but requires recompiling the C++ library. # (what exactly does that mean?) -# -fvtable-thunks eliminates the compiler warning, but "import test" still -# causes a crash. +# -fvtable-thunks eliminates the compiler warning, +# but "import boost_python_test" still causes a crash. BOOST_UNIX= /net/cci/rwgk/boost BOOST_WIN= "L:\boost" @@ -82,7 +82,7 @@ $(BPL_EXA)/test_getting_started4.py \ $(BPL_EXA)/test_getting_started5.py DEFS= \ -test \ +boost_python_test \ abstract \ getting_started1 \ getting_started2 \ @@ -96,7 +96,7 @@ OBJ = classes.o conversions.o extension_class.o functions.o \ .SUFFIXES: .o .cpp -all: libbpl.a test.pyd abstract.pyd \ +all: libbpl.a boost_python_test.pyd abstract.pyd \ getting_started1.pyd getting_started2.pyd getting_started3.pyd \ getting_started4.pyd getting_started5.pyd @@ -143,10 +143,10 @@ libbpl.a: $(OBJ) DLLWRAPOPTS= -s --driver-name g++ -s --entry _DllMainCRTStartup@12 --target=i386-mingw32 -test.pyd: $(OBJ) comprehensive.o +boost_python_test.pyd: $(OBJ) comprehensive.o dllwrap $(DLLWRAPOPTS) \ - --dllname test.pyd \ - --def test.def \ + --dllname boost_python_test.pyd \ + --def boost_python_test.def \ $(OBJ) comprehensive.o $(PYLIB) abstract.pyd: $(OBJ) abstract.o @@ -199,7 +199,7 @@ test: clean: rm -f $(OBJ) libbpl.a libbpl.a.input - rm -f comprehensive.o test.pyd + rm -f comprehensive.o boost_python_test.pyd rm -f abstract.o abstract.pyd rm -f getting_started1.o getting_started1.pyd rm -f getting_started2.o getting_started2.pyd diff --git a/build/Makefile.tru64_cxx b/build/Makefile.tru64_cxx index 7b932bd3..2b417944 100644 --- a/build/Makefile.tru64_cxx +++ b/build/Makefile.tru64_cxx @@ -79,7 +79,7 @@ DEPOBJ= $(OBJ) comprehensive.o abstract.o \ .SUFFIXES: .o .cpp -all: libbpl.a test.so abstract.so \ +all: libbpl.a boost_python_test.so abstract.so \ getting_started1.so getting_started2.so getting_started3.so \ getting_started4.so getting_started5.so @@ -115,8 +115,8 @@ libbpl.a: $(OBJ) rm -f libbpl.a.input ar r libbpl.a $(OBJ) -test.so: $(OBJ) comprehensive.o - $(LD) $(LDOPTS) $(OBJ) comprehensive.o -o test.so -lm +boost_python_test.so: $(OBJ) comprehensive.o + $(LD) $(LDOPTS) $(OBJ) comprehensive.o -o boost_python_test.so -lm abstract.so: $(OBJ) abstract.o $(LD) $(LDOPTS) $(OBJ) abstract.o -o abstract.so @@ -150,7 +150,7 @@ test: clean: rm -f $(OBJ) libbpl.a libbpl.a.input - rm -f comprehensive.o test.so + rm -f comprehensive.o boost_python_test.so rm -f abstract.o abstract.so rm -f getting_started1.o getting_started1.so rm -f getting_started2.o getting_started2.so From 5ad51c36fb5bc0d3055977409512e099a0e79a38 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 5 Mar 2001 03:43:10 +0000 Subject: [PATCH 060/154] Turned off "enable minimal rebuild", which causes INTERNAL COMPILER ERRORs [SVN r9437] --- build/bpl_static.dsp | 4 ++-- build/example1/example1.dsp | 4 ++-- build/rwgk1/rwgk1.dsp | 4 ++-- build/test/test.dsp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/bpl_static.dsp b/build/bpl_static.dsp index 92af59c7..ca70236d 100644 --- a/build/bpl_static.dsp +++ b/build/bpl_static.dsp @@ -65,7 +65,7 @@ LIB32=link.exe -lib # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W4 /WX /Gm /GR /GX /Zi /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W4 /WX /Gm- /GR /GX /Zi /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe @@ -88,7 +88,7 @@ LIB32=link.exe -lib # PROP Intermediate_Dir "DebugPython" # PROP Target_Dir "" # ADD BASE CPP /nologo /MDd /W4 /WX /Gm /GR /GX /Zi /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W4 /WX /Gm /GR /GX /Zi /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "BOOST_DEBUG_PYTHON" /FR /YX /FD /GZ /EHs /c +# ADD CPP /nologo /MDd /W4 /WX /Gm- /GR /GX /Zi /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "BOOST_DEBUG_PYTHON" /FR /YX /FD /GZ /EHs /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe diff --git a/build/example1/example1.dsp b/build/example1/example1.dsp index dcff3f55..4d95aa97 100644 --- a/build/example1/example1.dsp +++ b/build/example1/example1.dsp @@ -70,7 +70,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm- /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" @@ -97,7 +97,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /EHs /c +# ADD CPP /nologo /MDd /W3 /Gm- /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /EHs /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" diff --git a/build/rwgk1/rwgk1.dsp b/build/rwgk1/rwgk1.dsp index daf736b3..67476984 100644 --- a/build/rwgk1/rwgk1.dsp +++ b/build/rwgk1/rwgk1.dsp @@ -69,7 +69,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm- /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" @@ -96,7 +96,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm- /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" diff --git a/build/test/test.dsp b/build/test/test.dsp index 0816bf1e..4bd2822a 100644 --- a/build/test/test.dsp +++ b/build/test/test.dsp @@ -71,7 +71,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /Zm200 /c +# ADD CPP /nologo /MDd /W3 /Gm- /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /Zm200 /c # SUBTRACT CPP /Fr # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 @@ -100,7 +100,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /Zm200 /c -# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /Zm200 /EHs /c +# ADD CPP /nologo /MDd /W3 /Gm- /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /Zm200 /EHs /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" From 7d29c6a0f79680e5a0512b396dc4c0691a2a5482 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 5 Mar 2001 03:44:46 +0000 Subject: [PATCH 061/154] tests for null pointer <=> None conversions [SVN r9438] --- test/comprehensive.cpp | 24 +++++++++++++++++++++++- test/comprehensive.py | 15 +++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/test/comprehensive.cpp b/test/comprehensive.cpp index 57edd687..3d173310 100644 --- a/test/comprehensive.cpp +++ b/test/comprehensive.cpp @@ -242,6 +242,23 @@ boost::shared_ptr Baz::create_foo() return boost::shared_ptr(new DerivedFromFoo(0)); } +// Used to check conversion to None +boost::shared_ptr foo_factory(bool create) +{ + return boost::shared_ptr(create ? new DerivedFromFoo(0) : 0); +} + +// Used to check conversion from None +bool foo_ptr_is_null(Foo* p) +{ + return p == 0; +} + +bool foo_shared_ptr_is_null(boost::shared_ptr p) +{ + return p.get() == 0; +} + // We can accept smart pointer parameters int Baz::get_foo_value(boost::shared_ptr foo) { @@ -408,7 +425,7 @@ static int testUpcast(Base* b) static std::auto_ptr derived1Factory(int i) { - return std::auto_ptr(new Derived1(i)); + return std::auto_ptr(i < 0 ? 0 : new Derived1(i)); } static std::auto_ptr derived2Factory(int i) @@ -1081,6 +1098,11 @@ void init_module(boost::python::module_builder& m) m.def(fpolar, "fpolar"); m.def(freal, "freal"); m.def(fimag, "fimag"); + + // Test new null-pointer<->None conversions + m.def(foo_factory, "foo_factory"); + m.def(foo_ptr_is_null, "foo_ptr_is_null"); + m.def(foo_shared_ptr_is_null, "foo_shared_ptr_is_null"); } PyObject* raw(const boost::python::tuple& args, const boost::python::dictionary& keywords) diff --git a/test/comprehensive.py b/test/comprehensive.py index c8033575..c1424d25 100644 --- a/test/comprehensive.py +++ b/test/comprehensive.py @@ -73,6 +73,21 @@ We can subclass Foo. >>> b.call_pure() 'not pure anymore!' +None corresponds to a NULL pointer or smart pointer + >>> f = foo_factory(1) + >>> f.add_len('xxx') + 1000 + >>> foo_factory(0) is None + 1 + >>> foo_ptr_is_null(None) + 1 + >>> foo_ptr_is_null(f) + 0 + >>> foo_shared_ptr_is_null(None) + 1 + >>> foo_shared_ptr_is_null(f) + 0 + If no __init__ function is defined, the one from the base class takes effect, just like in a Python class. From a559a371b1c839e7189afa3aa7c8b8da9890d17e Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 5 Mar 2001 03:48:38 +0000 Subject: [PATCH 062/154] enable null pointer <=> None conversions [SVN r9439] --- .../boost/python/detail/extension_class.hpp | 82 +++++++++++++++---- src/gen_extclass.py | 82 +++++++++++++++---- 2 files changed, 130 insertions(+), 34 deletions(-) diff --git a/include/boost/python/detail/extension_class.hpp b/include/boost/python/detail/extension_class.hpp index bf43ec5c..987d753e 100644 --- a/include/boost/python/detail/extension_class.hpp +++ b/include/boost/python/detail/extension_class.hpp @@ -22,6 +22,7 @@ # include # include # include +# include namespace boost { namespace python { @@ -133,6 +134,26 @@ class class_registry static std::vector static_derived_class_info; }; +template +struct is_null_helper +{ + template + static bool test(Ptr x) { return x == 0; } +}; + +template <> +struct is_null_helper +{ + template + static bool test(const Ptr& x) { return x.get() == 0; } +}; + +template +bool is_null(const Ptr& x) +{ + return is_null_helper<(is_pointer::value)>::test(x); +}; + }}} // namespace boost::python::detail BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE @@ -178,9 +199,9 @@ class python_extension_class_converters new boost::python::detail::instance_value_holder(result.get(), x))); return result.release(); } - - // Convert to T* - friend T* from_python(PyObject* obj, boost::python::type) + + friend + T* non_null_from_python(PyObject* obj, boost::python::type) { // downcast to an extension_instance, then find the actual T boost::python::detail::extension_instance* self = boost::python::detail::get_extension_instance(obj); @@ -201,9 +222,18 @@ class python_extension_class_converters throw boost::python::argument_error(); } - // Convert to PtrType, where PtrType can be dereferenced to obtain a T. + // Convert to T* + friend T* from_python(PyObject* obj, boost::python::type) + { + if (obj == Py_None) + return 0; + else + return non_null_from_python(obj, boost::python::type()); + } + + // Extract from obj a mutable reference to the PtrType object which is holding a T. template - static PtrType& ptr_from_python(PyObject* obj, boost::python::type) + static PtrType& smart_ptr_reference(PyObject* obj, boost::python::type) { // downcast to an extension_instance, then find the actual T boost::python::detail::extension_instance* self = boost::python::detail::get_extension_instance(obj); @@ -220,9 +250,27 @@ class python_extension_class_converters throw boost::python::argument_error(); } + // Extract from obj a constant reference to the PtrType object which is holding a T. + // If obj is None, the reference denotes a default-constructed PtrType template - static PyObject* ptr_to_python(PtrType x) + static const PtrType& smart_ptr_value(PyObject* obj, boost::python::type) { + if (obj == Py_None) + { + static PtrType null_ptr; + return null_ptr; + } + return smart_ptr_reference(obj, boost::python::type()); + } + + template + static PyObject* smart_ptr_to_python(PtrType x) + { + if (boost::python::detail::is_null(x)) + { + return boost::python::detail::none(); + } + boost::python::reference result(create_instance()); result->add_implementation( std::auto_ptr( @@ -254,7 +302,7 @@ class python_extension_class_converters // Convert to T& friend T& from_python(PyObject* p, boost::python::type) - { return *boost::python::detail::check_non_null(from_python(p, boost::python::type())); } + { return *boost::python::detail::check_non_null(non_null_from_python(p, boost::python::type())); } // Convert to const T& friend const T& from_python(PyObject* p, boost::python::type) @@ -265,28 +313,28 @@ class python_extension_class_converters { return from_python(p, boost::python::type()); } friend std::auto_ptr& from_python(PyObject* p, boost::python::type&>) - { return ptr_from_python(p, boost::python::type >()); } + { return smart_ptr_reference(p, boost::python::type >()); } - friend std::auto_ptr& from_python(PyObject* p, boost::python::type >) - { return ptr_from_python(p, boost::python::type >()); } + friend const std::auto_ptr& from_python(PyObject* p, boost::python::type >) + { return smart_ptr_value(p, boost::python::type >()); } friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&>) - { return ptr_from_python(p, boost::python::type >()); } + { return smart_ptr_value(p, boost::python::type >()); } friend PyObject* to_python(std::auto_ptr x) - { return ptr_to_python(x); } + { return smart_ptr_to_python(x); } friend boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) - { return ptr_from_python(p, boost::python::type >()); } + { return smart_ptr_reference(p, boost::python::type >()); } - friend boost::shared_ptr& from_python(PyObject* p, boost::python::type >) - { return ptr_from_python(p, boost::python::type >()); } + friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type >) + { return smart_ptr_value(p, boost::python::type >()); } friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) - { return ptr_from_python(p, boost::python::type >()); } + { return smart_ptr_value(p, boost::python::type >()); } friend PyObject* to_python(boost::shared_ptr x) - { return ptr_to_python(x); } + { return smart_ptr_to_python(x); } }; // Convert T to_python, instantiated on demand and only if there isn't a diff --git a/src/gen_extclass.py b/src/gen_extclass.py index 7c378d45..2d261289 100644 --- a/src/gen_extclass.py +++ b/src/gen_extclass.py @@ -27,6 +27,7 @@ def gen_extclass(args): # include # include # include +# include namespace boost { namespace python { @@ -138,6 +139,26 @@ class class_registry static std::vector static_derived_class_info; }; +template +struct is_null_helper +{ + template + static bool test(Ptr x) { return x == 0; } +}; + +template <> +struct is_null_helper +{ + template + static bool test(const Ptr& x) { return x.get() == 0; } +}; + +template +bool is_null(const Ptr& x) +{ + return is_null_helper<(is_pointer::value)>::test(x); +}; + }}} // namespace boost::python::detail BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE @@ -183,9 +204,9 @@ class python_extension_class_converters new boost::python::detail::instance_value_holder(result.get(), x))); return result.release(); } - - // Convert to T* - friend T* from_python(PyObject* obj, boost::python::type) + + friend + T* non_null_from_python(PyObject* obj, boost::python::type) { // downcast to an extension_instance, then find the actual T boost::python::detail::extension_instance* self = boost::python::detail::get_extension_instance(obj); @@ -206,9 +227,18 @@ class python_extension_class_converters throw boost::python::argument_error(); } - // Convert to PtrType, where PtrType can be dereferenced to obtain a T. + // Convert to T* + friend T* from_python(PyObject* obj, boost::python::type) + { + if (obj == Py_None) + return 0; + else + return non_null_from_python(obj, boost::python::type()); + } + + // Extract from obj a mutable reference to the PtrType object which is holding a T. template - static PtrType& ptr_from_python(PyObject* obj, boost::python::type) + static PtrType& smart_ptr_reference(PyObject* obj, boost::python::type) { // downcast to an extension_instance, then find the actual T boost::python::detail::extension_instance* self = boost::python::detail::get_extension_instance(obj); @@ -225,9 +255,27 @@ class python_extension_class_converters throw boost::python::argument_error(); } + // Extract from obj a constant reference to the PtrType object which is holding a T. + // If obj is None, the reference denotes a default-constructed PtrType template - static PyObject* ptr_to_python(PtrType x) + static const PtrType& smart_ptr_value(PyObject* obj, boost::python::type) { + if (obj == Py_None) + { + static PtrType null_ptr; + return null_ptr; + } + return smart_ptr_reference(obj, boost::python::type()); + } + + template + static PyObject* smart_ptr_to_python(PtrType x) + { + if (boost::python::detail::is_null(x)) + { + return boost::python::detail::none(); + } + boost::python::reference result(create_instance()); result->add_implementation( std::auto_ptr( @@ -259,7 +307,7 @@ class python_extension_class_converters // Convert to T& friend T& from_python(PyObject* p, boost::python::type) - { return *boost::python::detail::check_non_null(from_python(p, boost::python::type())); } + { return *boost::python::detail::check_non_null(non_null_from_python(p, boost::python::type())); } // Convert to const T& friend const T& from_python(PyObject* p, boost::python::type) @@ -270,28 +318,28 @@ class python_extension_class_converters { return from_python(p, boost::python::type()); } friend std::auto_ptr& from_python(PyObject* p, boost::python::type&>) - { return ptr_from_python(p, boost::python::type >()); } + { return smart_ptr_reference(p, boost::python::type >()); } - friend std::auto_ptr& from_python(PyObject* p, boost::python::type >) - { return ptr_from_python(p, boost::python::type >()); } + friend const std::auto_ptr& from_python(PyObject* p, boost::python::type >) + { return smart_ptr_value(p, boost::python::type >()); } friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&>) - { return ptr_from_python(p, boost::python::type >()); } + { return smart_ptr_value(p, boost::python::type >()); } friend PyObject* to_python(std::auto_ptr x) - { return ptr_to_python(x); } + { return smart_ptr_to_python(x); } friend boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) - { return ptr_from_python(p, boost::python::type >()); } + { return smart_ptr_reference(p, boost::python::type >()); } - friend boost::shared_ptr& from_python(PyObject* p, boost::python::type >) - { return ptr_from_python(p, boost::python::type >()); } + friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type >) + { return smart_ptr_value(p, boost::python::type >()); } friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) - { return ptr_from_python(p, boost::python::type >()); } + { return smart_ptr_value(p, boost::python::type >()); } friend PyObject* to_python(boost::shared_ptr x) - { return ptr_to_python(x); } + { return smart_ptr_to_python(x); } }; // Convert T to_python, instantiated on demand and only if there isn't a From 1edec9ff89141b4624e8824f7b806369d70c8fe1 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 5 Mar 2001 14:41:57 +0000 Subject: [PATCH 063/154] no message [SVN r9443] --- build/build.opt | Bin 80384 -> 86528 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/build/build.opt b/build/build.opt index 9cdea95b7eef30bf876fd69fc7e9971cd8f4a6f9..5086795feff7997de1d0b50d82b2404da330c819 100644 GIT binary patch literal 86528 zcmca`Uhu)fjZzO8(10BSGsD0CoD6J8;!F$-42&?o00YCn|NsAkxG);Tu3%tb_&*AU zObGn_|Np-N0|Nsy0|NsK0|Nsq0|PkD*%=rZI2afhI2jlixEL51xEUbv&C9^Rz{kMA zz|X+IAi%)DAjrVLAjH7HAk4tPAi}`FAPQ9{&cMJR!N9;E$-uxM#lXNI&A`AQ!@$5G z%fP@O$H2fK4^`*Sz`&ryz`&r)z`&rwz`&r&z`&r!z`&r+z`&rvz`&r%z`&pdRjb3m zz@W>(z@W##z@X2-z+k|@z+lM0z+l9{z+lY4z+eJZXU4$5V9vn6V8Ot^V9CJ1V8y_| zV9mh5V8g(`V9UV3V8_6~V9&t7;K0DZ;K;zh-~`p@!oa}b%D}+j#=yYf&cMLn!N9=a z$-uzi#lXPe&A`Cm!@$7c%fP_k2UXw9z`zj5z`zj1z`zj9z`zi~z`zj7z`zj3z`zjB zz`zi}z`zj6z`zj2z`zg<)f3CWz!1m4z!1;Cz>vVez>vtmz>vhiz>v(qz>vbgz>vzo zz>vnkz>vvYfz>vwnz>vkjz>v+rz>vehz>o_yC!c|Vp@4ybp^$-rp@@Njp_qYz zp@e~fp_GAvp^Slnp&Y6X6u(sr3=Gu_3=B043=Fjl3=DM)3=H)Q3=9omx92nDGn6nW zFt{@0F_bVAF;s%GG0|9zffb(Lk;@8f1}MDhZ&P1-fDyU82xrJ=C}PNFC}t>NNMuN6 zNM%r92xcf@NMtAhhXposki`@jm>5Bs4U|4XG_o8nHmDo}CsuIW7ct~Blrt1Fq=Lf{ zmmXZ=0t`%ypu7XhE5zE*12PPhS-|Nng&~un1RM$=VNx+40}~@Ce}e1=VPf=)ffPaQ zXJlXn=X;it)Z!8iXRDZ`{QTmQn4HX{;+TTUl8pSkn55FooRk=lJebf+DJ}rj0$fQ2 zIq}6Mi6xoInt1dfRKYZ|7L})G8*1Uv16B|NCSjU5QY#X33vyBo4e;oLsfmFxV7fu& z8Z(0=0}}&N5vYa&;cJWx41A0X3}#FW4BJ2<0>z+E1YuJq28NxCkdl#+fuR8;whOAB zxq&k%H9fPqB(QB7&j>2DL2QtZKw${NfBygf|MLI; z{~$RK-p|CqFbx#e4V>ZmMcKs#iOH#EoS;BrW?*GtWDqC@nFxwCSh${rhAqfsQ2zV( z|9?HmKe;G1H4l`#K_-B_%Ul8~lR+`52(2SQW`Qu+MGd@Q+ZB8> z^D>=@z$s+&Q9&Cc-u zKV#`xGyt+0gdw(b1f>?|mlh?bLNtN0+W-H|1T?X^WG3e1r^|!Gor!^&;s1XYtXg1h z1(){F5G#d;7>9FyUP)1YPBAFBKn)*|L9C?)po9pjl0k(6)YC`~b}vdS$jD4C7G(sr zmRP{Hvw<~%6jd=XFnBRS>VFU)2*TY)lv<14B6z z1H)-XNRtBHm?I1f3{BAH26F>vNNPoiLP&mojyMa*L68vSD4hg#xdsyh!wG0cftkeI zz~Y*cSpo}kCQ$8-HT)17SY1++O4H52Ar5NM{r}HUwulkZ=4)kww2eTjVIdAmqqYnT z4O1Bz7$(C*oXx2yzq~jV)c67=PmsloWoYT+EXWuT1_d2+18ZPuYEdPqsR+^`3(CLc z_;m=lB$gy5B^IYDxMU`#7bWH*Yi1;%nKdLaDJKp3*%;gr0kVa)E zBczcB@(~C_e8m!$nOcr)3k#^R29kqgkYW%92{1SC1%q>m0yN3OLJ(Xq5^x|}P-=31 zQ3}j935Ngw69{PG49~1eEJ|@oEHZ+|I1j`B{~hHMnHU&AF*<>nf#EAOfg#8Epa1{s zGng0{BAFni(t|hsjQ{^LGH@_ByW}Tlhv%g*GRUwnH2nJizaA9%utF8mhm-=f%E5Ik z0|RT3BttQ%RR?OMf`Wj7f#JoR4o2k$CQ$#g;V0CDzu+<-s(_&a)E}*fmk1H+6W1_q^K28OA{3=Fy@3=9S(3=D=P3=E|u3=ES>7#P-;Ffgny zVPM!^!oYB^gn@yjl!1Z0l!1Yxlz}0vl!2kDl!0MFDFefiQU-=&r3?(`N*Ng5mNGDW zC}m*ySjxcQSjNE6TE@U|v5bL1qMU&trksIcWjO=GnQ{h(kL3&uIu#5IdKC-|W)%z! zu@wvqy%h`$eH9E02P+sDu2nEFysKbf(5Pf!aI9otNUmgHSW?NraIlhr;cX=YgJ~55 zLs%69Lr)b0!)<5>&7qosVOliIMdeoec~OyFeYgMg|70Mg|7$Mg|7cMg|7Y zMg|6-Mg|7oMh1r2jSLL88yOgsniv?on-~~6niv?mniv=+H!(2mYhqw{+{D1}q=|t+ zvYCNFu9<-$rI~@DznOtyW-|lBnq~%u_00?n8=4syZZ|V9+-+uHc-G9oAkxCXpx?s4 zVA8_CP}{=5P}jo1u)BqU;dKiGgJ3HIgLEqcgMBLlgHtO5gL5kbgIg;DLv||zLtZNb zLw+j*Lw73!!T43AqG7zElF7=+pw7=+sx81&m17&6)z7&_Y+7`odS7oeT`$I~f>QyBHYQyBHWax)>N#x)>Pzx)>M& zx)>PhyBHW6yBHXnx)>Oyb}=yA>0)5G*Tujf-Oa$@*v-HY*Ui9?(9OV**v-ID(#^oI zx0``se>VdIQx5}!Mh^o+a1R4RK@S5%Q4a${aSsDSTMq-nnH~m)b3F_U-+LGse)cdh z{OVy~;O%8#i0oxxi0)-zXzyiU=Q+;FgpJCe{}qBbo_60{BLypZ*=@` zbo>w6JQ$@0Q3(8pj{k8eq_f;e0CoEZk>f_4G8zJ-Awbg*;9y{8@b&TXVPfD6Ni8mM zE-flcRdlh6DK1KmNh~fXOEv>hp(U9)Fj_CUpkOO#xg%)hZ$N5MT7FS(VqS8pf{{W% zeo+Zw&AOn45+F|{_?fbS)*1gu&}DnhzyO+=XZXAaJR->elLM&(VbH+dS3GjR@yPu{ zlLOf&zzDIAWiP6IAUQ#(92*unA*dWT7P%KtKM0`7f!q(mAU}xWk(0t92O4dWMUw-$ zlNIU~Y;wX-IVCLmM4*cZRj|mh;gMs9nu)Ftu$Z6w|)4?NW zh(it(W+rHIpfKZr`T?69%$??F`at3!4Dy5M`=8~YC4e_rY{6+4Bo4wLIcYp{N;u>| zdX@3Wf#gT=Xb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S0iBLx1lLe~FPFzPdmj{i|3 zL`TgS4S}H(0@(Inhcjd{ecgC|2CLmC5UuRBN|Hmm{N{|&Mmgt4hX7t;m_K=(g; zG6XPqGQ=|^F%*DpEQanq&jjzt2PwplwAhj4-g2OE{Cl#Sb9=>^3K^?qnT-{2+M4_N4KPxr4M59HEaR{JT3Q+?g(R{-&I{wQ5 zABP8xosN$GGBAve{}L{fMpcZ4z-S1JhQMeDjE2By2#kinXb6mkz-R~z&JY+K{~et1 zGU}?)5THj0IL?6_9426smtUfg3^^1nCpE=RBpJ(DkPMKqLShv|PI@F(HT;N23=JGG zw=gguojM5`KO7zZ1D&ahwq6l5RyVr-lYs%-8qd-7pY$kIM(r34fzc2c4S~@R7!85Z z5Eu=C(GVC7fzc2cj3F>O{x=w7Wzu z0~aK;-HY-|3!o}kIYeB%!ci7L;!($(l3KvXAj076l3I|Omy(*7T z=jNxB=A`0N#g&|&mzJ51-%1Y1NB@t>!6L$*dNy$tmB7iwEa|`l|O7L06lbfGXTv|X#8GB}O zD*mLwnM~OC{H1xB$@wWnWMPhiNQPIs?l$e)Jgw1@psU;ctDTF=4 zm6%jqQk0mCH+Z>0DpHdY2_)U*{JgT%qTDAW0i6LX0xhae3$WD?Zg8^xm`Fd71*Auv!OFgpG>P$55R?`Q}Nd{0*PL6oYAjhXFWPL5d(VpCFICVTIhV4q^{s zUqhk}3v$^DRt@wt2|6e}z}cxZGbaU_KI2nhDfA61 zH#oW>xd`M*M94sAK+&g{ab_A&fq)}5fu!&TG)Mu|K59=a^97|ALvE)BP3sopnSw^z zxx>gH1ewrIO)f!9NJCvn%^7IOXe-esLX<D&7#J9M85kIdwLb=Ayb6dw*bm{6PI56Yf$as^4Z_5j zkOxu(J%8SrA%`K6p_rkVA&eoDA(f$=L4kq9^Y=-%zY@uQ*!+(qf!SpEQDuq$2&+JL(d<{s*?_6KR}!bpID<6D(4IjPCzJ z3y{(MUzJG7V|4!)V%BeT{}+4$baek0sGTy3M?+vV1cqV=jL!cI#aJ74^JoZACj>_4 zf2b3Vqo$08z)%bU*!aH$Xy6-l3>&g)odYC+KKhSSwFpQx+!&;>f5ryTEy18cRKyrD z!2xo_h&yBexd(MlASpk;xFjC3HzXcpF^Tg7pmT(ZQZrKXiZjbntrbwXh|zx?1$ABB zq@w)n)I8n9(vp1Lf|4T4jUGZE`{5o3&jElu3-LC{^+b3UGV%^m{E~Ihc@+|EAU`2S z!Eq)7kTQtZL9ADx%b^(tp}#;*dc(@Arw@)VNO}i}QF~edYpwv57FbdZNEm0hf+R=h z1dtCCL?7|zCGyxi;!h;w0iDAHImip&fk&jCLPzYmQ$!zRMdHClM4nqmR02-qFE2_gfHs-%JCFE*Z6eR4B<^rlBF?}h_ViF< zXKaW)p^)%iCr;3zbOd66*fUzNS%AtRJ#hK}Oi6x~)1d}g>myZBDIB$IJ>rEG4e$CI0M8Vo!%9 zYSSk%CkqpK3MXlYOT&(q#+PG>If0m*U3*kKla}~HJ&9bs!c&w8s<%Ps+~Nxw>sO)G64A&5Vt^bi>KsuihbR{I(o=u0 z2g;-=R19MV3@VN^g9a5ro4J6Bq7U*yh2bOXP(E~?1t7Jo1>U?|5p z!jb_wEI`YaSiw7dsbv}qXsHkb10y3w5DS8)E#NDX^sxJnkpWFv1|&WRdjoxcItv2> z1K2T0Q4jGdJOuy$XJCMwX*;_9CkERwub`ZOSP%tWn}fbBcy#>_-R>M6UH?Pm#bu-G ze-Qf_QK~Y$7uJrh|A7{9qw9a5MH)HBuOkuK$5%u+jBDm>Fzz z{ZBITkp!dbe{kI^Kf3-0GxK0y{{z|oo5}{8|0Dg@-qH0x!*y(E)L+9t1R5C_7@8Ou z824}E=n&@U_-}l1 zNn%N6GH5gz8d{^{zeObq1G|M6wAXWV|0iU{Gsg4*7vzdA_oDpL0%)HUq7tcO7AWPtK3HSe=^`4LMcwnO(kw?Z%Srz3E|CPqx(O>7o&~t z|3odGNB4hXIh=WP|0hOKjlMJp@7&tx`0wcWZ*Z_v(CGe8(5TEP9t{CpA>hK0%8XgnM3bQVhmc1{ ziP1OSEo>Sm@r6TJcJVul8txKbMf)1RnRjsMRqkP2$1=sj;3Bn8yg^p z><|g*A?#?-904fA(L;KFby`t=F7)swo=(I>so*Vqhb02x03`$MTFG?BQ@wb;uuO;TC z5ArhQ2zfs9FH0@T$xloHrOd${b!2)FIqMB>5AG%}2Ho=W2e-fevoKbJ+ZBk`2&91# zkJhq?ha4YTl3G-Z)Kqaa)Iqdc9KqcUP*G}UWmTM;SX2^UP*N0Mk`HSE6_=z~S%FUE z28pAXGO#Tjb3=SBo&VgF1(A^sS^z_uZdO(qsW~a}nR&$}iFwJX$iZP`r+^~__4M=x zv`t7Lq$o>FPRNPLiQL5GWH_i36F)_X3DiCzH93Lw4AlfhS=MvQ&qper-175b^$m{P z1|3DYpX5axK zTwVG9LIa<623>%G0t@G@4j@So)=IXDDap^zK^Z?SNCqD^4;@l9GKf#nOUcP$kY!+C zU}a!*-~?TOP?Vpe>kMmja4;}B@WMo$ic%A^VKPh%3=N_#i6x1k5h4ZO%;LnH%=En6 z)Vvay3RVV&0|Ji8$*IM~3SpV~IpEV%VUlbN3j)H$dYEfbyTuC1T!vPVflFYKqlvIVJN`O!v-b>h5(Q|L4F#=qalDL1V+#Q!xAW?LZcxtLPB8l{J#+r(WBlR4FN16P|w^r zdj2Pta2XXE4S~@R7!85Z5Eu=C;T!^N42%q%3>BuTBNlnht($q+TFFXXVR?xJ=vT|6#pu)hw z!rUY^(FC!G*oXnN8XRK33xtA`YB-k{!|pyT2A!6xR&C_yYGm$c?5t~O?q;fMXy{^~ z>*!|aq-$W{Xy9yV;AZLKYF5j@09|~}02&+vEwcpSKmY&#fBFCae~=sq-)CfC*u}`e zz&^m?a+869;WacQU^JA=fCv}xWFvHvAO^A|AOZGgiCUwYAkrx$GDf=DwN1qD!wzP=x%uCKGO-YUM zb@lZRill0oTw;RcBbEUU6Oi9QafD2R*dVNoEliw)LSjI}^nR}4dd>j>R4H6Q83=^` zK?8+(fCFU-BLl-$P$|fOpg{ow!V1_k5oi+#Ct z7(|e0ko!Pb8y+IayIerWxyN9f+)kC`0;-2V_yRKngEkLV)D`Tzj?)(`FZilIf=!^*w@=TB^E=@|1GhCo&ReE z={w?HPCmN+7u4RfvKn3gi!WV`uKy*jkQ!b8TZFa;$SIKuX=il(Z+>10XjSm&`rrIK eP?roe#4)=5cXa(P+7jc@^}nFZF^WfS2mk=&D+65s literal 80384 zcmca`Uhu)fjZzO8(10BSGsD0CoD6J8;!F$-42&?o00YCn|NsAkxG);Tu3%tb_&*AU zObGn_|Np-N0|Nsy0|NsK0|Nsq0|PkD*%=rZI2afhI2jlixEL51xEUbv&C9^Rz{kMA zz|X+IAi%)DAjrVLAjH7HAk4tPAi}`FAPQ9{&cMJR!N9;E$-uxM#lXNI&A`AQ!@$5G z%fP@O$H2fK4^`*Sz`&ryz`&r)z`&rwz`&r&z`&r!z`&r+z`&rvz`&r%z`&pdRjb3m zz@W>(z@W##z@X2-z+k|@z+lM0z+l9{z+lY4z+eJZXU4$5V9vn6V8Ot^V9CJ1V8y_| zV9mh5V8g(`V9UV3V8_6~V9&t7;K0DZ;K;zh-~`p@!oa}b%D}+j#=yYf&cMLn!N9=a z$-uzi#lXPe&A`Cm!@$7c%fP_k2UXw9z`zj5z`zj1z`zj9z`zi~z`zj7z`zj3z`zjB zz`zi}z`zj6z`zj2z`zg<)f3CWz!1m4z!1;Cz>vVez>vtmz>vhiz>v(qz>vbgz>vzo zz>vnkz>vvYfz>vwnz>vkjz>v+rz>vehz>o_yC!c|Vp@4ybp^$-rp@@Njp_qYz zp@e~fp_GAvp^Slnp&Y6X6u(sr3=Gu_3=B043=Fjl3=DM)3=H)Q3=9omx92nDGn6nW zFt{@0F_bVAF;s%GG0|9zffb(Lk;@8f1~eopN*q~ofDyU82xrJ=C}PNFC}t>NNMuN6 zNM%r92xcf@NMtAhhXposki`@jm>5Bs4U|4XG_o8nHmDo}CsuIW7ct~Blrt1Fq=Lf{ zmmXZ=0t`%ypu7XhE5zE*12PPhS-|Nng&~un1RM$=VNx+40}~@Ce}e1=VPf=)ffPaQ zXJlXn=X;it)Z!8iXRDZ`{QTmQn4HX{;+TTUl8pSkn55FooRk=lJebf+DJ}rj0$fQ2 zIq}6Mi6xoInt1dfRKYZ|7L})G8*1Uv16B|NCSjU5QY#X33vyBo4e;oLsfmFxV7fKp z^OLetlS>q|bQIuBO&zR86&EGPWaed-#HW?!C6{F8=jkOE6o8aE`TGZl#Q1nR1;+$L zhIsh<#W;m}`nbe|xCV#BxVSony2FG)3gaQ1c#v$oi=K;*PpyKUktrzXVHiEWW>kah zwX#adk55j_$r&t;HU^cmFgJrUJDkJ7z%c4)>Lm|j15i;S0m^C$x(eZ$dB#QxE~!bS z=>g!J2+DOJtd(pPQ<9&b1J9wLBwLUS$)}J^Yh)0gqL-4B!ytrd7%28cP=te0b5awF zK~)d9er9E0bl`N(&nqd)&(U=TDF@lg!NBOi3lnuJN=*b+N#OP%69Yqos7qo=Vo7B| zs)BE3abiwpdR}g79;iYBt6*hdI3VDdoSa%*tPqx&pOXm6S1^Ow7#I%ldgdtvB&Me- zxE2-VgX%M|HdzLS1Hzs;IjQN1ISQV6#U(|h;2a6l*~7qaK-96QD6vw(DZex?rC7nW zA~`iRB^6YYf=%dUU^pP=mXn`YqTrI6mtT~dn4{odkXn?O2UpU^z;HkWswA^4GbL3a zsZt>-wFp$hg3V9^yCSbFF()%c!6mb}Aip>h+5PtCm&RUgYBQhz;HkiA{AVcn4GQPoROLg5B$jt z3vd2>sxmMfknqdTOU}NFOv*_Ghg$)% zdkA@Y3MgPb^GZ_FQ;QT_u!b8EN~VI+118l7@H05Oq!y&+ zrKIMesNyLAS&)-jmYRc48GBlJie5%R0d9l%lM;(lp_MXzl^l8bd8zo7aF-M%CZ{GP zCTHVw6fdl5FUD`0aB4+KYF=?>eqMZXPGT_u)x7zjf~6$Ch=4ktocz3WNP7gIBe}s= zrV=oWzq}~1ARZE9_&vjul9^mWgtf($#kt^QkI!)&$@zI{nd$hH@FthVmlP#tmJsj( zZ*gv7QAvD3NfCbc^A_i1CZ`hi0DD1YZfY(*mvMsXDMGGF163M?ZQ}y9)KUpJT@ci+ zL$oLHW(U69)RK(+6k=?KMghLe#hsZ~Qj`p;FYpBj2VvXziZj#m5=%;p2qwtnd{8^R zg0PXi#hH2OIjJT2dH5rqBQv)kzo-PC2e=`&5r|VRSfa%nVx=XSIhiGu_}#=+P?-v9 zsTAXL6(^`Q-Ta=oXT9lfXOrVq$f>;_4ZZQ%{ zy!@aPPFzkdO3X_qB8PG%CKZFqX}nR&Sx^b;T&Cg+6CO}GPB`d<@{_tS3>rfOVVGH<@h%XS`!5d~ax`P`bBPC815z`J85l;x zU^EQqod%deT}(Fcus^6r48jpi3=E(w3mVo3Wn&Q50p(NZ)Bs2g2n#baFl>j4gVccV zA1EKx1p%o6VVHR!c^E#yz`!sKT3mqCfbbb61_llA*epyH0|QJQ$XJjX5XNO5NEb*u zNDT<%QwLHDG84;iC#aK!+FqmH0MF?7AM(I5Ekk;U4qA?m|AAW7u-rL1{s$_fM#uj~ z$N%#4K!bar0uwUSGdliqGxpc z4|DQsbo_60{BLxuir!;YqxMlh&2ca=Gx+*=`7kkXhNKpkIF}Zcr7F5uftMO278jHy zo5ds+7lf8%=D=vsa=5La<&L10zX7R5X`od#dC92?MhXG>MJ0qa>w*S3M#ujk>*PU0 z9WXq)l#Y5Mt)t_AqwD_|7#K#^|BbHy8(sgGoH4ro4|#>-==wk0%Q3k}*Z+YQ!Sar- z|3euC8eRW~5*(xJ|FA3x=N(=DhqR1-bp0P}yau$G2-L>~t^EVx(e;1SAIE`(^(Z|W zwxpy1Z2Pan88R927*fFdqCxoW0ZCw3>?2t(w@NQA)ek5cG z4p4oE&?6t7UzA;3keHmRpbp+!pl+pLqEJwj588XJQLHJD1m7~Qkd~Q~TFeuiUs{x$ zssJ*km=CsV8zRRI-v13@bAcUzsfEWQH8CZ%2%;b2FeIfo1PHkjq76c#d2n?9_vrp_ z8XgZYy8nB0|96Q3`cCH2^`E2bKS$Sp20I0f?*GPIi8Q+Z8~tE{(f!|`)--gf>*)S( zq`(;6{|!wQqx-*c&wq{X{{{~&z{YGx_kWL$Cz3LrII4DNr5DFJkaJ%JZ1VC;6hKFU z73JsTq^8($Bty@FWMDu#=@CPj2uvCBk&z4x@Z%bZ)c`pZl33N?5lhhc;pq4u_&6}| za$Q<&S|6fIDZ$kklt3SuAG9lNK}(}Y&wm8P8fa2!bpJOf6h_DYM#uj~$Nxsh|F9mz zIXeC~I{t^}aMjWAztQnO%t?dM@xRgWztQs_N6%Yi7+PahqhpKIkFSJRkUPEPke23Q zxq5;RAq}}xg@eI40J5%+fKDldPWYV`(EBDp>n0gNmk=?4Sg%+?om~*?H<$$)1dza@ z8GIoINEv>u1e`_K0O(v910w@BgL6n?QF>~LXGv-<9{=EVF-Vetn?OpSwxTSIWMtri zgtmK8erW+z1*H5&SpbPg9dk-*0V9J5@>%|%t2`1j^HPgY45X$)!e{^UWR|2BC6?q9 zI6s}Yq_iN1h=Zkx+q*{8G%yF`oHcw0JPVO@tTZtPh7-H#jHt7~!OL|CACApU)Okll z-uA$glUYo}9RtK(4M1G)MKrM}vm_%owInl{s1v@4Ia!>a=u_-@K&z4o2Qx7z1`%LTvu6@IOrA5Duk3Q;5jI90iqxjyV?r#SQ2Vo>Zcuo7i1x z#9zEX%<=Wa9YiRaoS#>gS_HmfgqXWBsJN$$Jvp@ubW%L-o)9tD7Z6@-MeMa5L|=pe zDijE(IKHIPw6xSB!U~DKwT0MgN{G8XhlmsRh(C9Y$O~nNye)wvIkC6|{|y2hpbJ#+ zE0HWIO3W(;oec!dr18ZCsmb{D2tr~DssX=RevlK0QYnJ&68r{>z%MT&%5?tX#9ZRa zAxMJ_nZ!DvOMEdz)NLlC_rD;Hb|k9dM_hYobpQA0{_mtxy!T&Gv92bvtwzrMFW|di zKpoFfJQ@O{Aut*OqaiRF0;3@?VnV=+nUNVZ7GA-q&+tN|9yA0$V*Ebp(a{hX=^+4{ z|C50qzJX=-j|V1+KKF-Lmjp}~?s-2p1_p+gtdn&!6?Bsolpy!KDrBVQddV3nnME4vdV2a01Ue8zT@$VxFMe$H!Lu&;Tu3k}To<_8~ zZkc+lrV_|yFIc6}F5!-W&I+Ygq=E`f$dn~W=^Ivdq)AQ01g03wE_fK=oW2AZGepAz z4+8*D%Tct-3sQga3xGTKVCi4f%wlGt0UN9X@W=l`&bg^teuL9_Gd{9h`T zGA}(`cKoTk-f`I{MKZHj*$;H3~J`x+` zcMvAVgglTU==t-`3^@#m48;t^3}FnJ45iM9Cnkv8_5t!0VnA334QTMu@z*Hg&D|y zuRvE`gHJ9*1PF9g41HPvYpwtlF<4R!NEm0hf+V4KjLr#w#|h9!{CSBy_Kx@y$#{|z zb8?arle6(JE+zF8I%3bABKjaJA~&KCdE_FghpZ8KLL=en1j6T%5pgslKjK_90&9W= z!RaL)d|P=cfnz9%Iq8m=)3XR4aYx)4XGEU1Na`VT#EoDRc_Jj?GeG&15{pygAq%+i zXR*=yUonqzAHDwpTn!)%pc9^w;sl)?N1$9F_9#{^Q0+jd;1EQ;nk%EA0QdOg==eW+ zgpQ8?kB{-g(GVC7fzc2c4S~@R z7YR_m0jD`T2A+U$}2RPq? z&TZY$MgF<1UQCQEpxI1N-j}d#9L@h^#>c3((GVDlApl$dBg24nJ|pN#NVN3@j11i1 znbOo^z2t%dP>F#u#|jk_POT^bt;5OBiwCQQspU;8%}XxH%+G`CMw=3W>PKIg4i$zU z?*!#TCvc!Vv^x+P7&u^ut}-w%GNSo|fdNA~#u1hb$YB905m~`Ie6fTIS*EdomI`4p zjFCYQb?p*%|6wT0fW!x3Z=ml_XJKGq06PXL>LFf*hv5JJ3=DbDlU70Jtb!sQvD^jc zIu($z(e*!xuscIX*Z)8#uF+TPKsF%|y+4--g`?|#Qj<&Y-C8=j{wKK-X|=%U`X7w_ z&7L1y8Z{LcmpjYEK1Hu1+8Aiz2=CB z(}?+sGt=`DOG=AU2`r5u{^n%f;>^7CoYa#1JOa!9AU8qatJL5f1iX1=^!!)o+Hv%5 z7T!=J{vKLlZ(8Oe<^T<1Zs{If|AW$&A?Nc0@1_ov( zMnj*{n3N2;o8o3L$LpAR>r~(P4rPVUCXf#ut|)mSiS_ zsyk?CF*2YHO=Aq~LIV$Nz#2o@==d*aK%K6ehC$=oqx(NW$$79{#A6fPH@vMso&lQW_oqMH!9YO)iTsDN4*NAuwRbTb!F%R1#lMLSXkb zu@}jWj{lC1|67LW}xAcBFxg(06InW2;+mm!rQkD-L27$QtG3A%p>c{G(6jgvr% zp!e^9n3Q5t?Wfc}bp4dr&&9yZ06xeJZYan!I0rO}Uky6F#L6lqKOS_}i3aqj9tABO z1vpbv$Jr_de2!mCPG(Xubirs$aZz#%NOL@F`7dZaFi5GBzkhH@jE|>Na7;jCh=;#l zj8mwmk4sF5Yj8-6i>p(pJ4_g)Fdo8*2g$~}=(+g#)GFv1nIb!K)X}sHX=8&S7}7)3 z(V*#boU5uqlLsKIm24GLlAoW0lFtf~!DpC3v!0Pbe2QL5P7VW(69#dvNS0+_U|?ln zbl?On)h)`;(RBtzKFC%M21W;7n5a`xYGO7_hKYfpLDVI&BoTD3l7eq$abiwpdR}g7 zUI|PED+9v;0mtOz)Z$`=u+03NM9^LUm?Rqm!vS8;JcWS7^i%~`(CI5M8CeE~1Hzs; zIjQN1ISQV6#U(|h;9UeT`5p#_1EP*aMTwOPPWh#IDa8t|70IcoDXA$i6}=1$2gKZR z@)JuGTvGG$i*gfl6#NTPixTtTO8OWW4v0XNWR_*7q$(s;Dnz9g<-^QS1G^%xEHNiD zMZqPrxFEkc6WRU!2m?IxQY#XZOB8}qi%WChzMsIra6lYlgD2D&up5vKnaIF!fDfX^ zzbv&VEhoPmX8$Axh692Sso;{t|_Rp1N;!#(7Y5>o#G4(2RQxm6?{{3 z^NYZ@zJVfAm4V@agkOGMa(-S(W?pGxQcfy3+zOE0L&(!pKmqHSSCX2ZTBP8DHQb0$ zG8L3AV5Xq^dm6}!fTGN@%$(Hp)D&z9;4diDAc2Ce+mw;v0I!RWkAh!*iGmv_b-+T* ziIL%eBuK_HFS8^wF(|;O~ zxEo#nJG%ZCl{7OBUK@H@ve5qv!vjFX$dU|8MmCKkNhg zqw9ZBDsFPt|8j`9c!h)7CZl*X1V%$(Gz3ONU^E0qLtw;&!07pZBPOaxJvtf!7$LyM z02%;9KKE;MDvfqiX+v_-a)?f)At&`AlBSIfM(6)V=l{@WvPS3sM(6+X^FWh(p!GDP z^MCkmPvR~qN=#0L+}4MC_6lh`D&D!6(fuE|cE)gw&i`?UfTm?e@Bd28Lz#paJ^u$j z?aK+e*|4NI1>Y<=UoLow3GDhq++`MLeo|IuZb1${!+48Q(^894^O95XpQto?{txbO d9^L-|?l{5D>=`}(XK=3DAKgze8ZXpH0|0G)Qbqs( From 2e145ea9163340ef7f4ab94cf7bb3ddbc74d511d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 5 Mar 2001 23:41:37 +0000 Subject: [PATCH 064/154] Use file name "libboost_python.a"; rename makefiles. [SVN r9449] --- build/{Makefile.linux_gcc => linux_gcc.mak} | 10 +++++----- build/{Makefile.mingw32 => mingw32.mak} | 10 +++++----- build/{Makefile.tru64_cxx => tru64_cxx.mak} | 16 ++++++++-------- 3 files changed, 18 insertions(+), 18 deletions(-) rename build/{Makefile.linux_gcc => linux_gcc.mak} (96%) rename build/{Makefile.mingw32 => mingw32.mak} (96%) rename build/{Makefile.tru64_cxx => tru64_cxx.mak} (93%) diff --git a/build/Makefile.linux_gcc b/build/linux_gcc.mak similarity index 96% rename from build/Makefile.linux_gcc rename to build/linux_gcc.mak index 7021e221..a07bb5da 100644 --- a/build/Makefile.linux_gcc +++ b/build/linux_gcc.mak @@ -79,7 +79,7 @@ DEPOBJ= $(OBJ) comprehensive.o abstract.o \ .SUFFIXES: .o .cpp -all: libbpl.a boost_python_test.so abstract.so \ +all: libboost_python.a boost_python_test.so abstract.so \ getting_started1.so getting_started2.so getting_started3.so \ getting_started4.so getting_started5.so @@ -107,9 +107,9 @@ unlink: fi; \ done -libbpl.a: $(OBJ) - rm -f libbpl.a - ar r libbpl.a $(OBJ) +libboost_python.a: $(OBJ) + rm -f libboost_python.a + ar r libboost_python.a $(OBJ) boost_python_test.so: $(OBJ) comprehensive.o $(LD) $(LDOPTS) $(OBJ) comprehensive.o -o boost_python_test.so -lm @@ -145,7 +145,7 @@ test: $(PYEXE) test_getting_started5.py clean: - rm -f $(OBJ) libbpl.a libbpl.a.input + rm -f $(OBJ) libboost_python.a libboost_python.a.input rm -f comprehensive.o boost_python_test.so rm -f abstract.o abstract.so rm -f getting_started1.o getting_started1.so diff --git a/build/Makefile.mingw32 b/build/mingw32.mak similarity index 96% rename from build/Makefile.mingw32 rename to build/mingw32.mak index 7c5f2c52..014af132 100644 --- a/build/Makefile.mingw32 +++ b/build/mingw32.mak @@ -96,7 +96,7 @@ OBJ = classes.o conversions.o extension_class.o functions.o \ .SUFFIXES: .o .cpp -all: libbpl.a boost_python_test.pyd abstract.pyd \ +all: libboost_python.a boost_python_test.pyd abstract.pyd \ getting_started1.pyd getting_started2.pyd getting_started3.pyd \ getting_started4.pyd getting_started5.pyd @@ -136,9 +136,9 @@ rmdefs: rm $$def.def; \ done -libbpl.a: $(OBJ) - del libbpl.a - ar r libbpl.a $(OBJ) +libboost_python.a: $(OBJ) + del libboost_python.a + ar r libboost_python.a $(OBJ) DLLWRAPOPTS= -s --driver-name g++ -s --entry _DllMainCRTStartup@12 --target=i386-mingw32 @@ -198,7 +198,7 @@ test: $(PYEXE) test_getting_started5.py clean: - rm -f $(OBJ) libbpl.a libbpl.a.input + rm -f $(OBJ) libboost_python.a libboost_python.a.input rm -f comprehensive.o boost_python_test.pyd rm -f abstract.o abstract.pyd rm -f getting_started1.o getting_started1.pyd diff --git a/build/Makefile.tru64_cxx b/build/tru64_cxx.mak similarity index 93% rename from build/Makefile.tru64_cxx rename to build/tru64_cxx.mak index 2b417944..3fd584b7 100644 --- a/build/Makefile.tru64_cxx +++ b/build/tru64_cxx.mak @@ -79,7 +79,7 @@ DEPOBJ= $(OBJ) comprehensive.o abstract.o \ .SUFFIXES: .o .cpp -all: libbpl.a boost_python_test.so abstract.so \ +all: libboost_python.a boost_python_test.so abstract.so \ getting_started1.so getting_started2.so getting_started3.so \ getting_started4.so getting_started5.so @@ -107,13 +107,13 @@ unlink: fi; \ done -libbpl.a: $(OBJ) - rm -f libbpl.a +libboost_python.a: $(OBJ) + rm -f libboost_python.a cd cxx_repository; \ - ls -1 > ../libbpl.a.input; \ - ar r ../libbpl.a -input ../libbpl.a.input - rm -f libbpl.a.input - ar r libbpl.a $(OBJ) + ls -1 > ../libboost_python.a.input; \ + ar r ../libboost_python.a -input ../libboost_python.a.input + rm -f libboost_python.a.input + ar r libboost_python.a $(OBJ) boost_python_test.so: $(OBJ) comprehensive.o $(LD) $(LDOPTS) $(OBJ) comprehensive.o -o boost_python_test.so -lm @@ -149,7 +149,7 @@ test: $(PYEXE) test_getting_started5.py clean: - rm -f $(OBJ) libbpl.a libbpl.a.input + rm -f $(OBJ) libboost_python.a libboost_python.a.input rm -f comprehensive.o boost_python_test.so rm -f abstract.o abstract.so rm -f getting_started1.o getting_started1.so From 149cc499ede69475159d5a120c3213597c9d410a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 5 Mar 2001 23:46:43 +0000 Subject: [PATCH 065/154] Remove spurious ";" [SVN r9450] --- include/boost/python/detail/extension_class.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/python/detail/extension_class.hpp b/include/boost/python/detail/extension_class.hpp index 987d753e..4afffcae 100644 --- a/include/boost/python/detail/extension_class.hpp +++ b/include/boost/python/detail/extension_class.hpp @@ -152,7 +152,7 @@ template bool is_null(const Ptr& x) { return is_null_helper<(is_pointer::value)>::test(x); -}; +} }}} // namespace boost::python::detail From fdff5e33b3745a4768caf0145d57d3cce7f1a668 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 6 Mar 2001 00:02:01 +0000 Subject: [PATCH 066/154] temp file for branching [SVN r9451] --- src/x_class_builder.cpp | 118 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 src/x_class_builder.cpp diff --git a/src/x_class_builder.cpp b/src/x_class_builder.cpp new file mode 100644 index 00000000..cf81a3f7 --- /dev/null +++ b/src/x_class_builder.cpp @@ -0,0 +1,118 @@ +# include +namespace python = boost::python; +# include // MSVC6.0SP4 does not know std::fprintf +# include // MSVC6.0SP4 does not know std::strcmp + +namespace { + + PyObject *get_module_dict(const char *module_name) + { + python::ref module_obj(PyImport_ImportModule((char*) module_name)); + PyObject *module_dict = PyModule_GetDict(module_obj.get()); + if (module_dict == 0) throw python::import_error(); + return module_dict; + } +} + +namespace boost { namespace python { namespace detail { + +#ifndef SPECIAL_PYCVTSOBJECT + +void *import_converters(const std::string& module_name, + const std::string& klass_name, + const std::string& attribute_name) +{ + static std::string err; + PyObject *module_dict + = get_module_dict(const_cast(module_name.c_str())); + PyObject *klass + = PyDict_GetItemString(module_dict, const_cast(klass_name.c_str())); + if (klass == 0) { + err = std::string("module ") + module_name + " has no attribute " + + klass_name; + PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); + throw python::import_error(); + } + python::ref c_obj(PyObject_GetAttrString(klass, + const_cast(attribute_name.c_str())), ref::null_ok); + if (c_obj.get() == 0) { + err = std::string("object ") + module_name + "." + klass_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 + "." + klass_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()); +} + +#else + +PyObject *new_import_converters(const std::string& module_name, + const std::string& klass_name, + const std::string& attribute_name) +{ + static std::string err; + PyObject *module_dict + = get_module_dict(const_cast(module_name.c_str())); + PyObject *klass + = PyDict_GetItemString(module_dict, const_cast(klass_name.c_str())); + if (klass == 0) { + err = std::string("module ") + module_name + " has no attribute " + + klass_name; + PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); + throw python::import_error(); + } + python::ref cvts_obj(PyObject_GetAttrString(klass, + const_cast(attribute_name.c_str())), ref::null_ok); + if (cvts_obj.get() == 0) { + err = std::string("object ") + module_name + "." + klass_name + + " has no attribute " + attribute_name; + PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); + throw python::import_error(); + } + // Weak point: direct access to ob_type->tp_name + if (strcmp(cvts_obj->ob_type->tp_name, "PyCvtsObject") != 0) { + err = std::string("object ") + module_name + "." + klass_name + "." + + attribute_name + " is not a PyCvtsObject"; + PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); + throw python::import_error(); + } + return cvts_obj.release(); +} + +#endif // SPECIAL_PYCVTSOBJECT + +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 From f49141f71ede423a1ae6f52f85f3a5b054c869e9 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 6 Mar 2001 00:04:28 +0000 Subject: [PATCH 067/154] temp file removed after branching [SVN r9452] --- src/x_class_builder.cpp | 118 ---------------------------------------- 1 file changed, 118 deletions(-) delete mode 100644 src/x_class_builder.cpp diff --git a/src/x_class_builder.cpp b/src/x_class_builder.cpp deleted file mode 100644 index cf81a3f7..00000000 --- a/src/x_class_builder.cpp +++ /dev/null @@ -1,118 +0,0 @@ -# include -namespace python = boost::python; -# include // MSVC6.0SP4 does not know std::fprintf -# include // MSVC6.0SP4 does not know std::strcmp - -namespace { - - PyObject *get_module_dict(const char *module_name) - { - python::ref module_obj(PyImport_ImportModule((char*) module_name)); - PyObject *module_dict = PyModule_GetDict(module_obj.get()); - if (module_dict == 0) throw python::import_error(); - return module_dict; - } -} - -namespace boost { namespace python { namespace detail { - -#ifndef SPECIAL_PYCVTSOBJECT - -void *import_converters(const std::string& module_name, - const std::string& klass_name, - const std::string& attribute_name) -{ - static std::string err; - PyObject *module_dict - = get_module_dict(const_cast(module_name.c_str())); - PyObject *klass - = PyDict_GetItemString(module_dict, const_cast(klass_name.c_str())); - if (klass == 0) { - err = std::string("module ") + module_name + " has no attribute " - + klass_name; - PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); - throw python::import_error(); - } - python::ref c_obj(PyObject_GetAttrString(klass, - const_cast(attribute_name.c_str())), ref::null_ok); - if (c_obj.get() == 0) { - err = std::string("object ") + module_name + "." + klass_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 + "." + klass_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()); -} - -#else - -PyObject *new_import_converters(const std::string& module_name, - const std::string& klass_name, - const std::string& attribute_name) -{ - static std::string err; - PyObject *module_dict - = get_module_dict(const_cast(module_name.c_str())); - PyObject *klass - = PyDict_GetItemString(module_dict, const_cast(klass_name.c_str())); - if (klass == 0) { - err = std::string("module ") + module_name + " has no attribute " - + klass_name; - PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); - throw python::import_error(); - } - python::ref cvts_obj(PyObject_GetAttrString(klass, - const_cast(attribute_name.c_str())), ref::null_ok); - if (cvts_obj.get() == 0) { - err = std::string("object ") + module_name + "." + klass_name - + " has no attribute " + attribute_name; - PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); - throw python::import_error(); - } - // Weak point: direct access to ob_type->tp_name - if (strcmp(cvts_obj->ob_type->tp_name, "PyCvtsObject") != 0) { - err = std::string("object ") + module_name + "." + klass_name + "." - + attribute_name + " is not a PyCvtsObject"; - PyErr_SetString(PyExc_RuntimeError, const_cast(err.c_str())); - throw python::import_error(); - } - return cvts_obj.release(); -} - -#endif // SPECIAL_PYCVTSOBJECT - -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 From 23725680c9b8ab8068e26b46512936d260fb95df Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 6 Mar 2001 00:05:41 +0000 Subject: [PATCH 068/154] temp file before branching [SVN r9453] --- include/boost/python/x_class_builder.hpp | 361 +++++++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100644 include/boost/python/x_class_builder.hpp diff --git a/include/boost/python/x_class_builder.hpp b/include/boost/python/x_class_builder.hpp new file mode 100644 index 00000000..4b3da600 --- /dev/null +++ b/include/boost/python/x_class_builder.hpp @@ -0,0 +1,361 @@ +#ifndef X_CLASS_BUILDER_HPP +# define X_CLASS_BUILDER_HPP + +# include + +//QUESTIONMARK +// Do we really need the special PyCvtsObject? +// Is there a better way of creating the special PyCvtsObject? +// My solution adds a lot of code including several reinterpret_cast. +//#define SPECIAL_PYCVTSOBJECT + +namespace boost { namespace python { + struct import_error : error_already_set {}; + struct export_error : error_already_set {}; +}} + +namespace boost { namespace python { 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 = 1; +const int EXPORT_CONVERTERS_API_MINOR = 1; +const std::string converters_attribute_name = "__converters__"; +#ifndef SPECIAL_PYCVTSOBJECT +void *import_converters(const std::string& module_name, + const std::string& klass_name, + const std::string& attribute_name); +#else +PyObject *new_import_converters(const std::string& module_name, + const std::string& klass_name, + const std::string& attribute_name); +#endif +void check_export_converters_api(const int importing_major, + const int importing_minor, + const int imported_major, + const int imported_minor); + +}}} + +// forward declaration +namespace boost { namespace python { namespace detail { +template class import_extension_class; +}}} + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + +//QUESTIONMARK +// This class is a look-alike of class python_extension_class_converters. +// Is there a way to ensure that the siblings stay in sync? +template +class python_import_extension_class_converters +{ + public: + + friend python_import_extension_class_converters py_extension_class_converters(boost::python::type) + { + return python_import_extension_class_converters(); + } + + PyObject* to_python(const T& x) const + { + return boost::python::detail::import_extension_class::get_converters()->to_python(x); + } + + friend T* from_python(PyObject* obj, boost::python::type) + { + return boost::python::detail::import_extension_class::get_converters()->Tptr_from_python(obj); + } + + // Convert to const T* + friend const T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to const T* const& + friend const T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T* const& + friend T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T& + friend T& from_python(PyObject* p, boost::python::type) + { return *boost::python::detail::check_non_null(from_python(p, boost::python::type())); } + + // Convert to const T& + friend const T& from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T + friend const T& from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + friend std::auto_ptr& from_python(PyObject* p, boost::python::type&>) { + return boost::python::detail::import_extension_class::get_converters()->auto_ptr_from_python(p); + } + + friend std::auto_ptr& from_python(PyObject* p, boost::python::type >) { + return boost::python::detail::import_extension_class::get_converters()->auto_ptr_from_python(p); + } + + friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&>) { + return boost::python::detail::import_extension_class::get_converters()->auto_ptr_from_python(p); + } + + friend PyObject* to_python(std::auto_ptr x) { + return boost::python::detail::import_extension_class::get_converters()->to_python(x); + } + + friend boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) { + return boost::python::detail::import_extension_class::get_converters()->shared_ptr_from_python(p); + } + + friend boost::shared_ptr& from_python(PyObject* p, boost::python::type >) { + return boost::python::detail::import_extension_class::get_converters()->shared_ptr_from_python(p); + } + + friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) { + return boost::python::detail::import_extension_class::get_converters()->shared_ptr_from_python(p); + } + + friend PyObject* to_python(boost::shared_ptr x) { + return boost::python::detail::import_extension_class::get_converters()->to_python(x); + } +}; + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +namespace boost { namespace python { + +BOOST_PYTHON_IMPORT_CONVERSION(python_import_extension_class_converters); + +// A pointer to this class is exported/imported via the Python API. +// All functions are virtual. This is, what we really export/import +// is essentially just a pointer to a vtbl. +template +struct export_converters_base +{ + virtual const int get_api_major() const { + return detail::EXPORT_CONVERTERS_API_MAJOR; } + virtual const int get_api_minor() const { + return detail::EXPORT_CONVERTERS_API_MINOR; } + virtual PyObject *to_python(const T& x) = 0; + virtual PyObject *to_python(std::auto_ptr x) = 0; + virtual PyObject *to_python(boost::shared_ptr x) = 0; + virtual T* Tptr_from_python(PyObject* obj) = 0; + virtual std::auto_ptr& auto_ptr_from_python(PyObject *obj) = 0; + virtual boost::shared_ptr& shared_ptr_from_python(PyObject *obj) = 0; +}; + +// Converters to be used if T is not copyable. +template +struct export_ptr_converters : export_converters_base +{ + virtual PyObject *to_python(const T& x) { + PyErr_SetString(PyExc_RuntimeError, + "to_python(const T&) converter not exported"); + throw import_error(); + } + virtual PyObject *to_python(std::auto_ptr x) { + return BOOST_PYTHON_CONVERSION::to_python(x); + } + virtual PyObject *to_python(boost::shared_ptr x) { + return BOOST_PYTHON_CONVERSION::to_python(x); + } + virtual T* Tptr_from_python(PyObject* obj) { + return BOOST_PYTHON_CONVERSION::from_python(obj, boost::python::type()); + } + virtual std::auto_ptr& auto_ptr_from_python(PyObject *obj) { + return BOOST_PYTHON_CONVERSION::python_extension_class_converters::ptr_from_python(obj, boost::python::type >()); + } + virtual boost::shared_ptr& shared_ptr_from_python(PyObject *obj) { + return BOOST_PYTHON_CONVERSION::python_extension_class_converters::ptr_from_python(obj, boost::python::type >()); + } +}; + +// The addditional to_python() converter that can be used if T is copyable. +template +struct export_converters : export_ptr_converters +{ + virtual PyObject *to_python(const T& x) { + BOOST_PYTHON_CONVERSION::python_extension_class_converters cv; + return cv.to_python(x); + } +}; + +namespace detail { + +//QUESTIONMARK +// A stripped-down, modified version of class extension_class. +// Would it make sense to establish a formal relationship +// between the two classes? +template +class import_extension_class + : public python_import_extension_class_converters +{ + public: + inline import_extension_class(const char *module, const char* klass) { + m_module = module; + m_klass = klass; + } + + static boost::python::export_converters_base* get_converters(); + + private: + static std::string m_module; + static std::string m_klass; + static boost::python::export_converters_base* imported_converters; +}; + +template std::string import_extension_class::m_module; +template std::string import_extension_class::m_klass; +template +boost::python::export_converters_base* +import_extension_class::imported_converters = 0; + +#ifdef SPECIAL_PYCVTSOBJECT + +// A special PyObject for passing pointers to export_converters_base +template +struct PyCvtsObject { + PyObject_HEAD + export_converters_base* cvts; +}; + +template +void DEL_PyCvtsObject(PyCvtsObject* self) { PyMem_DEL(self); } + +template +PyObject *create_PyCvtsObject(export_converters_base* cvts) +{ + static char PyCvtsObject_Type__doc__[] = + "Boost Python Library (BPL) converters objects to be exported from\n" + "one extension module to another."; + + static PyTypeObject PyCvtsObject_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "PyCvtsObject", /*tp_name*/ + sizeof(PyCvtsObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)(static_cast*)> + (DEL_PyCvtsObject)), /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)0, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + + /* Space for future expansion */ + 0L,0L,0L,0L, + PyCvtsObject_Type__doc__ /* Documentation string */ + }; + + PyCvtsObject* self = PyObject_NEW(PyCvtsObject, &PyCvtsObject_Type); + if (self == 0) throw export_error(); + self->cvts = cvts; + return reinterpret_cast(self); +} + +#endif // SPECIAL_PYCVTSOBJECT + +template +boost::python::export_converters_base* +import_extension_class::get_converters() { + if (imported_converters == 0) { +#ifndef SPECIAL_PYCVTSOBJECT + void *cobject + = import_converters(m_module, m_klass, converters_attribute_name); + imported_converters + = static_cast*>(cobject); +#else + ref cvts_obj( + new_import_converters(m_module, m_klass, converters_attribute_name)); + PyCvtsObject* cvts = reinterpret_cast*>(cvts_obj.get()); + imported_converters = cvts->cvts; +#endif + 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; +} + +}}} // namespace boost::python::detail + +namespace boost { namespace python { + +//QUESTIONMARK +// A stripped-down, modified version of class class_builder. +// Would it make sense to establish a formal relationship +// between the two classes? +template +class import_class_builder + : python_import_extension_class_converters +{ + public: + import_class_builder(const char *module, const char* klass) + : m_class(new detail::import_extension_class(module, klass)) + { } + private: + + //QUESTIONMARK + //reference > m_class; + boost::shared_ptr > m_class; +}; + +}} // namespace boost::python + +namespace boost { namespace python { + +// A class_builder that exports the converter functions. +template , + class C = export_converters > +class x_class_builder + : public class_builder +{ + private: + static C export_cvts; + + public: + x_class_builder(module_builder& module, const char* name) + : class_builder(module, name) { +#ifndef SPECIAL_PYCVTSOBJECT + add( + ref(PyCObject_FromVoidPtr(reinterpret_cast(&export_cvts), NULL)), + const_cast(detail::converters_attribute_name.c_str())); +#else + add(ref(detail::create_PyCvtsObject(&export_cvts)), + const_cast(detail::converters_attribute_name.c_str())); +#endif + } +}; + +template +C x_class_builder::export_cvts; + +//QUESTIONMARK +// Is there a better way of making it easy for the end-user +// to choose between x_class_builder and xptr_class_builder? +template , + class C = export_ptr_converters > +class xptr_class_builder : public x_class_builder +{ + public: + xptr_class_builder(module_builder& module, const char* name) + : x_class_builder(module, name) { } +}; + +}} // namespace boost::python + +#endif // X_CLASS_BUILDER_HPP From 5b13e75fa585d73753627a2f4df1cb2c8fa2128e Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 6 Mar 2001 00:06:55 +0000 Subject: [PATCH 069/154] temp file removed after branching. [SVN r9454] --- include/boost/python/x_class_builder.hpp | 361 ----------------------- 1 file changed, 361 deletions(-) delete mode 100644 include/boost/python/x_class_builder.hpp diff --git a/include/boost/python/x_class_builder.hpp b/include/boost/python/x_class_builder.hpp deleted file mode 100644 index 4b3da600..00000000 --- a/include/boost/python/x_class_builder.hpp +++ /dev/null @@ -1,361 +0,0 @@ -#ifndef X_CLASS_BUILDER_HPP -# define X_CLASS_BUILDER_HPP - -# include - -//QUESTIONMARK -// Do we really need the special PyCvtsObject? -// Is there a better way of creating the special PyCvtsObject? -// My solution adds a lot of code including several reinterpret_cast. -//#define SPECIAL_PYCVTSOBJECT - -namespace boost { namespace python { - struct import_error : error_already_set {}; - struct export_error : error_already_set {}; -}} - -namespace boost { namespace python { 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 = 1; -const int EXPORT_CONVERTERS_API_MINOR = 1; -const std::string converters_attribute_name = "__converters__"; -#ifndef SPECIAL_PYCVTSOBJECT -void *import_converters(const std::string& module_name, - const std::string& klass_name, - const std::string& attribute_name); -#else -PyObject *new_import_converters(const std::string& module_name, - const std::string& klass_name, - const std::string& attribute_name); -#endif -void check_export_converters_api(const int importing_major, - const int importing_minor, - const int imported_major, - const int imported_minor); - -}}} - -// forward declaration -namespace boost { namespace python { namespace detail { -template class import_extension_class; -}}} - -BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE - -//QUESTIONMARK -// This class is a look-alike of class python_extension_class_converters. -// Is there a way to ensure that the siblings stay in sync? -template -class python_import_extension_class_converters -{ - public: - - friend python_import_extension_class_converters py_extension_class_converters(boost::python::type) - { - return python_import_extension_class_converters(); - } - - PyObject* to_python(const T& x) const - { - return boost::python::detail::import_extension_class::get_converters()->to_python(x); - } - - friend T* from_python(PyObject* obj, boost::python::type) - { - return boost::python::detail::import_extension_class::get_converters()->Tptr_from_python(obj); - } - - // Convert to const T* - friend const T* from_python(PyObject* p, boost::python::type) - { return from_python(p, boost::python::type()); } - - // Convert to const T* const& - friend const T* from_python(PyObject* p, boost::python::type) - { return from_python(p, boost::python::type()); } - - // Convert to T* const& - friend T* from_python(PyObject* p, boost::python::type) - { return from_python(p, boost::python::type()); } - - // Convert to T& - friend T& from_python(PyObject* p, boost::python::type) - { return *boost::python::detail::check_non_null(from_python(p, boost::python::type())); } - - // Convert to const T& - friend const T& from_python(PyObject* p, boost::python::type) - { return from_python(p, boost::python::type()); } - - // Convert to T - friend const T& from_python(PyObject* p, boost::python::type) - { return from_python(p, boost::python::type()); } - - friend std::auto_ptr& from_python(PyObject* p, boost::python::type&>) { - return boost::python::detail::import_extension_class::get_converters()->auto_ptr_from_python(p); - } - - friend std::auto_ptr& from_python(PyObject* p, boost::python::type >) { - return boost::python::detail::import_extension_class::get_converters()->auto_ptr_from_python(p); - } - - friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&>) { - return boost::python::detail::import_extension_class::get_converters()->auto_ptr_from_python(p); - } - - friend PyObject* to_python(std::auto_ptr x) { - return boost::python::detail::import_extension_class::get_converters()->to_python(x); - } - - friend boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) { - return boost::python::detail::import_extension_class::get_converters()->shared_ptr_from_python(p); - } - - friend boost::shared_ptr& from_python(PyObject* p, boost::python::type >) { - return boost::python::detail::import_extension_class::get_converters()->shared_ptr_from_python(p); - } - - friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) { - return boost::python::detail::import_extension_class::get_converters()->shared_ptr_from_python(p); - } - - friend PyObject* to_python(boost::shared_ptr x) { - return boost::python::detail::import_extension_class::get_converters()->to_python(x); - } -}; - -BOOST_PYTHON_END_CONVERSION_NAMESPACE - -namespace boost { namespace python { - -BOOST_PYTHON_IMPORT_CONVERSION(python_import_extension_class_converters); - -// A pointer to this class is exported/imported via the Python API. -// All functions are virtual. This is, what we really export/import -// is essentially just a pointer to a vtbl. -template -struct export_converters_base -{ - virtual const int get_api_major() const { - return detail::EXPORT_CONVERTERS_API_MAJOR; } - virtual const int get_api_minor() const { - return detail::EXPORT_CONVERTERS_API_MINOR; } - virtual PyObject *to_python(const T& x) = 0; - virtual PyObject *to_python(std::auto_ptr x) = 0; - virtual PyObject *to_python(boost::shared_ptr x) = 0; - virtual T* Tptr_from_python(PyObject* obj) = 0; - virtual std::auto_ptr& auto_ptr_from_python(PyObject *obj) = 0; - virtual boost::shared_ptr& shared_ptr_from_python(PyObject *obj) = 0; -}; - -// Converters to be used if T is not copyable. -template -struct export_ptr_converters : export_converters_base -{ - virtual PyObject *to_python(const T& x) { - PyErr_SetString(PyExc_RuntimeError, - "to_python(const T&) converter not exported"); - throw import_error(); - } - virtual PyObject *to_python(std::auto_ptr x) { - return BOOST_PYTHON_CONVERSION::to_python(x); - } - virtual PyObject *to_python(boost::shared_ptr x) { - return BOOST_PYTHON_CONVERSION::to_python(x); - } - virtual T* Tptr_from_python(PyObject* obj) { - return BOOST_PYTHON_CONVERSION::from_python(obj, boost::python::type()); - } - virtual std::auto_ptr& auto_ptr_from_python(PyObject *obj) { - return BOOST_PYTHON_CONVERSION::python_extension_class_converters::ptr_from_python(obj, boost::python::type >()); - } - virtual boost::shared_ptr& shared_ptr_from_python(PyObject *obj) { - return BOOST_PYTHON_CONVERSION::python_extension_class_converters::ptr_from_python(obj, boost::python::type >()); - } -}; - -// The addditional to_python() converter that can be used if T is copyable. -template -struct export_converters : export_ptr_converters -{ - virtual PyObject *to_python(const T& x) { - BOOST_PYTHON_CONVERSION::python_extension_class_converters cv; - return cv.to_python(x); - } -}; - -namespace detail { - -//QUESTIONMARK -// A stripped-down, modified version of class extension_class. -// Would it make sense to establish a formal relationship -// between the two classes? -template -class import_extension_class - : public python_import_extension_class_converters -{ - public: - inline import_extension_class(const char *module, const char* klass) { - m_module = module; - m_klass = klass; - } - - static boost::python::export_converters_base* get_converters(); - - private: - static std::string m_module; - static std::string m_klass; - static boost::python::export_converters_base* imported_converters; -}; - -template std::string import_extension_class::m_module; -template std::string import_extension_class::m_klass; -template -boost::python::export_converters_base* -import_extension_class::imported_converters = 0; - -#ifdef SPECIAL_PYCVTSOBJECT - -// A special PyObject for passing pointers to export_converters_base -template -struct PyCvtsObject { - PyObject_HEAD - export_converters_base* cvts; -}; - -template -void DEL_PyCvtsObject(PyCvtsObject* self) { PyMem_DEL(self); } - -template -PyObject *create_PyCvtsObject(export_converters_base* cvts) -{ - static char PyCvtsObject_Type__doc__[] = - "Boost Python Library (BPL) converters objects to be exported from\n" - "one extension module to another."; - - static PyTypeObject PyCvtsObject_Type = { - PyObject_HEAD_INIT(&PyType_Type) - 0, /*ob_size*/ - "PyCvtsObject", /*tp_name*/ - sizeof(PyCvtsObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)(static_cast*)> - (DEL_PyCvtsObject)), /*tp_dealloc*/ - (printfunc)0, /*tp_print*/ - (getattrfunc)0, /*tp_getattr*/ - (setattrfunc)0, /*tp_setattr*/ - (cmpfunc)0, /*tp_compare*/ - (reprfunc)0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - (hashfunc)0, /*tp_hash*/ - (ternaryfunc)0, /*tp_call*/ - (reprfunc)0, /*tp_str*/ - - /* Space for future expansion */ - 0L,0L,0L,0L, - PyCvtsObject_Type__doc__ /* Documentation string */ - }; - - PyCvtsObject* self = PyObject_NEW(PyCvtsObject, &PyCvtsObject_Type); - if (self == 0) throw export_error(); - self->cvts = cvts; - return reinterpret_cast(self); -} - -#endif // SPECIAL_PYCVTSOBJECT - -template -boost::python::export_converters_base* -import_extension_class::get_converters() { - if (imported_converters == 0) { -#ifndef SPECIAL_PYCVTSOBJECT - void *cobject - = import_converters(m_module, m_klass, converters_attribute_name); - imported_converters - = static_cast*>(cobject); -#else - ref cvts_obj( - new_import_converters(m_module, m_klass, converters_attribute_name)); - PyCvtsObject* cvts = reinterpret_cast*>(cvts_obj.get()); - imported_converters = cvts->cvts; -#endif - 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; -} - -}}} // namespace boost::python::detail - -namespace boost { namespace python { - -//QUESTIONMARK -// A stripped-down, modified version of class class_builder. -// Would it make sense to establish a formal relationship -// between the two classes? -template -class import_class_builder - : python_import_extension_class_converters -{ - public: - import_class_builder(const char *module, const char* klass) - : m_class(new detail::import_extension_class(module, klass)) - { } - private: - - //QUESTIONMARK - //reference > m_class; - boost::shared_ptr > m_class; -}; - -}} // namespace boost::python - -namespace boost { namespace python { - -// A class_builder that exports the converter functions. -template , - class C = export_converters > -class x_class_builder - : public class_builder -{ - private: - static C export_cvts; - - public: - x_class_builder(module_builder& module, const char* name) - : class_builder(module, name) { -#ifndef SPECIAL_PYCVTSOBJECT - add( - ref(PyCObject_FromVoidPtr(reinterpret_cast(&export_cvts), NULL)), - const_cast(detail::converters_attribute_name.c_str())); -#else - add(ref(detail::create_PyCvtsObject(&export_cvts)), - const_cast(detail::converters_attribute_name.c_str())); -#endif - } -}; - -template -C x_class_builder::export_cvts; - -//QUESTIONMARK -// Is there a better way of making it easy for the end-user -// to choose between x_class_builder and xptr_class_builder? -template , - class C = export_ptr_converters > -class xptr_class_builder : public x_class_builder -{ - public: - xptr_class_builder(module_builder& module, const char* name) - : x_class_builder(module, name) { } -}; - -}} // namespace boost::python - -#endif // X_CLASS_BUILDER_HPP From 2d568b1c0fd9b786d93b10e5f96a9118ce865274 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 6 Mar 2001 01:13:35 +0000 Subject: [PATCH 070/154] Fixed a bug which prevented auto_ptr values from being converted to_python [SVN r9455] --- include/boost/python/detail/extension_class.hpp | 14 ++++++++++---- src/gen_extclass.py | 16 +++++++++++----- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/include/boost/python/detail/extension_class.hpp b/include/boost/python/detail/extension_class.hpp index 4afffcae..125f1eed 100644 --- a/include/boost/python/detail/extension_class.hpp +++ b/include/boost/python/detail/extension_class.hpp @@ -9,6 +9,10 @@ // This file automatically generated for 10-argument constructors by // gen_extclass.python +// Revision History: +// 05 Mar 01 Fixed a bug which prevented auto_ptr values from being converted +// to_python (Dave Abrahams) + #ifndef EXTENSION_CLASS_DWA052000_H_ # define EXTENSION_CLASS_DWA052000_H_ @@ -250,10 +254,12 @@ class python_extension_class_converters throw boost::python::argument_error(); } - // Extract from obj a constant reference to the PtrType object which is holding a T. - // If obj is None, the reference denotes a default-constructed PtrType + // Extract from obj a reference to the PtrType object which is holding a + // T. If it weren't for auto_ptr, it would be a constant reference. Do not + // modify the referent except by copying an auto_ptr! If obj is None, the + // reference denotes a default-constructed PtrType template - static const PtrType& smart_ptr_value(PyObject* obj, boost::python::type) + static PtrType& smart_ptr_value(PyObject* obj, boost::python::type) { if (obj == Py_None) { @@ -315,7 +321,7 @@ class python_extension_class_converters friend std::auto_ptr& from_python(PyObject* p, boost::python::type&>) { return smart_ptr_reference(p, boost::python::type >()); } - friend const std::auto_ptr& from_python(PyObject* p, boost::python::type >) + friend std::auto_ptr from_python(PyObject* p, boost::python::type >) { return smart_ptr_value(p, boost::python::type >()); } friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&>) diff --git a/src/gen_extclass.py b/src/gen_extclass.py index 2d261289..8de8a1ae 100644 --- a/src/gen_extclass.py +++ b/src/gen_extclass.py @@ -14,6 +14,10 @@ def gen_extclass(args): // This file automatically generated for %d-argument constructors by // gen_extclass.python +// Revision History: +// 05 Mar 01 Fixed a bug which prevented auto_ptr values from being converted +// to_python (Dave Abrahams) + #ifndef EXTENSION_CLASS_DWA052000_H_ # define EXTENSION_CLASS_DWA052000_H_ @@ -157,7 +161,7 @@ template bool is_null(const Ptr& x) { return is_null_helper<(is_pointer::value)>::test(x); -}; +} }}} // namespace boost::python::detail @@ -255,10 +259,12 @@ class python_extension_class_converters throw boost::python::argument_error(); } - // Extract from obj a constant reference to the PtrType object which is holding a T. - // If obj is None, the reference denotes a default-constructed PtrType + // Extract from obj a reference to the PtrType object which is holding a + // T. If it weren't for auto_ptr, it would be a constant reference. Do not + // modify the referent except by copying an auto_ptr! If obj is None, the + // reference denotes a default-constructed PtrType template - static const PtrType& smart_ptr_value(PyObject* obj, boost::python::type) + static PtrType& smart_ptr_value(PyObject* obj, boost::python::type) { if (obj == Py_None) { @@ -320,7 +326,7 @@ class python_extension_class_converters friend std::auto_ptr& from_python(PyObject* p, boost::python::type&>) { return smart_ptr_reference(p, boost::python::type >()); } - friend const std::auto_ptr& from_python(PyObject* p, boost::python::type >) + friend std::auto_ptr from_python(PyObject* p, boost::python::type >) { return smart_ptr_value(p, boost::python::type >()); } friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&>) From b0d6d40c2a800159cacbe796f96c069ec503fc2a Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 6 Mar 2001 01:14:47 +0000 Subject: [PATCH 071/154] Suppress warnings under Cygwin with Python 2.0 [SVN r9456] --- include/boost/python/detail/wrap_python.hpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/include/boost/python/detail/wrap_python.hpp b/include/boost/python/detail/wrap_python.hpp index d5b75374..b7a47513 100644 --- a/include/boost/python/detail/wrap_python.hpp +++ b/include/boost/python/detail/wrap_python.hpp @@ -16,9 +16,13 @@ // compiler command-line. // Revision History: +// 05 Mar 01 Suppress warnings under Cygwin with Python 2.0 (Dave Abrahams) // 04 Mar 01 Rolled in some changes from the Dragon fork (Dave Abrahams) // 01 Mar 01 define PyObject_INIT() for Python 1.x (Dave Abrahams) + +#include + #ifdef _DEBUG # ifndef BOOST_DEBUG_PYTHON # undef _DEBUG // Don't let Python force the debug library just because we're debugging. @@ -37,9 +41,11 @@ typedef int pid_t; # define WORD_BIT 32 # define hypot _hypot # include -# define HAVE_CLOCK -# define HAVE_STRFTIME -# define HAVE_STRERROR +# 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 From dd0e42cf7252e41d3c3e1c5d5854d614c446d57a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 6 Mar 2001 02:44:32 +0000 Subject: [PATCH 072/154] temp files before branching [SVN r9457] --- example/dvect.cpp | 68 ++++++++++++++++++++++++++++++++++ example/dvect.h | 32 ++++++++++++++++ example/ivect.cpp | 68 ++++++++++++++++++++++++++++++++++ example/ivect.h | 32 ++++++++++++++++ example/noncopyable.h | 14 +++++++ example/noncopyable_export.cpp | 23 ++++++++++++ example/noncopyable_import.cpp | 41 ++++++++++++++++++++ example/tst_dvect.py | 16 ++++++++ example/tst_ivect.py | 16 ++++++++ example/tst_noncopyable.py | 8 ++++ 10 files changed, 318 insertions(+) create mode 100644 example/dvect.cpp create mode 100644 example/dvect.h create mode 100644 example/ivect.cpp create mode 100644 example/ivect.h create mode 100644 example/noncopyable.h create mode 100644 example/noncopyable_export.cpp create mode 100644 example/noncopyable_import.cpp create mode 100644 example/tst_dvect.py create mode 100644 example/tst_ivect.py create mode 100644 example/tst_noncopyable.py diff --git a/example/dvect.cpp b/example/dvect.cpp new file mode 100644 index 00000000..47f70d3b --- /dev/null +++ b/example/dvect.cpp @@ -0,0 +1,68 @@ +#include "ivect.h" +#include "dvect.h" +#include +namespace python = boost::python; + +namespace { + + vects::ivect dvect_as_ivect(const vects::dvect& dv) + { + vects::ivect iv(dv.size()); + vects::ivect::iterator iviter = iv.begin(); + for (int i = 0; i < dv.size(); i++) iviter[i] = static_cast(dv[i]); + return iv; + } + + boost::python::tuple ivect_as_tuple(const vects::ivect& iv) + { + return iv.as_tuple(); + } + + std::auto_ptr auto_ptr_ivect(const vects::dvect& dv) + { + return std::auto_ptr(new vects::ivect(dvect_as_ivect(dv))); + } + + boost::shared_ptr shared_ptr_ivect(const vects::dvect& dv) + { + return boost::shared_ptr(new vects::ivect(dvect_as_ivect(dv))); + } + + boost::python::tuple auto_ptr_ivect_as_tuple(std::auto_ptr& iv) + { + return iv->as_tuple(); + } + + boost::python::tuple shared_ptr_ivect_as_tuple(boost::shared_ptr& iv) + { + return iv->as_tuple(); + } +} + +extern "C" +DL_EXPORT(void) +initdvect() +{ + try + { + python::module_builder this_module("dvect"); + + python::x_class_builder dvect_class(this_module, "dvect"); + + python::import_class_builder ivect_class("ivect", "ivect"); + + dvect_class.def(python::constructor()); + dvect_class.def(&vects::dvect::as_tuple, "as_tuple"); + dvect_class.def(dvect_as_ivect, "as_ivect"); + + this_module.def(ivect_as_tuple, "ivect_as_tuple"); + dvect_class.def(auto_ptr_ivect, "auto_ptr_ivect"); + dvect_class.def(shared_ptr_ivect, "shared_ptr_ivect"); + this_module.def(auto_ptr_ivect_as_tuple, "auto_ptr_ivect_as_tuple"); + this_module.def(shared_ptr_ivect_as_tuple, "shared_ptr_ivect_as_tuple"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/dvect.h b/example/dvect.h new file mode 100644 index 00000000..8ffe7b50 --- /dev/null +++ b/example/dvect.h @@ -0,0 +1,32 @@ +#ifndef DVECT_H +#define DVECT_H + +#include +#include + +namespace vects { + + struct dvect : public std::vector + { + dvect() : std::vector() {} + dvect(size_t n) : std::vector(n) {} + dvect(boost::python::tuple tuple) : std::vector(tuple.size()) + { + std::vector::iterator v_it = begin(); + for (int i = 0; i < tuple.size(); i++) + v_it[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), + boost::python::type()); + } + + boost::python::tuple as_tuple() const + { + boost::python::tuple t(size()); + for (int i = 0; i < size(); i++) + t.set_item(i, + boost::python::ref(BOOST_PYTHON_CONVERSION::to_python((*this)[i]))); + return t; + } + }; +} + +#endif // DVECT_H diff --git a/example/ivect.cpp b/example/ivect.cpp new file mode 100644 index 00000000..dfd90fc9 --- /dev/null +++ b/example/ivect.cpp @@ -0,0 +1,68 @@ +#include "ivect.h" +#include "dvect.h" +#include +namespace python = boost::python; + +namespace { + + vects::dvect ivect_as_dvect(const vects::ivect& iv) + { + vects::dvect dv(iv.size()); + vects::dvect::iterator dviter = dv.begin(); + for (int i = 0; i < iv.size(); i++) dviter[i] = static_cast(iv[i]); + return dv; + } + + boost::python::tuple dvect_as_tuple(const vects::dvect& dv) + { + return dv.as_tuple(); + } + + std::auto_ptr auto_ptr_dvect(const vects::ivect& iv) + { + return std::auto_ptr(new vects::dvect(ivect_as_dvect(iv))); + } + + boost::shared_ptr shared_ptr_dvect(const vects::ivect& iv) + { + return boost::shared_ptr(new vects::dvect(ivect_as_dvect(iv))); + } + + boost::python::tuple auto_ptr_dvect_as_tuple(std::auto_ptr& dv) + { + return dv->as_tuple(); + } + + boost::python::tuple shared_ptr_dvect_as_tuple(boost::shared_ptr& dv) + { + return dv->as_tuple(); + } +} + +extern "C" +DL_EXPORT(void) +initivect() +{ + try + { + python::module_builder this_module("ivect"); + + python::x_class_builder ivect_class(this_module, "ivect"); + + python::import_class_builder dvect_class("dvect", "dvect"); + + ivect_class.def(python::constructor()); + ivect_class.def(&vects::ivect::as_tuple, "as_tuple"); + ivect_class.def(ivect_as_dvect, "as_dvect"); + + this_module.def(dvect_as_tuple, "dvect_as_tuple"); + ivect_class.def(auto_ptr_dvect, "auto_ptr_dvect"); + ivect_class.def(shared_ptr_dvect, "shared_ptr_dvect"); + this_module.def(auto_ptr_dvect_as_tuple, "auto_ptr_dvect_as_tuple"); + this_module.def(shared_ptr_dvect_as_tuple, "shared_ptr_dvect_as_tuple"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/ivect.h b/example/ivect.h new file mode 100644 index 00000000..a0187307 --- /dev/null +++ b/example/ivect.h @@ -0,0 +1,32 @@ +#ifndef IVECT_H +#define IVECT_H + +#include +#include + +namespace vects { + + struct ivect : public std::vector + { + ivect() : std::vector() {} + ivect(size_t n) : std::vector(n) {} + ivect(boost::python::tuple tuple) : std::vector(tuple.size()) + { + std::vector::iterator v_it = begin(); + for (int i = 0; i < tuple.size(); i++) + v_it[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), + boost::python::type()); + } + + boost::python::tuple as_tuple() const + { + boost::python::tuple t(size()); + for (int i = 0; i < size(); i++) + t.set_item(i, + boost::python::ref(BOOST_PYTHON_CONVERSION::to_python((*this)[i]))); + return t; + } + }; +} + +#endif // IVECT_H diff --git a/example/noncopyable.h b/example/noncopyable.h new file mode 100644 index 00000000..de7b3672 --- /dev/null +++ b/example/noncopyable.h @@ -0,0 +1,14 @@ +#ifndef NONCOPYABLE_H +#define NONCOPYABLE_H + +class store +{ + private: + store(const store&) { } // Disable the copy constructor. + int number; + public: + store(const int i) : number(i) { } + int recall() const { return number; } +}; + +#endif // NONCOPYABLE_H diff --git a/example/noncopyable_export.cpp b/example/noncopyable_export.cpp new file mode 100644 index 00000000..31cbe7c8 --- /dev/null +++ b/example/noncopyable_export.cpp @@ -0,0 +1,23 @@ +#include +namespace python = boost::python; + +#include "noncopyable.h" + +extern "C" +DL_EXPORT(void) +initnoncopyable_export() +{ + try + { + python::module_builder this_module("noncopyable_export"); + + python::xptr_class_builder store_class(this_module, "store"); + + store_class.def(python::constructor()); + store_class.def(&store::recall, "recall"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/noncopyable_import.cpp b/example/noncopyable_import.cpp new file mode 100644 index 00000000..f2b2c6d0 --- /dev/null +++ b/example/noncopyable_import.cpp @@ -0,0 +1,41 @@ +#include +namespace python = boost::python; + +#include "noncopyable.h" + +namespace { // Avoid cluttering the global namespace. + + // A function with store objects as both input and output parameters. + // Because the copy constructor is disabled, we cannot pass a store + // object by value. Instead, we pass a smart pointer. + std::auto_ptr add_stores(const store& s1, const store& s2) + { + int sum = s1.recall() + s2.recall(); + std::auto_ptr ss = std::auto_ptr(new store(sum)); + return ss; + } +} + +extern "C" +DL_EXPORT(void) +initnoncopyable_import() +{ + try + { + python::module_builder this_module("noncopyable_import"); + + python::import_class_builder + dvect_class("noncopyable_export", "store"); + + // Imagine all the additional classes with member functions + // that have store objects as input and output parameters. + // Lots and lots of them. + // However, to keep this example simple, we only define a + // module-level function. + this_module.def(add_stores, "add_stores"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/tst_dvect.py b/example/tst_dvect.py new file mode 100644 index 00000000..563f0ad5 --- /dev/null +++ b/example/tst_dvect.py @@ -0,0 +1,16 @@ +import dvect +print dvect.dvect.__converters__ +dv = dvect.dvect((1,2,3,4,5)) +print dv +print dv.as_tuple() +iv = dv.as_ivect() +print iv +print iv.as_tuple() +print dvect.ivect_as_tuple(iv) +aiv = dv.auto_ptr_ivect() +print aiv +siv = dv.shared_ptr_ivect() +print dvect.auto_ptr_ivect_as_tuple(aiv) +print dvect.ivect_as_tuple(aiv) +print dvect.shared_ptr_ivect_as_tuple(siv) +print dvect.ivect_as_tuple(siv) diff --git a/example/tst_ivect.py b/example/tst_ivect.py new file mode 100644 index 00000000..58bc323f --- /dev/null +++ b/example/tst_ivect.py @@ -0,0 +1,16 @@ +import ivect +print ivect.ivect.__converters__ +iv = ivect.ivect((1,2,3,4,5)) +print iv +print iv.as_tuple() +dv = iv.as_dvect() +print dv +print dv.as_tuple() +print ivect.dvect_as_tuple(dv) +adv = iv.auto_ptr_dvect() +print adv +sdv = iv.shared_ptr_dvect() +print ivect.auto_ptr_dvect_as_tuple(adv) +print ivect.dvect_as_tuple(adv) +print ivect.shared_ptr_dvect_as_tuple(sdv) +print ivect.dvect_as_tuple(sdv) diff --git a/example/tst_noncopyable.py b/example/tst_noncopyable.py new file mode 100644 index 00000000..913df039 --- /dev/null +++ b/example/tst_noncopyable.py @@ -0,0 +1,8 @@ +import noncopyable_export +import noncopyable_import +s1 = noncopyable_export.store(1) +print s1.recall() +s2 = noncopyable_export.store(2) +print s2.recall() +s3 = noncopyable_import.add_stores(s1, s2) +print s3.recall() From 53d2398e0654b67463c4326b7dc8ba134d925711 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 6 Mar 2001 02:45:39 +0000 Subject: [PATCH 073/154] remove temp files after branching. [SVN r9459] --- example/dvect.cpp | 68 ---------------------------------- example/dvect.h | 32 ---------------- example/ivect.cpp | 68 ---------------------------------- example/ivect.h | 32 ---------------- example/noncopyable.h | 14 ------- example/noncopyable_export.cpp | 23 ------------ example/noncopyable_import.cpp | 41 -------------------- example/tst_dvect.py | 16 -------- example/tst_ivect.py | 16 -------- example/tst_noncopyable.py | 8 ---- 10 files changed, 318 deletions(-) delete mode 100644 example/dvect.cpp delete mode 100644 example/dvect.h delete mode 100644 example/ivect.cpp delete mode 100644 example/ivect.h delete mode 100644 example/noncopyable.h delete mode 100644 example/noncopyable_export.cpp delete mode 100644 example/noncopyable_import.cpp delete mode 100644 example/tst_dvect.py delete mode 100644 example/tst_ivect.py delete mode 100644 example/tst_noncopyable.py diff --git a/example/dvect.cpp b/example/dvect.cpp deleted file mode 100644 index 47f70d3b..00000000 --- a/example/dvect.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "ivect.h" -#include "dvect.h" -#include -namespace python = boost::python; - -namespace { - - vects::ivect dvect_as_ivect(const vects::dvect& dv) - { - vects::ivect iv(dv.size()); - vects::ivect::iterator iviter = iv.begin(); - for (int i = 0; i < dv.size(); i++) iviter[i] = static_cast(dv[i]); - return iv; - } - - boost::python::tuple ivect_as_tuple(const vects::ivect& iv) - { - return iv.as_tuple(); - } - - std::auto_ptr auto_ptr_ivect(const vects::dvect& dv) - { - return std::auto_ptr(new vects::ivect(dvect_as_ivect(dv))); - } - - boost::shared_ptr shared_ptr_ivect(const vects::dvect& dv) - { - return boost::shared_ptr(new vects::ivect(dvect_as_ivect(dv))); - } - - boost::python::tuple auto_ptr_ivect_as_tuple(std::auto_ptr& iv) - { - return iv->as_tuple(); - } - - boost::python::tuple shared_ptr_ivect_as_tuple(boost::shared_ptr& iv) - { - return iv->as_tuple(); - } -} - -extern "C" -DL_EXPORT(void) -initdvect() -{ - try - { - python::module_builder this_module("dvect"); - - python::x_class_builder dvect_class(this_module, "dvect"); - - python::import_class_builder ivect_class("ivect", "ivect"); - - dvect_class.def(python::constructor()); - dvect_class.def(&vects::dvect::as_tuple, "as_tuple"); - dvect_class.def(dvect_as_ivect, "as_ivect"); - - this_module.def(ivect_as_tuple, "ivect_as_tuple"); - dvect_class.def(auto_ptr_ivect, "auto_ptr_ivect"); - dvect_class.def(shared_ptr_ivect, "shared_ptr_ivect"); - this_module.def(auto_ptr_ivect_as_tuple, "auto_ptr_ivect_as_tuple"); - this_module.def(shared_ptr_ivect_as_tuple, "shared_ptr_ivect_as_tuple"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/dvect.h b/example/dvect.h deleted file mode 100644 index 8ffe7b50..00000000 --- a/example/dvect.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef DVECT_H -#define DVECT_H - -#include -#include - -namespace vects { - - struct dvect : public std::vector - { - dvect() : std::vector() {} - dvect(size_t n) : std::vector(n) {} - dvect(boost::python::tuple tuple) : std::vector(tuple.size()) - { - std::vector::iterator v_it = begin(); - for (int i = 0; i < tuple.size(); i++) - v_it[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), - boost::python::type()); - } - - boost::python::tuple as_tuple() const - { - boost::python::tuple t(size()); - for (int i = 0; i < size(); i++) - t.set_item(i, - boost::python::ref(BOOST_PYTHON_CONVERSION::to_python((*this)[i]))); - return t; - } - }; -} - -#endif // DVECT_H diff --git a/example/ivect.cpp b/example/ivect.cpp deleted file mode 100644 index dfd90fc9..00000000 --- a/example/ivect.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "ivect.h" -#include "dvect.h" -#include -namespace python = boost::python; - -namespace { - - vects::dvect ivect_as_dvect(const vects::ivect& iv) - { - vects::dvect dv(iv.size()); - vects::dvect::iterator dviter = dv.begin(); - for (int i = 0; i < iv.size(); i++) dviter[i] = static_cast(iv[i]); - return dv; - } - - boost::python::tuple dvect_as_tuple(const vects::dvect& dv) - { - return dv.as_tuple(); - } - - std::auto_ptr auto_ptr_dvect(const vects::ivect& iv) - { - return std::auto_ptr(new vects::dvect(ivect_as_dvect(iv))); - } - - boost::shared_ptr shared_ptr_dvect(const vects::ivect& iv) - { - return boost::shared_ptr(new vects::dvect(ivect_as_dvect(iv))); - } - - boost::python::tuple auto_ptr_dvect_as_tuple(std::auto_ptr& dv) - { - return dv->as_tuple(); - } - - boost::python::tuple shared_ptr_dvect_as_tuple(boost::shared_ptr& dv) - { - return dv->as_tuple(); - } -} - -extern "C" -DL_EXPORT(void) -initivect() -{ - try - { - python::module_builder this_module("ivect"); - - python::x_class_builder ivect_class(this_module, "ivect"); - - python::import_class_builder dvect_class("dvect", "dvect"); - - ivect_class.def(python::constructor()); - ivect_class.def(&vects::ivect::as_tuple, "as_tuple"); - ivect_class.def(ivect_as_dvect, "as_dvect"); - - this_module.def(dvect_as_tuple, "dvect_as_tuple"); - ivect_class.def(auto_ptr_dvect, "auto_ptr_dvect"); - ivect_class.def(shared_ptr_dvect, "shared_ptr_dvect"); - this_module.def(auto_ptr_dvect_as_tuple, "auto_ptr_dvect_as_tuple"); - this_module.def(shared_ptr_dvect_as_tuple, "shared_ptr_dvect_as_tuple"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/ivect.h b/example/ivect.h deleted file mode 100644 index a0187307..00000000 --- a/example/ivect.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef IVECT_H -#define IVECT_H - -#include -#include - -namespace vects { - - struct ivect : public std::vector - { - ivect() : std::vector() {} - ivect(size_t n) : std::vector(n) {} - ivect(boost::python::tuple tuple) : std::vector(tuple.size()) - { - std::vector::iterator v_it = begin(); - for (int i = 0; i < tuple.size(); i++) - v_it[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), - boost::python::type()); - } - - boost::python::tuple as_tuple() const - { - boost::python::tuple t(size()); - for (int i = 0; i < size(); i++) - t.set_item(i, - boost::python::ref(BOOST_PYTHON_CONVERSION::to_python((*this)[i]))); - return t; - } - }; -} - -#endif // IVECT_H diff --git a/example/noncopyable.h b/example/noncopyable.h deleted file mode 100644 index de7b3672..00000000 --- a/example/noncopyable.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef NONCOPYABLE_H -#define NONCOPYABLE_H - -class store -{ - private: - store(const store&) { } // Disable the copy constructor. - int number; - public: - store(const int i) : number(i) { } - int recall() const { return number; } -}; - -#endif // NONCOPYABLE_H diff --git a/example/noncopyable_export.cpp b/example/noncopyable_export.cpp deleted file mode 100644 index 31cbe7c8..00000000 --- a/example/noncopyable_export.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include -namespace python = boost::python; - -#include "noncopyable.h" - -extern "C" -DL_EXPORT(void) -initnoncopyable_export() -{ - try - { - python::module_builder this_module("noncopyable_export"); - - python::xptr_class_builder store_class(this_module, "store"); - - store_class.def(python::constructor()); - store_class.def(&store::recall, "recall"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/noncopyable_import.cpp b/example/noncopyable_import.cpp deleted file mode 100644 index f2b2c6d0..00000000 --- a/example/noncopyable_import.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -namespace python = boost::python; - -#include "noncopyable.h" - -namespace { // Avoid cluttering the global namespace. - - // A function with store objects as both input and output parameters. - // Because the copy constructor is disabled, we cannot pass a store - // object by value. Instead, we pass a smart pointer. - std::auto_ptr add_stores(const store& s1, const store& s2) - { - int sum = s1.recall() + s2.recall(); - std::auto_ptr ss = std::auto_ptr(new store(sum)); - return ss; - } -} - -extern "C" -DL_EXPORT(void) -initnoncopyable_import() -{ - try - { - python::module_builder this_module("noncopyable_import"); - - python::import_class_builder - dvect_class("noncopyable_export", "store"); - - // Imagine all the additional classes with member functions - // that have store objects as input and output parameters. - // Lots and lots of them. - // However, to keep this example simple, we only define a - // module-level function. - this_module.def(add_stores, "add_stores"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/tst_dvect.py b/example/tst_dvect.py deleted file mode 100644 index 563f0ad5..00000000 --- a/example/tst_dvect.py +++ /dev/null @@ -1,16 +0,0 @@ -import dvect -print dvect.dvect.__converters__ -dv = dvect.dvect((1,2,3,4,5)) -print dv -print dv.as_tuple() -iv = dv.as_ivect() -print iv -print iv.as_tuple() -print dvect.ivect_as_tuple(iv) -aiv = dv.auto_ptr_ivect() -print aiv -siv = dv.shared_ptr_ivect() -print dvect.auto_ptr_ivect_as_tuple(aiv) -print dvect.ivect_as_tuple(aiv) -print dvect.shared_ptr_ivect_as_tuple(siv) -print dvect.ivect_as_tuple(siv) diff --git a/example/tst_ivect.py b/example/tst_ivect.py deleted file mode 100644 index 58bc323f..00000000 --- a/example/tst_ivect.py +++ /dev/null @@ -1,16 +0,0 @@ -import ivect -print ivect.ivect.__converters__ -iv = ivect.ivect((1,2,3,4,5)) -print iv -print iv.as_tuple() -dv = iv.as_dvect() -print dv -print dv.as_tuple() -print ivect.dvect_as_tuple(dv) -adv = iv.auto_ptr_dvect() -print adv -sdv = iv.shared_ptr_dvect() -print ivect.auto_ptr_dvect_as_tuple(adv) -print ivect.dvect_as_tuple(adv) -print ivect.shared_ptr_dvect_as_tuple(sdv) -print ivect.dvect_as_tuple(sdv) diff --git a/example/tst_noncopyable.py b/example/tst_noncopyable.py deleted file mode 100644 index 913df039..00000000 --- a/example/tst_noncopyable.py +++ /dev/null @@ -1,8 +0,0 @@ -import noncopyable_export -import noncopyable_import -s1 = noncopyable_export.store(1) -print s1.recall() -s2 = noncopyable_export.store(2) -print s2.recall() -s3 = noncopyable_import.add_stores(s1, s2) -print s3.recall() From 116b3db1d1b6ebbaab7aca99401b6a8dd332d613 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 6 Mar 2001 20:55:09 +0000 Subject: [PATCH 074/154] Fixed typo in use of "PYTHON_LIB" [SVN r9467] --- build/como.mak | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/como.mak b/build/como.mak index c6f340a5..581eefea 100644 --- a/build/como.mak +++ b/build/como.mak @@ -1,5 +1,7 @@ # Revision History: +# 06 Mar 01 Fixed typo in use of "PYTHON_LIB" (Dave Abrahams) # 04 Mar 01 Changed library name to libboost_python.a (David Abrahams) + LIBSRC = \ classes.cpp \ conversions.cpp \ @@ -33,7 +35,7 @@ endif [ -s $@ ] || rm -f $@ example1: example1.o libboost_python.a - como-dyn-link -o ../example/hellomodule.$(MODULE_EXTENSION) $(PYHTON_LIB) example1.o -L. -lboost_python + como-dyn-link -o ../example/hellomodule.$(MODULE_EXTENSION) $(PYTHON_LIB) example1.o -L. -lboost_python python ../example/test_example1.py example1.o: ../example/example1.cpp From 617bcdac9f81d1486c585158b9c7694f2f5c48fd Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 7 Mar 2001 03:39:31 +0000 Subject: [PATCH 075/154] Major doc updates [SVN r9470] --- doc/building.html | 195 +++++++++++++++++++++++++++++-------- doc/comparisons.html | 61 +++++++----- doc/enums.html | 43 +++++--- doc/example1.html | 112 ++++++--------------- doc/exporting_classes.html | 144 +++++++++++++++++++++++++++ doc/extending.html | 4 +- doc/index.html | 91 +++++++++-------- doc/inheritance.html | 26 ++--- doc/overloading.html | 6 +- doc/overriding.html | 98 +++++++++++-------- doc/pickle.html | 28 +++--- doc/pointers.html | 4 +- doc/special.html | 28 +++--- doc/under-the-hood.html | 4 +- 14 files changed, 551 insertions(+), 293 deletions(-) create mode 100644 doc/exporting_classes.html diff --git a/doc/building.html b/doc/building.html index 4ac2343c..6627bbe8 100644 --- a/doc/building.html +++ b/doc/building.html @@ -1,44 +1,157 @@ - - - Building an Extension Module - + + + + + Building an Extension Module +
      -

      - c++boost.gif (8819 bytes)Building an Extension Module -

      -

      - Right now, the only supported configuration is one in which the BPL - source files are statically linked with the source for your extension - module. You may first build them into a library and link it with your - extension module source, but the effect is the same as compiling all - the source files together. Some users have successfully built the - sources into a shared library, and support for a shared library - build is planned, but not yet implemented. The BPL source files are: -

      -
      -extclass.cpp
      -functions.cpp
      -init_function.cpp
      -module.cpp
      -newtypes.cpp
      -objects.cpp
      -py.cpp
      -subclass.cpp
      -         
      -
      -

      - Next: Enums - Previous: A Peek Under the Hood - Up: Top -

      - © Copyright David Abrahams 2000. Permission to copy, use, modify, - sell and distribute this document is granted provided this copyright - notice appears in all copies. This document is provided ``as - is'' without express or implied warranty, and with no claim as to - its suitability for any purpose. -

      - Updated: Nov 26, 2000 +

      c++boost.gif (8819 bytes)Building an + Extension Module

      + +

      The build process for Boost is currently undergoing some evolution, + and, it is to be hoped, improvement. The following facts may help: + +

        +
      • + Makefiles for various platforms reside in the Boost subdirectory + libs/python/build: + +
          +
        • como.mak (Comeau C++ on Linux) + +
        • linux_gcc.mak (GCC on + Linux/Unix) + +
        • gcc.mak (older makefile for GCC + on Linux/Unix. Deprecated.) + +
        • mingw32.mak + (highly-specialized makefile for mingw32 (Win32-targeted) GCC. Read + the header comment). + +
        • tru64_cxx.mak (Compaq + Alpha). +
        +
        + +
      • + A project workspace for Microsoft Visual Studio is provided at libs/python/build/build.dsw. The + include paths for this project may need to be changed for your + installation. They currently assume that python has been installed at + c:\tools\python. Three configurations of all targets are + supported: + +
          +
        • Release (optimization, -DNDEBUG) + +
        • Debug (no optimization -D_DEBUG) + +
        • DebugPython (no optimization, -D_DEBUG + -DBOOST_DEBUG_PYTHON) +
        + +

        When extension modules are built with Visual C++ using + -D_DEBUG, Python defaults to force linking with a + special debugging version of the Python DLL. Since this debug DLL + isn't supplied with the default Python installation for Windows, + Boost.Python uses boost/python/detail/wrap_python.hpp + to temporarily undefine _DEBUG when Python.h is + #included. + +

        If you want the extra runtime checks available with the debugging + version of the library, #define BOOST_DEBUG_PYTHON to + re-enable library forcing, and link with the DebugPython version of + boost_python.lib. You'll need to get the debugging version + of the Python executable (python_d.exe) and DLL + (python20_d.dll or python15_d.dll). The Python + sources include project files for building these. If you download them, change the name of the + top-level directory to src, and install it under + c:\tools\python, the workspace supplied by Boost.Python will + be able to use it without modification. Just open + c:\tools\python\src\pcbuild\pcbuild.dsw and invoke "build + all" to generate all the debugging targets. + +

        If you do not #define BOOST_DEBUG_PYTHON, be sure that + any source files #include <boost/python/detail/wrap_python.hpp> + instead of the usual Python.h, or you will have link + incompatibilities.
        +
        + + +

      • + The makefiles and Visual Studio project can all build at least the + following: + +
          +
        • The boost_python library for static linking with your + extension module. On the various Unices, this library will be + called libboost_python.a. On Win32 platforms, the library + will be called boost_python.lib. + +
        • A comprehensive test of Boost.Python features. This test builds + a Boost.Python extension module, then runs Python to import the + module, and runs a series of tests on it using doctest. Source code for the module + and tests is available in the Boost subdirectory + libs/python/test.
          + + +
        • Various examples from the Boost subdirectory + libs/python/example. Which examples are built currently + depends on the platform. The most up-to-date examples are + getting_startedn.cpp from Ralf W. + Grosse-Kunstleve. All these examples include a doctest modeled + on the comprehensive test above.
          +
          + +
        + +
      • + If your platform isn't directly supported, you can build a static + library from the following source files (in the Boost subdirectory + libs/python/src), or compile them directly and link the + resulting objects into your extension module: + + +
      + +

      Next: Wrapping Enums Previous: A Peek Under the Hood Up: Top + +

      © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided ``as is'' without + express or implied warranty, and with no claim as to its suitability for + any purpose. + +

      Updated: Mar 6, 2001

      diff --git a/doc/comparisons.html b/doc/comparisons.html index 336220fb..6f082d51 100644 --- a/doc/comparisons.html +++ b/doc/comparisons.html @@ -6,13 +6,14 @@

      c++boost.gif (8819 bytes)Comparisons with + src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">
      + Comparisons with Other Systems

      CXX

      - Like BPL, CXX attempts to + Like Boost.Python, CXX attempts to provide a C++-oriented interface to Python. In most cases, as with the boost library, it relieves the user from worrying about reference-counts. Both libraries automatically convert thrown C++ @@ -40,9 +41,15 @@

      As far as I can tell, CXX enables one to write what is essentially idiomatic Python code in C++, manipulating Python objects through the - same fully-generic interfaces we use in Python. While you're hardly programming directly to the ``bare - metal'' with CXX, it basically presents a ``C++-ized'' - version of the Python 'C' API. + same fully-generic interfaces we use in Python. While you're hardly + programming directly to the ``bare metal'' with CXX, it basically + presents a ``C++-ized'' version of the Python 'C' API. Some fraction of + that capability is available in Boost.Python through boost/python/objects.hpp, + which provides C++ objects corresponding to Python lists, tuples, + strings, and dictionaries, and through boost/python/callback.hpp, + which allows you to call back into python with C++ arguments.

      Paul F. Dubois, the original @@ -65,7 +72,7 @@ that.''
      -Paul Dubois languages. Swig relies on a parser to read your source code and produce additional source code files which can be compiled into a Python (or Perl or Tcl) extension module. It has been successfully used to create - many Python extension modules. Like BPL, SWIG is trying to allow an + many Python extension modules. Like Boost.Python, SWIG is trying to allow an existing interface to be wrapped with little or no change to the existing code. The documentation says ``SWIG parses a form of ANSI C syntax that has been extended with a number of special directives. As a @@ -78,15 +85,15 @@ that.''
      -Paul Dubois couldnt handle templates, didnt do func overloading properly etc. For ANSI C libraries this was fine. But for usual C++ code this was a problem. Simple things work. But for anything very complicated (or - realistic), one had to write code by hand. I believe BPL doesn't have + realistic), one had to write code by hand. I believe Boost.Python doesn't have this problem[sic]... IMHO overloaded functions are very important to wrap correctly.''
      -Prabhu Ramachandran

  • - By contrast, BPL doesn't attempt to parse C++ - the problem is simply + By contrast, Boost.Python doesn't attempt to parse C++ - the problem is simply too complex to do correctly. Technically, one does - write code by hand to use BPL. The goal, however, has been to make + write code by hand to use Boost.Python. The goal, however, has been to make that code nearly as simple as listing the names of the classes and member functions you want to expose in Python. @@ -95,7 +102,7 @@ that.''
    -Paul Dubois SIP is a system similar to SWIG, though seemingly more - C++-oriented. The author says that like BPL, SIP supports overriding + C++-oriented. The author says that like Boost.Python, SIP supports overriding extension class member functions in Python subclasses. It appears to have been designed specifically to directly support some features of PyQt/PyKDE, which is its primary client. Documentation is almost @@ -113,7 +120,7 @@ that.''
    -Paul Dubois to a wide range of computer languages, including Common Lisp, C++, C, Modula-3, and Python. ILU can parse the ISL to generate a C++ language header file describing the interface, of which the user is expected to - provide an implementation. Unlike BPL, this means that the system + provide an implementation. Unlike Boost.Python, this means that the system imposes implementation details on your C++ code at the deepest level. It is worth noting that some of the C++ names generated by ILU are supposed to be reserved to the C++ implementation. It is unclear from the @@ -148,7 +155,7 @@ an inheritance relationship?

    Zope ExtensionClasses

    - ExtensionClasses in Zope use the same underlying mechanism as BPL + ExtensionClasses in Zope use the same underlying mechanism as Boost.Python to support subclassing of extension types in Python, including multiple-inheritance. Both systems support pickling/unpickling of extension class instances in very similar ways. Both systems rely on the @@ -158,31 +165,35 @@ an inheritance relationship?

    The major differences are:

      +
    • Zope is entirely 'C' language-based. It doesn't require a C++ + compiler, so it's much more portable than Boost.Python, which stresses + the limits of even some modern C++ implementations. +
    • - BPL lifts the burden on the user to parse and convert function + Boost.Python lifts the burden on the user to parse and convert function argument types. Zope provides no such facility.
    • - BPL lifts the burden on the user to maintain Python + Boost.Python lifts the burden on the user to maintain Python reference-counts.
    • - BPL supports function overloading; Zope does not. + Boost.Python supports function overloading; Zope does not.
    • - BPL supplies a simple mechanism for exposing read-only and + Boost.Python supplies a simple mechanism for exposing read-only and read/write access to data members of the wrapped C++ type as Python attributes.
    • Writing a Zope ExtensionClass is significantly more complex than - exposing a C++ class to python using BPL (mostly a summary of the + exposing a C++ class to python using Boost.Python (mostly a summary of the previous 4 items). A Zope Example illustrates the differences.
    • Zope's ExtensionClasses are specifically motivated by ``the need for a - C-based persistence mechanism''. BPL's are motivated by the desire + C-based persistence mechanism''. Boost.Python's are motivated by the desire to simply reflect a C++ API into Python with as little modification as possible.
    • - The following Zope restriction does not apply to BPL: ``At most one + The following Zope restriction does not apply to Boost.Python: ``At most one base extension direct or indirect super class may define C data members. If an extension subclass inherits from multiple base extension classes, then all but one must be mix-in classes that @@ -191,21 +202,21 @@ an inheritance relationship? Zope requires use of the somewhat funky inheritedAttribute (search for ``inheritedAttribute'' on this page) - method to access base class methods. In BPL, base class methods can + method to access base class methods. In Boost.Python, base class methods can be accessed in the usual way by writing ``BaseClass.method''.
    • Zope supplies some creative but esoteric idioms such as - Acquisition. No specific support for this is built into BPL. + Acquisition. No specific support for this is built into Boost.Python.
    • Zope's ComputedAttribute support is designed to be used from Python. The analogous feature of - BPL can be used from C++ or Python. The feature is arguably - easier to use in BPL. + Boost.Python can be used from C++ or Python. The feature is arguably + easier to use in Boost.Python.

    - Next: A Simple Example Using BPL + Next: A Simple Example Using Boost.Python Previous: A Brief Introduction to writing Python Extension Modules Up: Top

    @@ -215,6 +226,6 @@ an inheritance relationship? express or implied warranty, and with no claim as to its suitability for any purpose.

    - Updated: Nov 26, 2000 + Updated: Mar 6, 2001

    diff --git a/doc/enums.html b/doc/enums.html index 04138ff1..32d61447 100644 --- a/doc/enums.html +++ b/doc/enums.html @@ -6,7 +6,8 @@

    c++boost.gif (8819 bytes)Wrapping enums + src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">
    + Wrapping enums

    Because there is in general no way to deduce that a value of arbitrary type T @@ -17,24 +18,39 @@ enums). Once you have done that, you can write some simple from_python() and to_python() functions.

    If you are satisfied with a Python int as a way to represent your enum -values, we provide a shorthand for these functions. You just need to -instantiate boost::python::enum_as_int_converters<EnumType> where +values, we provide a shorthand for these functions. You just need to cause +boost::python::enum_as_int_converters<EnumType> to be +instantiated, where EnumType is your enumerated type. There are two convenient ways to do this:

      -
    1. +
    2. Explicit instantiation: + +
      +  template class boost::python::enum_as_int_converters<my_enum>;
      +
      + +Some buggy C++ implementations require a class to be instantiated in the same +namespace in which it is defined. In that case, the simple incantation above becomes: + +
          ...
       } // close my_namespace
      +
       // drop into namespace python and explicitly instantiate
      -BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
      -  template class enum_as_int_converters;
      -BOOST_PYTHON_END_CONVERSION_NAMESPACE
      +namespace boost { namespace python {
      +  template class enum_as_int_converters<my_enum_type>;
      +}} // namespace boost::python
      +
       namespace my_namespace { // re-open my_namespace
          ...
       
      -
    3. +
      +
      +
    4. If you have such an implementation, you may find this technique more convenient +
       // instantiate as base class in any namespace
       struct EnumTypeConverters
           : boost::python::enum_as_int_converters<EnumType>
      @@ -71,7 +87,8 @@ BOOST_PYTHON_END_CONVERSION_NAMESPACE
        long type.
       
       You may also want to add a bunch of lines like this to your module
      -initialization:
      +initialization. These bind the corresponding enum values to the appropriate
      +names so they can be used from Python:
       
       
       mymodule.add(boost::python::to_python(enum_value_1), "enum_value_1");
      @@ -83,12 +100,12 @@ You can also add these to an extension class definition, if your enum happens to
       be local to a class and you want the analogous interface in Python:
       
       
      -my_class.add(boost::python::to_python(enum_value_1), "enum_value_1");
      -my_class.add(boost::python::to_python(enum_value_2), "enum_value_2");
      +my_class_builder.add(boost::python::to_python(enum_value_1), "enum_value_1");
      +my_class_builder.add(boost::python::to_python(enum_value_2), "enum_value_2");
       ...
       

      - Next: Pointers + Next: Pointers and Smart Pointers Previous: Building an Extension Module Up: Top

      @@ -98,6 +115,6 @@ my_class.add(boost::python::to_python(enum_value_2), "enum_value_2"); is'' without express or implied warranty, and with no claim as to its suitability for any purpose.

      - Updated: Nov 26, 2000 + Updated: Mar 6, 2001

    diff --git a/doc/example1.html b/doc/example1.html index 655f3d6a..402cc7a6 100644 --- a/doc/example1.html +++ b/doc/example1.html @@ -18,104 +18,56 @@
     #include <string>
     
    -namespace hello {
    -  class world
    -  {
    -   public:
    -      world(int);
    -      ~world();
    -      std::string greet() const { return "hi, world"; }
    -    ...
    -  };
    -  std::size_t length(const world& x) { return std::strlen(x.greet()); }
    +namespace { // Avoid cluttering the global namespace.
    +
    +  // A couple of simple C++ functions that we want to expose to Python.
    +  std::string greet() { return "hello, world"; }
    +  int square(int number) { return number * number; }
     }
     
     

    - Here is the C++ code for a python module called hello - which exposes the API using: + Here is the C++ code for a python module called getting_started1 + which exposes the API.

     #include <boost/python/class_builder.hpp>
    -// Python requires an exported function called init<module-name> in every
    -// extension module. This is where we build the module contents.
    -extern "C"
    -#ifdef _WIN32
    -__declspec(dllexport)
    -#endif
    -void inithello()
    +namespace python = boost::python;
    +
    +BOOST_PYTHON_MODULE_INIT(getting_started1)
     {
    -    try
    -    {
    -       // create an object representing this extension module
    -       boost::python::module_builder m("hello");
    -       // Create the Python type object for our extension class
    -       boost::python::class_builder<hello::world> world_class(m, "world");
    -       // Add the __init__ function
    -       world_class.def(boost::python::constructor<int>());
    -       // Add a regular member function
    -       world_class.def(&hello::world::get, "get");
    -       // Add a regular function to the module
    -       m.def(hello::length, "length");
    -    }
    -    catch(...)
    -    {
    -       boost::python::handle_exception();    // Deal with the exception for Python
    -    }
    +  try
    +  {
    +    // Create an object representing this extension module.
    +    python::module_builder this_module("getting_started1");
    +
    +    // Add regular functions to the module.
    +    this_module.def(greet, "greet");
    +    this_module.def(square, "square");
    +  }
    +  catch(...)
    +  {
    +    python::handle_exception(); // Deal with the exception for Python
    +  }
     }
    -// Win32 DLL boilerplate
    -#if defined(_WIN32)
    -#include <windows.h>
    -extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID)
    -{
    -    return 1;
    -}
    -#endif // _WIN32
     

    That's it! If we build this shared library and put it on our - PYTHONPATH we can now access our C++ class and function from + PYTHONPATH we can now access our C++ functions from Python.

    ->>> import hello
    ->>> hi_world = hello.world(3)
    ->>> hi_world.greet()
    -'hi, world'
    ->>> hello.length(hi_world)
    -9
    +>>> import getting_started1
    +>>> print getting_started1.greet()
    +hello, world
    +>>> number = 11
    +>>> print number, '*', number, '=', getting_started1.square(number)
    +11 * 11 = 121
     
    -

    - We can even make a subclass of hello.world: -

    -
    ->>> class my_subclass(hello.world):
    -...     def greet(self):
    -...         return 'hello, world'
    -...
    ->>> y = my_subclass(4)
    ->>> y.greet()
    -'hello, world'
    -
    -
    -

    - Pretty cool! You can't do that with an ordinary Python extension type! -

    -
    ->>> hello.length(y)
    -9
    -
    -
    -

    - Of course, you may now have a slightly empty feeling in the pit of - your little pythonic stomach. Perhaps you feel your subclass deserves - to have a length() of 12? If so, read on... -

    - Next: Overridable virtual functions + Next: Exporting Classes Previous: Comparisons with other systems Up: Top

    @@ -125,6 +77,6 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) express or implied warranty, and with no claim as to its suitability for any purpose.

    - Updated: Nov 26, 2000 + Updated: Mar 6, 2000 diff --git a/doc/exporting_classes.html b/doc/exporting_classes.html new file mode 100644 index 00000000..e5932e70 --- /dev/null +++ b/doc/exporting_classes.html @@ -0,0 +1,144 @@ + + + Exporting Classes + +

    +

    + + +

    +

    + Exporting Classes +

    +

    + Now let's expose a C++ class to Python: + +

    +#include <iostream>
    +#include <string>
    +
    +namespace { // Avoid cluttering the global namespace.
    +
    +  // A friendly class.
    +  class hello
    +  {
    +    public:
    +      hello(const std::string& country) { this->country = country; }
    +      std::string greet() const { return "Hello from " + country; }
    +    private:
    +      std::string country;
    +  };
    +
    +  // A function taking a hello object as an argument.
    +  std::string invite(const hello& w) {
    +    return w.greet() + "! Please come soon!";
    +  }
    +}
    +
    +

    + To expose the class, we use a class_builder in addition to the + module_builder from the previous example. Class member functions + are exposed by using the def() member function on the + class_builder: +

    +#include <boost/python/class_builder.hpp>
    +namespace python = boost::python;
    +
    +BOOST_PYTHON_MODULE_INIT(getting_started2)
    +{
    +  try
    +  {
    +    // Create an object representing this extension module.
    +    python::module_builder this_module("getting_started2");
    +
    +    // Create the Python type object for our extension class.
    +    python::class_builder<hello> hello_class(this_module, "hello");
    +
    +    // Add the __init__ function.
    +    hello_class.def(python::constructor<std::string>());
    +    // Add a regular member function.
    +    hello_class.def(&hello::greet, "greet");
    +
    +    // Add invite() as a regular function to the module.
    +    this_module.def(invite, "invite");
    +
    +    // Even better, invite() can also be made a member of hello_class!!!
    +    hello_class.def(invite, "invite");
    +  }
    +  catch(...)
    +  {
    +    python::handle_exception(); // Deal with the exception for Python
    +  }
    +}
    +
    +

    +Now we can use the class normally from Python: + +

    +>>> from getting_started2 import *
    +>>> hi = hello('California')
    +>>> hi.greet()
    +'Hello from California'
    +>>> invite(hi)
    +'Hello from California! Please come soon!'
    +>>> hi.invite()
    +'Hello from California! Please come soon!'
    +
    + +Notes:
      +
    • We expose the class' constructor by calling def() on the + class_builder with an argument whose type is + constructor<params>, where params + matches the list of constructor argument types: + + +
    • Regular member functions are defined by calling def() with a + member function pointer and its Python name: + +
    • Any function added to a class whose initial argument matches the class (or +any base) will act like a member function in Python. +
    +

    + We can even make a subclass of hello.world: + +

    +>>> class wordy(hello):
    +...     def greet(self):
    +...         return hello.greet(self) + ', where the weather is fine'
    +...
    +>>> hi2 = wordy('Florida')
    +>>> hi2.greet()
    +'Hello from Florida, where the weather is fine'
    +>>> invite(hi2)
    +'Hello from Florida! Please come soon!'
    +
    +

    + Pretty cool! You can't do that with an ordinary Python extension type! + + Of course, you may now have a slightly empty feeling in the pit of + your little pythonic stomach. Perhaps you wanted to see the following + wordy invitation: + +

    +'Hello from Florida, where the weather is fine! Please come soon!'
    +
    + + After all, invite calls hello::greet(), and you + reimplemented that in your Python subclass, wordy. If so, read on... + +

    + Next: Overridable virtual functions + Previous: A Simple Example Up: + Top +

    + © Copyright David Abrahams 2000. Permission to copy, use, modify, + sell and distribute this document is granted provided this copyright + notice appears in all copies. This document is provided "as is" without + express or implied warranty, and with no claim as to its suitability + for any purpose. +

    + Updated: Mar 6, 2001 +

    + diff --git a/doc/extending.html b/doc/extending.html index c4a3a5e4..8839ab43 100644 --- a/doc/extending.html +++ b/doc/extending.html @@ -56,10 +56,10 @@ sublcassing the extension type. Aside from being tedious, it's not really the same as having a true class, because there's no way for the user to override a method of the extension type which is called from the - extension module. BPL solves this problem by taking advantage of Python's metaclass feature to provide objects which look, walk, and hiss almost exactly - like regular Python classes. BPL classes are actually cleaner than + like regular Python classes. Boost.Python classes are actually cleaner than Python classes in some subtle ways; a more detailed discussion will follow (someday).

    Next: Comparisons with Other Systems Up: - The Boost Python Library (BPL) + The Boost Python Library (Boost.Python)

    c++boost.gif (8819 bytes)The Boost Python Library (BPL) + align="center" height="86">
    The Boost Python Library (Boost.Python)

    Synopsis

    @@ -15,9 +15,9 @@ href="http://www.python.org">Python
    such that the Python interface is very similar to the C++ interface. It is designed to be minimally intrusive on your C++ design. In most cases, you should not have to alter - your C++ classes in any way in order to use them with BPL. The system + your C++ classes in any way in order to use them with Boost.Python. The system should simply ``reflect'' your C++ classes and functions into - Python. The major features of BPL include support for: + Python. The major features of Boost.Python include support for:
    • Subclassing extension types in Python
    • Overriding virtual functions in Python @@ -28,9 +28,27 @@ among others.

      Supported Platforms

      -

      BPL has been tested in the following configurations: +

      Boost.Python is known to have been tested in the following configurations:

        +
      • Against Python 2.0 using the following compiler/library combinations: + +
      • Against Python 1.5.2 using the following compiler/library:
          @@ -52,24 +70,17 @@ among others. href="mailto:rwgk@cci.lbl.gov">Ralf W. Grosse-Kunstleve]
        • An upcoming release of Metrowerks CodeWarrior - Pro6 for Windows (the first release has a bug that's fatal to BPL) + Pro6 for Windows (the first release has a bug that's fatal to Boost.Python)
        -
        -
      • Against Python 2.0 using the following compiler/library combinations: -

      Credits

      • David Abrahams originated - and wrote the library. + and wrote most of the library, and continues to coordinate development.
      • Ullrich Koethe - had independently developed a similar system. When he discovered BPL, + had independently developed a similar system. When he discovered Boost.Python, he generously contributed countless hours of coding and much insight into improving it. He is responsible for an early version of the support for function overloading and wrote the support for @@ -78,16 +89,22 @@ among others. Python and C++, and has designed an extremely easy-to-use way of exposing numeric operators, including a way to avoid explicit coercion by means of overloading. + +
      • Ralf W. + Grosse-Kunstleve contributed pickle support + and numerous other small improvements. He's working on a way to allow + types exported by multiple modules to interact.
      • The members of the boost mailing list and the Python community supplied invaluable early feedback. In particular, Ron Clarke, Mark Evans, - Anton Gluck, Ralf W. Grosse-Kunstleve, Chuck Ingold, Prabhu Ramachandran, - and Barry Scott took the brave step of trying to use BPL while it was - still in early stages of development. + Anton Gluck, Chuck Ingold, Prabhu Ramachandran,n and Barry Scott took the + brave step of trying to use Boost.Python while it was still in early + stages of development. -
      • The development of BPL wouldn't have been - possible without the generous support of Dragon Systems/Lernout and - Hauspie, Inc who supported its development as an open-source project. +
      • The development of Boost.Python wouldn't have been possible without + the generous support of Dragon + Systems/Lernout and Hauspie, Inc who supported its development as an + open-source project.

      Table of Contents

      @@ -96,11 +113,13 @@ among others.
    • A Brief Introduction to writing Python extension modules -
    • Comparisons between BPL and other +
    • Comparisons between Boost.Python and other systems for extending Python
    • A Simple Example +
    • Exporting Classes +
    • Overridable Virtual Functions
    • Function Overloading @@ -113,33 +132,19 @@ among others.
    • Building an Extension Module -
    • Advanced Topics +
    • Pickle Support -
        -
      1. Pickle Support +
      2. Wrapping Enums -
      3. class_builder<> +
      4. Pointers and Smart Pointers -
      5. enums - -
      6. References - -
      7. Pointers and Smart Pointers - -
      8. Built-in Python Types - -
      9. Other Extension Types - -
      10. Templates - -
      11. Internal Data Structures -
      +
    • Internal Data Structures

      Documentation is a major ongoing project; assistance is greatly - appreciated! In the meantime, useful examples of every BPL feature should + appreciated! In the meantime, useful examples of every Boost.Python feature should be evident in the regression test files test/comprehensive.[py/hpp/the boost mailing list.

      - © Copyright David Abrahams 2000. Permission to copy, use, modify, + © Copyright David Abrahams 2001. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided ``as is'' without express or implied warranty, and with no claim as to its suitability for any purpose.

      - Updated: Nov 26, 2000 + Updated: Mar 6, 2001 diff --git a/doc/inheritance.html b/doc/inheritance.html index d11899c8..cd95c744 100644 --- a/doc/inheritance.html +++ b/doc/inheritance.html @@ -12,10 +12,10 @@

      Inheritance in Python

      - BPL extension classes support single and multiple-inheritance in + Boost.Python extension classes support single and multiple-inheritance in Python, just like regular Python classes. You can arbitrarily mix built-in Python classes with extension classes in a derived class' - tuple of bases. Whenever a BPL extension class is among the bases for a + tuple of bases. Whenever a Boost.Python extension class is among the bases for a new class in Python, the result is an extension class:

      @@ -37,7 +37,7 @@
       
       

      Reflecting C++ Inheritance Relationships

      - BPL also allows us to represent C++ inheritance relationships so that + Boost.Python also allows us to represent C++ inheritance relationships so that wrapped derived classes may be passed where values, pointers, or references to a base class are expected as arguments. The declare_base member function of @@ -76,11 +76,7 @@ int get_derived_x(const Derived& d) { // namespace alias for code brevity namespace python = boost::python; -extern "C" -#ifdef _WIN32 -__declspec(dllexport) -#endif -void initmy_module() +BOOST_PYTHON_MODULE_INIT(my_module) {     try     { @@ -115,11 +111,19 @@ void initmy_module() >>> derived = Derived() >>> get_name(base) 'Base' -

      objects of wrapped class Derived may be passed where Base is expected
      +
      +
      +objects of wrapped class Derived may be passed where Base is expected +
      +
       >>> get_name(derived) 
       'Derived'
      -
      objects of wrapped class Derived can be passed where Derived is -expected but where type information has been lost.
      +
      +
      +objects of wrapped class Derived can be passed where Derived is +expected but where type information has been lost. +
      +
       >>> get_derived_x(derived_as_base()) 
       -1
       
      diff --git a/doc/overloading.html b/doc/overloading.html index 6979efd0..242e023f 100644 --- a/doc/overloading.html +++ b/doc/overloading.html @@ -29,7 +29,7 @@ private: }; ... -void initoverload_demo() +BOOST_PYTHON_MODULE_INIT(overload_demo) {     try     { @@ -144,12 +144,12 @@ namespace scope as Python member functions. Previous: Overridable Virtual Functions Up: Top

      - © Copyright David Abrahams 2000. Permission to copy, use, modify, + © Copyright David Abrahams 2001. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided ``as is'' without express or implied warranty, and with no claim as to its suitability for any purpose.

      - Updated: Nov 26, 2000 + Updated: Mar 6, 2001 diff --git a/doc/overriding.html b/doc/overriding.html index ae629580..7b28add1 100644 --- a/doc/overriding.html +++ b/doc/overriding.html @@ -9,7 +9,7 @@

      Overridable Virtual Functions

      - In the previous example we exposed a simple + In the previous example we exposed a simple C++ class in Python and showed that we could write a subclass. We even redefined one of the functions in our derived class. Now we will learn how to make the function behave virtually when called from C++. @@ -17,16 +17,17 @@

      Example

      -

      In this example, it is assumed that world::greet() is a virtual +

      In this example, it is assumed that hello::greet() is a virtual member function:

      -class world
      +class hello
       {
        public:
      -    world(int);
      -    virtual ~world();
      -    virtual std::string greet() const { return "hi, world"; }
      +    hello(const std::string& country) { this->country = country; }
      +    virtual std::string greet() const { return "Hello from " + country; }
      +    virtual ~hello(); // Good practice 
      +    ...
       };
       
      @@ -37,21 +38,28 @@ class world
        -
      1. A PyObject* data member that holds a - reference to the corresponding Python object. +
      2. A PyObject* data member (usually + called self) that holds a pointer to the Python object corresponding + to our C++ hello instance. -
      3. A constructor for each exposed constructor of the - base class which stores an additional initial PyObject* argument - in the data member described above. +
      4. For each exposed constructor of the + base class T, a constructor which takes the same parameters preceded by an initial + PyObject* argument. The initial argument should be stored in the self data + member described above. + +
      5. If the class being wrapped is ever returned by + value from a wrapped function, be sure you do the same for the + T's copy constructor: you'll need a constructor taking arguments + (PyObject*, const T&).
      6. An implementation of each virtual function you may wish to override in Python which uses - boost::python::callback<return-type>::call_method() to call + callback<return-type>::call_method(self, "name", args...) to call the Python override.
      7. For each non-pure virtual function meant to be overridable from Python, a static member function (or a free function) taking - a reference or pointer to the base type as the first parameter and which + a reference or pointer to the T as the first parameter and which forwards any additional parameters neccessary to the default implementation of the virtual function. See also this note if the base class virtual function is private. @@ -59,52 +67,60 @@ class world
      -struct world_callback : world
      +struct hello_callback : hello
       {
      -    world_callback(PyObject* self, int x) // 2
      -        : world(x),
      -          m_self(self) {}
      +    // hello constructor storing initial self_ parameter
      +    hello_callback(PyObject* self_, const std::string& x) // 2
      +        : hello(x), self(self_) {}
       
      -    std::string greet() const // 3
      -        { return boost::python::callback<std::string>::call_method(m_self, "get"); }
      +    // In case hello is returned by-value from a wrapped function
      +    hello_callback(PyObject* self_, const hello& x) // 3
      +        : hello(x), self(self_) {}
       
      -    static std::string default_get(const hello::world& self) const // 4
      -        { return self.world::greet(); }
      +    // Override greet to call back into Python
      +    std::string greet() const // 4
      +        { return boost::python::callback<std::string>::call_method(m_self, "greet"); }
      +
      +    // Supplies the default implementation of greet
      +    static std::string default_greet(const hello& self) const // 5
      +        { return self.hello::greet(); }
        private:
           PyObject* m_self; // 1
       };
       

      - Finally, we add world_callback to the - class_builder<> declaration in our module initialization + Finally, we add hello_callback to the + class_builder<> declaration in our module initialization function, and when we define the function, we must tell py_cpp about the default implementation:

       // Create the Python type object for our extension class
      -boost::python::class_builder<hello::world,world_callback> world_class(hello, "world");
      +"hello_class">Python type object for our extension class
      +boost::python::class_builder<hello,hello_callback> hello_class(hello, "hello");
       // Add a virtual member function
      -world_class.def(&world::get, "get", &world_callback::default_get);
      +hello_class.def(&hello::greet, "greet", &hello_callback::default_greet);
       

      - Now our subclass of hello.world behaves as expected: + Now our Python subclass of hello behaves as expected:

      ->>> class my_subclass(hello.world):
      +>>> class wordy(hello):
       ...     def greet(self):
      -...         return 'hello, world'
      +...         return hello.greet(self) + ', where the weather is fine'
       ...
      ->>> hello.length(my_subclass())
      -12
      +>>> hi2 = wordy('Florida')
      +>>> hi2.greet()
      +'Hello from Florida, where the weather is fine'
      +>>> invite(hi2)
      +'Hello from Florida, where the weather is fine! Please come soon!'
       
      -

      *You may ask, "Why do we need this derived class? This could have been designed so that everything gets done right - inside of hello::world." One of the goals of py_cpp is to be + inside of hello." One of the goals of py_cpp is to be minimally intrusive on an existing C++ design. In principle, it should be possible to expose the interface for a 3rd party library without changing it. To unintrusively hook into the virtual functions so that a Python @@ -117,10 +133,10 @@ world_class.def(&world::get, "get", &world_callback::default_get) deal with than a virtual function with a default implementation. First of all, you obviously don't need to supply a default implementation. Secondly, you don't need to call - def() on the extension_class<> instance + def() on the extension_class<> instance for the virtual function. In fact, you wouldn't want to: if the corresponding attribute on the Python class stays undefined, you'll get an - AttributeError in Python when you try to call the function, + AttributeError in Python when you try to call the function, indicating that it should have been implemented. For example:

      @@ -132,11 +148,7 @@ struct baz_callback {
           int pure(int x) { boost::python::callback<int>::call_method(m_self, "pure", x); }
       };
       
      -extern "C"
      -#ifdef _WIN32
      -__declspec(dllexport)
      -#endif
      -initfoobar()
      +BOOST_PYTHON_MODULE_INIT(foobar)
       {
           try
           {
      @@ -182,14 +194,14 @@ href="http://cs.calvin.edu/c++/C++Standard-Nov97/basic.html#basic.def.odr">ODR
             Next: Function Overloading
      -      Previous: A Simple Example Using py_cpp
      +      Previous: Exporting Classes
             Up: Top
           

      - © Copyright David Abrahams 2000. Permission to copy, use, modify, + © Copyright David Abrahams 2001. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.

      - Updated: Nov 26, 2000 + Updated: Mar 6, 2001 diff --git a/doc/pickle.html b/doc/pickle.html index 0e64d6fc..7b559e68 100644 --- a/doc/pickle.html +++ b/doc/pickle.html @@ -1,6 +1,6 @@ - BPL Pickle Support + Boost.Python Pickle Support @@ -11,7 +11,7 @@


      -

      BPL Pickle Support

      +

      Boost.Python Pickle Support

      Pickle is a Python module for object serialization, also known as persistence, marshalling, or flattening. @@ -39,16 +39,16 @@ described in detail in the Python Library Reference for pickle:

      -

      The BPL Pickle Interface

      +

      The Boost.Python Pickle Interface

      -At the user level, the BPL pickle interface involves three special +At the user level, the Boost.Python pickle interface involves three special methods:
      __getinitargs__
      - When an instance of a BPL extension class is pickled, the pickler + When an instance of a Boost.Python extension class is pickled, the pickler tests if the instance has a __getinitargs__ method. This method must return a Python tuple. When the instance is restored by the unpickler, the contents of this tuple are used as the arguments for @@ -63,7 +63,7 @@ methods: __getstate__
      - When an instance of a BPL extension class is pickled, the pickler + When an instance of a Boost.Python extension class is pickled, the pickler tests if the instance has a __getstate__ method. This method should return a Python object representing the state of the instance. @@ -76,7 +76,7 @@ methods: __setstate__
      - When an instance of a BPL extension class is restored by the + When an instance of a Boost.Python extension class is restored by the unpickler, it is first constructed using the result of __getinitargs__ as arguments (see above). Subsequently the unpickler tests if the new instance has a __setstate__ method. If so, this @@ -96,13 +96,13 @@ __setstate__ methods can do what they want.

      Pitfalls and Safety Guards

      -In BPL extension modules with many extension classes, providing +In Boost.Python extension modules with many extension classes, providing complete pickle support for all classes would be a significant overhead. In general complete pickle support should only be implemented for extension classes that will eventually be pickled. However, the -author of a BPL extension module might not anticipate correctly which +author of a Boost.Python extension module might not anticipate correctly which classes need support for pickle. Unfortunately, the pickle protocol -described above has two important pitfalls that the end user of a BPL +described above has two important pitfalls that the end user of a Boost.Python extension module might not be aware of:
      @@ -116,10 +116,10 @@ Both __getinitargs__ and __getstate__ are not defined. that of the new instance.

      - However, most C++ classes wrapped with the BPL will have member data + However, most C++ classes wrapped with Boost.Python will have member data that are not restored correctly by this procedure. To alert the user to this problem, a safety guard is provided. If both __getinitargs__ - and __getstate__ are not defined, the BPL tests if the class has an + and __getstate__ are not defined, Boost.Python tests if the class has an attribute __dict_defines_state__. An exception is raised if this attribute is not defined: @@ -151,7 +151,7 @@ Both __getinitargs__ and __getstate__ are not defined. __getstate__ is defined and the instance's __dict__ is not empty.

      - The author of a BPL extension class might provide a __getstate__ + The author of a Boost.Python extension class might provide a __getstate__ method without considering the possibilities that:

      @@ -170,7 +170,7 @@ __getstate__ is defined and the instance's __dict__ is not empty. To alert the user to this highly unobvious problem, a safety guard is provided. If __getstate__ is defined and the instance's __dict__ is - not empty, the BPL tests if the class has an attribute + not empty, Boost.Python tests if the class has an attribute __getstate_manages_dict__. An exception is raised if this attribute is not defined: diff --git a/doc/pointers.html b/doc/pointers.html index e26cea02..fdbee797 100644 --- a/doc/pointers.html +++ b/doc/pointers.html @@ -13,7 +13,7 @@

      In general, raw pointers passed to or returned from functions are problematic -for BPL because pointers have too many potential meanings. Is it an iterator? +for Boost.Python because pointers have too many potential meanings. Is it an iterator? A pointer to a single element? An array? When used as a return value, is the caller expected to manage (delete) the pointed-to object or is the pointer really just a reference? If the latter, what happens to Python references to the @@ -46,7 +46,7 @@ const Foo& f_wrapper() { return *f(); } my_module.def(f_wrapper, "f");

      -Foo must have a public copy constructor for this technique to work, since BPL +Foo must have a public copy constructor for this technique to work, since Boost.Python converts const T& values to_python by copying the T value into a new extension instance. diff --git a/doc/special.html b/doc/special.html index 50cee505..0caa1924 100644 --- a/doc/special.html +++ b/doc/special.html @@ -12,7 +12,7 @@ Overview

      - BPL supports all of the standard special method names supported by real Python class instances except __complex__ (more on the reasons my_class.def(boost::python::constructor<...>()) - (see section "A Simple Example Using BPL").

      + (see section "A Simple Example Using Boost.Python").

      __del__(self)
      @@ -104,7 +104,7 @@ std::string to_string(Foo const& f) boost::python::class_builder<Foo> foo_class(my_module, "Foo"); foo_class.def(&to_string, "__str__"); - Note that BPL also supports automatic wrapping of + Note that Boost.Python also supports automatic wrapping of __str__ and __cmp__. This is explained in the next section and the Table of Automatically Wrapped Methods. @@ -117,7 +117,7 @@ foo_class.def(&to_string, "__str__"); href="http://www.python.org/doc/current/ref/numeric-types.html">numeric protocols. This is the same basic technique used to expose to_string() as __str__() above, and is covered in detail below. BPL also supports + href="#numeric_manual">covered in detail below. Boost.Python also supports automatic wrapping of numeric operators whenever they have already been defined in C++. @@ -174,7 +174,7 @@ a = i + b; bignum_class.def(boost::python::operators<boost::python::op_add>(), boost::python::right_operand<int>()); bignum_class.def(boost::python::operators<boost::python::op_add>(), boost::python::left_operand<int>()); - BPL uses overloading to register several variants of the same + Boost.Python uses overloading to register several variants of the same operation (more on this in the context of coercion). Again, several operators can be exported at once:
      @@ -283,13 +283,13 @@ bignum_class.def(&rmod,  "__rmod__");
             coercion functions can be difficult if many type combinations must be
             supported. 
             

      - BPL solves this problem the same way that C++ does: with overloading. This technique drastically simplifies the code neccessary to support operators: you just register - operators for all desired type combinations, and BPL automatically + operators for all desired type combinations, and Boost.Python automatically ensures that the correct function is called in each case; there is no need for user-defined coercion functions. To enable operator - overloading, BPL provides a standard coercion which is implicitly + overloading, Boost.Python provides a standard coercion which is implicitly registered whenever automatic operator wrapping is used.

      If you wrap all operator functions manually, but still want to use @@ -370,7 +370,7 @@ bignum_class.def((ternary_function2)&power, "__pow__"); In the second variant, however, BigNum appears only as second argument, and in the last one it's the third argument. These functions - must be presented to BPL such that that the BigNum + must be presented to Boost.Python such that that the BigNum argument appears in first position:

      @@ -397,7 +397,7 @@ Note that "__rrpow__" is an extension not present in plain Python.
       
       

      Table of Automatically Wrapped Methods

      - BPL can automatically wrap the following special methods: @@ -772,13 +772,13 @@ KeyError: 2

      Customized Attribute Access

      - Just like built-in Python classes, BPL extension classes support special the usual attribute access methods __getattr__, __setattr__, and __delattr__. Because writing these functions can be tedious in the common case where the attributes being accessed are - known statically, BPL checks the special names + known statically, Boost.Python checks the special names

      • @@ -794,7 +794,7 @@ KeyError: 2 following shows how we can implement a ``computed attribute'' in Python:
        ->>> class Range(AnyBPLExtensionClass):
        +>>> class Range(AnyBoost.PythonExtensionClass):
         ...    def __init__(self, start, end):
         ...        self.start = start
         ...        self.end = end
        @@ -810,7 +810,7 @@ KeyError: 2
                  Direct Access to Data Members
               
               

        - BPL uses the special + Boost.Python uses the special __xxxattr__<name>__ functionality described above to allow direct access to data members through the following special functions on class_builder<> and diff --git a/doc/under-the-hood.html b/doc/under-the-hood.html index 902804d3..733f0f54 100644 --- a/doc/under-the-hood.html +++ b/doc/under-the-hood.html @@ -22,7 +22,7 @@ "example1.html#add_world_class">add it to the module it goes into the module's dictionary to be looked up under the name "world".

        - BPL uses C++'s template argument deduction mechanism to determine the + Boost.Python uses C++'s template argument deduction mechanism to determine the types of arguments to functions (except constructors, for which we must provide an argument list because they can't be named in C++). Then, it calls the appropriate @@ -48,7 +48,7 @@ the top of your module's init function, then def the member functions later to avoid problems with inter-class dependencies.

        - Next: Building a Module with BPL + Next: Building a Module with Boost.Python Previous: Special Method and Operator Support Up: Top

        From 00cea4ff83e2d64c3273fab652171cf4ca192a88 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 7 Mar 2001 03:40:47 +0000 Subject: [PATCH 076/154] Added getting_started targets [SVN r9471] --- build/build.dsw | 34 ++++++++++++++++++++++++++++++++++ build/build.opt | Bin 86528 -> 116224 bytes 2 files changed, 34 insertions(+) diff --git a/build/build.dsw b/build/build.dsw index f4ee1a11..8de38493 100644 --- a/build/build.dsw +++ b/build/build.dsw @@ -30,6 +30,40 @@ Package=<4> ############################################################################### +Project: "getting_started1"=.\getting_started1\getting_started1.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name bpl_static + End Project Dependency +}}} + +############################################################################### + +Project: "getting_started2"=.\getting_started2\getting_started2.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + getting_started2 + .\getting_started2 + end source code control +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name bpl_static + End Project Dependency +}}} + +############################################################################### + Project: "rwgk1"=.\rwgk1\rwgk1.dsp - Package Owner=<4> Package=<5> diff --git a/build/build.opt b/build/build.opt index 5086795feff7997de1d0b50d82b2404da330c819..89eb84a706504d37bff9685be4808fda8baf9b81 100644 GIT binary patch literal 116224 zcmca`Uhu)fjZzO8(10BSGsD0CoD6J8;!F$-42&?o00YCn|NsAkxG);Tu3}(d_&*AU zObGn_|Np-N0|Nsy0|NsK0|Nsq0|PkD*%=rZI2afhI2jlixEL51xEUbv&C9^Rz{kMA zz|X+IAi%)DAjrVLAjH7HAk4tPAi}`FAPQ9{&cMJR!N9;E$-uxM#lXNI&A`AQ!@$5G z%fP@O$H2fK4^(z@W##z@X2-z+k|@z+lM0z+l9{z+lY4z+eJZXU4$5V9vn6V8Ot^V9CJ1V8y_| zV9mh5V8g(`V9UV3V8_6~V9&t7;K0DZ;K;zh;Kabd;LO0l;KIPb;L50|P@M0|P@60|P@c0|P?} z0|P@UR8Kks149M_14AYQ149-A14A|g149l214AwY14AAI14BLo1497=14AJL149u5 z14A(b149V|14AhT149`D14B6j149J^14AX$JWxE>FfcIGGB7aIF)%RHGcYhTfZd+Y zkk3%UpuphDkjGHMPz2Ti%E`oGF$Pw6en&1VumLn?y;Loh=LLn1>7I4rQ5gCwZHz{Cj3Y@l=rqLHLDA=7H=6VPf=) zffPaQXJlXn=XaKp)Z!8iXRDZ`{QTmQn4HX{;+TTUl8pSkn55FooRk=lJebf+DJ}rj z0$fQ2Iq}6Mi6xoInt1dfRKYZ|7L})G8*1Uv16B|NCSjU5QY#X33vyBo4e;oLsfmFx zV7dj;Q%g!R^U^`?Eh~hEf)gs8gN9V)j%%dNInlmsioPNPx3)WJQ+6AUT64>g% zhO5T{Kng$@)W!v=gEoJlOb7*%2eF_us3{C?+nhan_AHV(xS>X@`$0Vv3wSo2B`&=%pe*WlUeV8jX*XJZV9N*Ph`CbD}_ON zQR^KBaQy=k2Vsz9Ao?Em^Z-N*|7$gSbg6LZy1`-B|fw&<0Hi&_QL1G{-h`s}2 zAYqUghzp|cf*42`BnIMw=zAar5(bHZxFGsIh=GJbVjwPz2C-rIO~wJxP!gC68V9?f z!o>p`QveGvFff2?Wyo+1Ob9&Q2H|jkYG4SHfq~%%!*50=1|Eh3&#y8V{6mED1gOQ# zOpJy;rOBBoi3-m7dBypk7#NvAtp%9+?~DJGUl8D`1&t|y#{Q7q0V}&46XK1dA+!_0%J0nsNI7#OBOryW3QK==$31A_*%tOKb5VVF9Q zu^=@djLSTbdXRRI8W6^(4x|=jCbp4I^x;1Akvc=zNFDm9;^_F_;7;qKWzpb@A5bP7 z#Um#KM#uj~$Nxsh{{~kXJQC}~kyGN1`VT?anRi00<@%T$Nxs_bXeLLrH58p;9y{8@b&TXVPfD6 zNi8mME-flcRdlh6DK1KmNh~fXOEv>hp(U9)Fj_CUpkOO#xg%)hZ$N5MT7FS(VqS8p zf{{W%eo+Zw&AQMzh0*ap;FdAJu(cfvV+pH9@K^y#Um#KM#uj~$Nxsh|3+3B zPiY-N3;iRf#2xi1CDwebJyY5+7D#U}6N7p`bGYkk_o^)1wHIgzi5MX2@qKWhesg{ElaE zX2^%`LeFQ&VTfn&WXNMk1MhVQX~Bjy7(lC+K{i7$HZ|yC+8_a_{hkZ~44w?}3`ql2}d(Sh$JMuva@nbm#CPvVrL(qapkPGmuhRB+NDA3^r;PV9__NOvbFeEbMf?bgc zKGguEh%lCd?tcf_4Z?(VFfjOn6oC$B058B~Wx!a+$myJuSX>;InOe?jqhIM!4*HCVrUePoDdit{~aCw9UcE2TxIY`tP@90i9703 zPzZqfr=#P)qvOAzv;f1PGy!6R=+W`t(edArSPzc+d9*F&I0tg(E5;b0b~5g>AkoL) z7)Vi!VUvJOUVe!}a(-S(QGQNNYKol*HmeyJz(-UPs~B>~B(bXDr%PgJ;DEV>fdT2j zOYo@Z==k3VTdz1;UQ)Nb1hv0L@yH2*(ec00@xRgWKkAmDqjeJL;W=_j+)x$ zz)c_}P+L(J9WpX-K|?$VOXoXnC+{Lbeo zNGwUt$Vn|r#cL@~PG&I??&nP|BP!6iGxJJ{k~311v+?;6|omo=BDQ2Q^8xDlbK9Z@Pi9(!d?Rv z3WQbhC6%V7r4|uZ$eUjPse%X;;Jn4TiA5#x1tkRPDsD){QB<0TFH|@PJB**`x`ihv zpO`eklUABXL|)}cPAo3LpXE79DnW@0U(L=BQbJUk7AYx8%qs?+`9qxY#GK6Zyxi2h z5~7sz7boTtS58QxyCc51AT=3(KnOyjktmlynpZ?Ln}|)3#HBRilM&&(OjIL=$Ye%j z(~ro82X$MB#8+1&wE+pYhe@p3h$uyfZBp_Q*<2*1jY4E2kk|s1s74?W?Gz%KeMC0q zh;JPd(^98P#5975>yHfPMjdet6jFOF#P*r!+C(I_aYsa}p2$WF zAEbW|sdw?Uu!w2B65U87Vl;p{%_edhA;dSeNNKJR-*6Hktwly+dynX56Om;%kwX+j zb@GU)e~Ij76Wit^wiF<~h9cZkB(i=Yrj{VN&?B;qKvXqL+*l*welc-fdtw`|)E=E6 zrj8}tSR$@(K|=8ly7wJlaZOycPkh6i=xUJY3Wad%ow(s=B3jVIwIGP>Xc1k>k=XeF zIg;?;ED<$7alK07#yE)W#t_?IB)<1dR0EiZaamFu=Y)Ih#Ef?n(^?{_uS;ydlRC{N z;u|Z(HO8 z#=yYvhLs&@KLBJG07(1=t5mX8Oi6xzPH_xml^&GRORY!+DR{{`SvONbH(5amvVK+} zBQ+-{-&z66%P+Q8$S>AQ&Pd5D(ooma(}y6?!NBU8a8)V!$siFlrBIh6sRJpBhYA~7 zE1+=oic0e|qSbZF)MGW3KpP8w!#6O9!L-1`0356!MUd?aAdkFZWd)0Z*hARYkf;NB z4dH*h2?V4R5(*#|L^~)924}>AT=s%h13gWGE=mk=b}G%xNr9%%_!L+QeZ$HPj#x-8 z0(lYb?5OX2q==y&mmVpy7Ur6FScP702i|AQzqF3G!xfF%Cl@mm)93p<|naHJcM6MU0(v0lr`hU=t zNTj`vkV=4vDu&n;NnA=JJ{b|t%fzkJAa0w<==y)ywppY!LSofML@7e-It*eL&JeMB ziO3a}L~p1XUH=c>HcrIaAtD!>lG^GZW@RU0`O|p@MkZ!P9)>Uf|NjSd6JU4(Xfr&cxI3za>fXabUJhDQ-kl_LoGsw%# z`V0&p3}TOBx`zPl{=*`Ma)xwufqPey^Hq4y8M>@Q(R zWdPm12$CWN3o$S;@-Z+l@G~$l5Nm%L$N~)z!N35sKb;|!p@g9XeDh^GLp<0mi3~*y zAa|wU2^B2{CPr2U1_o{t?5_q{Z37~RwciM$7z?RI#{HKwLFTA{2nGh&{EsB$@P5lo;qx8j&h7M~&h3B=h0og1U~UI$0eE5u%to2j0S*46PE;XA@`b_5 z;T{H$_=D6FF_kkIJqekM0!>yxW@JDtglBQbJ4hWw2gviNQy(Cam#l-&wLe3bp8iibRmrzkIw(#J}{5?oq^=+vLj{FAEYWEqUIQ#|3OaM#2q|I z?0#P2wrCT-&77n?v4nS!kIw%XEj~Gn@Ln94~t25zxRld<+{pXwLx>L?8Lb zsuHUpXvmbY0kpyc#6pY>6C4;vjI=`rj(bq&0+RCci%a4mdqUztP9$+&0CXaGQEEnN zUU6nws=TToJjxxqsSWIsIIz+?X)&qBNnay=2A zg^aj^6u)F0bY6u-8^}+H(QgS%Pb0QCK)epp@Cr0B#xMx|1#;3GR$e`QaC||W4icmG zbO6>|0m}DSQVmELXSjkSN90_9Ao!r;_$1Kwnp6U3xf8Jzng?`BJLH&ue8-^^vzDGC zFF%jKT?<4X|5#p>SO6{0@Sk8VoLW%=Dz@_T;=uufUo|&aO)8a+$|rW9ixae#oPeE( z^@jzx2LnkQUf~6;WG>0f&m&+rH)J~kAyq_Ow8B@MnVy$eQd&ePkOedIGE3rNF2o;g zLiG}b$kPzeuVd9DaF4(O-_;NRqYuQOZ z{WLQ#Jtws!KM#NO62HWsA9SThJS4f|H6NH;>oZ};U12HiNt`oOalW^0OwB8zt#|#rQ%}4yqIMFlm zM0P2OYYG!Lzfas@^MpG@#N7lyO!t+@+X6sy;e<;SqFRC=qXfScWC6|9&Is*dJn;M~d4`PY z8V!Nb5Eu=C(GVC7fzc2cQX$aDz`)SNz`)SVz`)SLz`)STz`)SPz`)SXz`)SKz`)SS zz`)SOz`)SWz`)SMz`)SUz`)SQz`)SYz`!tpfq`Kn0|Ub(1_p-73=9lY7#J9)GB7Yq zV_;yI&cMJhgMoqJ-~a#rXE87^%w}LkLUmVtp`9RmZydIkoD4Gatn z8yOfFHZd?TY-V6!*uucTuobFyI|Bp54h9B>oeT^NyBHW4b~7+A>|tPF*vr7cu#bU( zVLw#eK?VkfLktWIhZz_cjxaDV9A#i&IL5%haGZgG;RFK%!$}4PhEog-45t|w7|t*- zFq~yzU^vIXz;K>{f#CuJ1H(lI28K%v3=Ef{=7CyJ*BBTWt}`$&++bi}xXHl4aEpO~ z;Wh&U!yN_&hPw<54EGoq816GLFg##jV0Z}C2RgfAATVtGr(Ak!Nl9j2dVFz7Vo^zI ziXrNnMiF#r^i`n*^edq2hZ_%FY6@zDLe7GQEW{&l_BZ+p(M_l;MA2;{v_KSkN;lGZ z-^G>1)(XXy#d-yaB^i2&1)$^qK&Obu#DLa5A}IuM<1y{SDvVfM3Oy(s+u}+BAxUyT zA+IhSM!}?l9_H{Ag|w&>J+MeTy&H3d=u6gN6ok+frRaxP5X`Hf3XVW31t}pahCm9T z?id!QToAuVftZB_q%Q0sdbtbX#j8Xt)gf|jmdIHtBGy)swA6vRmO(1P1m)M02 zB}IvO#cBCPx$z}MiJ2t?7UL1W_J-IAeqyGOiM&pps8w6Uu2&*vnFFayCwPmAo02AK zAy|H1T4p-_6`8~=Atz^ImAFZ4B367+`zCu*mMjsq2m>;6PAF3ly?TuBx)>totO>9C zAZ|vVs0HT4E;%Ch++XnK(nIWeTf%Eih+OAKpits8XVpd?$Y`q~ViyjFt9)_%1BH|Pw5*wJr z#W0asos^oJ$a0O?G(%ioC#Ri6M5CUlW%xvuaKvr2<0rbULTopVxRsH_W_04au0%C( zi0t+eS0)gyaf#_p6H~Gf+fg8;pdh~MMohPX$VLM(y(l7k@FexSiAx;B?UEv5On~?{ zAkhN?wCTSS-TO@@Tz3=Gfg-hsOwzJ^;#(uc?l>WOOBadFN#aH(U^{aObT^6XeG}1K zC%$1ye2IipoiSMP6*kmR=c0oi-lW=dJ*d8-+dr?Vgj}ke~Ky<$vRD%*O zGKlJl5ZenPc7&1WUMaB_6EP}HTvwlP+nw0q3R1`Di5Oudy4yfZqlZ-Y5!?7AqPQU< zwuo$j5ZRa{qP;*;TZZT+0}By!k}=u>!zZN!q;AtI{fPSju~k*C~{(76ZC!VvC!5IY`BM9&VCs7BNr0`bGL zkZuDq30hq>ibq3WGz3ONU^E0qLjW@b{xdSNF$pj*jPC!$44YAr(GVC7fzc2c4S~@R z7!85Z5Eu=C(GVDJA%JWDuMz5YO7#7|MuhhNqUlH9Q;3j8+W!mL4NKJiUqbsZjp)4N z*T`A{+m2r&lpVhypCL9bgHjUuE=okOfH$#%G!VQ$W(WrbWNR{LlP)CcK`g{AGwAzA z(E^98Yg<4eitXl?AsL9E;DQ7kC@n!JUC?*)5=df5I)}yn+X0#fDJd<;A>zJtVwYl% zym=7fXE_M3+!|dKm6u$JbSLlVswn(>bw^i4A*U8n*NqdqVPd4LiXwU;JF&~BMps3_ zSCovdigHN>okWz1TELI4ipont3lbtXNfEJCgXlHvL~gevZbxBeUJ2o4H8fcjMf}zj z;?_?M z=>0DvEyhRvI~oFr5b$IOVDMy!M+lI};$mQ8K)$zt80~97ibOyJ1A{X|4nrbCF+(v! z7(*sQDnmJg0z)`MCPN-W3PV0aIYbd2Qi%-vw}H%q+V8@U%8}0gw$EAcBFxg(06InW2;+mm!rQkD-L27$QtGDME(*S3suAfCvT#*!nLS2Ck%n z9MJ6#C7H<#42%qDt3enU;G@0C1qGm$Cn&o_p<)3ra1{FD*(=MVNpT79ax! z(C-=mg&n$}5d#AQBWqE4dN$SUWdW@zqn0N?xfJAX7-nH$U;tZybp02;1J?+jiZ#0a z3v)3}a$-(SQetv8{&kq6r(&Tl>l!^33(HzJB2S{GJ!^LKzDx| z{JYNZees|23j$oVJPZsBoD2*M%&_hv0|Ns)6i)#4i5VCe5};V_zq|qi1A`ezDM$*Y zZj?rZ*=SgdhQ(k^1B?u;44_SM|Nk>Ga5FeN=M=l;qy*>WCn1drf%A0(d{hX+g$xxz z*x+F#2orr&%n-XUXt0c-Bp!C`x*l{W550Q{6&@Y`3q~8DBx4YBbo?*1A{CU>NB4h* zXXY6jDS)>agR&=d=nQSdpNqjcpeR4fy(qu50ICAAgc>dF;Z%n)u8vbBQdz^uAOx{D zHMs=Qw};wK#6?P@k%q)RRaW(Hx*1qDer`M@Zy{$xaK^K;f=F0d zl~fj_+JF}Gf>w`OSp_AQholylC}`Pf>gegkz!6xNK17p#N@_`BW{!SpMM-L2ab|vA zJosW4P`8;%iO9&v5??CXL!RH95{pv@x5o~U=P{SmqRg_?6vN@{IitbtxfA5YoHKN( z3n{G2fe*aVGubX z2ayxGLF8mOsDp@`qEzITpO2J`-175btp5B0VBg_myOE@GzT^rOB>LJI0gO(qHuvW5FOi6xz4$4qOL2^=Q zW=;xpbi&9WK1DAjCx-$3YXt{q$oc}*BK-V@-hblqXREY)Tt;nF&ies#K6!X>XKNJ2;N3%+EP6kJmC@{4j4a}@kR*A?f%mGm(%91wvj$t=rENmWRyRESC~ z%7>Yu26jbWSz=CRih@gKaY24@CbBE~5e9hXrB);+mna0K7MJG0eLsPL;ea^A22ZFl zU^gHeGLeDd03SpRs2!D-lMmjT3<`xw3=9VZAyUC5iOJat&Kar6@W7wUz;J*cA{&~Q zl3IkUQ=Ea}0H>fg%o&pM3 z&%Bb<^wc5+7p&n%gp#SCbOAF3-QUwdRs*Qq798XpLxfflG}FOGgLdq)g(sFI zXBaXtKo~|ahB1s`!oaYBiGd*i*U-E;kt% z7+yo&3!|Z2q;LUGVnJs%Vj!!zVnD;oJw_|l6OJiTBG7et!LC@7#x*oZMOFo5t$ zXxOj~aM<)QFfh!6CK4D8~Ixb%4VJ2rFX?6X&3i7|?LNpKG|Db3g!93KviY0^xtqKw%l+Kv}}b zz_1lm3Nj#QP=J820`^P3`_$YIQtkF7_Nds0*Qul8D!vr z11WRiOLnN1R6rRAgr7k}gK>aE<0Gilhh`ozC=Ck@gJjr-2uNr^rUhX&Gumn>s)bMl z0|NsHb3-!|!vKd6C^Wc11Oo#DjD~Uub>Z0Y*b-<(RfI*3BbRF>MI^dGzjL~(#pekt;lN(z@W##z@X2-z+k|@z+lM0z+l9{z+lY4z+eJZXU4$5V9vn6V8Ot^V9CJ1V8y_| zV9mh5V8g(`V9UV3V8_6~V9&t7;K0DZ;K;zh-~`p@!oa}b%D}+j#=yYf&cMLn!N9=a z$-uzi#lXPe&A`Cm!@$7c%fP_k2UXw9z`zj5z`zj1z`zj9z`zi~z`zj7z`zj3z`zjB zz`zi}z`zj6z`zj2z`zg<)f3CWz!1m4z!1;Cz>vVez>vtmz>vhiz>v(qz>vbgz>vzo zz>vnkz>vvYfz>vwnz>vkjz>v+rz>vehz>o_yC!c|Vp@4ybp^$-rp@@Njp_qYz zp@e~fp_GAvp^Slnp&Y6X6u(sr3=Gu_3=B043=Fjl3=DM)3=H)Q3=9omx92nDGn6nW zFt{@0F_bVAF;s%GG0|9zffb(Lk;@8f1}MDhZ&P1-fDyU82xrJ=C}PNFC}t>NNMuN6 zNM%r92xcf@NMtAhhXposki`@jm>5Bs4U|4XG_o8nHmDo}CsuIW7ct~Blrt1Fq=Lf{ zmmXZ=0t`%ypu7XhE5zE*12PPhS-|Nng&~un1RM$=VNx+40}~@Ce}e1=VPf=)ffPaQ zXJlXn=X;it)Z!8iXRDZ`{QTmQn4HX{;+TTUl8pSkn55FooRk=lJebf+DJ}rj0$fQ2 zIq}6Mi6xoInt1dfRKYZ|7L})G8*1Uv16B|NCSjU5QY#X33vyBo4e;oLsfmFxV7fu& z8Z(0=0}}&N5vYa&;cJWx41A0X3}#FW4BJ2<0>z+E1YuJq28NxCkdl#+fuR8;whOAB zxq&k%H9fPqB(QB7&j>2DL2QtZKw${NfBygf|MLI; z{~$RK-p|CqFbx#e4V>ZmMcKs#iOH#EoS;BrW?*GtWDqC@nFxwCSh${rhAqfsQ2zV( z|9?HmKe;G1H4l`#K_-B_%Ul8~lR+`52(2SQW`Qu+MGd@Q+ZB8> z^D>=@z$s+&Q9&Cc-u zKV#`xGyt+0gdw(b1f>?|mlh?bLNtN0+W-H|1T?X^WG3e1r^|!Gor!^&;s1XYtXg1h z1(){F5G#d;7>9FyUP)1YPBAFBKn)*|L9C?)po9pjl0k(6)YC`~b}vdS$jD4C7G(sr zmRP{Hvw<~%6jd=XFnBRS>VFU)2*TY)lv<14B6z z1H)-XNRtBHm?I1f3{BAH26F>vNNPoiLP&mojyMa*L68vSD4hg#xdsyh!wG0cftkeI zz~Y*cSpo}kCQ$8-HT)17SY1++O4H52Ar5NM{r}HUwulkZ=4)kww2eTjVIdAmqqYnT z4O1Bz7$(C*oXx2yzq~jV)c67=PmsloWoYT+EXWuT1_d2+18ZPuYEdPqsR+^`3(CLc z_;m=lB$gy5B^IYDxMU`#7bWH*Yi1;%nKdLaDJKp3*%;gr0kVa)E zBczcB@(~C_e8m!$nOcr)3k#^R29kqgkYW%92{1SC1%q>m0yN3OLJ(Xq5^x|}P-=31 zQ3}j935Ngw69{PG49~1eEJ|@oEHZ+|I1j`B{~hHMnHU&AF*<>nf#EAOfg#8Epa1{s zGng0{BAFni(t|hsjQ{^LGH@_ByW}Tlhv%g*GRUwnH2nJizaA9%utF8mhm-=f%E5Ik z0|RT3BttQ%RR?OMf`Wj7f#JoR4o2k$CQ$#g;V0CDzu+<-s(_&a)E}*fmk1H+6W1_q^K28OA{3=Fy@3=9S(3=D=P3=E|u3=ES>7#P-;Ffgny zVPM!^!oYB^gn@yjl!1Z0l!1Yxlz}0vl!2kDl!0MFDFefiQU-=&r3?(`N*Ng5mNGDW zC}m*ySjxcQSjNE6TE@U|v5bL1qMU&trksIcWjO=GnQ{h(kL3&uIu#5IdKC-|W)%z! zu@wvqy%h`$eH9E02P+sDu2nEFysKbf(5Pf!aI9otNUmgHSW?NraIlhr;cX=YgJ~55 zLs%69Lr)b0!)<5>&7qosVOliIMdeoec~OyFeYgMg|70Mg|7$Mg|7cMg|7Y zMg|6-Mg|7oMh1r2jSLL88yOgsniv?on-~~6niv?mniv=+H!(2mYhqw{+{D1}q=|t+ zvYCNFu9<-$rI~@DznOtyW-|lBnq~%u_00?n8=4syZZ|V9+-+uHc-G9oAkxCXpx?s4 zVA8_CP}{=5P}jo1u)BqU;dKiGgJ3HIgLEqcgMBLlgHtO5gL5kbgIg;DLv||zLtZNb zLw+j*Lw73!!T43AqG7zElF7=+pw7=+sx81&m17&6)z7&_Y+7`odS7oeT`$I~f>QyBHYQyBHWax)>N#x)>Pzx)>M& zx)>PhyBHW6yBHXnx)>Oyb}=yA>0)5G*Tujf-Oa$@*v-HY*Ui9?(9OV**v-ID(#^oI zx0``se>VdIQx5}!Mh^o+a1R4RK@S5%Q4a${aSsDSTMq-nnH~m)b3F_U-+LGse)cdh z{OVy~;O%8#i0oxxi0)-zXzyiU=Q+;FgpJCe{}qBbo_60{BLypZ*=@` zbo>w6JQ$@0Q3(8pj{k8eq_f;e0CoEZk>f_4G8zJ-Awbg*;9y{8@b&TXVPfD6Ni8mM zE-flcRdlh6DK1KmNh~fXOEv>hp(U9)Fj_CUpkOO#xg%)hZ$N5MT7FS(VqS8pf{{W% zeo+Zw&AOn45+F|{_?fbS)*1gu&}DnhzyO+=XZXAaJR->elLM&(VbH+dS3GjR@yPu{ zlLOf&zzDIAWiP6IAUQ#(92*unA*dWT7P%KtKM0`7f!q(mAU}xWk(0t92O4dWMUw-$ zlNIU~Y;wX-IVCLmM4*cZRj|mh;gMs9nu)Ftu$Z6w|)4?NW zh(it(W+rHIpfKZr`T?69%$??F`at3!4Dy5M`=8~YC4e_rY{6+4Bo4wLIcYp{N;u>| zdX@3Wf#gT=Xb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S0iBLx1lLe~FPFzPdmj{i|3 zL`TgS4S}H(0@(Inhcjd{ecgC|2CLmC5UuRBN|Hmm{N{|&Mmgt4hX7t;m_K=(g; zG6XPqGQ=|^F%*DpEQanq&jjzt2PwplwAhj4-g2OE{Cl#Sb9=>^3K^?qnT-{2+M4_N4KPxr4M59HEaR{JT3Q+?g(R{-&I{wQ5 zABP8xosN$GGBAve{}L{fMpcZ4z-S1JhQMeDjE2By2#kinXb6mkz-R~z&JY+K{~et1 zGU}?)5THj0IL?6_9426smtUfg3^^1nCpE=RBpJ(DkPMKqLShv|PI@F(HT;N23=JGG zw=gguojM5`KO7zZ1D&ahwq6l5RyVr-lYs%-8qd-7pY$kIM(r34fzc2c4S~@R7!85Z z5Eu=C(GVC7fzc2cj3F>O{x=w7Wzu z0~aK;-HY-|3!o}kIYeB%!ci7L;!($(l3KvXAj076l3I|Omy(*7T z=jNxB=A`0N#g&|&mzJ51-%1Y1NB@t>!6L$*dNy$tmB7iwEa|`l|O7L06lbfGXTv|X#8GB}O zD*mLwnM~OC{H1xB$@wWnWMPhiNQPIs?l$e)Jgw1@psU;ctDTF=4 zm6%jqQk0mCH+Z>0DpHdY2_)U*{JgT%qTDAW0i6LX0xhae3$WD?Zg8^xm`Fd71*Auv!OFgpG>P$55R?`Q}Nd{0*PL6oYAjhXFWPL5d(VpCFICVTIhV4q^{s zUqhk}3v$^DRt@wt2|6e}z}cxZGbaU_KI2nhDfA61 zH#oW>xd`M*M94sAK+&g{ab_A&fq)}5fu!&TG)Mu|K59=a^97|ALvE)BP3sopnSw^z zxx>gH1ewrIO)f!9NJCvn%^7IOXe-esLX<D&7#J9M85kIdwLb=Ayb6dw*bm{6PI56Yf$as^4Z_5j zkOxu(J%8SrA%`K6p_rkVA&eoDA(f$=L4kq9^Y=-%zY@uQ*!+(qf!SpEQDuq$2&+JL(d<{s*?_6KR}!bpID<6D(4IjPCzJ z3y{(MUzJG7V|4!)V%BeT{}+4$baek0sGTy3M?+vV1cqV=jL!cI#aJ74^JoZACj>_4 zf2b3Vqo$08z)%bU*!aH$Xy6-l3>&g)odYC+KKhSSwFpQx+!&;>f5ryTEy18cRKyrD z!2xo_h&yBexd(MlASpk;xFjC3HzXcpF^Tg7pmT(ZQZrKXiZjbntrbwXh|zx?1$ABB zq@w)n)I8n9(vp1Lf|4T4jUGZE`{5o3&jElu3-LC{^+b3UGV%^m{E~Ihc@+|EAU`2S z!Eq)7kTQtZL9ADx%b^(tp}#;*dc(@Arw@)VNO}i}QF~edYpwv57FbdZNEm0hf+R=h z1dtCCL?7|zCGyxi;!h;w0iDAHImip&fk&jCLPzYmQ$!zRMdHClM4nqmR02-qFE2_gfHs-%JCFE*Z6eR4B<^rlBF?}h_ViF< zXKaW)p^)%iCr;3zbOd66*fUzNS%AtRJ#hK}Oi6x~)1d}g>myZBDIB$IJ>rEG4e$CI0M8Vo!%9 zYSSk%CkqpK3MXlYOT&(q#+PG>If0m*U3*kKla}~HJ&9bs!c&w8s<%Ps+~Nxw>sO)G64A&5Vt^bi>KsuihbR{I(o=u0 z2g;-=R19MV3@VN^g9a5ro4J6Bq7U*yh2bOXP(E~?1t7Jo1>U?|5p z!jb_wEI`YaSiw7dsbv}qXsHkb10y3w5DS8)E#NDX^sxJnkpWFv1|&WRdjoxcItv2> z1K2T0Q4jGdJOuy$XJCMwX*;_9CkERwub`ZOSP%tWn}fbBcy#>_-R>M6UH?Pm#bu-G ze-Qf_QK~Y$7uJrh|A7{9qw9a5MH)HBuOkuK$5%u+jBDm>Fzz z{ZBITkp!dbe{kI^Kf3-0GxK0y{{z|oo5}{8|0Dg@-qH0x!*y(E)L+9t1R5C_7@8Ou z824}E=n&@U_-}l1 zNn%N6GH5gz8d{^{zeObq1G|M6wAXWV|0iU{Gsg4*7vzdA_oDpL0%)HUq7tcO7AWPtK3HSe=^`4LMcwnO(kw?Z%Srz3E|CPqx(O>7o&~t z|3odGNB4hXIh=WP|0hOKjlMJp@7&tx`0wcWZ*Z_v(CGe8(5TEP9t{CpA>hK0%8XgnM3bQVhmc1{ ziP1OSEo>Sm@r6TJcJVul8txKbMf)1RnRjsMRqkP2$1=sj;3Bn8yg^p z><|g*A?#?-904fA(L;KFby`t=F7)swo=(I>so*Vqhb02x03`$MTFG?BQ@wb;uuO;TC z5ArhQ2zfs9FH0@T$xloHrOd${b!2)FIqMB>5AG%}2Ho=W2e-fevoKbJ+ZBk`2&91# zkJhq?ha4YTl3G-Z)Kqaa)Iqdc9KqcUP*G}UWmTM;SX2^UP*N0Mk`HSE6_=z~S%FUE z28pAXGO#Tjb3=SBo&VgF1(A^sS^z_uZdO(qsW~a}nR&$}iFwJX$iZP`r+^~__4M=x zv`t7Lq$o>FPRNPLiQL5GWH_i36F)_X3DiCzH93Lw4AlfhS=MvQ&qper-175b^$m{P z1|3DYpX5axK zTwVG9LIa<623>%G0t@G@4j@So)=IXDDap^zK^Z?SNCqD^4;@l9GKf#nOUcP$kY!+C zU}a!*-~?TOP?Vpe>kMmja4;}B@WMo$ic%A^VKPh%3=N_#i6x1k5h4ZO%;LnH%=En6 z)Vvay3RVV&0|Ji8$*IM~3SpV~IpEV%VUlbN3j)H$dYEfbyTuC1T!vPVflFYKqlvIVJN`O!v-b>h5(Q|L4F#=qalDL1V+#Q!xAW?LZcxtLPB8l{J#+r(WBlR4FN16P|w^r zdj2Pta2XXE4S~@R7!85Z5Eu=C;T!^N42%q%3>BuTBNlnht($q+TFFXXVR?xJ=vT|6#pu)hw z!rUY^(FC!G*oXnN8XRK33xtA`YB-k{!|pyT2A!6xR&C_yYGm$c?5t~O?q;fMXy{^~ z>*!|aq-$W{Xy9yV;AZLKYF5j@09|~}02&+vEwcpSKmY&#fBFCae~=sq-)CfC*u}`e zz&^m?a+869;WacQU^JA=fCv}xWFvHvAO^A|AOZGgiCUwYAkrx$GDf=DwN1qD!wzP=x%uCKGO-YUM zb@lZRill0oTw;RcBbEUU6Oi9QafD2R*dVNoEliw)LSjI}^nR}4dd>j>R4H6Q83=^` zK?8+(fCFU-BLl-$P$|fOpg{ow!V1_k5oi+#Ct z7(|e0ko!Pb8y+IayIerWxyN9f+)kC`0;-2V_yRKngEkLV)D`Tzj?)(`FZilIf=!^*w@=TB^E=@|1GhCo&ReE z={w?HPCmN+7u4RfvKn3gi!WV`uKy*jkQ!b8TZFa;$SIKuX=il(Z+>10XjSm&`rrIK eP?roe#4)=5cXa(P+7jc@^}nFZF^WfS2mk=&D+65s From 98b31ed07389a28079818dc2806674e5da1f2137 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 7 Mar 2001 03:53:14 +0000 Subject: [PATCH 077/154] use BOOST_PYTHON_MODULE_INIT, update getting_started2 for better documentation [SVN r9472] --- example/getting_started1.cpp | 4 +--- example/getting_started2.cpp | 33 ++++++++++++++++---------------- example/getting_started3.cpp | 4 +--- example/getting_started4.cpp | 4 +--- example/getting_started5.cpp | 4 +--- example/test_getting_started2.py | 26 +++++++++++++++++-------- 6 files changed, 38 insertions(+), 37 deletions(-) diff --git a/example/getting_started1.cpp b/example/getting_started1.cpp index 9679a2a4..7a8e9087 100644 --- a/example/getting_started1.cpp +++ b/example/getting_started1.cpp @@ -12,9 +12,7 @@ namespace python = boost::python; // Python requires an exported function called init in every // extension module. This is where we build the module contents. -extern "C" -DL_EXPORT(void) -initgetting_started1() +BOOST_PYTHON_MODULE_INIT(getting_started1) { try { diff --git a/example/getting_started2.cpp b/example/getting_started2.cpp index 82b4a6df..72b04105 100644 --- a/example/getting_started2.cpp +++ b/example/getting_started2.cpp @@ -1,29 +1,28 @@ #include #include -#include -namespace python = boost::python; namespace { // Avoid cluttering the global namespace. // A friendly class. - class world + class hello { + public: + hello(const std::string& country) { this->country = country; } + std::string greet() const { return "Hello from " + country; } private: std::string country; - public: - world(const std::string& country) { this->country = country; } - std::string greet() const { return "Hello from " + country + "!"; } }; - // A function taking a world object as an argument. - std::string invite(const world& w) { - return w.greet() + " Please come soon!"; + // A function taking a hello object as an argument. + std::string invite(const hello& w) { + return w.greet() + "! Please come soon!"; } } -extern "C" -DL_EXPORT(void) -initgetting_started2() +#include +namespace python = boost::python; + +BOOST_PYTHON_MODULE_INIT(getting_started2) { try { @@ -31,18 +30,18 @@ initgetting_started2() python::module_builder this_module("getting_started2"); // Create the Python type object for our extension class. - python::class_builder world_class(this_module, "world"); + python::class_builder hello_class(this_module, "hello"); // Add the __init__ function. - world_class.def(python::constructor()); + hello_class.def(python::constructor()); // Add a regular member function. - world_class.def(&world::greet, "greet"); + hello_class.def(&hello::greet, "greet"); // Add invite() as a regular function to the module. this_module.def(invite, "invite"); - // Even better, invite() can also be made a member of world_class!!! - world_class.def(invite, "invite"); + // Even better, invite() can also be made a member of hello_class!!! + hello_class.def(invite, "invite"); } catch(...) { diff --git a/example/getting_started3.cpp b/example/getting_started3.cpp index 7e827249..799f5cac 100644 --- a/example/getting_started3.cpp +++ b/example/getting_started3.cpp @@ -91,9 +91,7 @@ namespace { // Avoid cluttering the global namespace. } } -extern "C" -DL_EXPORT(void) -initgetting_started3() +BOOST_PYTHON_MODULE_INIT(getting_started3) { try { diff --git a/example/getting_started4.cpp b/example/getting_started4.cpp index 0c7bd7ee..199ef7a9 100644 --- a/example/getting_started4.cpp +++ b/example/getting_started4.cpp @@ -74,9 +74,7 @@ namespace { // Avoid cluttering the global namespace. } } -extern "C" -DL_EXPORT(void) -initgetting_started4() +BOOST_PYTHON_MODULE_INIT(getting_started4) { try { diff --git a/example/getting_started5.cpp b/example/getting_started5.cpp index c9f1ce36..be033224 100644 --- a/example/getting_started5.cpp +++ b/example/getting_started5.cpp @@ -103,9 +103,7 @@ BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE BOOST_PYTHON_END_CONVERSION_NAMESPACE -extern "C" -DL_EXPORT(void) -initgetting_started5() +BOOST_PYTHON_MODULE_INIT(getting_started5) { try { diff --git a/example/test_getting_started2.py b/example/test_getting_started2.py index 09215816..49cf765d 100644 --- a/example/test_getting_started2.py +++ b/example/test_getting_started2.py @@ -1,11 +1,21 @@ -r'''>>> import getting_started2 - >>> w = getting_started2.world('California') - >>> print w.greet() - Hello from California! - >>> print getting_started2.invite(w) - Hello from California! Please come soon! - >>> print w.invite() - Hello from California! Please come soon! +r'''>>> from getting_started2 import * + >>> hi = hello('California') + >>> hi.greet() + 'Hello from California' + >>> invite(hi) + 'Hello from California! Please come soon!' + >>> hi.invite() + 'Hello from California! Please come soon!' + + >>> class wordy(hello): + ... def greet(self): + ... return hello.greet(self) + ', where the weather is fine' + ... + >>> hi2 = wordy('Florida') + >>> hi2.greet() + 'Hello from Florida, where the weather is fine' + >>> invite(hi2) + 'Hello from Florida! Please come soon!' ''' def run(args = None): From 041409d71570d18cd25351936c4f817db47cd520 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 7 Mar 2001 03:53:56 +0000 Subject: [PATCH 078/154] use BOOST_PYTHON_MODULE_INIT [SVN r9473] --- test/comprehensive.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/comprehensive.cpp b/test/comprehensive.cpp index 3d173310..7699b01f 100644 --- a/test/comprehensive.cpp +++ b/test/comprehensive.cpp @@ -1131,11 +1131,7 @@ void init_module() boost_python_test.add(new boost::python::meta_class); } -extern "C" -#ifdef _WIN32 -__declspec(dllexport) -#endif -void initboost_python_test() +BOOST_PYTHON_MODULE_INIT(boost_python_test) { try { bpl_test::init_module(); From a350b666faafe048311aabcc7d9baa48732fce72 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 7 Mar 2001 03:56:25 +0000 Subject: [PATCH 079/154] Added BOOST_PYTHON_MODULE_INIT [SVN r9475] --- include/boost/python/detail/config.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/boost/python/detail/config.hpp b/include/boost/python/detail/config.hpp index 3207f7c6..9792695e 100644 --- a/include/boost/python/detail/config.hpp +++ b/include/boost/python/detail/config.hpp @@ -57,4 +57,10 @@ # define BOOST_CSTD_ std # endif +#ifdef _WIN32 +# define BOOST_PYTHON_MODULE_INIT(name) extern "C" __declspec(dllexport) void init##name() +#else +# define BOOST_PYTHON_MODULE_INIT(name) extern "C" void init##name() +#endif + #endif // CONFIG_DWA052200_H_ From 5759ce9ba0ad80126051762d56492ce0a33b5239 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 7 Mar 2001 22:27:22 +0000 Subject: [PATCH 080/154] no message [SVN r9482] --- build/getting_started1/getting_started1.dsp | 136 ++++++++++++++++++++ build/getting_started2/getting_started2.dsp | 135 +++++++++++++++++++ 2 files changed, 271 insertions(+) create mode 100644 build/getting_started1/getting_started1.dsp create mode 100644 build/getting_started2/getting_started2.dsp diff --git a/build/getting_started1/getting_started1.dsp b/build/getting_started1/getting_started1.dsp new file mode 100644 index 00000000..a41eb057 --- /dev/null +++ b/build/getting_started1/getting_started1.dsp @@ -0,0 +1,136 @@ +# Microsoft Developer Studio Project File - Name="getting_started1" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=getting_started1 - Win32 DebugPython +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "getting_started1.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "getting_started1.mak" CFG="getting_started1 - Win32 DebugPython" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "getting_started1 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "getting_started1 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "getting_started1 - Win32 DebugPython" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=xicl6.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "getting_started1 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /libpath:"c:\tools\python\libs" + +!ELSEIF "$(CFG)" == "getting_started1 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /GR /GX /ZI /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs" + +!ELSEIF "$(CFG)" == "getting_started1 - Win32 DebugPython" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DebugPython" +# PROP BASE Intermediate_Dir "DebugPython" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugPython" +# PROP Intermediate_Dir "DebugPython" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /D "BOOST_DEBUG_PYTHON" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /pdb:"DebugPython/boost_python_test_d.pdb" /debug /machine:I386 /out:"DebugPython/getting_started1_d.dll" /pdbtype:sept /libpath:"c:\tools\python\src\PCbuild" +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "getting_started1 - Win32 Release" +# Name "getting_started1 - Win32 Debug" +# Name "getting_started1 - Win32 DebugPython" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\example\getting_started1.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/build/getting_started2/getting_started2.dsp b/build/getting_started2/getting_started2.dsp new file mode 100644 index 00000000..284bab21 --- /dev/null +++ b/build/getting_started2/getting_started2.dsp @@ -0,0 +1,135 @@ +# Microsoft Developer Studio Project File - Name="getting_started2" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=getting_started2 - Win32 DebugPython +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "getting_started2.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "getting_started2.mak" CFG="getting_started2 - Win32 DebugPython" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "getting_started2 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "getting_started2 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "getting_started2 - Win32 DebugPython" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "getting_started2" +# PROP Scc_LocalPath "." +CPP=xicl6.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "getting_started2 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /libpath:"c:\tools\python\libs" + +!ELSEIF "$(CFG)" == "getting_started2 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm- /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs" + +!ELSEIF "$(CFG)" == "getting_started2 - Win32 DebugPython" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "getting_started2___Win32_DebugPython" +# PROP BASE Intermediate_Dir "getting_started2___Win32_DebugPython" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "getting_started2___Win32_DebugPython" +# PROP Intermediate_Dir "getting_started2___Win32_DebugPython" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm- /GR /GX /Zi /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /D "BOOST_DEBUG_PYTHON" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"DebugPython/getting_started2_d.dll" /pdbtype:sept /libpath:"c:\tools\python\src\pcbuild" + +!ENDIF + +# Begin Target + +# Name "getting_started2 - Win32 Release" +# Name "getting_started2 - Win32 Debug" +# Name "getting_started2 - Win32 DebugPython" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\example\getting_started2.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project From 945344b3cd440b9260b2536cb2b3c3f9e0c24714 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 7 Mar 2001 23:31:32 +0000 Subject: [PATCH 081/154] *** empty log message *** [SVN r9483] --- doc/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/index.html b/doc/index.html index 5a64bf62..c6e0722e 100644 --- a/doc/index.html +++ b/doc/index.html @@ -97,7 +97,7 @@ among others.

      • The members of the boost mailing list and the Python community supplied invaluable early feedback. In particular, Ron Clarke, Mark Evans, - Anton Gluck, Chuck Ingold, Prabhu Ramachandran,n and Barry Scott took the + Anton Gluck, Chuck Ingold, Prabhu Ramachandran, and Barry Scott took the brave step of trying to use Boost.Python while it was still in early stages of development. From bdbd9a0f5fcd711bd3fbca0477914fbf9c741348 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 8 Mar 2001 01:32:12 +0000 Subject: [PATCH 082/154] class_builder -> class_builder<your_class> [SVN r9484] --- doc/pickle.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/pickle.html b/doc/pickle.html index 7b559e68..ef3d8d0d 100644 --- a/doc/pickle.html +++ b/doc/pickle.html @@ -132,7 +132,7 @@ Both __getinitargs__ and __getstate__ are not defined. this is, e.g.:
        -    class_builder py_your_class(your_module, "your_class");
        +    class_builder<your_class> py_your_class(your_module, "your_class");
             py_your_class.dict_defines_state();
         
        @@ -185,7 +185,7 @@ __getstate__ is defined and the instance's __dict__ is not empty. E.g. in C++:
        -    class_builder py_your_class(your_module, "your_class");
        +    class_builder<your_class> py_your_class(your_module, "your_class");
             py_your_class.getstate_manages_dict();
         
        From a55948071695439f870126c1d686d4aeac4df8b3 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Thu, 8 Mar 2001 03:01:29 +0000 Subject: [PATCH 083/154] py_cpp => Boost.Python [SVN r9485] --- doc/overriding.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/overriding.html b/doc/overriding.html index 7b28add1..b29bf0e6 100644 --- a/doc/overriding.html +++ b/doc/overriding.html @@ -92,7 +92,7 @@ struct hello_callback : hello

        Finally, we add hello_callback to the class_builder<> declaration in our module initialization - function, and when we define the function, we must tell py_cpp about the default + function, and when we define the function, we must tell Boost.Python about the default implementation:

        @@ -120,7 +120,7 @@ hello_class.def(&hello::greet, "greet", &hello_callback::default_gree
             

        *You may ask, "Why do we need this derived class? This could have been designed so that everything gets done right - inside of hello." One of the goals of py_cpp is to be + inside of hello." One of the goals of Boost.Python is to be minimally intrusive on an existing C++ design. In principle, it should be possible to expose the interface for a 3rd party library without changing it. To unintrusively hook into the virtual functions so that a Python From 33ea0dbdeeadd3b4ad77f223843276d9a08867f6 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 9 Mar 2001 02:40:06 +0000 Subject: [PATCH 084/154] temp file before branching [SVN r9515] --- doc/cross_module_dependencies.html | 253 +++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 doc/cross_module_dependencies.html diff --git a/doc/cross_module_dependencies.html b/doc/cross_module_dependencies.html new file mode 100644 index 00000000..3d416bf5 --- /dev/null +++ b/doc/cross_module_dependencies.html @@ -0,0 +1,253 @@ + + + Cross-extension-module dependencies + + + +c++boost.gif (8819 bytes) + + +


        +

        Cross-extension-module dependencies

        + +It is good programming practice to organize large projects as modules +that interact with each other via well defined interfaces. With +Boost.Python it is possible to reflect this organization at the C++ +level at the Python level. This is, each logical C++ module can be +organized as a separate Python extension module. + +

        +At first sight this might seem natural and straightforward. However, it +is a fairly complex problem to establish cross-extension-module +dependencies while maintaining the same ease of use Boost.Python +provides for classes that are wrapped in the same extension module. To +a large extent this complexity can be hidden from the author of a +Boost.Python extension module, but not entirely. + +

        The recipe

        + +Suppose there is an extension module that exposes certain instances of +the C++ std::vector template library such that it can be used from +Python in the following manner: + +
        +import std_vector
        +v = std_vector.double([1, 2, 3, 4])
        +v.push_back(5)
        +v.size()
        +
        + +Suppose the std_vector module is done well and reflects all C++ +functions that are useful at the Python level, for all C++ built-in +data types (std_vector.int, std_vector.long, etc.). + +

        +Suppose further that there is statistic module with a C++ class that +has constructors or member functions that use or return a std::vector. +For example: + +

        +class xy {
        +  private:
        +    std::vector<double> m_x;
        +    std::vector<double> m_y;
        +  public:
        +    xy(const std::vector<double>& x, const std::vector<double>& y) : m_x(x), m_y(y) {}
        +    const std::vector<double>& x() const { return m_x; }
        +    const std::vector<double>& y() const { return m_y; }
        +    double correlation();
        +}
        +
        + +What is more natural then reusing the std_vector extension module to +expose these constructors or functions to Python? + +

        +Unfortunately, what seems natural needs a little work in both the +std_vector and the statistics module. + +

        +In the std_vector extension module, std::vector<double> needs to be +exposed to Python with the x_class_builder<> template instead of the +regular class_builder<>. For example: + +

        +  x_class_builder<std::vector<double> > v_double(std_vector_module, "double");
        +
        + +In the extension module that wraps class xy we need to use +the import_class_builder<> template: + +
        +  import_class_builder<std::vector<double> > v_double("std_vector", "double");
        +
        + +That is all. All the properties that are defined for std_vector.double +in the std_vector Boost.Python module will be available for the +returned objects of xy.x() and xy.y(). Similarly, the constructor for +xy will accept objects that were created by the std_vector module. + +

        Non-copyable types

        + +The x_class_builder<T> instantiates template functions that invoke the +copy constructor of T. For a T that is non-copyable this will result in +compile-time error messages. In such a case, another variety of the +class_builder<>, the xptr_class_builder<> must be used. +For example: + +
        +xptr_class_builder<store> py_store(your_module, "store");
        +
        + +The corresponding import_class_builder<> does not need any special +attention: + +
        +import_class_builder<store> py_store("noncopyable_export", "store");
        +
        + +

        Python module search path

        + +The std_vector and statistics modules can now be used in the following +way: + +
        +import std_vector
        +import statistics
        +x = std_vector.double([1, 2, 3, 4])
        +y = std_vector.double([2, 4, 6, 8])
        +xy = statistics.xy(x, y)
        +xy.correlation()
        +
        + +In this example it is clear that Python has to be able to find both the +std_vector and the statistics extension module. In other words, both +extension modules need to be in the Python module search path +(sys.path). + +

        +The situation is not always that obvious. Suppose the statistics +module has a random function that returns a vector of random +numbers with a given length: + +

        +import statistics
        +x = statistics.random(5)
        +y = statistics.random(5)
        +xy = statistics.xy(x, y)
        +xy.correlation()
        +
        + +A naive user will not easily anticipate that the std_vector module is +used to pass the x and y vectors around. If the std_vector module is in +the Python module search path, this form of ignorance is of no harm. +On the contrary, we are glad that we do not have to bother the user +with details like this. + +

        +If the std_vector module is not in the Python module search path, a +Python exception will be raised: + +

        +Traceback (innermost last):
        +  File "foo.py", line 2, in ?
        +    x = statistics.random(5)
        +ImportError: No module named std_vector
        +
        + +As is the case with any system of a non-trivial complexity, it is +important that the setup is consistent and complete. + +

        Two-way module dependencies

        + +Boost.Python supports two-way module dependencies. This is best +illustrated by a simple example. + +

        +Suppose there is a module ivect that implements vectors of integers, +and a similar module dvect that implements vectors of doubles. We want +to be able do convert an integer vector to a double vector and vice +versa. For example: + +

        +import ivect
        +iv = ivect.ivect((1,2,3,4,5))
        +dv = iv.as_dvect()
        +
        + +The last expression will implicitly import the dvect module in order to +enable the conversion of the C++ representation of dvect to a Python +object. The analogous is possible for a dvect: + +
        +import dvect
        +dv = dvect.dvect((1,2,3,4,5))
        +iv = dv.as_ivect()
        +
        + +Now the ivect module is imported implicitly. + +

        +Note that the two-way dependencies are possible because the +dependencies are resolved only when needed. This is, the initialization +of the ivect module does not rely on the dvect module, and vice versa. +Only if as_dvect() or as_ivect() is actually invoked will the +corresponding module be implicitly imported. This also means that, for +example, the dvect module does not have to be available at all if +as_dvect() is never used. + +

        Clarification of compile-time and link-time dependencies

        + +Boost.Python's support for resolving cross-module dependencies at +runtime does not imply that compile-time dependencies are eliminated. +For example, the statistics extension module in the example above will +need to #include <vector>. This is immediately obvious from the +definition of class xy. + +

        +If a library is wrapped that consists of both header files and compiled +components (e.g. libdvect.a, dvect.lib, etc.), both the Boost.Python +extension module with the x_class_wrapper<> and the module with the +import_class_wrapper<> need to be linked against the object library. +Ideally one would build a shared library (e.g. libdvect.so, dvect.dll, +etc.). However, this introduces the issue of getting the search path +for the dynamic loading configured correctly. For small libraries it is +therefore often more convenient to ignore the fact that the object +files are loaded into memory more than once. + +

        +The main purpose of Boost.Python's support for resolving cross-module +dependencies at runtime is to allow for a modular system layout. With +this support it is straightforward to reflect C++ code organization at +the Python level. Without the cross-module support, a multi-purpose +module like std_vector would be impractical because the entire wrapper +code would somehow have to be duplicated in all extension modules that +use it, making them harder to maintain and harder to build. + +

        +Finally, there is an important psychological component. If a group of +classes is lumped together with many others in a huge module, the +authors will have difficulties in being identified with their work. +The situation is much more transparent if the work is represented by +a module with a recognizable name. This is not just a question of +strong egos, but also of getting credit and funding. + +

        Why not use the x_class_builder universally?

        + +There is some overhead associated with the Boost.Python cross-module +support. Depending on the platform, the code generated by +x_class_builder<> is roughly 10%-20% larger than that generated by +class_builder<>. For a large extension module with many wrapped +classes, this could mean a significant difference. Therefore the +general recommendation is to use x_class_wrapper<> only for classes +that are likely to be used as function arguments or return values in +other modules. + +
        +
        +Author: Ralf W. Grosse-Kunstleve, March 2001 +
        + From a6b0fa546a1d0f0cfc08068ebaa9bfad3c7c8b9a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 9 Mar 2001 02:41:16 +0000 Subject: [PATCH 085/154] temp file removed after branching. [SVN r9516] --- doc/cross_module_dependencies.html | 253 ----------------------------- 1 file changed, 253 deletions(-) delete mode 100644 doc/cross_module_dependencies.html diff --git a/doc/cross_module_dependencies.html b/doc/cross_module_dependencies.html deleted file mode 100644 index 3d416bf5..00000000 --- a/doc/cross_module_dependencies.html +++ /dev/null @@ -1,253 +0,0 @@ - - - Cross-extension-module dependencies - - - -c++boost.gif (8819 bytes) - - -
        -

        Cross-extension-module dependencies

        - -It is good programming practice to organize large projects as modules -that interact with each other via well defined interfaces. With -Boost.Python it is possible to reflect this organization at the C++ -level at the Python level. This is, each logical C++ module can be -organized as a separate Python extension module. - -

        -At first sight this might seem natural and straightforward. However, it -is a fairly complex problem to establish cross-extension-module -dependencies while maintaining the same ease of use Boost.Python -provides for classes that are wrapped in the same extension module. To -a large extent this complexity can be hidden from the author of a -Boost.Python extension module, but not entirely. - -

        The recipe

        - -Suppose there is an extension module that exposes certain instances of -the C++ std::vector template library such that it can be used from -Python in the following manner: - -
        -import std_vector
        -v = std_vector.double([1, 2, 3, 4])
        -v.push_back(5)
        -v.size()
        -
        - -Suppose the std_vector module is done well and reflects all C++ -functions that are useful at the Python level, for all C++ built-in -data types (std_vector.int, std_vector.long, etc.). - -

        -Suppose further that there is statistic module with a C++ class that -has constructors or member functions that use or return a std::vector. -For example: - -

        -class xy {
        -  private:
        -    std::vector<double> m_x;
        -    std::vector<double> m_y;
        -  public:
        -    xy(const std::vector<double>& x, const std::vector<double>& y) : m_x(x), m_y(y) {}
        -    const std::vector<double>& x() const { return m_x; }
        -    const std::vector<double>& y() const { return m_y; }
        -    double correlation();
        -}
        -
        - -What is more natural then reusing the std_vector extension module to -expose these constructors or functions to Python? - -

        -Unfortunately, what seems natural needs a little work in both the -std_vector and the statistics module. - -

        -In the std_vector extension module, std::vector<double> needs to be -exposed to Python with the x_class_builder<> template instead of the -regular class_builder<>. For example: - -

        -  x_class_builder<std::vector<double> > v_double(std_vector_module, "double");
        -
        - -In the extension module that wraps class xy we need to use -the import_class_builder<> template: - -
        -  import_class_builder<std::vector<double> > v_double("std_vector", "double");
        -
        - -That is all. All the properties that are defined for std_vector.double -in the std_vector Boost.Python module will be available for the -returned objects of xy.x() and xy.y(). Similarly, the constructor for -xy will accept objects that were created by the std_vector module. - -

        Non-copyable types

        - -The x_class_builder<T> instantiates template functions that invoke the -copy constructor of T. For a T that is non-copyable this will result in -compile-time error messages. In such a case, another variety of the -class_builder<>, the xptr_class_builder<> must be used. -For example: - -
        -xptr_class_builder<store> py_store(your_module, "store");
        -
        - -The corresponding import_class_builder<> does not need any special -attention: - -
        -import_class_builder<store> py_store("noncopyable_export", "store");
        -
        - -

        Python module search path

        - -The std_vector and statistics modules can now be used in the following -way: - -
        -import std_vector
        -import statistics
        -x = std_vector.double([1, 2, 3, 4])
        -y = std_vector.double([2, 4, 6, 8])
        -xy = statistics.xy(x, y)
        -xy.correlation()
        -
        - -In this example it is clear that Python has to be able to find both the -std_vector and the statistics extension module. In other words, both -extension modules need to be in the Python module search path -(sys.path). - -

        -The situation is not always that obvious. Suppose the statistics -module has a random function that returns a vector of random -numbers with a given length: - -

        -import statistics
        -x = statistics.random(5)
        -y = statistics.random(5)
        -xy = statistics.xy(x, y)
        -xy.correlation()
        -
        - -A naive user will not easily anticipate that the std_vector module is -used to pass the x and y vectors around. If the std_vector module is in -the Python module search path, this form of ignorance is of no harm. -On the contrary, we are glad that we do not have to bother the user -with details like this. - -

        -If the std_vector module is not in the Python module search path, a -Python exception will be raised: - -

        -Traceback (innermost last):
        -  File "foo.py", line 2, in ?
        -    x = statistics.random(5)
        -ImportError: No module named std_vector
        -
        - -As is the case with any system of a non-trivial complexity, it is -important that the setup is consistent and complete. - -

        Two-way module dependencies

        - -Boost.Python supports two-way module dependencies. This is best -illustrated by a simple example. - -

        -Suppose there is a module ivect that implements vectors of integers, -and a similar module dvect that implements vectors of doubles. We want -to be able do convert an integer vector to a double vector and vice -versa. For example: - -

        -import ivect
        -iv = ivect.ivect((1,2,3,4,5))
        -dv = iv.as_dvect()
        -
        - -The last expression will implicitly import the dvect module in order to -enable the conversion of the C++ representation of dvect to a Python -object. The analogous is possible for a dvect: - -
        -import dvect
        -dv = dvect.dvect((1,2,3,4,5))
        -iv = dv.as_ivect()
        -
        - -Now the ivect module is imported implicitly. - -

        -Note that the two-way dependencies are possible because the -dependencies are resolved only when needed. This is, the initialization -of the ivect module does not rely on the dvect module, and vice versa. -Only if as_dvect() or as_ivect() is actually invoked will the -corresponding module be implicitly imported. This also means that, for -example, the dvect module does not have to be available at all if -as_dvect() is never used. - -

        Clarification of compile-time and link-time dependencies

        - -Boost.Python's support for resolving cross-module dependencies at -runtime does not imply that compile-time dependencies are eliminated. -For example, the statistics extension module in the example above will -need to #include <vector>. This is immediately obvious from the -definition of class xy. - -

        -If a library is wrapped that consists of both header files and compiled -components (e.g. libdvect.a, dvect.lib, etc.), both the Boost.Python -extension module with the x_class_wrapper<> and the module with the -import_class_wrapper<> need to be linked against the object library. -Ideally one would build a shared library (e.g. libdvect.so, dvect.dll, -etc.). However, this introduces the issue of getting the search path -for the dynamic loading configured correctly. For small libraries it is -therefore often more convenient to ignore the fact that the object -files are loaded into memory more than once. - -

        -The main purpose of Boost.Python's support for resolving cross-module -dependencies at runtime is to allow for a modular system layout. With -this support it is straightforward to reflect C++ code organization at -the Python level. Without the cross-module support, a multi-purpose -module like std_vector would be impractical because the entire wrapper -code would somehow have to be duplicated in all extension modules that -use it, making them harder to maintain and harder to build. - -

        -Finally, there is an important psychological component. If a group of -classes is lumped together with many others in a huge module, the -authors will have difficulties in being identified with their work. -The situation is much more transparent if the work is represented by -a module with a recognizable name. This is not just a question of -strong egos, but also of getting credit and funding. - -

        Why not use the x_class_builder universally?

        - -There is some overhead associated with the Boost.Python cross-module -support. Depending on the platform, the code generated by -x_class_builder<> is roughly 10%-20% larger than that generated by -class_builder<>. For a large extension module with many wrapped -classes, this could mean a significant difference. Therefore the -general recommendation is to use x_class_wrapper<> only for classes -that are likely to be used as function arguments or return values in -other modules. - -
        -
        -Author: Ralf W. Grosse-Kunstleve, March 2001 -
        - From 55321b87785ef71e51669bc562211dc534884032 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 9 Mar 2001 18:59:59 +0000 Subject: [PATCH 086/154] HTML 4.0 Strict fixes. [SVN r9530] --- doc/pickle.html | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/doc/pickle.html b/doc/pickle.html index ef3d8d0d..49f5c605 100644 --- a/doc/pickle.html +++ b/doc/pickle.html @@ -1,15 +1,15 @@ - - - Boost.Python Pickle Support - - + + +Boost.Python Pickle Support + +
        c++boost.gif (8819 bytes) -

        Boost.Python Pickle Support

        @@ -28,15 +28,14 @@ can be written to a file.

        The Boost Python Library supports the pickle module by emulating the interface implemented by Jim Fulton's ExtensionClass module that is -included in the ZOPE distribution -(http://www.zope.org/). +included in the +ZOPE +distribution. This interface is similar to that for regular Python classes as -described in detail in the Python Library Reference for pickle: - -

        - http://www.python.org/doc/current/lib/module-pickle.html -
        +described in detail in the +Python Library Reference for pickle.

        The Boost.Python Pickle Interface

        @@ -220,4 +219,4 @@ __getstate__ is defined and the instance's __dict__ is not empty.
        Author: Ralf W. Grosse-Kunstleve, March 2001
        - +
        From 494f12090f4090d1678f7f2b5fb06130e9814fca Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 9 Mar 2001 19:02:12 +0000 Subject: [PATCH 087/154] Use only one

        (although the validator did not complain). [SVN r9531] --- doc/pickle.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/pickle.html b/doc/pickle.html index 49f5c605..3ec8c928 100644 --- a/doc/pickle.html +++ b/doc/pickle.html @@ -38,7 +38,7 @@ described in detail in the >Python Library Reference for pickle.
        -

        The Boost.Python Pickle Interface

        +

        The Boost.Python Pickle Interface

        At the user level, the Boost.Python pickle interface involves three special methods: @@ -93,7 +93,7 @@ returned by __getstate__ need not be a dictionary. The __getstate__ and __setstate__ methods can do what they want.
        -

        Pitfalls and Safety Guards

        +

        Pitfalls and Safety Guards

        In Boost.Python extension modules with many extension classes, providing complete pickle support for all classes would be a significant @@ -202,7 +202,7 @@ __getstate__ is defined and the instance's __dict__ is not empty.
        -

        Practical Advice

        +

        Practical Advice

        • From 585063f6e18a37e90febc4409595f99f8d35c3f8 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 9 Mar 2001 20:04:56 +0000 Subject: [PATCH 088/154] Small enhancements. [SVN r9532] --- doc/pickle.html | 136 +++++++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 59 deletions(-) diff --git a/doc/pickle.html b/doc/pickle.html index 3ec8c928..39cb07dc 100644 --- a/doc/pickle.html +++ b/doc/pickle.html @@ -45,81 +45,87 @@ methods:
          -__getinitargs__ +__getinitargs__
          - When an instance of a Boost.Python extension class is pickled, the pickler - tests if the instance has a __getinitargs__ method. This method must - return a Python tuple. When the instance is restored by the + When an instance of a Boost.Python extension class is pickled, the + pickler tests if the instance has a __getinitargs__ method. + This method must return a Python tuple (it is most convenient to use + a boost::python::tuple). When the instance is restored by the unpickler, the contents of this tuple are used as the arguments for the class constructor.

          - If __getinitargs__ is not defined, the class constructor will be - called without arguments. + If __getinitargs__ is not defined, the class constructor + will be called without arguments.

          -__getstate__ +__getstate__
          - When an instance of a Boost.Python extension class is pickled, the pickler - tests if the instance has a __getstate__ method. This method should - return a Python object representing the state of the instance. + When an instance of a Boost.Python extension class is pickled, the + pickler tests if the instance has a __getstate__ method. + This method should return a Python object representing the state of + the instance.

          - If __getstate__ is not defined, the instance's __dict__ is pickled - (if it is not empty). + If __getstate__ is not defined, the instance's + __dict__ is pickled (if it is not empty).

          -__setstate__ +__setstate__
          When an instance of a Boost.Python extension class is restored by the unpickler, it is first constructed using the result of - __getinitargs__ as arguments (see above). Subsequently the unpickler - tests if the new instance has a __setstate__ method. If so, this - method is called with the result of __getstate__ (a Python object) as - the argument. + __getinitargs__ as arguments (see above). Subsequently the + unpickler tests if the new instance has a __setstate__ + method. If so, this method is called with the result of + __getstate__ (a Python object) as the argument.

          - If __setstate__ is not defined, the result of __getstate__ must be - a Python dictionary. The items of this dictionary are added to - the instance's __dict__. + If __setstate__ is not defined, the result of + __getstate__ must be a Python dictionary. The items of this + dictionary are added to the instance's __dict__. +

          -If both __getstate__ and __setstate__ are defined, the Python object -returned by __getstate__ need not be a dictionary. The __getstate__ and -__setstate__ methods can do what they want. +If both __getstate__ and __setstate__ are defined, +the Python object returned by __getstate__ need not be a +dictionary. The __getstate__ and __setstate__ methods +can do what they want.

          Pitfalls and Safety Guards

          -In Boost.Python extension modules with many extension classes, providing -complete pickle support for all classes would be a significant -overhead. In general complete pickle support should only be implemented -for extension classes that will eventually be pickled. However, the -author of a Boost.Python extension module might not anticipate correctly which -classes need support for pickle. Unfortunately, the pickle protocol -described above has two important pitfalls that the end user of a Boost.Python -extension module might not be aware of: +In Boost.Python extension modules with many extension classes, +providing complete pickle support for all classes would be a +significant overhead. In general complete pickle support should only be +implemented for extension classes that will eventually be pickled. +However, the author of a Boost.Python extension module might not +anticipate correctly which classes need support for pickle. +Unfortunately, the pickle protocol described above has two important +pitfalls that the end user of a Boost.Python extension module might not +be aware of:
          Pitfall 1: -Both __getinitargs__ and __getstate__ are not defined. +Both __getinitargs__ and __getstate__ are not defined.
          In this situation the unpickler calls the class constructor without - arguments and then adds the __dict__ that was pickled by default to - that of the new instance. + arguments and then adds the __dict__ that was pickled by + default to that of the new instance.

          - However, most C++ classes wrapped with Boost.Python will have member data - that are not restored correctly by this procedure. To alert the user - to this problem, a safety guard is provided. If both __getinitargs__ - and __getstate__ are not defined, Boost.Python tests if the class has an - attribute __dict_defines_state__. An exception is raised if this + However, most C++ classes wrapped with Boost.Python will have member + data that are not restored correctly by this procedure. To alert the + user to this problem, a safety guard is provided. If both + __getinitargs__ and __getstate__ are not defined, + Boost.Python tests if the class has an attribute + __dict_defines_state__. An exception is raised if this attribute is not defined:

          @@ -147,41 +153,44 @@ Both __getinitargs__ and __getstate__ are not defined.
           

          Pitfall 2: -__getstate__ is defined and the instance's __dict__ is not empty. +__getstate__ is defined and the instance's __dict__ is not empty.
          - The author of a Boost.Python extension class might provide a __getstate__ - method without considering the possibilities that: + The author of a Boost.Python extension class might provide a + __getstate__ method without considering the possibilities + that:

          • - his class is used as a base class. Most likely the __dict__ of - instances of the derived class needs to be pickled in order to - restore the instances correctly. + his class is used in Python as a base class. Most likely the + __dict__ of instances of the derived class needs to be + pickled in order to restore the instances correctly.

          • - the user adds items to the instance's __dict__ directly. Again, - the __dict__ of the instance then needs to be pickled. + the user adds items to the instance's __dict__ directly. + Again, the __dict__ of the instance then needs to be + pickled. +

          To alert the user to this highly unobvious problem, a safety guard is - provided. If __getstate__ is defined and the instance's __dict__ is - not empty, Boost.Python tests if the class has an attribute - __getstate_manages_dict__. An exception is raised if this attribute - is not defined: + provided. If __getstate__ is defined and the instance's + __dict__ is not empty, Boost.Python tests if the class has + an attribute __getstate_manages_dict__. An exception is + raised if this attribute is not defined:

               RuntimeError: Incomplete pickle support (__getstate_manages_dict__ not set)
           
          To resolve this problem, it should first be established that the - __getstate__ and __setstate__ methods manage the instances's __dict__ - correctly. Note that this can be done both at the C++ and the Python - level. Finally, the safety guard should intentionally be overridden. - E.g. in C++: + __getstate__ and __setstate__ methods manage the + instances's __dict__ correctly. Note that this can be done + both at the C++ and the Python level. Finally, the safety guard + should intentionally be overridden. E.g. in C++:
               class_builder<your_class> py_your_class(your_module, "your_class");
          @@ -206,15 +215,24 @@ __getstate__ is defined and the instance's __dict__ is not empty.
           
           
          • - Avoid using __getstate__ if the instance can also be reconstructed - by way of __getinitargs__. This automatically avoids Pitfall 2. + Avoid using __getstate__ if the instance can also be + reconstructed by way of __getinitargs__. This automatically + avoids Pitfall 2.

          • - If __getstate__ is required, include the instance's __dict__ in the - Python object that is returned. + If __getstate__ is required, include the instance's + __dict__ in the Python object that is returned. +
          +
          +

          Example

          + +An example that shows how to provide pickle support is available in the +boost/lib/python/example directory +(getting_started3.cpp). +
          Author: Ralf W. Grosse-Kunstleve, March 2001 From f5416ebce07b914ed6fd83754f414e53bd2b5563 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sat, 10 Mar 2001 00:36:03 +0000 Subject: [PATCH 089/154] Fixed some doc bugs and improved an example [SVN r9533] --- doc/overriding.html | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/overriding.html b/doc/overriding.html index b29bf0e6..0fc7a2e6 100644 --- a/doc/overriding.html +++ b/doc/overriding.html @@ -142,6 +142,7 @@ hello_class.def(&hello::greet, "greet", &hello_callback::default_gree
           struct baz {
               virtual int pure(int) = 0;
          +    int calls_pure(int x) { return pure(x) + 1000; }
           };
           
           struct baz_callback {
          @@ -154,7 +155,7 @@ BOOST_PYTHON_MODULE_INIT(foobar)
               {
                  boost::python::module_builder foobar("foobar");
                  boost::python::class_builder<baz,baz_callback> baz_class("baz");
          -       baz_class.def(&baz::pure, "pure");
          +       baz_class.def(&baz::calls_pure, "calls_pure");
               }
               catch(...)
               {
          @@ -173,12 +174,18 @@ BOOST_PYTHON_MODULE_INIT(foobar)
           Traceback (innermost last):
             File "<stdin>", line 1, in ?
           AttributeError: pure
          +>>> x.calls_pure(1)
          +Traceback (innermost last):
          +  File "<stdin>", line 1, in ?
          +AttributeError: pure
           >>> class mumble(baz):
           ...    def pure(self, x): return x + 1
           ...
           >>> y = mumble()
           >>> y.pure(99)
           100
          +>>> y.calls_pure(99)
          +1100
           

        Private Non-Pure Virtual Functions

        @@ -192,6 +199,7 @@ this limited way without breaking binary compatibility (though it will certainly break the ODR). +

        Next: Function Overloading Previous: Exporting Classes From 678fa006de24673b654fc057a165e79a2108a734 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 10 Mar 2001 08:23:37 +0000 Subject: [PATCH 090/154] Copyright notice & minor fixes. [SVN r9536] --- doc/pickle.html | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/doc/pickle.html b/doc/pickle.html index 39cb07dc..842112d3 100644 --- a/doc/pickle.html +++ b/doc/pickle.html @@ -8,7 +8,7 @@ c++boost.gif (8819 bytes) + width="277" height="86">


        Boost.Python Pickle Support

        @@ -229,12 +229,17 @@ Both __getinitargs__ and __getstate__ are not defined.

        Example

        -An example that shows how to provide pickle support is available in the +An example that shows how to configure pickle support is available in the boost/lib/python/example directory (getting_started3.cpp).
        -
        -Author: Ralf W. Grosse-Kunstleve, March 2001 -
        +© Copyright Ralf W. Grosse-Kunstleve 2001. Permission to copy, +use, modify, sell and distribute this document is granted provided this +copyright notice appears in all copies. This document is provided "as +is" without express or implied warranty, and with no claim as to its +suitability for any purpose. + +

        +Updated: March 10, 2001 From 14acb1af8c1ef20c1a49ea1a2901e6b49817f2e2 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sat, 10 Mar 2001 19:09:10 +0000 Subject: [PATCH 091/154] Fix bugs (m_self => self) [SVN r9539] --- doc/overriding.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/overriding.html b/doc/overriding.html index 0fc7a2e6..66c3610c 100644 --- a/doc/overriding.html +++ b/doc/overriding.html @@ -79,13 +79,13 @@ struct hello_callback : hello // Override greet to call back into Python std::string greet() const // 4 - { return boost::python::callback<std::string>::call_method(m_self, "greet"); } + { return boost::python::callback<std::string>::call_method(self, "greet"); } // Supplies the default implementation of greet static std::string default_greet(const hello& self) const // 5 { return self.hello::greet(); } private: - PyObject* m_self; // 1 + PyObject* self; // 1 };

      • From 7dc8fab961c798a832c959096462f901c8ec48f7 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 11 Mar 2001 21:29:31 +0000 Subject: [PATCH 092/154] 11 Mar 01 std::string *MAY* include nulls (Alex Martelli) [SVN r9544] --- src/conversions.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/conversions.cpp b/src/conversions.cpp index 88e30048..9445c7f3 100644 --- a/src/conversions.cpp +++ b/src/conversions.cpp @@ -7,6 +7,7 @@ // producing this work. // // Revision History: +// 11 Mar 01 std::string *MAY* include nulls (Alex Martelli) // 04 Mar 01 std::complex<> fixes for MSVC (Dave Abrahams) // 03 Mar 01 added: converters for [plain] char (Ralf W. Grosse-Kunstleve) @@ -149,7 +150,7 @@ int from_python(PyObject* p, boost::python::type type) PyObject* to_python(unsigned int i) { - return integer_to_python(i); + return integer_to_python(i); } unsigned int from_python(PyObject* p, boost::python::type type) @@ -169,7 +170,7 @@ float from_python(PyObject* p, boost::python::type) PyObject* to_python(unsigned short i) { - return integer_to_python(i); + return integer_to_python(i); } unsigned short from_python(PyObject* p, boost::python::type type) @@ -197,7 +198,7 @@ char from_python(PyObject* p, boost::python::type) PyObject* to_python(unsigned char i) { - return integer_to_python(i); + return integer_to_python(i); } unsigned char from_python(PyObject* p, boost::python::type type) @@ -207,7 +208,7 @@ unsigned char from_python(PyObject* p, boost::python::type type) PyObject* to_python(signed char i) { - return integer_to_python(i); + return integer_to_python(i); } signed char from_python(PyObject* p, boost::python::type type) @@ -243,12 +244,15 @@ const char* from_python(PyObject* p, boost::python::type) PyObject* to_python(const std::string& s) { - return PyString_FromString(s.c_str()); + return PyString_FromStringAndSize(s.data(), s.size()); } std::string from_python(PyObject* p, boost::python::type) { - return std::string(from_python(p, boost::python::type())); + char* buffer = 0; + int length = 0; + int rc = PyString_AsStringAndSize(p, &buffer, &length); + return std::string(buffer, length); } bool from_python(PyObject* p, boost::python::type) From ed34cd45f1da43539e40e8b9d51e360312c422c0 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 12 Mar 2001 19:32:40 +0000 Subject: [PATCH 093/154] Python 1.5.2 fixes [SVN r9546] --- src/conversions.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/conversions.cpp b/src/conversions.cpp index 9445c7f3..1bc923b1 100644 --- a/src/conversions.cpp +++ b/src/conversions.cpp @@ -7,6 +7,7 @@ // producing this work. // // Revision History: +// 12 Mar 01 Python 1.5.2 fixes (Ralf W. Grosse-Kunstleve) // 11 Mar 01 std::string *MAY* include nulls (Alex Martelli) // 04 Mar 01 std::complex<> fixes for MSVC (Dave Abrahams) // 03 Mar 01 added: converters for [plain] char (Ralf W. Grosse-Kunstleve) @@ -249,10 +250,7 @@ PyObject* to_python(const std::string& s) std::string from_python(PyObject* p, boost::python::type) { - char* buffer = 0; - int length = 0; - int rc = PyString_AsStringAndSize(p, &buffer, &length); - return std::string(buffer, length); + return std::string(PyString_AsString(p), PyString_Size(p)); } bool from_python(PyObject* p, boost::python::type) From ff04d9f03c85e173a0d6084d20ef3f2416b699c7 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 12 Mar 2001 19:34:14 +0000 Subject: [PATCH 094/154] Minute enhancement. [SVN r9547] --- doc/overriding.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/overriding.html b/doc/overriding.html index 66c3610c..af458d79 100644 --- a/doc/overriding.html +++ b/doc/overriding.html @@ -82,8 +82,8 @@ struct hello_callback : hello { return boost::python::callback<std::string>::call_method(self, "greet"); } // Supplies the default implementation of greet - static std::string default_greet(const hello& self) const // 5 - { return self.hello::greet(); } + static std::string default_greet(const hello& self_) const // 5 + { return self_.hello::greet(); } private: PyObject* self; // 1 }; From 012b4025a48e056da251b58eb50c402079740894 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 13 Mar 2001 00:01:06 +0000 Subject: [PATCH 095/154] temp files before branching [SVN r9549] --- example/pickle1.cpp | 57 +++++++++++++++++++ example/pickle2.cpp | 80 ++++++++++++++++++++++++++ example/pickle3.cpp | 121 ++++++++++++++++++++++++++++++++++++++++ example/test_pickle1.py | 31 ++++++++++ example/test_pickle2.py | 45 +++++++++++++++ example/test_pickle3.py | 38 +++++++++++++ 6 files changed, 372 insertions(+) create mode 100644 example/pickle1.cpp create mode 100644 example/pickle2.cpp create mode 100644 example/pickle3.cpp create mode 100644 example/test_pickle1.py create mode 100644 example/test_pickle2.py create mode 100644 example/test_pickle3.py diff --git a/example/pickle1.cpp b/example/pickle1.cpp new file mode 100644 index 00000000..2f786f69 --- /dev/null +++ b/example/pickle1.cpp @@ -0,0 +1,57 @@ +/* + This example shows how to make an Extension Class "pickleable". + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include + +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class world + { + private: + std::string country; + int secret_number; + public: + world(const std::string& country) : secret_number(0) { + this->country = country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + }; + + // Support for pickle. + python::ref world_getinitargs(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_country()); + return result.reference(); + } +} + +BOOST_PYTHON_MODULE_INIT(pickle1) +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("pickle1"); + + // Create the Python type object for our extension class. + python::class_builder world_class(this_module, "world"); + + // Add the __init__ function. + world_class.def(python::constructor()); + // Add a regular member function. + world_class.def(&world::greet, "greet"); + + // Support for pickle. + world_class.def(world_getinitargs, "__getinitargs__"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/pickle2.cpp b/example/pickle2.cpp new file mode 100644 index 00000000..c33776a0 --- /dev/null +++ b/example/pickle2.cpp @@ -0,0 +1,80 @@ +/* + This example shows how to make an Extension Class "pickleable". + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include + +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class world + { + public: + world(const std::string& country) : secret_number(0) { + this->country = country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + void set_secret_number(int number) { secret_number = number; } + int get_secret_number() const { return secret_number; } + private: + std::string country; + int secret_number; + }; + + // Support for pickle. + python::ref world_getinitargs(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_country()); + return result.reference(); // returning the reference avoids the copying. + } + + python::ref world_getstate(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_secret_number()); + return result.reference(); // returning the reference avoids the copying. + } + + void world_setstate(world& w, python::tuple state) { + if (state.size() != 1) { + PyErr_SetString(PyExc_ValueError, + "Unexpected argument in call to __setstate__."); + throw python::error_already_set(); + } + int number = state[0].get(); + if (number != 42) + w.set_secret_number(number); + } +} + +BOOST_PYTHON_MODULE_INIT(pickle2) +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("pickle2"); + + // Create the Python type object for our extension class. + python::class_builder world_class(this_module, "world"); + + // Add the __init__ function. + world_class.def(python::constructor()); + // Add a regular member function. + world_class.def(&world::greet, "greet"); + world_class.def(&world::get_secret_number, "get_secret_number"); + world_class.def(&world::set_secret_number, "set_secret_number"); + + // Support for pickle. + world_class.def(world_getinitargs, "__getinitargs__"); + world_class.def(world_getstate, "__getstate__"); + world_class.def(world_setstate, "__setstate__"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/pickle3.cpp b/example/pickle3.cpp new file mode 100644 index 00000000..19ddec43 --- /dev/null +++ b/example/pickle3.cpp @@ -0,0 +1,121 @@ +/* + This example shows how to make an Extension Class "pickleable". + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include + +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class world + { + public: + world(const std::string& country) : secret_number(0) { + this->country = country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + void set_secret_number(int number) { secret_number = number; } + int get_secret_number() const { return secret_number; } + private: + std::string country; + int secret_number; + }; + + // Support for pickle. + python::ref world_getinitargs(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_country()); + return result.reference(); // returning the reference avoids the copying. + } + + python::ref world_getstate(python::tuple const & args, + python::dictionary const & keywords); + + PyObject* world_setstate(python::tuple const & args, + python::dictionary const & keywords); +} + +BOOST_PYTHON_MODULE_INIT(pickle3) +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("pickle3"); + + // Create the Python type object for our extension class. + python::class_builder world_class(this_module, "world"); + + // Add the __init__ function. + world_class.def(python::constructor()); + // Add a regular member function. + world_class.def(&world::greet, "greet"); + world_class.def(&world::get_secret_number, "get_secret_number"); + world_class.def(&world::set_secret_number, "set_secret_number"); + + // Support for pickle. + world_class.def(world_getinitargs, "__getinitargs__"); + world_class.def_raw(world_getstate, "__getstate__"); + world_class.def_raw(world_setstate, "__setstate__"); + world_class.getstate_manages_dict(); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} + +namespace { + + python::ref world_getstate(python::tuple const & args, + python::dictionary const & keywords) + { + if(args.size() != 1 || keywords.size() != 0) { + PyErr_SetString(PyExc_TypeError, "wrong number of arguments"); + throw boost::python::argument_error(); + } + const world& w = args[0].get(); + python::ref mydict(args[0].getattr("__dict__")); + python::tuple result(2); + // store the object's __dict__ + result.set_item(0, mydict); + // store the internal state of the C++ object + result.set_item(1, w.get_secret_number()); + return result.reference(); // returning the reference avoids the copying. + } + + PyObject* world_setstate(python::tuple const & args, + python::dictionary const & keywords) + { + if(args.size() != 2 || keywords.size() != 0) { + PyErr_SetString(PyExc_TypeError, "wrong number of arguments"); + throw boost::python::argument_error(); + } + world& w = args[0].get(); + python::ref mydict(args[0].getattr("__dict__")); + const python::tuple& state(args[1].get()); + if (state.size() != 2) { + PyErr_SetString(PyExc_ValueError, + "Unexpected argument in call to __setstate__."); + throw python::error_already_set(); + } + // restore the object's __dict__ + python::dictionary odict(mydict.get()); + const python::dictionary& pdict(state[0].get()); + python::list pkeys(pdict.keys()); + for (int i = 0; i < pkeys.size(); i++) { + python::ref k(pkeys[i]); + //odict[k] = pdict[k]; // XXX memory leak! + odict[k] = pdict.get_item(k); // this does not leak. + } + // restore the internal state of the C++ object + int number = state[1].get(); + if (number != 42) + w.set_secret_number(number); + return python::detail::none(); + } +} diff --git a/example/test_pickle1.py b/example/test_pickle1.py new file mode 100644 index 00000000..05696d4a --- /dev/null +++ b/example/test_pickle1.py @@ -0,0 +1,31 @@ +r'''>>> import pickle1 + >>> import re + >>> import pickle + >>> pickle1.world.__module__ + 'pickle1' + >>> pickle1.world.__safe_for_unpickling__ + 1 + >>> pickle1.world.__reduce__() + 'world' + >>> assert re.match( + ... "\(, \('Hello',\)\)", + ... repr(pickle1.world('Hello').__reduce__())) + >>> + >>> wd = pickle1.world('California') + >>> pstr = pickle.dumps(wd) + >>> wl = pickle.loads(pstr) + >>> print wd.greet() + Hello from California! + >>> print wl.greet() + Hello from California! +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_pickle1 + doctest.testmod(test_pickle1) + +if __name__ == '__main__': + run() diff --git a/example/test_pickle2.py b/example/test_pickle2.py new file mode 100644 index 00000000..463befa6 --- /dev/null +++ b/example/test_pickle2.py @@ -0,0 +1,45 @@ +r'''>>> import pickle2 + >>> import re + >>> import pickle + >>> pickle2.world.__module__ + 'pickle2' + >>> pickle2.world.__safe_for_unpickling__ + 1 + >>> pickle2.world.__reduce__() + 'world' + >>> assert re.match( + ... "\(, \('Hello',\), \(0,\)\)", + ... repr(pickle2.world('Hello').__reduce__())) + >>> + >>> for number in (24, 42): + ... wd = pickle2.world('California') + ... wd.set_secret_number(number) + ... pstr = pickle.dumps(wd) + ... wl = pickle.loads(pstr) + ... print wd.greet(), wd.get_secret_number() + ... print wl.greet(), wl.get_secret_number() + Hello from California! 24 + Hello from California! 24 + Hello from California! 42 + Hello from California! 0 + +# Now show that the __dict__ is not taken care of. + >>> wd = pickle2.world('California') + >>> wd.x = 1 + >>> wd.__dict__ + {'x': 1} + >>> try: pstr = pickle.dumps(wd) + ... except RuntimeError, err: print err[0] + ... + Incomplete pickle support (__getstate_manages_dict__ not set) +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_pickle2 + doctest.testmod(test_pickle2) + +if __name__ == '__main__': + run() diff --git a/example/test_pickle3.py b/example/test_pickle3.py new file mode 100644 index 00000000..b964f1a2 --- /dev/null +++ b/example/test_pickle3.py @@ -0,0 +1,38 @@ +r'''>>> import pickle3 + >>> import re + >>> import pickle + >>> pickle3.world.__module__ + 'pickle3' + >>> pickle3.world.__safe_for_unpickling__ + 1 + >>> pickle3.world.__reduce__() + 'world' + >>> assert re.match( + ... "\(, \('Hello',\), \(\{\}, 0\)\)", + ... repr(pickle3.world('Hello').__reduce__())) + >>> + >>> for number in (24, 42): + ... wd = pickle3.world('California') + ... wd.set_secret_number(number) + ... wd.x = 2 * number + ... wd.y = 'y' * number + ... wd.z = 3. * number + ... pstr = pickle.dumps(wd) + ... wl = pickle.loads(pstr) + ... print wd.greet(), wd.get_secret_number(), wd.__dict__ + ... print wl.greet(), wl.get_secret_number(), wl.__dict__ + Hello from California! 24 {'z': 72.0, 'x': 48, 'y': 'yyyyyyyyyyyyyyyyyyyyyyyy'} + Hello from California! 24 {'z': 72.0, 'x': 48, 'y': 'yyyyyyyyyyyyyyyyyyyyyyyy'} + Hello from California! 42 {'z': 126.0, 'x': 84, 'y': 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'} + Hello from California! 0 {'z': 126.0, 'x': 84, 'y': 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'} +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_pickle3 + doctest.testmod(test_pickle3) + +if __name__ == '__main__': + run() From c979ab01af48fc814c42beb89f857d7db4e85068 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 13 Mar 2001 00:03:58 +0000 Subject: [PATCH 096/154] temp files removed after branching. [SVN r9551] --- example/pickle1.cpp | 57 ------------------- example/pickle2.cpp | 80 -------------------------- example/pickle3.cpp | 121 ---------------------------------------- example/test_pickle1.py | 31 ---------- example/test_pickle2.py | 45 --------------- example/test_pickle3.py | 38 ------------- 6 files changed, 372 deletions(-) delete mode 100644 example/pickle1.cpp delete mode 100644 example/pickle2.cpp delete mode 100644 example/pickle3.cpp delete mode 100644 example/test_pickle1.py delete mode 100644 example/test_pickle2.py delete mode 100644 example/test_pickle3.py diff --git a/example/pickle1.cpp b/example/pickle1.cpp deleted file mode 100644 index 2f786f69..00000000 --- a/example/pickle1.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - This example shows how to make an Extension Class "pickleable". - For more information refer to boost/libs/python/doc/pickle.html. - */ - -#include - -#include -namespace python = boost::python; - -namespace { // Avoid cluttering the global namespace. - - // A friendly class. - class world - { - private: - std::string country; - int secret_number; - public: - world(const std::string& country) : secret_number(0) { - this->country = country; - } - std::string greet() const { return "Hello from " + country + "!"; } - std::string get_country() const { return country; } - }; - - // Support for pickle. - python::ref world_getinitargs(const world& w) { - python::tuple result(1); - result.set_item(0, w.get_country()); - return result.reference(); - } -} - -BOOST_PYTHON_MODULE_INIT(pickle1) -{ - try - { - // Create an object representing this extension module. - python::module_builder this_module("pickle1"); - - // Create the Python type object for our extension class. - python::class_builder world_class(this_module, "world"); - - // Add the __init__ function. - world_class.def(python::constructor()); - // Add a regular member function. - world_class.def(&world::greet, "greet"); - - // Support for pickle. - world_class.def(world_getinitargs, "__getinitargs__"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/pickle2.cpp b/example/pickle2.cpp deleted file mode 100644 index c33776a0..00000000 --- a/example/pickle2.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - This example shows how to make an Extension Class "pickleable". - For more information refer to boost/libs/python/doc/pickle.html. - */ - -#include - -#include -namespace python = boost::python; - -namespace { // Avoid cluttering the global namespace. - - // A friendly class. - class world - { - public: - world(const std::string& country) : secret_number(0) { - this->country = country; - } - std::string greet() const { return "Hello from " + country + "!"; } - std::string get_country() const { return country; } - void set_secret_number(int number) { secret_number = number; } - int get_secret_number() const { return secret_number; } - private: - std::string country; - int secret_number; - }; - - // Support for pickle. - python::ref world_getinitargs(const world& w) { - python::tuple result(1); - result.set_item(0, w.get_country()); - return result.reference(); // returning the reference avoids the copying. - } - - python::ref world_getstate(const world& w) { - python::tuple result(1); - result.set_item(0, w.get_secret_number()); - return result.reference(); // returning the reference avoids the copying. - } - - void world_setstate(world& w, python::tuple state) { - if (state.size() != 1) { - PyErr_SetString(PyExc_ValueError, - "Unexpected argument in call to __setstate__."); - throw python::error_already_set(); - } - int number = state[0].get(); - if (number != 42) - w.set_secret_number(number); - } -} - -BOOST_PYTHON_MODULE_INIT(pickle2) -{ - try - { - // Create an object representing this extension module. - python::module_builder this_module("pickle2"); - - // Create the Python type object for our extension class. - python::class_builder world_class(this_module, "world"); - - // Add the __init__ function. - world_class.def(python::constructor()); - // Add a regular member function. - world_class.def(&world::greet, "greet"); - world_class.def(&world::get_secret_number, "get_secret_number"); - world_class.def(&world::set_secret_number, "set_secret_number"); - - // Support for pickle. - world_class.def(world_getinitargs, "__getinitargs__"); - world_class.def(world_getstate, "__getstate__"); - world_class.def(world_setstate, "__setstate__"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/pickle3.cpp b/example/pickle3.cpp deleted file mode 100644 index 19ddec43..00000000 --- a/example/pickle3.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - This example shows how to make an Extension Class "pickleable". - For more information refer to boost/libs/python/doc/pickle.html. - */ - -#include - -#include -namespace python = boost::python; - -namespace { // Avoid cluttering the global namespace. - - // A friendly class. - class world - { - public: - world(const std::string& country) : secret_number(0) { - this->country = country; - } - std::string greet() const { return "Hello from " + country + "!"; } - std::string get_country() const { return country; } - void set_secret_number(int number) { secret_number = number; } - int get_secret_number() const { return secret_number; } - private: - std::string country; - int secret_number; - }; - - // Support for pickle. - python::ref world_getinitargs(const world& w) { - python::tuple result(1); - result.set_item(0, w.get_country()); - return result.reference(); // returning the reference avoids the copying. - } - - python::ref world_getstate(python::tuple const & args, - python::dictionary const & keywords); - - PyObject* world_setstate(python::tuple const & args, - python::dictionary const & keywords); -} - -BOOST_PYTHON_MODULE_INIT(pickle3) -{ - try - { - // Create an object representing this extension module. - python::module_builder this_module("pickle3"); - - // Create the Python type object for our extension class. - python::class_builder world_class(this_module, "world"); - - // Add the __init__ function. - world_class.def(python::constructor()); - // Add a regular member function. - world_class.def(&world::greet, "greet"); - world_class.def(&world::get_secret_number, "get_secret_number"); - world_class.def(&world::set_secret_number, "set_secret_number"); - - // Support for pickle. - world_class.def(world_getinitargs, "__getinitargs__"); - world_class.def_raw(world_getstate, "__getstate__"); - world_class.def_raw(world_setstate, "__setstate__"); - world_class.getstate_manages_dict(); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} - -namespace { - - python::ref world_getstate(python::tuple const & args, - python::dictionary const & keywords) - { - if(args.size() != 1 || keywords.size() != 0) { - PyErr_SetString(PyExc_TypeError, "wrong number of arguments"); - throw boost::python::argument_error(); - } - const world& w = args[0].get(); - python::ref mydict(args[0].getattr("__dict__")); - python::tuple result(2); - // store the object's __dict__ - result.set_item(0, mydict); - // store the internal state of the C++ object - result.set_item(1, w.get_secret_number()); - return result.reference(); // returning the reference avoids the copying. - } - - PyObject* world_setstate(python::tuple const & args, - python::dictionary const & keywords) - { - if(args.size() != 2 || keywords.size() != 0) { - PyErr_SetString(PyExc_TypeError, "wrong number of arguments"); - throw boost::python::argument_error(); - } - world& w = args[0].get(); - python::ref mydict(args[0].getattr("__dict__")); - const python::tuple& state(args[1].get()); - if (state.size() != 2) { - PyErr_SetString(PyExc_ValueError, - "Unexpected argument in call to __setstate__."); - throw python::error_already_set(); - } - // restore the object's __dict__ - python::dictionary odict(mydict.get()); - const python::dictionary& pdict(state[0].get()); - python::list pkeys(pdict.keys()); - for (int i = 0; i < pkeys.size(); i++) { - python::ref k(pkeys[i]); - //odict[k] = pdict[k]; // XXX memory leak! - odict[k] = pdict.get_item(k); // this does not leak. - } - // restore the internal state of the C++ object - int number = state[1].get(); - if (number != 42) - w.set_secret_number(number); - return python::detail::none(); - } -} diff --git a/example/test_pickle1.py b/example/test_pickle1.py deleted file mode 100644 index 05696d4a..00000000 --- a/example/test_pickle1.py +++ /dev/null @@ -1,31 +0,0 @@ -r'''>>> import pickle1 - >>> import re - >>> import pickle - >>> pickle1.world.__module__ - 'pickle1' - >>> pickle1.world.__safe_for_unpickling__ - 1 - >>> pickle1.world.__reduce__() - 'world' - >>> assert re.match( - ... "\(, \('Hello',\)\)", - ... repr(pickle1.world('Hello').__reduce__())) - >>> - >>> wd = pickle1.world('California') - >>> pstr = pickle.dumps(wd) - >>> wl = pickle.loads(pstr) - >>> print wd.greet() - Hello from California! - >>> print wl.greet() - Hello from California! -''' - -def run(args = None): - if args is not None: - import sys - sys.argv = args - import doctest, test_pickle1 - doctest.testmod(test_pickle1) - -if __name__ == '__main__': - run() diff --git a/example/test_pickle2.py b/example/test_pickle2.py deleted file mode 100644 index 463befa6..00000000 --- a/example/test_pickle2.py +++ /dev/null @@ -1,45 +0,0 @@ -r'''>>> import pickle2 - >>> import re - >>> import pickle - >>> pickle2.world.__module__ - 'pickle2' - >>> pickle2.world.__safe_for_unpickling__ - 1 - >>> pickle2.world.__reduce__() - 'world' - >>> assert re.match( - ... "\(, \('Hello',\), \(0,\)\)", - ... repr(pickle2.world('Hello').__reduce__())) - >>> - >>> for number in (24, 42): - ... wd = pickle2.world('California') - ... wd.set_secret_number(number) - ... pstr = pickle.dumps(wd) - ... wl = pickle.loads(pstr) - ... print wd.greet(), wd.get_secret_number() - ... print wl.greet(), wl.get_secret_number() - Hello from California! 24 - Hello from California! 24 - Hello from California! 42 - Hello from California! 0 - -# Now show that the __dict__ is not taken care of. - >>> wd = pickle2.world('California') - >>> wd.x = 1 - >>> wd.__dict__ - {'x': 1} - >>> try: pstr = pickle.dumps(wd) - ... except RuntimeError, err: print err[0] - ... - Incomplete pickle support (__getstate_manages_dict__ not set) -''' - -def run(args = None): - if args is not None: - import sys - sys.argv = args - import doctest, test_pickle2 - doctest.testmod(test_pickle2) - -if __name__ == '__main__': - run() diff --git a/example/test_pickle3.py b/example/test_pickle3.py deleted file mode 100644 index b964f1a2..00000000 --- a/example/test_pickle3.py +++ /dev/null @@ -1,38 +0,0 @@ -r'''>>> import pickle3 - >>> import re - >>> import pickle - >>> pickle3.world.__module__ - 'pickle3' - >>> pickle3.world.__safe_for_unpickling__ - 1 - >>> pickle3.world.__reduce__() - 'world' - >>> assert re.match( - ... "\(, \('Hello',\), \(\{\}, 0\)\)", - ... repr(pickle3.world('Hello').__reduce__())) - >>> - >>> for number in (24, 42): - ... wd = pickle3.world('California') - ... wd.set_secret_number(number) - ... wd.x = 2 * number - ... wd.y = 'y' * number - ... wd.z = 3. * number - ... pstr = pickle.dumps(wd) - ... wl = pickle.loads(pstr) - ... print wd.greet(), wd.get_secret_number(), wd.__dict__ - ... print wl.greet(), wl.get_secret_number(), wl.__dict__ - Hello from California! 24 {'z': 72.0, 'x': 48, 'y': 'yyyyyyyyyyyyyyyyyyyyyyyy'} - Hello from California! 24 {'z': 72.0, 'x': 48, 'y': 'yyyyyyyyyyyyyyyyyyyyyyyy'} - Hello from California! 42 {'z': 126.0, 'x': 84, 'y': 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'} - Hello from California! 0 {'z': 126.0, 'x': 84, 'y': 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'} -''' - -def run(args = None): - if args is not None: - import sys - sys.argv = args - import doctest, test_pickle3 - doctest.testmod(test_pickle3) - -if __name__ == '__main__': - run() From 60b91ac6780ee9c7594892185377cebbde95652b Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Wed, 14 Mar 2001 15:11:55 +0000 Subject: [PATCH 097/154] 1.21.1 run up, including new download instructions and fix broken hyperlinks [SVN r9557] --- doc/building.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/building.html b/doc/building.html index 6627bbe8..2a8c9cae 100644 --- a/doc/building.html +++ b/doc/building.html @@ -57,7 +57,7 @@ special debugging version of the Python DLL. Since this debug DLL isn't supplied with the default Python installation for Windows, Boost.Python uses boost/python/detail/wrap_python.hpp + "../../../boost/python/detail/wrap_python.hpp">boost/python/detail/wrap_python.hpp to temporarily undefine _DEBUG when Python.h is #included. @@ -77,7 +77,7 @@

        If you do not #define BOOST_DEBUG_PYTHON, be sure that any source files #include <boost/python/detail/wrap_python.hpp> + "../../../boost/python/detail/wrap_python.hpp">boost/python/detail/wrap_python.hpp> instead of the usual Python.h, or you will have link incompatibilities.

        From c068a300f429a81a78c486579feda5418a8b22e8 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 15 Mar 2001 16:05:25 +0000 Subject: [PATCH 098/154] template file is not longer needed, causes "broken links" messages [SVN r9562] --- doc/template.html | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 doc/template.html diff --git a/doc/template.html b/doc/template.html deleted file mode 100644 index 1d0cd7a4..00000000 --- a/doc/template.html +++ /dev/null @@ -1,26 +0,0 @@ - - - The Title Of This Page - -

        -

        - c++boost.gif (8819 bytes)The Title Of This - Page -

        -

        -

        - Prev: Previous - Next: Next - Up: Top -

        - © Copyright David Abrahams 2000. Permission to copy, use, modify, - sell and distribute this document is granted provided this copyright - notice appears in all copies. This document is provided "as is" without - express or implied warranty, and with no claim as to its suitability - for any purpose. -

        - Updated: Nov 26, 2000 -

        - From 13b2e072d25cc3b7e11471afd3b8098a26c458ec Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Fri, 16 Mar 2001 21:56:41 +0000 Subject: [PATCH 099/154] Remove const qualifications that will confuse VC++'s buggy brain [SVN r9567] --- example/getting_started4.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/getting_started4.cpp b/example/getting_started4.cpp index 199ef7a9..cf6c2ff2 100644 --- a/example/getting_started4.cpp +++ b/example/getting_started4.cpp @@ -55,7 +55,7 @@ namespace { // Avoid cluttering the global namespace. // Function returning a vector_double object to Python. // - std::vector foo(const int n) + std::vector foo(int n) { std::vector vd(n); std::vector::iterator vditer = vd.begin(); @@ -65,7 +65,7 @@ namespace { // Avoid cluttering the global namespace. // Same as foo(), but avoid copying on return. // - std::auto_ptr > bar(const int n) + std::auto_ptr > bar(int n) { std::auto_ptr > vdptr(new std::vector(n)); std::vector::iterator vditer = vdptr->begin(); From 098eadefe0f4849d762d227c7df27fc6b82abffc Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 20 Mar 2001 02:07:39 +0000 Subject: [PATCH 100/154] temp file before branching [SVN r9599] --- include/boost/python/cross_module.hpp | 274 ++++++++++++++++++++++++++ src/cross_module.cpp | 77 ++++++++ 2 files changed, 351 insertions(+) create mode 100644 include/boost/python/cross_module.hpp create mode 100644 src/cross_module.cpp diff --git a/include/boost/python/cross_module.hpp b/include/boost/python/cross_module.hpp new file mode 100644 index 00000000..a6c32889 --- /dev/null +++ b/include/boost/python/cross_module.hpp @@ -0,0 +1,274 @@ +#ifndef CROSS_MODULE_HPP +# define CROSS_MODULE_HPP + +# include + +namespace boost { namespace python { + struct import_error : error_already_set {}; + struct export_error : error_already_set {}; +}} + +namespace boost { namespace python { 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 = 2; +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); + +}}} + +// forward declaration +namespace boost { namespace python { namespace detail { +template class import_extension_class; +}}} + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + +//QUESTIONMARK +// This class is a look-alike of class python_extension_class_converters. +// Is there a formal way to ensure that the siblings stay in sync? +template +class python_import_extension_class_converters +{ + public: + + friend python_import_extension_class_converters py_extension_class_converters(boost::python::type) + { + return python_import_extension_class_converters(); + } + + PyObject* to_python(const T& x) const + { + return boost::python::detail::import_extension_class::get_converters()->to_python(x); + } + + friend T* from_python(PyObject* p, boost::python::type) + { + return boost::python::detail::import_extension_class::get_converters()->T_pointer_from_python(p); + } + + // Convert to const T* + friend const T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to const T* const& + friend const T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T* const& + friend T* from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T& + friend T& from_python(PyObject* p, boost::python::type) { + return boost::python::detail::import_extension_class::get_converters()->T_reference_from_python(p); + } + + // Convert to const T& + friend const T& from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + // Convert to T + friend const T& from_python(PyObject* p, boost::python::type) + { return from_python(p, boost::python::type()); } + + friend std::auto_ptr& from_python(PyObject* p, boost::python::type&>) { + return boost::python::detail::import_extension_class::get_converters()->auto_ptr_reference_from_python(p); + } + + friend std::auto_ptr& from_python(PyObject* p, boost::python::type >) { + return boost::python::detail::import_extension_class::get_converters()->auto_ptr_value_from_python(p); + } + + friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&>) { + return boost::python::detail::import_extension_class::get_converters()->auto_ptr_value_from_python(p); + } + + friend PyObject* to_python(std::auto_ptr x) { + return boost::python::detail::import_extension_class::get_converters()->to_python(x); + } + + friend boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) { + return boost::python::detail::import_extension_class::get_converters()->shared_ptr_reference_from_python(p); + } + + friend boost::shared_ptr& from_python(PyObject* p, boost::python::type >) { + return boost::python::detail::import_extension_class::get_converters()->shared_ptr_value_from_python(p); + } + + friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) { + return boost::python::detail::import_extension_class::get_converters()->shared_ptr_value_from_python(p); + } + + friend PyObject* to_python(boost::shared_ptr x) { + return boost::python::detail::import_extension_class::get_converters()->to_python(x); + } +}; + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +namespace boost { namespace python { + +BOOST_PYTHON_IMPORT_CONVERSION(python_import_extension_class_converters); + +// A pointer to this class is exported/imported via the Python API. +// All functions are virtual. This is, what we really export/import +// is essentially just a pointer to a vtbl. +template +struct export_converter_object_base +{ + virtual const int get_api_major() const { + return detail::export_converters_api_major; } + virtual const int get_api_minor() const { + return detail::export_converters_api_minor; } + virtual PyObject* to_python(const T& x) = 0; + virtual PyObject* to_python(std::auto_ptr x) = 0; + virtual PyObject* to_python(boost::shared_ptr x) = 0; + virtual T* T_pointer_from_python(PyObject* obj) = 0; + virtual T& T_reference_from_python(PyObject* obj) = 0; + virtual std::auto_ptr& auto_ptr_reference_from_python(PyObject* obj) = 0; + virtual std::auto_ptr auto_ptr_value_from_python(PyObject* obj) = 0; + virtual boost::shared_ptr& shared_ptr_reference_from_python(PyObject* obj) = 0; + virtual boost::shared_ptr shared_ptr_value_from_python(PyObject* obj) = 0; +}; + +// Converters to be used if T is not copyable. +template +struct export_converter_object_noncopyable : export_converter_object_base +{ + virtual PyObject* to_python(const T& x) { + PyErr_SetString(PyExc_RuntimeError, + "to_python(const T&) converter not exported"); + throw import_error(); + } + virtual PyObject* to_python(std::auto_ptr x) { + return BOOST_PYTHON_CONVERSION::to_python(x); + } + virtual PyObject* to_python(boost::shared_ptr x) { + return BOOST_PYTHON_CONVERSION::to_python(x); + } + virtual T* T_pointer_from_python(PyObject* obj) { + return BOOST_PYTHON_CONVERSION::from_python(obj, boost::python::type()); + } + virtual T& T_reference_from_python(PyObject* obj) { + return BOOST_PYTHON_CONVERSION::from_python(obj, boost::python::type()); + } + virtual std::auto_ptr& auto_ptr_reference_from_python(PyObject* obj) { + return BOOST_PYTHON_CONVERSION::python_extension_class_converters::smart_ptr_reference(obj, boost::python::type >()); + } + virtual std::auto_ptr auto_ptr_value_from_python(PyObject* obj) { + return BOOST_PYTHON_CONVERSION::python_extension_class_converters::smart_ptr_value(obj, boost::python::type >()); + } + virtual boost::shared_ptr& shared_ptr_reference_from_python(PyObject* obj) { + return BOOST_PYTHON_CONVERSION::python_extension_class_converters::smart_ptr_reference(obj, boost::python::type >()); + } + virtual boost::shared_ptr shared_ptr_value_from_python(PyObject* obj) { + return BOOST_PYTHON_CONVERSION::python_extension_class_converters::smart_ptr_value(obj, boost::python::type >()); + } +}; + +// The addditional to_python() converter that can be used if T is copyable. +template +struct export_converter_object : export_converter_object_noncopyable +{ + virtual PyObject* to_python(const T& x) { + BOOST_PYTHON_CONVERSION::python_extension_class_converters cv; + return cv.to_python(x); + } +}; + +namespace detail { + +//QUESTIONMARK +// A stripped-down, modified version of class extension_class. +// Would it make sense to establish a formal relationship +// between the two classes? +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(); + + 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 +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; +} + +}}} // namespace boost::python::detail + +namespace boost { namespace python { + +template +void export_converters(class_builder& cb) +{ + static export_converter_object export_cvts; + cb.add( + ref(PyCObject_FromVoidPtr(reinterpret_cast(&export_cvts), NULL)), + detail::converters_attribute_name); +} + +template +void export_converters_noncopyable(class_builder& cb) +{ + static export_converter_object_noncopyable export_cvts; + cb.add( + ref(PyCObject_FromVoidPtr(reinterpret_cast(&export_cvts), NULL)), + detail::converters_attribute_name); +} + +template +class import_converters + : python_import_extension_class_converters +{ + public: + import_converters(const char* module, const char* py_class) + : m_class(new detail::import_extension_class(module, py_class)) + { } + private: + //QUESTIONMARK + //reference > m_class; + boost::shared_ptr > m_class; +}; + +}} // namespace boost::python + +#endif // CROSS_MODULE_HPP diff --git a/src/cross_module.cpp b/src/cross_module.cpp new file mode 100644 index 00000000..c14acfda --- /dev/null +++ b/src/cross_module.cpp @@ -0,0 +1,77 @@ +# include +namespace python = boost::python; +# include // MSVC6.0SP4 does not know std::fprintf +# include // MSVC6.0SP4 does not know std::strcmp + +namespace { + + PyObject* get_module_dict(const char* module_name) + { + python::ref module_obj(PyImport_ImportModule((char*) module_name)); + PyObject* module_dict = PyModule_GetDict(module_obj.get()); + if (module_dict == 0) throw python::import_error(); + return module_dict; + } +} + +namespace boost { namespace python { namespace detail { + +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) +{ + 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 + "." + + 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()); +} + +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 From db943b4109c71c61b7293bfcacb13becfe2d01db Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 20 Mar 2001 02:08:24 +0000 Subject: [PATCH 101/154] temp file removed after branching. [SVN r9600] --- include/boost/python/cross_module.hpp | 274 -------------------------- src/cross_module.cpp | 77 -------- 2 files changed, 351 deletions(-) delete mode 100644 include/boost/python/cross_module.hpp delete mode 100644 src/cross_module.cpp diff --git a/include/boost/python/cross_module.hpp b/include/boost/python/cross_module.hpp deleted file mode 100644 index a6c32889..00000000 --- a/include/boost/python/cross_module.hpp +++ /dev/null @@ -1,274 +0,0 @@ -#ifndef CROSS_MODULE_HPP -# define CROSS_MODULE_HPP - -# include - -namespace boost { namespace python { - struct import_error : error_already_set {}; - struct export_error : error_already_set {}; -}} - -namespace boost { namespace python { 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 = 2; -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); - -}}} - -// forward declaration -namespace boost { namespace python { namespace detail { -template class import_extension_class; -}}} - -BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE - -//QUESTIONMARK -// This class is a look-alike of class python_extension_class_converters. -// Is there a formal way to ensure that the siblings stay in sync? -template -class python_import_extension_class_converters -{ - public: - - friend python_import_extension_class_converters py_extension_class_converters(boost::python::type) - { - return python_import_extension_class_converters(); - } - - PyObject* to_python(const T& x) const - { - return boost::python::detail::import_extension_class::get_converters()->to_python(x); - } - - friend T* from_python(PyObject* p, boost::python::type) - { - return boost::python::detail::import_extension_class::get_converters()->T_pointer_from_python(p); - } - - // Convert to const T* - friend const T* from_python(PyObject* p, boost::python::type) - { return from_python(p, boost::python::type()); } - - // Convert to const T* const& - friend const T* from_python(PyObject* p, boost::python::type) - { return from_python(p, boost::python::type()); } - - // Convert to T* const& - friend T* from_python(PyObject* p, boost::python::type) - { return from_python(p, boost::python::type()); } - - // Convert to T& - friend T& from_python(PyObject* p, boost::python::type) { - return boost::python::detail::import_extension_class::get_converters()->T_reference_from_python(p); - } - - // Convert to const T& - friend const T& from_python(PyObject* p, boost::python::type) - { return from_python(p, boost::python::type()); } - - // Convert to T - friend const T& from_python(PyObject* p, boost::python::type) - { return from_python(p, boost::python::type()); } - - friend std::auto_ptr& from_python(PyObject* p, boost::python::type&>) { - return boost::python::detail::import_extension_class::get_converters()->auto_ptr_reference_from_python(p); - } - - friend std::auto_ptr& from_python(PyObject* p, boost::python::type >) { - return boost::python::detail::import_extension_class::get_converters()->auto_ptr_value_from_python(p); - } - - friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&>) { - return boost::python::detail::import_extension_class::get_converters()->auto_ptr_value_from_python(p); - } - - friend PyObject* to_python(std::auto_ptr x) { - return boost::python::detail::import_extension_class::get_converters()->to_python(x); - } - - friend boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) { - return boost::python::detail::import_extension_class::get_converters()->shared_ptr_reference_from_python(p); - } - - friend boost::shared_ptr& from_python(PyObject* p, boost::python::type >) { - return boost::python::detail::import_extension_class::get_converters()->shared_ptr_value_from_python(p); - } - - friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) { - return boost::python::detail::import_extension_class::get_converters()->shared_ptr_value_from_python(p); - } - - friend PyObject* to_python(boost::shared_ptr x) { - return boost::python::detail::import_extension_class::get_converters()->to_python(x); - } -}; - -BOOST_PYTHON_END_CONVERSION_NAMESPACE - -namespace boost { namespace python { - -BOOST_PYTHON_IMPORT_CONVERSION(python_import_extension_class_converters); - -// A pointer to this class is exported/imported via the Python API. -// All functions are virtual. This is, what we really export/import -// is essentially just a pointer to a vtbl. -template -struct export_converter_object_base -{ - virtual const int get_api_major() const { - return detail::export_converters_api_major; } - virtual const int get_api_minor() const { - return detail::export_converters_api_minor; } - virtual PyObject* to_python(const T& x) = 0; - virtual PyObject* to_python(std::auto_ptr x) = 0; - virtual PyObject* to_python(boost::shared_ptr x) = 0; - virtual T* T_pointer_from_python(PyObject* obj) = 0; - virtual T& T_reference_from_python(PyObject* obj) = 0; - virtual std::auto_ptr& auto_ptr_reference_from_python(PyObject* obj) = 0; - virtual std::auto_ptr auto_ptr_value_from_python(PyObject* obj) = 0; - virtual boost::shared_ptr& shared_ptr_reference_from_python(PyObject* obj) = 0; - virtual boost::shared_ptr shared_ptr_value_from_python(PyObject* obj) = 0; -}; - -// Converters to be used if T is not copyable. -template -struct export_converter_object_noncopyable : export_converter_object_base -{ - virtual PyObject* to_python(const T& x) { - PyErr_SetString(PyExc_RuntimeError, - "to_python(const T&) converter not exported"); - throw import_error(); - } - virtual PyObject* to_python(std::auto_ptr x) { - return BOOST_PYTHON_CONVERSION::to_python(x); - } - virtual PyObject* to_python(boost::shared_ptr x) { - return BOOST_PYTHON_CONVERSION::to_python(x); - } - virtual T* T_pointer_from_python(PyObject* obj) { - return BOOST_PYTHON_CONVERSION::from_python(obj, boost::python::type()); - } - virtual T& T_reference_from_python(PyObject* obj) { - return BOOST_PYTHON_CONVERSION::from_python(obj, boost::python::type()); - } - virtual std::auto_ptr& auto_ptr_reference_from_python(PyObject* obj) { - return BOOST_PYTHON_CONVERSION::python_extension_class_converters::smart_ptr_reference(obj, boost::python::type >()); - } - virtual std::auto_ptr auto_ptr_value_from_python(PyObject* obj) { - return BOOST_PYTHON_CONVERSION::python_extension_class_converters::smart_ptr_value(obj, boost::python::type >()); - } - virtual boost::shared_ptr& shared_ptr_reference_from_python(PyObject* obj) { - return BOOST_PYTHON_CONVERSION::python_extension_class_converters::smart_ptr_reference(obj, boost::python::type >()); - } - virtual boost::shared_ptr shared_ptr_value_from_python(PyObject* obj) { - return BOOST_PYTHON_CONVERSION::python_extension_class_converters::smart_ptr_value(obj, boost::python::type >()); - } -}; - -// The addditional to_python() converter that can be used if T is copyable. -template -struct export_converter_object : export_converter_object_noncopyable -{ - virtual PyObject* to_python(const T& x) { - BOOST_PYTHON_CONVERSION::python_extension_class_converters cv; - return cv.to_python(x); - } -}; - -namespace detail { - -//QUESTIONMARK -// A stripped-down, modified version of class extension_class. -// Would it make sense to establish a formal relationship -// between the two classes? -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(); - - 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 -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; -} - -}}} // namespace boost::python::detail - -namespace boost { namespace python { - -template -void export_converters(class_builder& cb) -{ - static export_converter_object export_cvts; - cb.add( - ref(PyCObject_FromVoidPtr(reinterpret_cast(&export_cvts), NULL)), - detail::converters_attribute_name); -} - -template -void export_converters_noncopyable(class_builder& cb) -{ - static export_converter_object_noncopyable export_cvts; - cb.add( - ref(PyCObject_FromVoidPtr(reinterpret_cast(&export_cvts), NULL)), - detail::converters_attribute_name); -} - -template -class import_converters - : python_import_extension_class_converters -{ - public: - import_converters(const char* module, const char* py_class) - : m_class(new detail::import_extension_class(module, py_class)) - { } - private: - //QUESTIONMARK - //reference > m_class; - boost::shared_ptr > m_class; -}; - -}} // namespace boost::python - -#endif // CROSS_MODULE_HPP diff --git a/src/cross_module.cpp b/src/cross_module.cpp deleted file mode 100644 index c14acfda..00000000 --- a/src/cross_module.cpp +++ /dev/null @@ -1,77 +0,0 @@ -# include -namespace python = boost::python; -# include // MSVC6.0SP4 does not know std::fprintf -# include // MSVC6.0SP4 does not know std::strcmp - -namespace { - - PyObject* get_module_dict(const char* module_name) - { - python::ref module_obj(PyImport_ImportModule((char*) module_name)); - PyObject* module_dict = PyModule_GetDict(module_obj.get()); - if (module_dict == 0) throw python::import_error(); - return module_dict; - } -} - -namespace boost { namespace python { namespace detail { - -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) -{ - 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 + "." - + 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()); -} - -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 From 1f45a846c64420b56fb9da13d963f97035a18525 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 20 Mar 2001 02:13:28 +0000 Subject: [PATCH 102/154] VC++ 6.0 fixes and misc. other modifications. [SVN r9601] --- example/getting_started4.cpp | 9 ++++----- example/getting_started5.cpp | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/example/getting_started4.cpp b/example/getting_started4.cpp index cf6c2ff2..fe6a3421 100644 --- a/example/getting_started4.cpp +++ b/example/getting_started4.cpp @@ -15,7 +15,7 @@ namespace { // Avoid cluttering the global namespace. vector_double_wrapper(PyObject* self) : std::vector() {} - vector_double_wrapper(PyObject* self, const int n) + vector_double_wrapper(PyObject* self, int n) : std::vector(n) {} vector_double_wrapper(PyObject* self, python::tuple tuple) @@ -28,17 +28,16 @@ namespace { // Avoid cluttering the global namespace. } }; - double getitem(const std::vector& vd, const std::size_t key) { + double getitem(const std::vector& vd, std::size_t key) { return vd[key]; } - void setitem(std::vector& vd, const std::size_t key, - const double &d) { + void setitem(std::vector& vd, std::size_t key, double d) { std::vector::iterator vditer = vd.begin(); vditer[key] = d; } - void delitem(std::vector& vd, const std::size_t key) { + void delitem(std::vector& vd, std::size_t key) { std::vector::iterator vditer = vd.begin(); vd.erase(&vditer[key]); } diff --git a/example/getting_started5.cpp b/example/getting_started5.cpp index be033224..9e9e7c75 100644 --- a/example/getting_started5.cpp +++ b/example/getting_started5.cpp @@ -60,7 +60,7 @@ namespace { // Avoid cluttering the global namespace. std::vector VMIx; public: void add(const MillerIndex& MIx) { VMIx.push_back(MIx); } - MillerIndex get(const std::size_t i) const { return VMIx[i]; } + MillerIndex get(std::size_t i) const { return VMIx[i]; } }; } From 591eaeaafbaa53bce030c06af0198690886a915a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 20 Mar 2001 02:16:08 +0000 Subject: [PATCH 103/154] VC++ 6.0 makefile; filemgr.py used by all ralf_grosse_kunstleve makefiles. [SVN r9602] --- build/filemgr.py | 122 ++++++++++++++++++++++++++++++++++++++++++++ build/vc60.mak | 129 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 build/filemgr.py create mode 100644 build/vc60.mak diff --git a/build/filemgr.py b/build/filemgr.py new file mode 100644 index 00000000..51c87403 --- /dev/null +++ b/build/filemgr.py @@ -0,0 +1,122 @@ +bpl_src = "/libs/python/src" +bpl_tst = "/libs/python/test" +bpl_exa = "/libs/python/example" +files = ( +bpl_src + "/classes.cpp", +bpl_src + "/conversions.cpp", +bpl_src + "/extension_class.cpp", +bpl_src + "/functions.cpp", +bpl_src + "/init_function.cpp", +bpl_src + "/module_builder.cpp", +bpl_src + "/objects.cpp", +bpl_src + "/types.cpp", +bpl_src + "/cross_module.cpp", +bpl_tst + "/comprehensive.cpp", +bpl_tst + "/comprehensive.hpp", +bpl_tst + "/comprehensive.py", +bpl_tst + "/doctest.py", +bpl_exa + "/abstract.cpp", +bpl_exa + "/getting_started1.cpp", +bpl_exa + "/getting_started2.cpp", +bpl_exa + "/getting_started3.cpp", +bpl_exa + "/getting_started4.cpp", +bpl_exa + "/getting_started5.cpp", +bpl_exa + "/pickle1.cpp", +bpl_exa + "/pickle2.cpp", +bpl_exa + "/pickle3.cpp", +bpl_exa + "/test_abstract.py", +bpl_exa + "/test_getting_started1.py", +bpl_exa + "/test_getting_started2.py", +bpl_exa + "/test_getting_started3.py", +bpl_exa + "/test_getting_started4.py", +bpl_exa + "/test_getting_started5.py", +bpl_exa + "/test_pickle1.py", +bpl_exa + "/test_pickle2.py", +bpl_exa + "/test_pickle3.py", +bpl_exa + "/noncopyable.h", +bpl_exa + "/noncopyable_export.cpp", +bpl_exa + "/noncopyable_import.cpp", +bpl_exa + "/tst_noncopyable.py", +bpl_exa + "/ivect.h", +bpl_exa + "/ivect.cpp", +bpl_exa + "/dvect.h", +bpl_exa + "/dvect.cpp", +bpl_exa + "/tst_ivect.py", +bpl_exa + "/tst_dvect.py", +) + +defs = ( +"boost_python_test", +"abstract", +"getting_started1", +"getting_started2", +"getting_started3", +"getting_started4", +"getting_started5", +"pickle1", +"pickle2", +"pickle3", +"noncopyable_export", +"noncopyable_import", +"ivect", +"dvect", +) + +if (__name__ == "__main__"): + + import sys, os, string + + path = sys.argv[1] + mode = sys.argv[2] + if (not mode in ("softlinks", "unlink", "cp", "rm", "copy", "del")): + raise RuntimeError, \ + "usage: python filemgr.py path " + + translation_table = string.maketrans("/", "\\") + + if (mode == "copy"): + for fn in files: + fn = string.translate(fn, translation_table) + os.system("copy " + path + fn + " .") + + elif (mode == "cp"): + for fn in files: + os.system("cp " + path + fn + " .") + + elif (mode == "softlinks"): + for fn in files: + f = string.split(fn, "/")[-1] + if (os.access(f, os.F_OK)): + print "File exists: " + f + else: + os.system("ln -s " + path + os.sep + fn + " .") + + elif (mode in ("rm", "del")): + for fn in files: + flds = string.split(fn, "/") + try: os.unlink(flds[-1]) + except: pass + + elif (mode == "unlink"): + for fn in files: + f = string.split(fn, "/")[-1] + if (os.system("test -e " + f) == 0): + if (os.system("test -L " + f) == 0): + try: os.unlink(f) + except: pass + else: + print "Not a softlink: " + f + + if (mode in ("softlinks", "cp", "copy")): + for d in defs: + fn = d + ".def" + f = open(fn, "w") + f.write("EXPORTS\n") + f.write("\tinit" + d + "\n") + f.close() + + if (mode in ("unlink", "rm", "del")): + for d in defs: + fn = d + ".def" + try: os.unlink(fn) + except: pass diff --git a/build/vc60.mak b/build/vc60.mak new file mode 100644 index 00000000..a05d04f4 --- /dev/null +++ b/build/vc60.mak @@ -0,0 +1,129 @@ +# Usage: +# +# make copy Copy the sources and tests +# make Compile all sources +# make test Run doctest tests +# make clean Remove all object files +# make del Remove the sources and tests + +BOOST_WIN= "L:\boost" +BOOST_UNIX= /net/cci/rwgk/boost + +PYEXE= "C:\Program files\Python\python.exe" +PYINC= /I"C:\Program files\Python\include" +PYLIB= "C:\Program files\Python\libs\python15.lib" + +STDOPTS= /nologo /MD /GR /GX /FD /Zm200 +WARNOPTS= + +CPP= cl.exe +CPPOPTS= $(STLPORTINC) $(STLPORTOPTS) /I$(BOOST_WIN) $(PYINC) \ + $(STDOPTS) $(WARNOPTS) + +LD= link.exe +LDOPTS= /nologo /dll /incremental:no + +OBJ = classes.obj conversions.obj extension_class.obj functions.obj \ + init_function.obj module_builder.obj \ + objects.obj types.obj cross_module.obj + +.SUFFIXES: .obj .cpp + +all: libboost_python.a \ + boost_python_test.pyd \ + abstract.pyd \ + getting_started1.pyd getting_started2.pyd getting_started3.pyd \ + getting_started4.pyd getting_started5.pyd \ + pickle1.pyd pickle2.pyd pickle3.pyd \ + noncopyable_export.pyd noncopyable_import.pyd \ + ivect.pyd dvect.pyd + +libboost_python.a: $(OBJ) + +boost_python_test.pyd: $(OBJ) comprehensive.obj + $(LD) $(LDOPTS) $(OBJ) comprehensive.obj $(PYLIB) /export:initboost_python_test /out:"boost_python_test.pyd" + +abstract.pyd: $(OBJ) abstract.obj + $(LD) $(LDOPTS) $(OBJ) abstract.obj $(PYLIB) /export:initabstract /out:"abstract.pyd" + +getting_started1.pyd: $(OBJ) getting_started1.obj + $(LD) $(LDOPTS) $(OBJ) getting_started1.obj $(PYLIB) /export:initgetting_started1 /out:"getting_started1.pyd" + +getting_started2.pyd: $(OBJ) getting_started2.obj + $(LD) $(LDOPTS) $(OBJ) getting_started2.obj $(PYLIB) /export:initgetting_started2 /out:"getting_started2.pyd" + +getting_started3.pyd: $(OBJ) getting_started3.obj + $(LD) $(LDOPTS) $(OBJ) getting_started3.obj $(PYLIB) /export:initgetting_started3 /out:"getting_started3.pyd" + +getting_started4.pyd: $(OBJ) getting_started4.obj + $(LD) $(LDOPTS) $(OBJ) getting_started4.obj $(PYLIB) /export:initgetting_started4 /out:"getting_started4.pyd" + +getting_started5.pyd: $(OBJ) getting_started5.obj + $(LD) $(LDOPTS) $(OBJ) getting_started5.obj $(PYLIB) /export:initgetting_started5 /out:"getting_started5.pyd" + +pickle1.pyd: $(OBJ) pickle1.obj + $(LD) $(LDOPTS) $(OBJ) pickle1.obj $(PYLIB) /export:initpickle1 /out:"pickle1.pyd" + +pickle2.pyd: $(OBJ) pickle2.obj + $(LD) $(LDOPTS) $(OBJ) pickle2.obj $(PYLIB) /export:initpickle2 /out:"pickle2.pyd" + +pickle3.pyd: $(OBJ) pickle3.obj + $(LD) $(LDOPTS) $(OBJ) pickle3.obj $(PYLIB) /export:initpickle3 /out:"pickle3.pyd" + +noncopyable_export.pyd: $(OBJ) noncopyable_export.obj + $(LD) $(LDOPTS) $(OBJ) noncopyable_export.obj $(PYLIB) /export:initnoncopyable_export /out:"noncopyable_export.pyd" + +noncopyable_import.pyd: $(OBJ) noncopyable_import.obj + $(LD) $(LDOPTS) $(OBJ) noncopyable_import.obj $(PYLIB) /export:initnoncopyable_import /out:"noncopyable_import.pyd" + +ivect.pyd: $(OBJ) ivect.obj + $(LD) $(LDOPTS) $(OBJ) ivect.obj $(PYLIB) /export:initivect /out:"ivect.pyd" + +dvect.pyd: $(OBJ) dvect.obj + $(LD) $(LDOPTS) $(OBJ) dvect.obj $(PYLIB) /export:initdvect /out:"dvect.pyd" + +.cpp.obj: + $(CPP) $(CPPOPTS) /c $*.cpp + +test: + $(PYEXE) comprehensive.py --broken-auto-ptr + $(PYEXE) test_abstract.py + $(PYEXE) test_getting_started1.py + $(PYEXE) test_getting_started2.py + $(PYEXE) test_getting_started3.py + $(PYEXE) test_getting_started4.py + $(PYEXE) test_getting_started5.py + $(PYEXE) test_pickle1.py + $(PYEXE) test_pickle2.py + $(PYEXE) test_pickle3.py + +tst: + $(PYEXE) tst_noncopyable.py + $(PYEXE) tst_ivect.py + $(PYEXE) tst_dvect.py + +clean: + del *.obj + del *.lib + del *.exp + del *.idb + del *.pyd + del *.pyc + +softlinks: + python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) softlinks + +unlink: + python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) unlink + +cp: + python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) cp + +rm: + python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) rm + +copy: + python $(BOOST_WIN)\libs\python\build\filemgr.py $(BOOST_WIN) copy + +del: + python $(BOOST_WIN)\libs\python\build\filemgr.py $(BOOST_WIN) del From c4775a581edb6aaf6c7e9cde17c5e4a26be9f36d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 21 Mar 2001 01:05:30 +0000 Subject: [PATCH 104/154] temp files before branching [SVN r9615] --- example/dvect_conversions.cpp | 51 +++++++++++++++++++++ example/dvect_defs.cpp | 13 ++++++ example/ivect_conversions.cpp | 51 +++++++++++++++++++++ example/ivect_defs.cpp | 13 ++++++ example/swap_iv_dv.sh | 1 + example/tst_dvect1.py | 23 ++++++++++ example/tst_dvect2.py | 85 +++++++++++++++++++++++++++++++++++ example/tst_ivect1.py | 23 ++++++++++ example/tst_ivect2.py | 85 +++++++++++++++++++++++++++++++++++ 9 files changed, 345 insertions(+) create mode 100644 example/dvect_conversions.cpp create mode 100644 example/dvect_defs.cpp create mode 100644 example/ivect_conversions.cpp create mode 100644 example/ivect_defs.cpp create mode 100644 example/swap_iv_dv.sh create mode 100644 example/tst_dvect1.py create mode 100644 example/tst_dvect2.py create mode 100644 example/tst_ivect1.py create mode 100644 example/tst_ivect2.py diff --git a/example/dvect_conversions.cpp b/example/dvect_conversions.cpp new file mode 100644 index 00000000..21527243 --- /dev/null +++ b/example/dvect_conversions.cpp @@ -0,0 +1,51 @@ + // basics first: const reference converters + boost::python::tuple const_dvect_reference_as_tuple(const vects::dvect& dv) + { + return dv.as_tuple(); + } + + // to_python smart pointer conversions + std::auto_ptr dvect_as_auto_ptr(const vects::dvect& dv) + { + return std::auto_ptr(new vects::dvect(dv)); + } + boost::shared_ptr dvect_as_shared_ptr(const vects::dvect& dv) + { + return boost::shared_ptr(new vects::dvect(dv)); + } + + // smart pointers passed by value + boost::python::ref auto_ptr_value_dvect_as_tuple(std::auto_ptr dv) + { + if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return dv->as_tuple().reference(); + } + boost::python::ref shared_ptr_value_dvect_as_tuple(boost::shared_ptr dv) + { + if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return dv->as_tuple().reference(); + } + + // smart pointers passed by reference + boost::python::ref auto_ptr_reference_dvect_as_tuple(std::auto_ptr& dv) + { + if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return dv->as_tuple().reference(); + } + boost::python::ref shared_ptr_reference_dvect_as_tuple(boost::shared_ptr& dv) + { + if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return dv->as_tuple().reference(); + } + + // smart pointers passed by const reference + boost::python::ref auto_ptr_const_reference_dvect_as_tuple(const std::auto_ptr& dv) + { + if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return dv->as_tuple().reference(); + } + boost::python::ref shared_ptr_const_reference_dvect_as_tuple(const boost::shared_ptr& dv) + { + if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return dv->as_tuple().reference(); + } diff --git a/example/dvect_defs.cpp b/example/dvect_defs.cpp new file mode 100644 index 00000000..2739b219 --- /dev/null +++ b/example/dvect_defs.cpp @@ -0,0 +1,13 @@ + this_module.def(dvect_as_auto_ptr, "dvect_as_auto_ptr"); + this_module.def(dvect_as_shared_ptr, "dvect_as_shared_ptr"); + + this_module.def(const_dvect_reference_as_tuple, "const_dvect_reference_as_tuple"); + + this_module.def(auto_ptr_value_dvect_as_tuple, "auto_ptr_value_dvect_as_tuple"); + this_module.def(shared_ptr_value_dvect_as_tuple, "shared_ptr_value_dvect_as_tuple"); + + this_module.def(auto_ptr_reference_dvect_as_tuple, "auto_ptr_reference_dvect_as_tuple"); + this_module.def(shared_ptr_reference_dvect_as_tuple, "shared_ptr_reference_dvect_as_tuple"); + + this_module.def(auto_ptr_const_reference_dvect_as_tuple, "auto_ptr_const_reference_dvect_as_tuple"); + this_module.def(shared_ptr_const_reference_dvect_as_tuple, "shared_ptr_const_reference_dvect_as_tuple"); diff --git a/example/ivect_conversions.cpp b/example/ivect_conversions.cpp new file mode 100644 index 00000000..4f59573d --- /dev/null +++ b/example/ivect_conversions.cpp @@ -0,0 +1,51 @@ + // basics first: const reference converters + boost::python::tuple const_ivect_reference_as_tuple(const vects::ivect& iv) + { + return iv.as_tuple(); + } + + // to_python smart pointer conversions + std::auto_ptr ivect_as_auto_ptr(const vects::ivect& iv) + { + return std::auto_ptr(new vects::ivect(iv)); + } + boost::shared_ptr ivect_as_shared_ptr(const vects::ivect& iv) + { + return boost::shared_ptr(new vects::ivect(iv)); + } + + // smart pointers passed by value + boost::python::ref auto_ptr_value_ivect_as_tuple(std::auto_ptr iv) + { + if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return iv->as_tuple().reference(); + } + boost::python::ref shared_ptr_value_ivect_as_tuple(boost::shared_ptr iv) + { + if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return iv->as_tuple().reference(); + } + + // smart pointers passed by reference + boost::python::ref auto_ptr_reference_ivect_as_tuple(std::auto_ptr& iv) + { + if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return iv->as_tuple().reference(); + } + boost::python::ref shared_ptr_reference_ivect_as_tuple(boost::shared_ptr& iv) + { + if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return iv->as_tuple().reference(); + } + + // smart pointers passed by const reference + boost::python::ref auto_ptr_const_reference_ivect_as_tuple(const std::auto_ptr& iv) + { + if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return iv->as_tuple().reference(); + } + boost::python::ref shared_ptr_const_reference_ivect_as_tuple(const boost::shared_ptr& iv) + { + if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return iv->as_tuple().reference(); + } diff --git a/example/ivect_defs.cpp b/example/ivect_defs.cpp new file mode 100644 index 00000000..811c243d --- /dev/null +++ b/example/ivect_defs.cpp @@ -0,0 +1,13 @@ + this_module.def(ivect_as_auto_ptr, "ivect_as_auto_ptr"); + this_module.def(ivect_as_shared_ptr, "ivect_as_shared_ptr"); + + this_module.def(const_ivect_reference_as_tuple, "const_ivect_reference_as_tuple"); + + this_module.def(auto_ptr_value_ivect_as_tuple, "auto_ptr_value_ivect_as_tuple"); + this_module.def(shared_ptr_value_ivect_as_tuple, "shared_ptr_value_ivect_as_tuple"); + + this_module.def(auto_ptr_reference_ivect_as_tuple, "auto_ptr_reference_ivect_as_tuple"); + this_module.def(shared_ptr_reference_ivect_as_tuple, "shared_ptr_reference_ivect_as_tuple"); + + this_module.def(auto_ptr_const_reference_ivect_as_tuple, "auto_ptr_const_reference_ivect_as_tuple"); + this_module.def(shared_ptr_const_reference_ivect_as_tuple, "shared_ptr_const_reference_ivect_as_tuple"); diff --git a/example/swap_iv_dv.sh b/example/swap_iv_dv.sh new file mode 100644 index 00000000..fc072bee --- /dev/null +++ b/example/swap_iv_dv.sh @@ -0,0 +1 @@ +sed 's/iv/xv/g' $1 | sed 's/dv/iv/g' | sed 's/xv/dv/g' diff --git a/example/tst_dvect1.py b/example/tst_dvect1.py new file mode 100644 index 00000000..12c53739 --- /dev/null +++ b/example/tst_dvect1.py @@ -0,0 +1,23 @@ +def f(): + import dvect + print dvect.dvect.__converters__ + dv = dvect.dvect((1,2,3,4,5)) + print dv + print dv.as_tuple() + iv = dv.as_ivect() + print iv + print iv.as_tuple() + print dvect.const_ivect_reference_as_tuple(iv) + aiv = dvect.ivect_as_auto_ptr(iv) + print dvect.const_ivect_reference_as_tuple(aiv) + siv = dvect.ivect_as_shared_ptr(iv) + print dvect.const_ivect_reference_as_tuple(siv) + print aiv.as_tuple() + print siv.as_tuple() + +if (__name__ == "__main__"): + import sys, string + n = 1 + if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) + for i in xrange(n): + f() diff --git a/example/tst_dvect2.py b/example/tst_dvect2.py new file mode 100644 index 00000000..868c107d --- /dev/null +++ b/example/tst_dvect2.py @@ -0,0 +1,85 @@ +def f(): + import dvect + import ivect + # + dv = dvect.dvect((1,2,3,4,5)) + iv = dv.as_ivect() + # + aiv = dvect.ivect_as_auto_ptr(iv) + print '1. auto_ptr_value_ivect_as_tuple' + print ivect.auto_ptr_value_ivect_as_tuple(aiv) + print '2. auto_ptr_value_ivect_as_tuple' + print ivect.auto_ptr_value_ivect_as_tuple(aiv) + # + adv = dvect.dvect_as_auto_ptr(dv) + print '1. auto_ptr_value_dvect_as_tuple' + print ivect.auto_ptr_value_dvect_as_tuple(adv) + print '2. auto_ptr_value_dvect_as_tuple' + print ivect.auto_ptr_value_dvect_as_tuple(adv) + # + siv = dvect.ivect_as_shared_ptr(iv) + print '1. shared_ptr_value_ivect_as_tuple' + print ivect.shared_ptr_value_ivect_as_tuple(siv) + print '2. shared_ptr_value_ivect_as_tuple' + print ivect.shared_ptr_value_ivect_as_tuple(siv) + # + sdv = dvect.dvect_as_shared_ptr(dv) + print '1. shared_ptr_value_dvect_as_tuple' + print ivect.shared_ptr_value_dvect_as_tuple(sdv) + print '2. shared_ptr_value_dvect_as_tuple' + print ivect.shared_ptr_value_dvect_as_tuple(sdv) + # + aiv = dvect.ivect_as_auto_ptr(iv) + print '1. auto_ptr_reference_ivect_as_tuple' + print ivect.auto_ptr_reference_ivect_as_tuple(aiv) + print '2. auto_ptr_reference_ivect_as_tuple' + print ivect.auto_ptr_reference_ivect_as_tuple(aiv) + # + adv = dvect.dvect_as_auto_ptr(dv) + print '1. auto_ptr_reference_dvect_as_tuple' + print ivect.auto_ptr_reference_dvect_as_tuple(adv) + print '2. auto_ptr_reference_dvect_as_tuple' + print ivect.auto_ptr_reference_dvect_as_tuple(adv) + # + siv = dvect.ivect_as_shared_ptr(iv) + print '1. shared_ptr_reference_ivect_as_tuple' + print ivect.shared_ptr_reference_ivect_as_tuple(siv) + print '2. shared_ptr_reference_ivect_as_tuple' + print ivect.shared_ptr_reference_ivect_as_tuple(siv) + # + sdv = dvect.dvect_as_shared_ptr(dv) + print '1. shared_ptr_reference_dvect_as_tuple' + print ivect.shared_ptr_reference_dvect_as_tuple(sdv) + print '2. shared_ptr_reference_dvect_as_tuple' + print ivect.shared_ptr_reference_dvect_as_tuple(sdv) + # + aiv = dvect.ivect_as_auto_ptr(iv) + print '1. auto_ptr_const_reference_ivect_as_tuple' + print ivect.auto_ptr_const_reference_ivect_as_tuple(aiv) + print '2. auto_ptr_const_reference_ivect_as_tuple' + print ivect.auto_ptr_const_reference_ivect_as_tuple(aiv) + # + adv = dvect.dvect_as_auto_ptr(dv) + print '1. auto_ptr_const_reference_dvect_as_tuple' + print ivect.auto_ptr_const_reference_dvect_as_tuple(adv) + print '2. auto_ptr_const_reference_dvect_as_tuple' + print ivect.auto_ptr_const_reference_dvect_as_tuple(adv) + # + siv = dvect.ivect_as_shared_ptr(iv) + print '1. shared_ptr_const_reference_ivect_as_tuple' + print ivect.shared_ptr_const_reference_ivect_as_tuple(siv) + print '2. shared_ptr_const_reference_ivect_as_tuple' + print ivect.shared_ptr_const_reference_ivect_as_tuple(siv) + # + sdv = dvect.dvect_as_shared_ptr(dv) + print '1. shared_ptr_const_reference_dvect_as_tuple' + print ivect.shared_ptr_const_reference_dvect_as_tuple(sdv) + print '2. shared_ptr_const_reference_dvect_as_tuple' + print ivect.shared_ptr_const_reference_dvect_as_tuple(sdv) + +if (__name__ == "__main__"): + import sys, string + n = 1 + if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) + for i in xrange(n): + f() diff --git a/example/tst_ivect1.py b/example/tst_ivect1.py new file mode 100644 index 00000000..62d3ecf4 --- /dev/null +++ b/example/tst_ivect1.py @@ -0,0 +1,23 @@ +def f(): + import ivect + print ivect.ivect.__converters__ + iv = ivect.ivect((1,2,3,4,5)) + print iv + print iv.as_tuple() + dv = iv.as_dvect() + print dv + print dv.as_tuple() + print ivect.const_dvect_reference_as_tuple(dv) + adv = ivect.dvect_as_auto_ptr(dv) + print ivect.const_dvect_reference_as_tuple(adv) + sdv = ivect.dvect_as_shared_ptr(dv) + print ivect.const_dvect_reference_as_tuple(sdv) + print adv.as_tuple() + print sdv.as_tuple() + +if (__name__ == "__main__"): + import sys, string + n = 1 + if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) + for i in xrange(n): + f() diff --git a/example/tst_ivect2.py b/example/tst_ivect2.py new file mode 100644 index 00000000..0db6903d --- /dev/null +++ b/example/tst_ivect2.py @@ -0,0 +1,85 @@ +def f(): + import ivect + import dvect + # + iv = ivect.ivect((1,2,3,4,5)) + dv = iv.as_dvect() + # + adv = ivect.dvect_as_auto_ptr(dv) + print '1. auto_ptr_value_dvect_as_tuple' + print dvect.auto_ptr_value_dvect_as_tuple(adv) + print '2. auto_ptr_value_dvect_as_tuple' + print dvect.auto_ptr_value_dvect_as_tuple(adv) + # + aiv = ivect.ivect_as_auto_ptr(iv) + print '1. auto_ptr_value_ivect_as_tuple' + print dvect.auto_ptr_value_ivect_as_tuple(aiv) + print '2. auto_ptr_value_ivect_as_tuple' + print dvect.auto_ptr_value_ivect_as_tuple(aiv) + # + sdv = ivect.dvect_as_shared_ptr(dv) + print '1. shared_ptr_value_dvect_as_tuple' + print dvect.shared_ptr_value_dvect_as_tuple(sdv) + print '2. shared_ptr_value_dvect_as_tuple' + print dvect.shared_ptr_value_dvect_as_tuple(sdv) + # + siv = ivect.ivect_as_shared_ptr(iv) + print '1. shared_ptr_value_ivect_as_tuple' + print dvect.shared_ptr_value_ivect_as_tuple(siv) + print '2. shared_ptr_value_ivect_as_tuple' + print dvect.shared_ptr_value_ivect_as_tuple(siv) + # + adv = ivect.dvect_as_auto_ptr(dv) + print '1. auto_ptr_reference_dvect_as_tuple' + print dvect.auto_ptr_reference_dvect_as_tuple(adv) + print '2. auto_ptr_reference_dvect_as_tuple' + print dvect.auto_ptr_reference_dvect_as_tuple(adv) + # + aiv = ivect.ivect_as_auto_ptr(iv) + print '1. auto_ptr_reference_ivect_as_tuple' + print dvect.auto_ptr_reference_ivect_as_tuple(aiv) + print '2. auto_ptr_reference_ivect_as_tuple' + print dvect.auto_ptr_reference_ivect_as_tuple(aiv) + # + sdv = ivect.dvect_as_shared_ptr(dv) + print '1. shared_ptr_reference_dvect_as_tuple' + print dvect.shared_ptr_reference_dvect_as_tuple(sdv) + print '2. shared_ptr_reference_dvect_as_tuple' + print dvect.shared_ptr_reference_dvect_as_tuple(sdv) + # + siv = ivect.ivect_as_shared_ptr(iv) + print '1. shared_ptr_reference_ivect_as_tuple' + print dvect.shared_ptr_reference_ivect_as_tuple(siv) + print '2. shared_ptr_reference_ivect_as_tuple' + print dvect.shared_ptr_reference_ivect_as_tuple(siv) + # + adv = ivect.dvect_as_auto_ptr(dv) + print '1. auto_ptr_const_reference_dvect_as_tuple' + print dvect.auto_ptr_const_reference_dvect_as_tuple(adv) + print '2. auto_ptr_const_reference_dvect_as_tuple' + print dvect.auto_ptr_const_reference_dvect_as_tuple(adv) + # + aiv = ivect.ivect_as_auto_ptr(iv) + print '1. auto_ptr_const_reference_ivect_as_tuple' + print dvect.auto_ptr_const_reference_ivect_as_tuple(aiv) + print '2. auto_ptr_const_reference_ivect_as_tuple' + print dvect.auto_ptr_const_reference_ivect_as_tuple(aiv) + # + sdv = ivect.dvect_as_shared_ptr(dv) + print '1. shared_ptr_const_reference_dvect_as_tuple' + print dvect.shared_ptr_const_reference_dvect_as_tuple(sdv) + print '2. shared_ptr_const_reference_dvect_as_tuple' + print dvect.shared_ptr_const_reference_dvect_as_tuple(sdv) + # + siv = ivect.ivect_as_shared_ptr(iv) + print '1. shared_ptr_const_reference_ivect_as_tuple' + print dvect.shared_ptr_const_reference_ivect_as_tuple(siv) + print '2. shared_ptr_const_reference_ivect_as_tuple' + print dvect.shared_ptr_const_reference_ivect_as_tuple(siv) + +if (__name__ == "__main__"): + import sys, string + n = 1 + if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) + for i in xrange(n): + f() From c7d7cec28190763156ebe44d950f830ffac07c77 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 21 Mar 2001 01:07:07 +0000 Subject: [PATCH 105/154] temp files removed after branching. [SVN r9616] --- example/dvect_conversions.cpp | 51 --------------------- example/dvect_defs.cpp | 13 ------ example/ivect_conversions.cpp | 51 --------------------- example/ivect_defs.cpp | 13 ------ example/swap_iv_dv.sh | 1 - example/tst_dvect1.py | 23 ---------- example/tst_dvect2.py | 85 ----------------------------------- example/tst_ivect1.py | 23 ---------- example/tst_ivect2.py | 85 ----------------------------------- 9 files changed, 345 deletions(-) delete mode 100644 example/dvect_conversions.cpp delete mode 100644 example/dvect_defs.cpp delete mode 100644 example/ivect_conversions.cpp delete mode 100644 example/ivect_defs.cpp delete mode 100644 example/swap_iv_dv.sh delete mode 100644 example/tst_dvect1.py delete mode 100644 example/tst_dvect2.py delete mode 100644 example/tst_ivect1.py delete mode 100644 example/tst_ivect2.py diff --git a/example/dvect_conversions.cpp b/example/dvect_conversions.cpp deleted file mode 100644 index 21527243..00000000 --- a/example/dvect_conversions.cpp +++ /dev/null @@ -1,51 +0,0 @@ - // basics first: const reference converters - boost::python::tuple const_dvect_reference_as_tuple(const vects::dvect& dv) - { - return dv.as_tuple(); - } - - // to_python smart pointer conversions - std::auto_ptr dvect_as_auto_ptr(const vects::dvect& dv) - { - return std::auto_ptr(new vects::dvect(dv)); - } - boost::shared_ptr dvect_as_shared_ptr(const vects::dvect& dv) - { - return boost::shared_ptr(new vects::dvect(dv)); - } - - // smart pointers passed by value - boost::python::ref auto_ptr_value_dvect_as_tuple(std::auto_ptr dv) - { - if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); - return dv->as_tuple().reference(); - } - boost::python::ref shared_ptr_value_dvect_as_tuple(boost::shared_ptr dv) - { - if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); - return dv->as_tuple().reference(); - } - - // smart pointers passed by reference - boost::python::ref auto_ptr_reference_dvect_as_tuple(std::auto_ptr& dv) - { - if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); - return dv->as_tuple().reference(); - } - boost::python::ref shared_ptr_reference_dvect_as_tuple(boost::shared_ptr& dv) - { - if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); - return dv->as_tuple().reference(); - } - - // smart pointers passed by const reference - boost::python::ref auto_ptr_const_reference_dvect_as_tuple(const std::auto_ptr& dv) - { - if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); - return dv->as_tuple().reference(); - } - boost::python::ref shared_ptr_const_reference_dvect_as_tuple(const boost::shared_ptr& dv) - { - if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); - return dv->as_tuple().reference(); - } diff --git a/example/dvect_defs.cpp b/example/dvect_defs.cpp deleted file mode 100644 index 2739b219..00000000 --- a/example/dvect_defs.cpp +++ /dev/null @@ -1,13 +0,0 @@ - this_module.def(dvect_as_auto_ptr, "dvect_as_auto_ptr"); - this_module.def(dvect_as_shared_ptr, "dvect_as_shared_ptr"); - - this_module.def(const_dvect_reference_as_tuple, "const_dvect_reference_as_tuple"); - - this_module.def(auto_ptr_value_dvect_as_tuple, "auto_ptr_value_dvect_as_tuple"); - this_module.def(shared_ptr_value_dvect_as_tuple, "shared_ptr_value_dvect_as_tuple"); - - this_module.def(auto_ptr_reference_dvect_as_tuple, "auto_ptr_reference_dvect_as_tuple"); - this_module.def(shared_ptr_reference_dvect_as_tuple, "shared_ptr_reference_dvect_as_tuple"); - - this_module.def(auto_ptr_const_reference_dvect_as_tuple, "auto_ptr_const_reference_dvect_as_tuple"); - this_module.def(shared_ptr_const_reference_dvect_as_tuple, "shared_ptr_const_reference_dvect_as_tuple"); diff --git a/example/ivect_conversions.cpp b/example/ivect_conversions.cpp deleted file mode 100644 index 4f59573d..00000000 --- a/example/ivect_conversions.cpp +++ /dev/null @@ -1,51 +0,0 @@ - // basics first: const reference converters - boost::python::tuple const_ivect_reference_as_tuple(const vects::ivect& iv) - { - return iv.as_tuple(); - } - - // to_python smart pointer conversions - std::auto_ptr ivect_as_auto_ptr(const vects::ivect& iv) - { - return std::auto_ptr(new vects::ivect(iv)); - } - boost::shared_ptr ivect_as_shared_ptr(const vects::ivect& iv) - { - return boost::shared_ptr(new vects::ivect(iv)); - } - - // smart pointers passed by value - boost::python::ref auto_ptr_value_ivect_as_tuple(std::auto_ptr iv) - { - if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); - return iv->as_tuple().reference(); - } - boost::python::ref shared_ptr_value_ivect_as_tuple(boost::shared_ptr iv) - { - if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); - return iv->as_tuple().reference(); - } - - // smart pointers passed by reference - boost::python::ref auto_ptr_reference_ivect_as_tuple(std::auto_ptr& iv) - { - if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); - return iv->as_tuple().reference(); - } - boost::python::ref shared_ptr_reference_ivect_as_tuple(boost::shared_ptr& iv) - { - if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); - return iv->as_tuple().reference(); - } - - // smart pointers passed by const reference - boost::python::ref auto_ptr_const_reference_ivect_as_tuple(const std::auto_ptr& iv) - { - if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); - return iv->as_tuple().reference(); - } - boost::python::ref shared_ptr_const_reference_ivect_as_tuple(const boost::shared_ptr& iv) - { - if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); - return iv->as_tuple().reference(); - } diff --git a/example/ivect_defs.cpp b/example/ivect_defs.cpp deleted file mode 100644 index 811c243d..00000000 --- a/example/ivect_defs.cpp +++ /dev/null @@ -1,13 +0,0 @@ - this_module.def(ivect_as_auto_ptr, "ivect_as_auto_ptr"); - this_module.def(ivect_as_shared_ptr, "ivect_as_shared_ptr"); - - this_module.def(const_ivect_reference_as_tuple, "const_ivect_reference_as_tuple"); - - this_module.def(auto_ptr_value_ivect_as_tuple, "auto_ptr_value_ivect_as_tuple"); - this_module.def(shared_ptr_value_ivect_as_tuple, "shared_ptr_value_ivect_as_tuple"); - - this_module.def(auto_ptr_reference_ivect_as_tuple, "auto_ptr_reference_ivect_as_tuple"); - this_module.def(shared_ptr_reference_ivect_as_tuple, "shared_ptr_reference_ivect_as_tuple"); - - this_module.def(auto_ptr_const_reference_ivect_as_tuple, "auto_ptr_const_reference_ivect_as_tuple"); - this_module.def(shared_ptr_const_reference_ivect_as_tuple, "shared_ptr_const_reference_ivect_as_tuple"); diff --git a/example/swap_iv_dv.sh b/example/swap_iv_dv.sh deleted file mode 100644 index fc072bee..00000000 --- a/example/swap_iv_dv.sh +++ /dev/null @@ -1 +0,0 @@ -sed 's/iv/xv/g' $1 | sed 's/dv/iv/g' | sed 's/xv/dv/g' diff --git a/example/tst_dvect1.py b/example/tst_dvect1.py deleted file mode 100644 index 12c53739..00000000 --- a/example/tst_dvect1.py +++ /dev/null @@ -1,23 +0,0 @@ -def f(): - import dvect - print dvect.dvect.__converters__ - dv = dvect.dvect((1,2,3,4,5)) - print dv - print dv.as_tuple() - iv = dv.as_ivect() - print iv - print iv.as_tuple() - print dvect.const_ivect_reference_as_tuple(iv) - aiv = dvect.ivect_as_auto_ptr(iv) - print dvect.const_ivect_reference_as_tuple(aiv) - siv = dvect.ivect_as_shared_ptr(iv) - print dvect.const_ivect_reference_as_tuple(siv) - print aiv.as_tuple() - print siv.as_tuple() - -if (__name__ == "__main__"): - import sys, string - n = 1 - if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) - for i in xrange(n): - f() diff --git a/example/tst_dvect2.py b/example/tst_dvect2.py deleted file mode 100644 index 868c107d..00000000 --- a/example/tst_dvect2.py +++ /dev/null @@ -1,85 +0,0 @@ -def f(): - import dvect - import ivect - # - dv = dvect.dvect((1,2,3,4,5)) - iv = dv.as_ivect() - # - aiv = dvect.ivect_as_auto_ptr(iv) - print '1. auto_ptr_value_ivect_as_tuple' - print ivect.auto_ptr_value_ivect_as_tuple(aiv) - print '2. auto_ptr_value_ivect_as_tuple' - print ivect.auto_ptr_value_ivect_as_tuple(aiv) - # - adv = dvect.dvect_as_auto_ptr(dv) - print '1. auto_ptr_value_dvect_as_tuple' - print ivect.auto_ptr_value_dvect_as_tuple(adv) - print '2. auto_ptr_value_dvect_as_tuple' - print ivect.auto_ptr_value_dvect_as_tuple(adv) - # - siv = dvect.ivect_as_shared_ptr(iv) - print '1. shared_ptr_value_ivect_as_tuple' - print ivect.shared_ptr_value_ivect_as_tuple(siv) - print '2. shared_ptr_value_ivect_as_tuple' - print ivect.shared_ptr_value_ivect_as_tuple(siv) - # - sdv = dvect.dvect_as_shared_ptr(dv) - print '1. shared_ptr_value_dvect_as_tuple' - print ivect.shared_ptr_value_dvect_as_tuple(sdv) - print '2. shared_ptr_value_dvect_as_tuple' - print ivect.shared_ptr_value_dvect_as_tuple(sdv) - # - aiv = dvect.ivect_as_auto_ptr(iv) - print '1. auto_ptr_reference_ivect_as_tuple' - print ivect.auto_ptr_reference_ivect_as_tuple(aiv) - print '2. auto_ptr_reference_ivect_as_tuple' - print ivect.auto_ptr_reference_ivect_as_tuple(aiv) - # - adv = dvect.dvect_as_auto_ptr(dv) - print '1. auto_ptr_reference_dvect_as_tuple' - print ivect.auto_ptr_reference_dvect_as_tuple(adv) - print '2. auto_ptr_reference_dvect_as_tuple' - print ivect.auto_ptr_reference_dvect_as_tuple(adv) - # - siv = dvect.ivect_as_shared_ptr(iv) - print '1. shared_ptr_reference_ivect_as_tuple' - print ivect.shared_ptr_reference_ivect_as_tuple(siv) - print '2. shared_ptr_reference_ivect_as_tuple' - print ivect.shared_ptr_reference_ivect_as_tuple(siv) - # - sdv = dvect.dvect_as_shared_ptr(dv) - print '1. shared_ptr_reference_dvect_as_tuple' - print ivect.shared_ptr_reference_dvect_as_tuple(sdv) - print '2. shared_ptr_reference_dvect_as_tuple' - print ivect.shared_ptr_reference_dvect_as_tuple(sdv) - # - aiv = dvect.ivect_as_auto_ptr(iv) - print '1. auto_ptr_const_reference_ivect_as_tuple' - print ivect.auto_ptr_const_reference_ivect_as_tuple(aiv) - print '2. auto_ptr_const_reference_ivect_as_tuple' - print ivect.auto_ptr_const_reference_ivect_as_tuple(aiv) - # - adv = dvect.dvect_as_auto_ptr(dv) - print '1. auto_ptr_const_reference_dvect_as_tuple' - print ivect.auto_ptr_const_reference_dvect_as_tuple(adv) - print '2. auto_ptr_const_reference_dvect_as_tuple' - print ivect.auto_ptr_const_reference_dvect_as_tuple(adv) - # - siv = dvect.ivect_as_shared_ptr(iv) - print '1. shared_ptr_const_reference_ivect_as_tuple' - print ivect.shared_ptr_const_reference_ivect_as_tuple(siv) - print '2. shared_ptr_const_reference_ivect_as_tuple' - print ivect.shared_ptr_const_reference_ivect_as_tuple(siv) - # - sdv = dvect.dvect_as_shared_ptr(dv) - print '1. shared_ptr_const_reference_dvect_as_tuple' - print ivect.shared_ptr_const_reference_dvect_as_tuple(sdv) - print '2. shared_ptr_const_reference_dvect_as_tuple' - print ivect.shared_ptr_const_reference_dvect_as_tuple(sdv) - -if (__name__ == "__main__"): - import sys, string - n = 1 - if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) - for i in xrange(n): - f() diff --git a/example/tst_ivect1.py b/example/tst_ivect1.py deleted file mode 100644 index 62d3ecf4..00000000 --- a/example/tst_ivect1.py +++ /dev/null @@ -1,23 +0,0 @@ -def f(): - import ivect - print ivect.ivect.__converters__ - iv = ivect.ivect((1,2,3,4,5)) - print iv - print iv.as_tuple() - dv = iv.as_dvect() - print dv - print dv.as_tuple() - print ivect.const_dvect_reference_as_tuple(dv) - adv = ivect.dvect_as_auto_ptr(dv) - print ivect.const_dvect_reference_as_tuple(adv) - sdv = ivect.dvect_as_shared_ptr(dv) - print ivect.const_dvect_reference_as_tuple(sdv) - print adv.as_tuple() - print sdv.as_tuple() - -if (__name__ == "__main__"): - import sys, string - n = 1 - if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) - for i in xrange(n): - f() diff --git a/example/tst_ivect2.py b/example/tst_ivect2.py deleted file mode 100644 index 0db6903d..00000000 --- a/example/tst_ivect2.py +++ /dev/null @@ -1,85 +0,0 @@ -def f(): - import ivect - import dvect - # - iv = ivect.ivect((1,2,3,4,5)) - dv = iv.as_dvect() - # - adv = ivect.dvect_as_auto_ptr(dv) - print '1. auto_ptr_value_dvect_as_tuple' - print dvect.auto_ptr_value_dvect_as_tuple(adv) - print '2. auto_ptr_value_dvect_as_tuple' - print dvect.auto_ptr_value_dvect_as_tuple(adv) - # - aiv = ivect.ivect_as_auto_ptr(iv) - print '1. auto_ptr_value_ivect_as_tuple' - print dvect.auto_ptr_value_ivect_as_tuple(aiv) - print '2. auto_ptr_value_ivect_as_tuple' - print dvect.auto_ptr_value_ivect_as_tuple(aiv) - # - sdv = ivect.dvect_as_shared_ptr(dv) - print '1. shared_ptr_value_dvect_as_tuple' - print dvect.shared_ptr_value_dvect_as_tuple(sdv) - print '2. shared_ptr_value_dvect_as_tuple' - print dvect.shared_ptr_value_dvect_as_tuple(sdv) - # - siv = ivect.ivect_as_shared_ptr(iv) - print '1. shared_ptr_value_ivect_as_tuple' - print dvect.shared_ptr_value_ivect_as_tuple(siv) - print '2. shared_ptr_value_ivect_as_tuple' - print dvect.shared_ptr_value_ivect_as_tuple(siv) - # - adv = ivect.dvect_as_auto_ptr(dv) - print '1. auto_ptr_reference_dvect_as_tuple' - print dvect.auto_ptr_reference_dvect_as_tuple(adv) - print '2. auto_ptr_reference_dvect_as_tuple' - print dvect.auto_ptr_reference_dvect_as_tuple(adv) - # - aiv = ivect.ivect_as_auto_ptr(iv) - print '1. auto_ptr_reference_ivect_as_tuple' - print dvect.auto_ptr_reference_ivect_as_tuple(aiv) - print '2. auto_ptr_reference_ivect_as_tuple' - print dvect.auto_ptr_reference_ivect_as_tuple(aiv) - # - sdv = ivect.dvect_as_shared_ptr(dv) - print '1. shared_ptr_reference_dvect_as_tuple' - print dvect.shared_ptr_reference_dvect_as_tuple(sdv) - print '2. shared_ptr_reference_dvect_as_tuple' - print dvect.shared_ptr_reference_dvect_as_tuple(sdv) - # - siv = ivect.ivect_as_shared_ptr(iv) - print '1. shared_ptr_reference_ivect_as_tuple' - print dvect.shared_ptr_reference_ivect_as_tuple(siv) - print '2. shared_ptr_reference_ivect_as_tuple' - print dvect.shared_ptr_reference_ivect_as_tuple(siv) - # - adv = ivect.dvect_as_auto_ptr(dv) - print '1. auto_ptr_const_reference_dvect_as_tuple' - print dvect.auto_ptr_const_reference_dvect_as_tuple(adv) - print '2. auto_ptr_const_reference_dvect_as_tuple' - print dvect.auto_ptr_const_reference_dvect_as_tuple(adv) - # - aiv = ivect.ivect_as_auto_ptr(iv) - print '1. auto_ptr_const_reference_ivect_as_tuple' - print dvect.auto_ptr_const_reference_ivect_as_tuple(aiv) - print '2. auto_ptr_const_reference_ivect_as_tuple' - print dvect.auto_ptr_const_reference_ivect_as_tuple(aiv) - # - sdv = ivect.dvect_as_shared_ptr(dv) - print '1. shared_ptr_const_reference_dvect_as_tuple' - print dvect.shared_ptr_const_reference_dvect_as_tuple(sdv) - print '2. shared_ptr_const_reference_dvect_as_tuple' - print dvect.shared_ptr_const_reference_dvect_as_tuple(sdv) - # - siv = ivect.ivect_as_shared_ptr(iv) - print '1. shared_ptr_const_reference_ivect_as_tuple' - print dvect.shared_ptr_const_reference_ivect_as_tuple(siv) - print '2. shared_ptr_const_reference_ivect_as_tuple' - print dvect.shared_ptr_const_reference_ivect_as_tuple(siv) - -if (__name__ == "__main__"): - import sys, string - n = 1 - if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) - for i in xrange(n): - f() From 4ec0b61de5ec0f677bb4ad7d6d6948bf8cbd00c4 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 21 Mar 2001 01:09:17 +0000 Subject: [PATCH 106/154] Now using BOOST_PYTHON_MODULE_INIT. [SVN r9617] --- example/abstract.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/example/abstract.cpp b/example/abstract.cpp index 41d34def..97e38c2e 100644 --- a/example/abstract.cpp +++ b/example/abstract.cpp @@ -21,9 +21,7 @@ struct Abstract_callback: Abstract PyObject * m_self; }; -extern "C" -DL_EXPORT(void) -initabstract() +BOOST_PYTHON_MODULE_INIT(abstract) { boost::python::module_builder a("abstract"); From f610e31a87aafbad86576d99c51c6c5347ca5c66 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 21 Mar 2001 01:15:53 +0000 Subject: [PATCH 107/154] temp files removed after branching. [SVN r9619] --- build/filemgr.py | 122 -------------------------------------------- build/vc60.mak | 129 ----------------------------------------------- 2 files changed, 251 deletions(-) delete mode 100644 build/filemgr.py delete mode 100644 build/vc60.mak diff --git a/build/filemgr.py b/build/filemgr.py deleted file mode 100644 index 51c87403..00000000 --- a/build/filemgr.py +++ /dev/null @@ -1,122 +0,0 @@ -bpl_src = "/libs/python/src" -bpl_tst = "/libs/python/test" -bpl_exa = "/libs/python/example" -files = ( -bpl_src + "/classes.cpp", -bpl_src + "/conversions.cpp", -bpl_src + "/extension_class.cpp", -bpl_src + "/functions.cpp", -bpl_src + "/init_function.cpp", -bpl_src + "/module_builder.cpp", -bpl_src + "/objects.cpp", -bpl_src + "/types.cpp", -bpl_src + "/cross_module.cpp", -bpl_tst + "/comprehensive.cpp", -bpl_tst + "/comprehensive.hpp", -bpl_tst + "/comprehensive.py", -bpl_tst + "/doctest.py", -bpl_exa + "/abstract.cpp", -bpl_exa + "/getting_started1.cpp", -bpl_exa + "/getting_started2.cpp", -bpl_exa + "/getting_started3.cpp", -bpl_exa + "/getting_started4.cpp", -bpl_exa + "/getting_started5.cpp", -bpl_exa + "/pickle1.cpp", -bpl_exa + "/pickle2.cpp", -bpl_exa + "/pickle3.cpp", -bpl_exa + "/test_abstract.py", -bpl_exa + "/test_getting_started1.py", -bpl_exa + "/test_getting_started2.py", -bpl_exa + "/test_getting_started3.py", -bpl_exa + "/test_getting_started4.py", -bpl_exa + "/test_getting_started5.py", -bpl_exa + "/test_pickle1.py", -bpl_exa + "/test_pickle2.py", -bpl_exa + "/test_pickle3.py", -bpl_exa + "/noncopyable.h", -bpl_exa + "/noncopyable_export.cpp", -bpl_exa + "/noncopyable_import.cpp", -bpl_exa + "/tst_noncopyable.py", -bpl_exa + "/ivect.h", -bpl_exa + "/ivect.cpp", -bpl_exa + "/dvect.h", -bpl_exa + "/dvect.cpp", -bpl_exa + "/tst_ivect.py", -bpl_exa + "/tst_dvect.py", -) - -defs = ( -"boost_python_test", -"abstract", -"getting_started1", -"getting_started2", -"getting_started3", -"getting_started4", -"getting_started5", -"pickle1", -"pickle2", -"pickle3", -"noncopyable_export", -"noncopyable_import", -"ivect", -"dvect", -) - -if (__name__ == "__main__"): - - import sys, os, string - - path = sys.argv[1] - mode = sys.argv[2] - if (not mode in ("softlinks", "unlink", "cp", "rm", "copy", "del")): - raise RuntimeError, \ - "usage: python filemgr.py path " - - translation_table = string.maketrans("/", "\\") - - if (mode == "copy"): - for fn in files: - fn = string.translate(fn, translation_table) - os.system("copy " + path + fn + " .") - - elif (mode == "cp"): - for fn in files: - os.system("cp " + path + fn + " .") - - elif (mode == "softlinks"): - for fn in files: - f = string.split(fn, "/")[-1] - if (os.access(f, os.F_OK)): - print "File exists: " + f - else: - os.system("ln -s " + path + os.sep + fn + " .") - - elif (mode in ("rm", "del")): - for fn in files: - flds = string.split(fn, "/") - try: os.unlink(flds[-1]) - except: pass - - elif (mode == "unlink"): - for fn in files: - f = string.split(fn, "/")[-1] - if (os.system("test -e " + f) == 0): - if (os.system("test -L " + f) == 0): - try: os.unlink(f) - except: pass - else: - print "Not a softlink: " + f - - if (mode in ("softlinks", "cp", "copy")): - for d in defs: - fn = d + ".def" - f = open(fn, "w") - f.write("EXPORTS\n") - f.write("\tinit" + d + "\n") - f.close() - - if (mode in ("unlink", "rm", "del")): - for d in defs: - fn = d + ".def" - try: os.unlink(fn) - except: pass diff --git a/build/vc60.mak b/build/vc60.mak deleted file mode 100644 index a05d04f4..00000000 --- a/build/vc60.mak +++ /dev/null @@ -1,129 +0,0 @@ -# Usage: -# -# make copy Copy the sources and tests -# make Compile all sources -# make test Run doctest tests -# make clean Remove all object files -# make del Remove the sources and tests - -BOOST_WIN= "L:\boost" -BOOST_UNIX= /net/cci/rwgk/boost - -PYEXE= "C:\Program files\Python\python.exe" -PYINC= /I"C:\Program files\Python\include" -PYLIB= "C:\Program files\Python\libs\python15.lib" - -STDOPTS= /nologo /MD /GR /GX /FD /Zm200 -WARNOPTS= - -CPP= cl.exe -CPPOPTS= $(STLPORTINC) $(STLPORTOPTS) /I$(BOOST_WIN) $(PYINC) \ - $(STDOPTS) $(WARNOPTS) - -LD= link.exe -LDOPTS= /nologo /dll /incremental:no - -OBJ = classes.obj conversions.obj extension_class.obj functions.obj \ - init_function.obj module_builder.obj \ - objects.obj types.obj cross_module.obj - -.SUFFIXES: .obj .cpp - -all: libboost_python.a \ - boost_python_test.pyd \ - abstract.pyd \ - getting_started1.pyd getting_started2.pyd getting_started3.pyd \ - getting_started4.pyd getting_started5.pyd \ - pickle1.pyd pickle2.pyd pickle3.pyd \ - noncopyable_export.pyd noncopyable_import.pyd \ - ivect.pyd dvect.pyd - -libboost_python.a: $(OBJ) - -boost_python_test.pyd: $(OBJ) comprehensive.obj - $(LD) $(LDOPTS) $(OBJ) comprehensive.obj $(PYLIB) /export:initboost_python_test /out:"boost_python_test.pyd" - -abstract.pyd: $(OBJ) abstract.obj - $(LD) $(LDOPTS) $(OBJ) abstract.obj $(PYLIB) /export:initabstract /out:"abstract.pyd" - -getting_started1.pyd: $(OBJ) getting_started1.obj - $(LD) $(LDOPTS) $(OBJ) getting_started1.obj $(PYLIB) /export:initgetting_started1 /out:"getting_started1.pyd" - -getting_started2.pyd: $(OBJ) getting_started2.obj - $(LD) $(LDOPTS) $(OBJ) getting_started2.obj $(PYLIB) /export:initgetting_started2 /out:"getting_started2.pyd" - -getting_started3.pyd: $(OBJ) getting_started3.obj - $(LD) $(LDOPTS) $(OBJ) getting_started3.obj $(PYLIB) /export:initgetting_started3 /out:"getting_started3.pyd" - -getting_started4.pyd: $(OBJ) getting_started4.obj - $(LD) $(LDOPTS) $(OBJ) getting_started4.obj $(PYLIB) /export:initgetting_started4 /out:"getting_started4.pyd" - -getting_started5.pyd: $(OBJ) getting_started5.obj - $(LD) $(LDOPTS) $(OBJ) getting_started5.obj $(PYLIB) /export:initgetting_started5 /out:"getting_started5.pyd" - -pickle1.pyd: $(OBJ) pickle1.obj - $(LD) $(LDOPTS) $(OBJ) pickle1.obj $(PYLIB) /export:initpickle1 /out:"pickle1.pyd" - -pickle2.pyd: $(OBJ) pickle2.obj - $(LD) $(LDOPTS) $(OBJ) pickle2.obj $(PYLIB) /export:initpickle2 /out:"pickle2.pyd" - -pickle3.pyd: $(OBJ) pickle3.obj - $(LD) $(LDOPTS) $(OBJ) pickle3.obj $(PYLIB) /export:initpickle3 /out:"pickle3.pyd" - -noncopyable_export.pyd: $(OBJ) noncopyable_export.obj - $(LD) $(LDOPTS) $(OBJ) noncopyable_export.obj $(PYLIB) /export:initnoncopyable_export /out:"noncopyable_export.pyd" - -noncopyable_import.pyd: $(OBJ) noncopyable_import.obj - $(LD) $(LDOPTS) $(OBJ) noncopyable_import.obj $(PYLIB) /export:initnoncopyable_import /out:"noncopyable_import.pyd" - -ivect.pyd: $(OBJ) ivect.obj - $(LD) $(LDOPTS) $(OBJ) ivect.obj $(PYLIB) /export:initivect /out:"ivect.pyd" - -dvect.pyd: $(OBJ) dvect.obj - $(LD) $(LDOPTS) $(OBJ) dvect.obj $(PYLIB) /export:initdvect /out:"dvect.pyd" - -.cpp.obj: - $(CPP) $(CPPOPTS) /c $*.cpp - -test: - $(PYEXE) comprehensive.py --broken-auto-ptr - $(PYEXE) test_abstract.py - $(PYEXE) test_getting_started1.py - $(PYEXE) test_getting_started2.py - $(PYEXE) test_getting_started3.py - $(PYEXE) test_getting_started4.py - $(PYEXE) test_getting_started5.py - $(PYEXE) test_pickle1.py - $(PYEXE) test_pickle2.py - $(PYEXE) test_pickle3.py - -tst: - $(PYEXE) tst_noncopyable.py - $(PYEXE) tst_ivect.py - $(PYEXE) tst_dvect.py - -clean: - del *.obj - del *.lib - del *.exp - del *.idb - del *.pyd - del *.pyc - -softlinks: - python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) softlinks - -unlink: - python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) unlink - -cp: - python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) cp - -rm: - python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) rm - -copy: - python $(BOOST_WIN)\libs\python\build\filemgr.py $(BOOST_WIN) copy - -del: - python $(BOOST_WIN)\libs\python\build\filemgr.py $(BOOST_WIN) del From 2a96c9f9eea85095c6c1ff889d3c264123e72945 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 21 Mar 2001 02:33:27 +0000 Subject: [PATCH 108/154] temp file before branching [SVN r9621] --- example/do_it_yourself_converters.cpp | 126 ++++++++++++++++++++++ example/simple_vector.cpp | 101 +++++++++++++++++ example/test_do_it_yourself_converters.py | 22 ++++ example/test_simple_vector.py | 35 ++++++ 4 files changed, 284 insertions(+) create mode 100644 example/do_it_yourself_converters.cpp create mode 100644 example/simple_vector.cpp create mode 100644 example/test_do_it_yourself_converters.py create mode 100644 example/test_simple_vector.py diff --git a/example/do_it_yourself_converters.cpp b/example/do_it_yourself_converters.cpp new file mode 100644 index 00000000..ad31f708 --- /dev/null +++ b/example/do_it_yourself_converters.cpp @@ -0,0 +1,126 @@ +/* + This example shows how to convert a class from and to native + Python objects, such as tuples. + + We do not want to expose the helper class MillerIndex as an + Extension Class. However, in order to simplify the wrapper code, + we want to define from_python() and to_python() functions for + class MillerIndex. + + Consider the alternatives: + + - Expose MillerIndex as an Extension Class. + We need a constructor MillerIndex(python::tuple). + Python function calls become more complex: + foo(MillerIndex((1,2,3)) instead of foo((1,2,3)) + We need a method such as MillerIndex().as_tuple(). + + - Define a wrapper function for each function that we + want to expose, e.g.: + void add(const IndexingSet& ixset, const python::tuple PyMIx) + + The first alternative introduces a new type that the user has to + deal with. Other modules using Miller indices might organize them in + different ways, for example to increase runtime efficiency for + important procedures. This means, the user has to know how to + convert between the different kinds of Miller index representations. + This can quickly become a nuisance. Relying on native Python data + structures minimizes the number of special types the user has to + learn and convert. Of course, this argument is only valid for + small and relatively simply classes. + + If there are many member functions with MillerIndex arguments, the + second alternative is impractical, and concentrating the conversion + mechanism in one central place is essential for code + maintainability. An added benefit is that more convenient (smarter) + conversion functions can be provided without cluttering the rest of + the wrapper code. + + */ + +#include +#include +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // The helper class. + // + class MillerIndex { + public: + int v[3]; + }; + + // The main class. Imagine that there are MANY member functions + // like add() and get(). + // + class IndexingSet { + private: + std::vector VMIx; + public: + void add(const MillerIndex& MIx) { VMIx.push_back(MIx); } + MillerIndex get(std::size_t i) const { return VMIx[i]; } + }; +} + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + + // Convert a Python tuple to a MillerIndex object. + // + MillerIndex from_python(PyObject* p, python::type) + { + python::tuple tup + = python::tuple(python::ref(p, python::ref::increment_count)); + if (tup.size() != 3) { + PyErr_SetString(PyExc_ValueError, + "expecting exactly 3 values in tuple."); + throw python::error_already_set(); + } + MillerIndex result; + for (int i = 0; i < 3; i++) + result.v[i] = from_python(tup[i].get(), python::type()); + return result; + } + + // Similar conversion for MillerIndex objects passed by value. + // Not actually used, but included to show the principle. + // + MillerIndex from_python(PyObject* p, python::type) + { + return from_python(p, python::type()); + } + + // Convert a MillerIndex object to a Python tuple. + // + PyObject* to_python(const MillerIndex& hkl) + { + python::tuple result(3); + for (int i = 0; i < 3; i++) + result.set_item(i, python::ref(to_python(hkl.v[i]))); + return result.reference().release(); + } + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +BOOST_PYTHON_MODULE_INIT(do_it_yourself_converters) +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("do_it_yourself_converters"); + + // Create the Python type object for our extension class. + python::class_builder ixset_class(this_module, "IndexingSet"); + + // Add the __init__ function. + ixset_class.def(python::constructor<>()); + // Add the member functions. + ixset_class.def(&IndexingSet::add, "add"); + ixset_class.def(&IndexingSet::get, "get"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/simple_vector.cpp b/example/simple_vector.cpp new file mode 100644 index 00000000..f18f2cad --- /dev/null +++ b/example/simple_vector.cpp @@ -0,0 +1,101 @@ +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // A wrapper is used to define additional constructors. + // + struct vector_double_wrapper: std::vector + { + // Tell the compiler how to convert a base class object to + // this wrapper object. + vector_double_wrapper(PyObject*, const std::vector& vd) + : std::vector(vd) {} + + vector_double_wrapper(PyObject* self) + : std::vector() {} + + vector_double_wrapper(PyObject* self, int n) + : std::vector(n) {} + + vector_double_wrapper(PyObject* self, python::tuple tuple) + : std::vector(tuple.size()) + { + std::vector::iterator vd = begin(); + for (int i = 0; i < tuple.size(); i++) + vd[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), + python::type()); + } + }; + + double getitem(const std::vector& vd, std::size_t key) { + return vd[key]; + } + + void setitem(std::vector& vd, std::size_t key, double d) { + std::vector::iterator vditer = vd.begin(); + vditer[key] = d; + } + + void delitem(std::vector& vd, std::size_t key) { + std::vector::iterator vditer = vd.begin(); + vd.erase(&vditer[key]); + } + + // Convert vector_double to a regular Python tuple. + // + python::tuple as_tuple(const std::vector& vd) + { + python::tuple t(vd.size()); + for (int i = 0; i < vd.size(); i++) t.set_item(i, + python::ref(BOOST_PYTHON_CONVERSION::to_python(vd[i]))); + return t; + } + + // Function returning a vector_double object to Python. + // + std::vector foo(int n) + { + std::vector vd(n); + std::vector::iterator vditer = vd.begin(); + for (int i = 0; i < n; i++) vditer[i] = double(i); + return vd; + } + + // Same as foo(), but avoid copying on return. + // + std::auto_ptr > bar(int n) + { + std::auto_ptr > vdptr(new std::vector(n)); + std::vector::iterator vditer = vdptr->begin(); + for (int i = 0; i < n; i++) vditer[i] = double(10 * i); + return vdptr; + } +} + +BOOST_PYTHON_MODULE_INIT(simple_vector) +{ + try + { + python::module_builder this_module("simple_vector"); + + python::class_builder, vector_double_wrapper> + vector_double(this_module, "vector_double"); + + 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__"); + vector_double.def(setitem, "__setitem__"); + vector_double.def(delitem, "__delitem__"); + vector_double.def(as_tuple, "as_tuple"); + + this_module.def(foo, "foo"); + this_module.def(bar, "bar"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/test_do_it_yourself_converters.py b/example/test_do_it_yourself_converters.py new file mode 100644 index 00000000..e256c614 --- /dev/null +++ b/example/test_do_it_yourself_converters.py @@ -0,0 +1,22 @@ +r'''>>> import do_it_yourself_converters + >>> ixset = do_it_yourself_converters.IndexingSet() + >>> ixset.add((1,2,3)) + >>> ixset.add((4,5,6)) + >>> ixset.add((7,8,9)) + >>> print ixset.get(0) + (1, 2, 3) + >>> print ixset.get(1) + (4, 5, 6) + >>> print ixset.get(2) + (7, 8, 9) +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_do_it_yourself_converters + doctest.testmod(test_do_it_yourself_converters) + +if __name__ == '__main__': + run() diff --git a/example/test_simple_vector.py b/example/test_simple_vector.py new file mode 100644 index 00000000..a19e205b --- /dev/null +++ b/example/test_simple_vector.py @@ -0,0 +1,35 @@ +r'''>>> import simple_vector + >>> v=simple_vector.vector_double() + >>> print v.as_tuple() + () + >>> v=simple_vector.vector_double(5) + >>> print v.as_tuple() + (0.0, 0.0, 0.0, 0.0, 0.0) + >>> print len(v) + 5 + >>> v=simple_vector.vector_double((3,4,5)) + >>> print v.as_tuple() + (3.0, 4.0, 5.0) + >>> print v[1] + 4.0 + >>> v[1] = 40 + >>> print v.as_tuple() + (3.0, 40.0, 5.0) + >>> del v[1] + >>> print v.as_tuple() + (3.0, 5.0) + >>> print simple_vector.foo(11).as_tuple() + (0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0) + >>> print simple_vector.bar(12).as_tuple() + (0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0) +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_simple_vector + doctest.testmod(test_simple_vector) + +if __name__ == '__main__': + run() From 01bcd460dabfdd58d435dc020d0025ef3a23b914 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 21 Mar 2001 02:35:32 +0000 Subject: [PATCH 109/154] temp files removed after branching. [SVN r9623] --- example/do_it_yourself_converters.cpp | 126 ---------------------- example/simple_vector.cpp | 101 ----------------- example/test_do_it_yourself_converters.py | 22 ---- example/test_simple_vector.py | 35 ------ 4 files changed, 284 deletions(-) delete mode 100644 example/do_it_yourself_converters.cpp delete mode 100644 example/simple_vector.cpp delete mode 100644 example/test_do_it_yourself_converters.py delete mode 100644 example/test_simple_vector.py diff --git a/example/do_it_yourself_converters.cpp b/example/do_it_yourself_converters.cpp deleted file mode 100644 index ad31f708..00000000 --- a/example/do_it_yourself_converters.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - This example shows how to convert a class from and to native - Python objects, such as tuples. - - We do not want to expose the helper class MillerIndex as an - Extension Class. However, in order to simplify the wrapper code, - we want to define from_python() and to_python() functions for - class MillerIndex. - - Consider the alternatives: - - - Expose MillerIndex as an Extension Class. - We need a constructor MillerIndex(python::tuple). - Python function calls become more complex: - foo(MillerIndex((1,2,3)) instead of foo((1,2,3)) - We need a method such as MillerIndex().as_tuple(). - - - Define a wrapper function for each function that we - want to expose, e.g.: - void add(const IndexingSet& ixset, const python::tuple PyMIx) - - The first alternative introduces a new type that the user has to - deal with. Other modules using Miller indices might organize them in - different ways, for example to increase runtime efficiency for - important procedures. This means, the user has to know how to - convert between the different kinds of Miller index representations. - This can quickly become a nuisance. Relying on native Python data - structures minimizes the number of special types the user has to - learn and convert. Of course, this argument is only valid for - small and relatively simply classes. - - If there are many member functions with MillerIndex arguments, the - second alternative is impractical, and concentrating the conversion - mechanism in one central place is essential for code - maintainability. An added benefit is that more convenient (smarter) - conversion functions can be provided without cluttering the rest of - the wrapper code. - - */ - -#include -#include -#include -namespace python = boost::python; - -namespace { // Avoid cluttering the global namespace. - - // The helper class. - // - class MillerIndex { - public: - int v[3]; - }; - - // The main class. Imagine that there are MANY member functions - // like add() and get(). - // - class IndexingSet { - private: - std::vector VMIx; - public: - void add(const MillerIndex& MIx) { VMIx.push_back(MIx); } - MillerIndex get(std::size_t i) const { return VMIx[i]; } - }; -} - -BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE - - // Convert a Python tuple to a MillerIndex object. - // - MillerIndex from_python(PyObject* p, python::type) - { - python::tuple tup - = python::tuple(python::ref(p, python::ref::increment_count)); - if (tup.size() != 3) { - PyErr_SetString(PyExc_ValueError, - "expecting exactly 3 values in tuple."); - throw python::error_already_set(); - } - MillerIndex result; - for (int i = 0; i < 3; i++) - result.v[i] = from_python(tup[i].get(), python::type()); - return result; - } - - // Similar conversion for MillerIndex objects passed by value. - // Not actually used, but included to show the principle. - // - MillerIndex from_python(PyObject* p, python::type) - { - return from_python(p, python::type()); - } - - // Convert a MillerIndex object to a Python tuple. - // - PyObject* to_python(const MillerIndex& hkl) - { - python::tuple result(3); - for (int i = 0; i < 3; i++) - result.set_item(i, python::ref(to_python(hkl.v[i]))); - return result.reference().release(); - } - -BOOST_PYTHON_END_CONVERSION_NAMESPACE - -BOOST_PYTHON_MODULE_INIT(do_it_yourself_converters) -{ - try - { - // Create an object representing this extension module. - python::module_builder this_module("do_it_yourself_converters"); - - // Create the Python type object for our extension class. - python::class_builder ixset_class(this_module, "IndexingSet"); - - // Add the __init__ function. - ixset_class.def(python::constructor<>()); - // Add the member functions. - ixset_class.def(&IndexingSet::add, "add"); - ixset_class.def(&IndexingSet::get, "get"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/simple_vector.cpp b/example/simple_vector.cpp deleted file mode 100644 index f18f2cad..00000000 --- a/example/simple_vector.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include -namespace python = boost::python; - -namespace { // Avoid cluttering the global namespace. - - // A wrapper is used to define additional constructors. - // - struct vector_double_wrapper: std::vector - { - // Tell the compiler how to convert a base class object to - // this wrapper object. - vector_double_wrapper(PyObject*, const std::vector& vd) - : std::vector(vd) {} - - vector_double_wrapper(PyObject* self) - : std::vector() {} - - vector_double_wrapper(PyObject* self, int n) - : std::vector(n) {} - - vector_double_wrapper(PyObject* self, python::tuple tuple) - : std::vector(tuple.size()) - { - std::vector::iterator vd = begin(); - for (int i = 0; i < tuple.size(); i++) - vd[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), - python::type()); - } - }; - - double getitem(const std::vector& vd, std::size_t key) { - return vd[key]; - } - - void setitem(std::vector& vd, std::size_t key, double d) { - std::vector::iterator vditer = vd.begin(); - vditer[key] = d; - } - - void delitem(std::vector& vd, std::size_t key) { - std::vector::iterator vditer = vd.begin(); - vd.erase(&vditer[key]); - } - - // Convert vector_double to a regular Python tuple. - // - python::tuple as_tuple(const std::vector& vd) - { - python::tuple t(vd.size()); - for (int i = 0; i < vd.size(); i++) t.set_item(i, - python::ref(BOOST_PYTHON_CONVERSION::to_python(vd[i]))); - return t; - } - - // Function returning a vector_double object to Python. - // - std::vector foo(int n) - { - std::vector vd(n); - std::vector::iterator vditer = vd.begin(); - for (int i = 0; i < n; i++) vditer[i] = double(i); - return vd; - } - - // Same as foo(), but avoid copying on return. - // - std::auto_ptr > bar(int n) - { - std::auto_ptr > vdptr(new std::vector(n)); - std::vector::iterator vditer = vdptr->begin(); - for (int i = 0; i < n; i++) vditer[i] = double(10 * i); - return vdptr; - } -} - -BOOST_PYTHON_MODULE_INIT(simple_vector) -{ - try - { - python::module_builder this_module("simple_vector"); - - python::class_builder, vector_double_wrapper> - vector_double(this_module, "vector_double"); - - 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__"); - vector_double.def(setitem, "__setitem__"); - vector_double.def(delitem, "__delitem__"); - vector_double.def(as_tuple, "as_tuple"); - - this_module.def(foo, "foo"); - this_module.def(bar, "bar"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/test_do_it_yourself_converters.py b/example/test_do_it_yourself_converters.py deleted file mode 100644 index e256c614..00000000 --- a/example/test_do_it_yourself_converters.py +++ /dev/null @@ -1,22 +0,0 @@ -r'''>>> import do_it_yourself_converters - >>> ixset = do_it_yourself_converters.IndexingSet() - >>> ixset.add((1,2,3)) - >>> ixset.add((4,5,6)) - >>> ixset.add((7,8,9)) - >>> print ixset.get(0) - (1, 2, 3) - >>> print ixset.get(1) - (4, 5, 6) - >>> print ixset.get(2) - (7, 8, 9) -''' - -def run(args = None): - if args is not None: - import sys - sys.argv = args - import doctest, test_do_it_yourself_converters - doctest.testmod(test_do_it_yourself_converters) - -if __name__ == '__main__': - run() diff --git a/example/test_simple_vector.py b/example/test_simple_vector.py deleted file mode 100644 index a19e205b..00000000 --- a/example/test_simple_vector.py +++ /dev/null @@ -1,35 +0,0 @@ -r'''>>> import simple_vector - >>> v=simple_vector.vector_double() - >>> print v.as_tuple() - () - >>> v=simple_vector.vector_double(5) - >>> print v.as_tuple() - (0.0, 0.0, 0.0, 0.0, 0.0) - >>> print len(v) - 5 - >>> v=simple_vector.vector_double((3,4,5)) - >>> print v.as_tuple() - (3.0, 4.0, 5.0) - >>> print v[1] - 4.0 - >>> v[1] = 40 - >>> print v.as_tuple() - (3.0, 40.0, 5.0) - >>> del v[1] - >>> print v.as_tuple() - (3.0, 5.0) - >>> print simple_vector.foo(11).as_tuple() - (0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0) - >>> print simple_vector.bar(12).as_tuple() - (0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0) -''' - -def run(args = None): - if args is not None: - import sys - sys.argv = args - import doctest, test_simple_vector - doctest.testmod(test_simple_vector) - -if __name__ == '__main__': - run() From 5a40cec1edd9ee8ca1f8396f1c0ffd230c53822c Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 1 Apr 2001 13:47:25 +0000 Subject: [PATCH 110/154] temp file before branching [SVN r9689] --- build/irix_CC.mak | 167 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 build/irix_CC.mak diff --git a/build/irix_CC.mak b/build/irix_CC.mak new file mode 100644 index 00000000..91eb819e --- /dev/null +++ b/build/irix_CC.mak @@ -0,0 +1,167 @@ +# Usage: +# +# Create a new empty directory anywhere (preferably not in the boost tree). +# Copy this Makefile to that new directory and rename it to "Makefile" +# Set the BOOST pathname below. +# +# make softlinks Create softlinks to source code and tests +# make Compile all sources +# make test Run doctest tests +# make clean Remove all object files +# make unlink Remove softlinks + +BOOST= /net/cci/rwgk/boost + +#PYEXE= /usr/bin/python +#PYINC= -I/usr/include/python1.5 +PYEXE= /usr/local/Python-1.5.2/bin/python +PYINC= -I/usr/local/Python-1.5.2/include/python1.5 +#PYEXE= /usr/local/Python-2.0/bin/python +#PYINC= -I/usr/local/Python-2.0/include/python2.0 +STLPORTINC= -I/net/cci/xp/C++_C_headers + +STDOPTS= +WARNOPTS= -woff 1001,1234,1682 + +CPP= CC -LANG:std -n32 -mips4 +CPPOPTS= $(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \ + $(STDOPTS) $(WARNOPTS) -g +MAKEDEP= -M + +LD= CC -LANG:std -n32 -mips4 +LDOPTS= -shared -all + +OBJ = classes.o conversions.o extension_class.o functions.o \ + init_function.o module_builder.o \ + objects.o types.o cross_module.o +DEPOBJ= $(OBJ) \ + comprehensive.o \ + abstract.o \ + getting_started1.o getting_started2.o getting_started3.o \ + simple_vector.o \ + do_it_yourself_converters.o \ + pickle1.o pickle2.o pickle3.o \ + noncopyable_export.o noncopyable_import.o \ + ivect.o dvect.o + +.SUFFIXES: .o .cpp + +all: libboost_python.a \ + boost_python_test.so \ + abstract.so \ + getting_started1.so getting_started2.so getting_started3.so \ + simple_vector.so \ + do_it_yourself_converters.so \ + pickle1.so pickle2.so pickle3.so \ + noncopyable_export.so noncopyable_import.so \ + ivect.so dvect.so + +libboost_python.a: $(OBJ) + rm -f libboost_python.a + $(CPP) -ar -all -o libboost_python.a $(OBJ) + +boost_python_test.so: $(OBJ) comprehensive.o + $(LD) $(LDOPTS) $(OBJ) comprehensive.o -o boost_python_test.so -lm + +abstract.so: $(OBJ) abstract.o + $(LD) $(LDOPTS) $(OBJ) abstract.o -o abstract.so + +getting_started1.so: $(OBJ) getting_started1.o + $(LD) $(LDOPTS) $(OBJ) getting_started1.o -o getting_started1.so + +getting_started2.so: $(OBJ) getting_started2.o + $(LD) $(LDOPTS) $(OBJ) getting_started2.o -o getting_started2.so + +getting_started3.so: $(OBJ) getting_started3.o + $(LD) $(LDOPTS) $(OBJ) getting_started3.o -o getting_started3.so + +simple_vector.so: $(OBJ) simple_vector.o + $(LD) $(LDOPTS) $(OBJ) simple_vector.o -o simple_vector.so + +do_it_yourself_converters.so: $(OBJ) do_it_yourself_converters.o + $(LD) $(LDOPTS) $(OBJ) do_it_yourself_converters.o -o do_it_yourself_converters.so + +pickle1.so: $(OBJ) pickle1.o + $(LD) $(LDOPTS) $(OBJ) pickle1.o -o pickle1.so + +pickle2.so: $(OBJ) pickle2.o + $(LD) $(LDOPTS) $(OBJ) pickle2.o -o pickle2.so + +pickle3.so: $(OBJ) pickle3.o + $(LD) $(LDOPTS) $(OBJ) pickle3.o -o pickle3.so + +noncopyable_export.so: $(OBJ) noncopyable_export.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \ + noncopyable_export.o -o noncopyable_export.so + +noncopyable_import.so: $(OBJ) noncopyable_import.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \ + noncopyable_import.o -o noncopyable_import.so + +ivect.so: $(OBJ) ivect.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) ivect.o -o ivect.so + +dvect.so: $(OBJ) dvect.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) dvect.o -o dvect.so + +.cpp.o: + $(CPP) $(CPPOPTS) -c $*.cpp + +test: + $(PYEXE) comprehensive.py + $(PYEXE) test_abstract.py + $(PYEXE) test_getting_started1.py + $(PYEXE) test_getting_started2.py + $(PYEXE) test_getting_started3.py + $(PYEXE) test_simple_vector.py + $(PYEXE) test_do_it_yourself_converters.py + $(PYEXE) test_pickle1.py + $(PYEXE) test_pickle2.py + $(PYEXE) test_pickle3.py + +tst: + $(PYEXE) tst_noncopyable.py + $(PYEXE) tst_ivect1.py + $(PYEXE) tst_dvect1.py + $(PYEXE) tst_ivect2.py + $(PYEXE) tst_dvect2.py + +clean: + rm -f $(OBJ) libboost_python.a libboost_python.a.input + rm -f comprehensive.o boost_python_test.so + rm -f abstract.o abstract.so + rm -f getting_started1.o getting_started1.so + rm -f getting_started2.o getting_started2.so + rm -f getting_started3.o getting_started3.so + rm -f simple_vector.o simple_vector.so + rm -f do_it_yourself_converters.o do_it_yourself_converters.so + rm -f pickle1.o pickle1.so + rm -f pickle2.o pickle2.so + rm -f pickle3.o pickle3.so + rm -f noncopyable_export.o noncopyable_export.so + rm -f noncopyable_import.o noncopyable_import.so + rm -f ivect.o ivect.so + rm -f dvect.o dvect.so + rm -f so_locations *.pyc + rm -rf ii_files + +softlinks: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) softlinks + +unlink: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) unlink + +cp: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) cp + +rm: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) rm + +depend: + @ cat Makefile.nodepend; \ + for obj in $(DEPOBJ); \ + do \ + bn=`echo "$$obj" | cut -d. -f1`; \ + $(CPP) $(CPPOPTS) $(MAKEDEP) "$$bn".cpp; \ + done + From 69e69a77d866b19cfe05298ffc580371d7d58983 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sun, 1 Apr 2001 13:49:05 +0000 Subject: [PATCH 111/154] temp file removed after branching. [SVN r9691] --- build/irix_CC.mak | 167 ---------------------------------------------- 1 file changed, 167 deletions(-) delete mode 100644 build/irix_CC.mak diff --git a/build/irix_CC.mak b/build/irix_CC.mak deleted file mode 100644 index 91eb819e..00000000 --- a/build/irix_CC.mak +++ /dev/null @@ -1,167 +0,0 @@ -# Usage: -# -# Create a new empty directory anywhere (preferably not in the boost tree). -# Copy this Makefile to that new directory and rename it to "Makefile" -# Set the BOOST pathname below. -# -# make softlinks Create softlinks to source code and tests -# make Compile all sources -# make test Run doctest tests -# make clean Remove all object files -# make unlink Remove softlinks - -BOOST= /net/cci/rwgk/boost - -#PYEXE= /usr/bin/python -#PYINC= -I/usr/include/python1.5 -PYEXE= /usr/local/Python-1.5.2/bin/python -PYINC= -I/usr/local/Python-1.5.2/include/python1.5 -#PYEXE= /usr/local/Python-2.0/bin/python -#PYINC= -I/usr/local/Python-2.0/include/python2.0 -STLPORTINC= -I/net/cci/xp/C++_C_headers - -STDOPTS= -WARNOPTS= -woff 1001,1234,1682 - -CPP= CC -LANG:std -n32 -mips4 -CPPOPTS= $(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \ - $(STDOPTS) $(WARNOPTS) -g -MAKEDEP= -M - -LD= CC -LANG:std -n32 -mips4 -LDOPTS= -shared -all - -OBJ = classes.o conversions.o extension_class.o functions.o \ - init_function.o module_builder.o \ - objects.o types.o cross_module.o -DEPOBJ= $(OBJ) \ - comprehensive.o \ - abstract.o \ - getting_started1.o getting_started2.o getting_started3.o \ - simple_vector.o \ - do_it_yourself_converters.o \ - pickle1.o pickle2.o pickle3.o \ - noncopyable_export.o noncopyable_import.o \ - ivect.o dvect.o - -.SUFFIXES: .o .cpp - -all: libboost_python.a \ - boost_python_test.so \ - abstract.so \ - getting_started1.so getting_started2.so getting_started3.so \ - simple_vector.so \ - do_it_yourself_converters.so \ - pickle1.so pickle2.so pickle3.so \ - noncopyable_export.so noncopyable_import.so \ - ivect.so dvect.so - -libboost_python.a: $(OBJ) - rm -f libboost_python.a - $(CPP) -ar -all -o libboost_python.a $(OBJ) - -boost_python_test.so: $(OBJ) comprehensive.o - $(LD) $(LDOPTS) $(OBJ) comprehensive.o -o boost_python_test.so -lm - -abstract.so: $(OBJ) abstract.o - $(LD) $(LDOPTS) $(OBJ) abstract.o -o abstract.so - -getting_started1.so: $(OBJ) getting_started1.o - $(LD) $(LDOPTS) $(OBJ) getting_started1.o -o getting_started1.so - -getting_started2.so: $(OBJ) getting_started2.o - $(LD) $(LDOPTS) $(OBJ) getting_started2.o -o getting_started2.so - -getting_started3.so: $(OBJ) getting_started3.o - $(LD) $(LDOPTS) $(OBJ) getting_started3.o -o getting_started3.so - -simple_vector.so: $(OBJ) simple_vector.o - $(LD) $(LDOPTS) $(OBJ) simple_vector.o -o simple_vector.so - -do_it_yourself_converters.so: $(OBJ) do_it_yourself_converters.o - $(LD) $(LDOPTS) $(OBJ) do_it_yourself_converters.o -o do_it_yourself_converters.so - -pickle1.so: $(OBJ) pickle1.o - $(LD) $(LDOPTS) $(OBJ) pickle1.o -o pickle1.so - -pickle2.so: $(OBJ) pickle2.o - $(LD) $(LDOPTS) $(OBJ) pickle2.o -o pickle2.so - -pickle3.so: $(OBJ) pickle3.o - $(LD) $(LDOPTS) $(OBJ) pickle3.o -o pickle3.so - -noncopyable_export.so: $(OBJ) noncopyable_export.o - $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \ - noncopyable_export.o -o noncopyable_export.so - -noncopyable_import.so: $(OBJ) noncopyable_import.o - $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \ - noncopyable_import.o -o noncopyable_import.so - -ivect.so: $(OBJ) ivect.o - $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) ivect.o -o ivect.so - -dvect.so: $(OBJ) dvect.o - $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) dvect.o -o dvect.so - -.cpp.o: - $(CPP) $(CPPOPTS) -c $*.cpp - -test: - $(PYEXE) comprehensive.py - $(PYEXE) test_abstract.py - $(PYEXE) test_getting_started1.py - $(PYEXE) test_getting_started2.py - $(PYEXE) test_getting_started3.py - $(PYEXE) test_simple_vector.py - $(PYEXE) test_do_it_yourself_converters.py - $(PYEXE) test_pickle1.py - $(PYEXE) test_pickle2.py - $(PYEXE) test_pickle3.py - -tst: - $(PYEXE) tst_noncopyable.py - $(PYEXE) tst_ivect1.py - $(PYEXE) tst_dvect1.py - $(PYEXE) tst_ivect2.py - $(PYEXE) tst_dvect2.py - -clean: - rm -f $(OBJ) libboost_python.a libboost_python.a.input - rm -f comprehensive.o boost_python_test.so - rm -f abstract.o abstract.so - rm -f getting_started1.o getting_started1.so - rm -f getting_started2.o getting_started2.so - rm -f getting_started3.o getting_started3.so - rm -f simple_vector.o simple_vector.so - rm -f do_it_yourself_converters.o do_it_yourself_converters.so - rm -f pickle1.o pickle1.so - rm -f pickle2.o pickle2.so - rm -f pickle3.o pickle3.so - rm -f noncopyable_export.o noncopyable_export.so - rm -f noncopyable_import.o noncopyable_import.so - rm -f ivect.o ivect.so - rm -f dvect.o dvect.so - rm -f so_locations *.pyc - rm -rf ii_files - -softlinks: - $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) softlinks - -unlink: - $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) unlink - -cp: - $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) cp - -rm: - $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) rm - -depend: - @ cat Makefile.nodepend; \ - for obj in $(DEPOBJ); \ - do \ - bn=`echo "$$obj" | cut -d. -f1`; \ - $(CPP) $(CPPOPTS) $(MAKEDEP) "$$bn".cpp; \ - done - From 748c118ea82c167f3b352023ac906d25ca5aa464 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 5 Apr 2001 17:46:24 +0000 Subject: [PATCH 112/154] added: from_python std::string type checking [SVN r9727] --- src/conversions.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/conversions.cpp b/src/conversions.cpp index 1bc923b1..4bfe2011 100644 --- a/src/conversions.cpp +++ b/src/conversions.cpp @@ -7,6 +7,7 @@ // producing this work. // // Revision History: +// 05 Apr 01 added: from_python std::string type checking (rwgk) // 12 Mar 01 Python 1.5.2 fixes (Ralf W. Grosse-Kunstleve) // 11 Mar 01 std::string *MAY* include nulls (Alex Martelli) // 04 Mar 01 std::complex<> fixes for MSVC (Dave Abrahams) @@ -250,6 +251,10 @@ PyObject* to_python(const std::string& s) std::string from_python(PyObject* p, boost::python::type) { + if (! PyString_Check(p)) { + PyErr_SetString(PyExc_TypeError, "expected a string"); + throw boost::python::argument_error(); + } return std::string(PyString_AsString(p), PyString_Size(p)); } From 9ee563b86415bc9f86cad7404cdf06296e2349fb Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 18:51:17 +0000 Subject: [PATCH 113/154] Comment added with reference to cross_module.hpp [SVN r9812] --- include/boost/python/detail/extension_class.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/boost/python/detail/extension_class.hpp b/include/boost/python/detail/extension_class.hpp index 125f1eed..5c8e720a 100644 --- a/include/boost/python/detail/extension_class.hpp +++ b/include/boost/python/detail/extension_class.hpp @@ -10,6 +10,7 @@ // gen_extclass.python // Revision History: +// 17 Apr 01 Comment added with reference to cross_module.hpp (R.W. Grosse-Kunstleve) // 05 Mar 01 Fixed a bug which prevented auto_ptr values from being converted // to_python (Dave Abrahams) @@ -166,6 +167,14 @@ BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // and U. T is the class the user really intends to wrap. U is a class derived // from T with some virtual function overriding boilerplate, or if there are no // virtual functions, U = held_instance. +// +// A look-alike of this class in root/boost/python/cross_module.hpp +// is used for the implementation of the cross-module support +// (export_converters and import_converters). If from_python +// and to_python converters are added or removed from the class +// below, the class python_import_extension_class_converters has +// to be modified accordingly. +// template > class python_extension_class_converters { From 533a0057641283e3ff949c8a0383a77a394e0caa Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 18:53:38 +0000 Subject: [PATCH 114/154] moved from branch ralf_grosse_kunstleve to trunk [SVN r9813] --- include/boost/python/cross_module.hpp | 322 ++++++++++++++++++++++++++ src/cross_module.cpp | 87 +++++++ 2 files changed, 409 insertions(+) create mode 100644 include/boost/python/cross_module.hpp create mode 100644 src/cross_module.cpp diff --git a/include/boost/python/cross_module.hpp b/include/boost/python/cross_module.hpp new file mode 100644 index 00000000..7c1fe507 --- /dev/null +++ b/include/boost/python/cross_module.hpp @@ -0,0 +1,322 @@ +/* (C) Copyright Ralf W. Grosse-Kunstleve 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. + + Revision History: + 17 Apr 01 merged into boost CVS trunk (Ralf W. Grosse-Kunstleve) +*/ + +/* Implementation of Boost.Python cross-module support. + See root/libs/python/doc/cross_module.html for details. +*/ + +#ifndef CROSS_MODULE_HPP +# define CROSS_MODULE_HPP + +# include + +namespace boost { namespace python { + struct import_error : error_already_set {}; + struct export_error : error_already_set {}; +}} + +namespace boost { namespace python { 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); + +}}} + +// forward declaration +namespace boost { namespace python { namespace detail { +template class import_extension_class; +}}} + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + +/* This class template is instantiated by import_converters. + This class is a look-alike of class python_extension_class_converters. + The converters in this class are wrappers that call converters + imported from another module. + To ensure that the dynamic loader resolves all symbols in the + intended way, the signature of all friend functions is changed with + respect to the original functions in class + python_extension_class_converters by adding an arbitrary additional + parameter with a default value, in this case "bool sig = false". + See also: comments for class export_converter_object_base below. + */ +template +class python_import_extension_class_converters +{ + public: + + friend python_import_extension_class_converters py_extension_class_converters(boost::python::type, bool sig = false) { + return python_import_extension_class_converters(); + } + + PyObject* to_python(const T& x) const { + return boost::python::detail::import_extension_class::get_converters()->to_python(x); + } + + friend T* from_python(PyObject* p, boost::python::type t, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->from_python_Ts(p, t); + } + friend const T* from_python(PyObject* p, boost::python::type t, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->from_python_cTs(p, t); + } + friend const T* from_python(PyObject* p, boost::python::type t, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->from_python_cTscr(p, t); + } + friend T* from_python(PyObject* p, boost::python::type t, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->from_python_Tscr(p, t); + } + friend T& from_python(PyObject* p, boost::python::type t, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->from_python_Tr(p, t); + } + friend const T& from_python(PyObject* p, boost::python::type t, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->from_python_cTr(p, t); + } + friend const T& from_python(PyObject* p, boost::python::type t, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->from_python_T(p, t); + } + + friend std::auto_ptr& from_python(PyObject* p, boost::python::type&> t, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->from_python_aTr(p, t); + } + friend std::auto_ptr from_python(PyObject* p, boost::python::type > t, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->from_python_aT(p, t); + } + friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&> t, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->from_python_caTr(p, t); + } + friend PyObject* to_python(std::auto_ptr x, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->to_python(x); + } + + friend boost::shared_ptr& from_python(PyObject* p, boost::python::type&> t, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->from_python_sTr(p, t); + } + friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type > t, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->from_python_sT(p, t); + } + friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type&> t, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->from_python_csTr(p, t); + } + friend PyObject* to_python(boost::shared_ptr x, bool sig = false) { + return boost::python::detail::import_extension_class::get_converters()->to_python(x); + } +}; + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +namespace boost { namespace python { + +BOOST_PYTHON_IMPORT_CONVERSION(python_import_extension_class_converters); + +/* This class template is instantiated by export_converters(). + A pointer to this class is exported/imported via the Python API. + Using the Python API ensures maximum portability. + All member functions are virtual. This is, what we export/import + is essentially just a pointer to a vtbl. + To work around a deficiency of Visual C++ 6.0, the name of each + from_python() member functions is made unique by appending a few + characters (derived in a ad-hoc manner from the corresponding type). + */ +template +struct export_converter_object_base +{ + virtual int get_api_major() const { return detail::export_converters_api_major; } + virtual int get_api_minor() const { return detail::export_converters_api_minor; } + + virtual PyObject* to_python(const T& x) = 0; + + virtual T* from_python_Ts(PyObject* p, boost::python::type t) = 0; + virtual const T* from_python_cTs(PyObject* p, boost::python::type t) = 0; + virtual const T* from_python_cTscr(PyObject* p, boost::python::type t) = 0; + virtual T* from_python_Tscr(PyObject* p, boost::python::type t) = 0; + virtual T& from_python_Tr(PyObject* p, boost::python::type t) = 0; + virtual const T& from_python_cTr(PyObject* p, boost::python::type t) = 0; + virtual const T& from_python_T(PyObject* p, boost::python::type t) = 0; + + virtual std::auto_ptr& from_python_aTr(PyObject* p, boost::python::type&> t) = 0; + virtual std::auto_ptr from_python_aT(PyObject* p, boost::python::type > t) = 0; + virtual const std::auto_ptr& from_python_caTr(PyObject* p, boost::python::type&> t) = 0; + virtual PyObject* to_python(std::auto_ptr x) = 0; + + virtual boost::shared_ptr& from_python_sTr(PyObject* p, boost::python::type&> t) = 0; + virtual const boost::shared_ptr& from_python_sT(PyObject* p, boost::python::type > t) = 0; + virtual const boost::shared_ptr& from_python_csTr(PyObject* p, boost::python::type&> t) = 0; + virtual PyObject* to_python(boost::shared_ptr x) = 0; +}; + +// Converters to be used if T is not copyable. +template +struct export_converter_object_noncopyable : export_converter_object_base +{ + virtual PyObject* to_python(const T& x) { + PyErr_SetString(PyExc_RuntimeError, + "to_python(const T&) converter not exported"); + throw import_error(); + } + + virtual T* from_python_Ts(PyObject* p, boost::python::type t) { + return BOOST_PYTHON_CONVERSION::from_python(p, t); + } + virtual const T* from_python_cTs(PyObject* p, boost::python::type t) { + return BOOST_PYTHON_CONVERSION::from_python(p, t); + } + virtual const T* from_python_cTscr(PyObject* p, boost::python::type t) { + return BOOST_PYTHON_CONVERSION::from_python(p, t); + } + virtual T* from_python_Tscr(PyObject* p, boost::python::type t) { + return BOOST_PYTHON_CONVERSION::from_python(p, t); + } + virtual T& from_python_Tr(PyObject* p, boost::python::type t) { + return BOOST_PYTHON_CONVERSION::from_python(p, t); + } + virtual const T& from_python_cTr(PyObject* p, boost::python::type t) { + return BOOST_PYTHON_CONVERSION::from_python(p, t); + } + virtual const T& from_python_T(PyObject* p, boost::python::type t) { + return BOOST_PYTHON_CONVERSION::from_python(p, t); + } + + virtual std::auto_ptr& from_python_aTr(PyObject* p, boost::python::type&> t) { + return BOOST_PYTHON_CONVERSION::from_python(p, t); + } + virtual std::auto_ptr from_python_aT(PyObject* p, boost::python::type > t) { + return BOOST_PYTHON_CONVERSION::from_python(p, t); + } + virtual const std::auto_ptr& from_python_caTr(PyObject* p, boost::python::type&> t) { + return BOOST_PYTHON_CONVERSION::from_python(p, t); + } + virtual PyObject* to_python(std::auto_ptr x) { + return BOOST_PYTHON_CONVERSION::to_python(x); + } + + virtual boost::shared_ptr& from_python_sTr(PyObject* p, boost::python::type&> t) { + return BOOST_PYTHON_CONVERSION::from_python(p, t); + } + virtual const boost::shared_ptr& from_python_sT(PyObject* p, boost::python::type > t) { + return BOOST_PYTHON_CONVERSION::from_python(p, t); + } + virtual const boost::shared_ptr& from_python_csTr(PyObject* p, boost::python::type&> t) { + return BOOST_PYTHON_CONVERSION::from_python(p, t); + } + virtual PyObject* to_python(boost::shared_ptr x) { + return BOOST_PYTHON_CONVERSION::to_python(x); + } +}; + +// The addditional to_python() converter that can be used if T is copyable. +template +struct export_converter_object : export_converter_object_noncopyable +{ + virtual PyObject* to_python(const T& x) { + return BOOST_PYTHON_CONVERSION::py_extension_class_converters(boost::python::type()).to_python(x); + } +}; + +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; + } + + 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; +}; + +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()); + } + return imported_converters; +} + +}}} // namespace boost::python::detail + +namespace boost { namespace python { + +// Implementation of export_converters(). +template +void export_converters(class_builder& cb) +{ + static export_converter_object export_cvts; + cb.add( + ref(PyCObject_FromVoidPtr(reinterpret_cast(&export_cvts), NULL)), + detail::converters_attribute_name); +} + +// Implementation of export_converters_noncopyable(). +template +void export_converters_noncopyable(class_builder& cb) +{ + static export_converter_object_noncopyable export_cvts; + cb.add( + ref(PyCObject_FromVoidPtr(reinterpret_cast(&export_cvts), NULL)), + detail::converters_attribute_name); +} + +// Implementation of import_converters. +template +class import_converters + : python_import_extension_class_converters // Works around MSVC6.x/GCC2.95.2 bug described + // at the bottom of class_builder.hpp. +{ + public: + import_converters(const char* module, const char* py_class) + : m_class(new detail::import_extension_class(module, py_class)) + { } + private: + boost::shared_ptr > m_class; +}; + +}} // namespace boost::python + +#endif // CROSS_MODULE_HPP diff --git a/src/cross_module.cpp b/src/cross_module.cpp new file mode 100644 index 00000000..ea5a08de --- /dev/null +++ b/src/cross_module.cpp @@ -0,0 +1,87 @@ +/* (C) Copyright Ralf W. Grosse-Kunstleve 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. + + Revision History: + 17 Apr 01 merged into boost CVS trunk (Ralf W. Grosse-Kunstleve) +*/ + +# include +namespace python = boost::python; +# include // MSVC6.0SP4 does not know std::fprintf +# include // MSVC6.0SP4 does not know std::strcmp + +namespace { + + PyObject* get_module_dict(const char* module_name) + { + python::ref module_obj(PyImport_ImportModule((char*) module_name)); + PyObject* module_dict = PyModule_GetDict(module_obj.get()); + if (module_dict == 0) throw python::import_error(); + return module_dict; + } +} + +namespace boost { namespace python { namespace detail { + +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) +{ + 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 + "." + + 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()); +} + +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 From 907033f725317d2c8cd7a1e00dc6d6b5ee2a321c Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 19:00:43 +0000 Subject: [PATCH 115/154] Obsolete files removed. [SVN r9814] --- example/getting_started3.cpp | 120 ----------------------------- example/getting_started4.cpp | 101 ------------------------- example/getting_started5.cpp | 126 ------------------------------- example/test_getting_started3.py | 56 -------------- example/test_getting_started4.py | 35 --------- example/test_getting_started5.py | 22 ------ 6 files changed, 460 deletions(-) delete mode 100644 example/getting_started3.cpp delete mode 100644 example/getting_started4.cpp delete mode 100644 example/getting_started5.cpp delete mode 100644 example/test_getting_started3.py delete mode 100644 example/test_getting_started4.py delete mode 100644 example/test_getting_started5.py diff --git a/example/getting_started3.cpp b/example/getting_started3.cpp deleted file mode 100644 index 799f5cac..00000000 --- a/example/getting_started3.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - This example shows how to make an Extension Class "pickleable". - - Python's pickle module implements a basic but powerful algorithm - for "pickling" (a.k.a. serializing, marshalling or flattening) - nearly arbitrary Python objects. - - The user can influence how an Extension Class instance is pickled - by defining three special methods: __getinitargs__(), - __getstate__(), and __setstate(). This interface is similar to - that for regular Python classes as described in detail in the - Python Library Reference for pickle: - - http://www.python.org/doc/current/lib/module-pickle.html - - When an Extension Class instance is pickled, __getinitargs__() is - called, if implemented. This method should return a tuple - containing the arguments to be passed to the class constructor when - the object is restored. - - If there is no __getstate__() method, the instance's __dict__ is - pickled if it is not empty. If __getstate__() is defined, it should - return an object representing the state of the instance. - - If there is no __setstate__() method, __getstate__() must return a - dictionary. When the instance is restored, the items in this dictionary - are added to the instance's __dict__. - - If the Extension Class defines __setstate__(), the pickle loader - calls it with the result of __getstate__() as arguments. In this - case, the state object need not be a dictionary. The - __getstate__() and __setstate__() methods can do what they want. - - If both __getinitargs__() and __getstate__() are defined, the - instance is restored by first calling the constructor with - the result of __getinitargs__() as argument. After the instance - is reconstructed, the __dict__ is updated or __setstate__() is - called if implemented. - - The mechanism described here is an exact replication of that one - implemented by Jim Fulton's ExtensionClass (included in Zope 2.2.2). - */ - -#include -#include - -#include -namespace python = boost::python; - -namespace { // Avoid cluttering the global namespace. - - // A friendly class. - class world - { - private: - std::string country; - int secret_number; - public: - world(const std::string& country) : secret_number(0) { - this->country = country; - } - std::string greet() const { return "Hello from " + country + "!"; } - std::string get_country() const { return country; } - void set_secret_number(int number) { secret_number = number; } - int get_secret_number() const { return secret_number; } - }; - - // Support for pickle. - python::tuple world_getinitargs(const world& w) { - python::tuple result(1); - result.set_item(0, w.get_country()); - return result; - } - - python::tuple world_getstate(const world& w) { - python::tuple result(1); - result.set_item(0, w.get_secret_number()); - return result; - } - - void world_setstate(world& w, python::tuple state) { - if (state.size() != 1) { - PyErr_SetString(PyExc_ValueError, - "Unexpected argument in call to __setstate__."); - throw python::error_already_set(); - } - int number = BOOST_PYTHON_CONVERSION::from_python(state[0].get(), - python::type()); - if (number != 42) - w.set_secret_number(number); - } -} - -BOOST_PYTHON_MODULE_INIT(getting_started3) -{ - try - { - // Create an object representing this extension module. - python::module_builder this_module("getting_started3"); - - // Create the Python type object for our extension class. - python::class_builder world_class(this_module, "world"); - - // Add the __init__ function. - world_class.def(python::constructor()); - // Add a regular member function. - world_class.def(&world::greet, "greet"); - world_class.def(&world::get_secret_number, "get_secret_number"); - world_class.def(&world::set_secret_number, "set_secret_number"); - - // Support for pickle. - world_class.def(world_getinitargs, "__getinitargs__"); - world_class.def(world_getstate, "__getstate__"); - world_class.def(world_setstate, "__setstate__"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/getting_started4.cpp b/example/getting_started4.cpp deleted file mode 100644 index fe6a3421..00000000 --- a/example/getting_started4.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include -namespace python = boost::python; - -namespace { // Avoid cluttering the global namespace. - - // A wrapper is used to define additional constructors. - // - struct vector_double_wrapper: std::vector - { - // Tell the compiler how to convert a base class object to - // this wrapper object. - vector_double_wrapper(PyObject*, const std::vector& vd) - : std::vector(vd) {} - - vector_double_wrapper(PyObject* self) - : std::vector() {} - - vector_double_wrapper(PyObject* self, int n) - : std::vector(n) {} - - vector_double_wrapper(PyObject* self, python::tuple tuple) - : std::vector(tuple.size()) - { - std::vector::iterator vd = begin(); - for (int i = 0; i < tuple.size(); i++) - vd[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), - python::type()); - } - }; - - double getitem(const std::vector& vd, std::size_t key) { - return vd[key]; - } - - void setitem(std::vector& vd, std::size_t key, double d) { - std::vector::iterator vditer = vd.begin(); - vditer[key] = d; - } - - void delitem(std::vector& vd, std::size_t key) { - std::vector::iterator vditer = vd.begin(); - vd.erase(&vditer[key]); - } - - // Convert vector_double to a regular Python tuple. - // - python::tuple as_tuple(const std::vector& vd) - { - python::tuple t(vd.size()); - for (int i = 0; i < vd.size(); i++) t.set_item(i, - python::ref(BOOST_PYTHON_CONVERSION::to_python(vd[i]))); - return t; - } - - // Function returning a vector_double object to Python. - // - std::vector foo(int n) - { - std::vector vd(n); - std::vector::iterator vditer = vd.begin(); - for (int i = 0; i < n; i++) vditer[i] = double(i); - return vd; - } - - // Same as foo(), but avoid copying on return. - // - std::auto_ptr > bar(int n) - { - std::auto_ptr > vdptr(new std::vector(n)); - std::vector::iterator vditer = vdptr->begin(); - for (int i = 0; i < n; i++) vditer[i] = double(10 * i); - return vdptr; - } -} - -BOOST_PYTHON_MODULE_INIT(getting_started4) -{ - try - { - python::module_builder this_module("getting_started4"); - - python::class_builder, vector_double_wrapper> - vector_double(this_module, "vector_double"); - - 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__"); - vector_double.def(setitem, "__setitem__"); - vector_double.def(delitem, "__delitem__"); - vector_double.def(as_tuple, "as_tuple"); - - this_module.def(foo, "foo"); - this_module.def(bar, "bar"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/getting_started5.cpp b/example/getting_started5.cpp deleted file mode 100644 index 9e9e7c75..00000000 --- a/example/getting_started5.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - This example shows how to convert a class from and to native - Python objects, such as tuples. - - We do not want to expose the helper class MillerIndex as an - Extension Class. However, in order to simplify the wrapper code, - we want to define from_python() and to_python() functions for - class MillerIndex. - - Consider the alternatives: - - - Expose MillerIndex as an Extension Class. - We need a constructor MillerIndex(python::tuple). - Python function calls become more complex: - foo(MillerIndex((1,2,3)) instead of foo((1,2,3)) - We need a method such as MillerIndex().as_tuple(). - - - Define a wrapper function for each function that we - want to expose, e.g.: - void add(const IndexingSet& ixset, const python::tuple PyMIx) - - The first alternative introduces a new type that the user has to - deal with. Other modules using Miller indices might organize them in - different ways, for example to increase runtime efficiency for - important procedures. This means, the user has to know how to - convert between the different kinds of Miller index representations. - This can quickly become a nuisance. Relying on native Python data - structures minimizes the number of special types the user has to - learn and convert. Of course, this argument is only valid for - small and relatively simply classes. - - If there are many member functions with MillerIndex arguments, the - second alternative is impractical, and concentrating the conversion - mechanism in one central place is essential for code - maintainability. An added benefit is that more convenient (smarter) - conversion functions can be provided without cluttering the rest of - the wrapper code. - - */ - -#include -#include -#include -namespace python = boost::python; - -namespace { // Avoid cluttering the global namespace. - - // The helper class. - // - class MillerIndex { - public: - int v[3]; - }; - - // The main class. Imagine that there are MANY member functions - // like add() and get(). - // - class IndexingSet { - private: - std::vector VMIx; - public: - void add(const MillerIndex& MIx) { VMIx.push_back(MIx); } - MillerIndex get(std::size_t i) const { return VMIx[i]; } - }; -} - -BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE - - // Convert a Python tuple to a MillerIndex object. - // - MillerIndex from_python(PyObject* p, python::type) - { - python::tuple tup - = python::tuple(python::ref(p, python::ref::increment_count)); - if (tup.size() != 3) { - PyErr_SetString(PyExc_ValueError, - "expecting exactly 3 values in tuple."); - throw python::error_already_set(); - } - MillerIndex result; - for (int i = 0; i < 3; i++) - result.v[i] = from_python(tup[i].get(), python::type()); - return result; - } - - // Similar conversion for MillerIndex objects passed by value. - // Not actually used, but included to show the principle. - // - MillerIndex from_python(PyObject* p, python::type) - { - return from_python(p, python::type()); - } - - // Convert a MillerIndex object to a Python tuple. - // - PyObject* to_python(const MillerIndex& hkl) - { - python::tuple result(3); - for (int i = 0; i < 3; i++) - result.set_item(i, python::ref(to_python(hkl.v[i]))); - return result.reference().release(); - } - -BOOST_PYTHON_END_CONVERSION_NAMESPACE - -BOOST_PYTHON_MODULE_INIT(getting_started5) -{ - try - { - // Create an object representing this extension module. - python::module_builder this_module("getting_started5"); - - // Create the Python type object for our extension class. - python::class_builder ixset_class(this_module, "IndexingSet"); - - // Add the __init__ function. - ixset_class.def(python::constructor<>()); - // Add the member functions. - ixset_class.def(&IndexingSet::add, "add"); - ixset_class.def(&IndexingSet::get, "get"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/test_getting_started3.py b/example/test_getting_started3.py deleted file mode 100644 index d62cf5a2..00000000 --- a/example/test_getting_started3.py +++ /dev/null @@ -1,56 +0,0 @@ -r'''>>> import getting_started3 - >>> import re - >>> import pickle - >>> getting_started3.world.__module__ - 'getting_started3' - >>> getting_started3.world.__safe_for_unpickling__ - 1 - >>> getting_started3.world.__reduce__() - 'world' - >>> assert re.match( - ... "\(, \('Hello',\), \(0,\)\)", - ... repr(getting_started3.world('Hello').__reduce__())) - >>> - >>> for number in (24, 42): - ... wd = getting_started3.world('California') - ... wd.set_secret_number(number) - ... pstr = pickle.dumps(wd) - ... print pstr - ... wl = pickle.loads(pstr) - ... print wd.greet(), wd.get_secret_number() - ... print wl.greet(), wl.get_secret_number() - cgetting_started3 - world - p0 - (S'California' - p1 - tp2 - R(I24 - tp3 - bp4 - . - Hello from California! 24 - Hello from California! 24 - cgetting_started3 - world - p0 - (S'California' - p1 - tp2 - R(I42 - tp3 - bp4 - . - Hello from California! 42 - Hello from California! 0 -''' - -def run(args = None): - if args is not None: - import sys - sys.argv = args - import doctest, test_getting_started3 - doctest.testmod(test_getting_started3) - -if __name__ == '__main__': - run() diff --git a/example/test_getting_started4.py b/example/test_getting_started4.py deleted file mode 100644 index 82b5c794..00000000 --- a/example/test_getting_started4.py +++ /dev/null @@ -1,35 +0,0 @@ -r'''>>> import getting_started4 - >>> v=getting_started4.vector_double() - >>> print v.as_tuple() - () - >>> v=getting_started4.vector_double(5) - >>> print v.as_tuple() - (0.0, 0.0, 0.0, 0.0, 0.0) - >>> print len(v) - 5 - >>> v=getting_started4.vector_double((3,4,5)) - >>> print v.as_tuple() - (3.0, 4.0, 5.0) - >>> print v[1] - 4.0 - >>> v[1] = 40 - >>> print v.as_tuple() - (3.0, 40.0, 5.0) - >>> del v[1] - >>> print v.as_tuple() - (3.0, 5.0) - >>> print getting_started4.foo(11).as_tuple() - (0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0) - >>> print getting_started4.bar(12).as_tuple() - (0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0) -''' - -def run(args = None): - if args is not None: - import sys - sys.argv = args - import doctest, test_getting_started4 - doctest.testmod(test_getting_started4) - -if __name__ == '__main__': - run() diff --git a/example/test_getting_started5.py b/example/test_getting_started5.py deleted file mode 100644 index 8eeba1e2..00000000 --- a/example/test_getting_started5.py +++ /dev/null @@ -1,22 +0,0 @@ -r'''>>> import getting_started5 - >>> ixset = getting_started5.IndexingSet() - >>> ixset.add((1,2,3)) - >>> ixset.add((4,5,6)) - >>> ixset.add((7,8,9)) - >>> print ixset.get(0) - (1, 2, 3) - >>> print ixset.get(1) - (4, 5, 6) - >>> print ixset.get(2) - (7, 8, 9) -''' - -def run(args = None): - if args is not None: - import sys - sys.argv = args - import doctest, test_getting_started5 - doctest.testmod(test_getting_started5) - -if __name__ == '__main__': - run() From dc520c6c32a4b0485d583d3ecc11e24df77a3eb7 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 19:04:16 +0000 Subject: [PATCH 116/154] Author included [SVN r9815] --- example/getting_started1.cpp | 2 ++ example/getting_started2.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/example/getting_started1.cpp b/example/getting_started1.cpp index 7a8e9087..c6a77723 100644 --- a/example/getting_started1.cpp +++ b/example/getting_started1.cpp @@ -1,3 +1,5 @@ +// Example by Ralf W. Grosse-Kunstleve + #include namespace { // Avoid cluttering the global namespace. diff --git a/example/getting_started2.cpp b/example/getting_started2.cpp index 72b04105..9121b1a0 100644 --- a/example/getting_started2.cpp +++ b/example/getting_started2.cpp @@ -1,3 +1,5 @@ +// Example by Ralf W. Grosse-Kunstleve + #include #include From 8158a509c92eeb0c8917ed7aca6276529ddad1e8 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 19:20:31 +0000 Subject: [PATCH 117/154] moved from branch ralf_grosse_kunstleve to trunk [SVN r9816] --- example/do_it_yourself_converters.cpp | 128 ++++++++++++++++++ example/dvect.cpp | 45 +++++++ example/dvect.h | 32 +++++ example/dvect_conversions.cpp | 51 ++++++++ example/dvect_defs.cpp | 13 ++ example/ivect.cpp | 45 +++++++ example/noncopyable.h | 14 ++ example/noncopyable_export.cpp | 25 ++++ example/noncopyable_import.cpp | 42 ++++++ example/pickle1.cpp | 64 +++++++++ example/pickle2.cpp | 100 +++++++++++++++ example/pickle3.cpp | 150 ++++++++++++++++++++++ example/simple_vector.cpp | 103 +++++++++++++++ example/test_do_it_yourself_converters.py | 22 ++++ example/test_pickle1.py | 31 +++++ example/test_pickle2.py | 45 +++++++ example/test_pickle3.py | 38 ++++++ example/test_simple_vector.py | 35 +++++ 18 files changed, 983 insertions(+) create mode 100644 example/do_it_yourself_converters.cpp create mode 100644 example/dvect.cpp create mode 100644 example/dvect.h create mode 100644 example/dvect_conversions.cpp create mode 100644 example/dvect_defs.cpp create mode 100644 example/ivect.cpp create mode 100644 example/noncopyable.h create mode 100644 example/noncopyable_export.cpp create mode 100644 example/noncopyable_import.cpp create mode 100644 example/pickle1.cpp create mode 100644 example/pickle2.cpp create mode 100644 example/pickle3.cpp create mode 100644 example/simple_vector.cpp create mode 100644 example/test_do_it_yourself_converters.py create mode 100644 example/test_pickle1.py create mode 100644 example/test_pickle2.py create mode 100644 example/test_pickle3.py create mode 100644 example/test_simple_vector.py diff --git a/example/do_it_yourself_converters.cpp b/example/do_it_yourself_converters.cpp new file mode 100644 index 00000000..6d2d2d6a --- /dev/null +++ b/example/do_it_yourself_converters.cpp @@ -0,0 +1,128 @@ +// Example by Ralf W. Grosse-Kunstleve +/* + + This example shows how to convert a class from and to native + Python objects, such as tuples. + + We do not want to expose the helper class MillerIndex as an + Extension Class. However, in order to simplify the wrapper code, + we want to define from_python() and to_python() functions for + class MillerIndex. + + Consider the alternatives: + + - Expose MillerIndex as an Extension Class. + We need a constructor MillerIndex(python::tuple). + Python function calls become more complex: + foo(MillerIndex((1,2,3)) instead of foo((1,2,3)) + We need a method such as MillerIndex().as_tuple(). + + - Define a wrapper function for each function that we + want to expose, e.g.: + void add(const IndexingSet& ixset, const python::tuple PyMIx) + + The first alternative introduces a new type that the user has to + deal with. Other modules using Miller indices might organize them in + different ways, for example to increase runtime efficiency for + important procedures. This means, the user has to know how to + convert between the different kinds of Miller index representations. + This can quickly become a nuisance. Relying on native Python data + structures minimizes the number of special types the user has to + learn and convert. Of course, this argument is only valid for + small and relatively simply classes. + + If there are many member functions with MillerIndex arguments, the + second alternative is impractical, and concentrating the conversion + mechanism in one central place is essential for code + maintainability. An added benefit is that more convenient (smarter) + conversion functions can be provided without cluttering the rest of + the wrapper code. + + */ + +#include +#include +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // The helper class. + // + class MillerIndex { + public: + int v[3]; + }; + + // The main class. Imagine that there are MANY member functions + // like add() and get(). + // + class IndexingSet { + private: + std::vector VMIx; + public: + void add(const MillerIndex& MIx) { VMIx.push_back(MIx); } + MillerIndex get(std::size_t i) const { return VMIx[i]; } + }; +} + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + + // Convert a Python tuple to a MillerIndex object. + // + MillerIndex from_python(PyObject* p, python::type) + { + python::tuple tup + = python::tuple(python::ref(p, python::ref::increment_count)); + if (tup.size() != 3) { + PyErr_SetString(PyExc_ValueError, + "expecting exactly 3 values in tuple."); + throw python::error_already_set(); + } + MillerIndex result; + for (int i = 0; i < 3; i++) + result.v[i] = from_python(tup[i].get(), python::type()); + return result; + } + + // Similar conversion for MillerIndex objects passed by value. + // Not actually used, but included to show the principle. + // + MillerIndex from_python(PyObject* p, python::type) + { + return from_python(p, python::type()); + } + + // Convert a MillerIndex object to a Python tuple. + // + PyObject* to_python(const MillerIndex& hkl) + { + python::tuple result(3); + for (int i = 0; i < 3; i++) + result.set_item(i, python::ref(to_python(hkl.v[i]))); + return result.reference().release(); + } + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +BOOST_PYTHON_MODULE_INIT(do_it_yourself_converters) +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("do_it_yourself_converters"); + + // Create the Python type object for our extension class. + python::class_builder ixset_class(this_module, "IndexingSet"); + + // Add the __init__ function. + ixset_class.def(python::constructor<>()); + // Add the member functions. + ixset_class.def(&IndexingSet::add, "add"); + ixset_class.def(&IndexingSet::get, "get"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/dvect.cpp b/example/dvect.cpp new file mode 100644 index 00000000..da6b35a3 --- /dev/null +++ b/example/dvect.cpp @@ -0,0 +1,45 @@ +// Example by Ralf W. Grosse-Kunstleve +// See root/libs/python/doc/cross_module.html for an introduction. + +#include "dvect.h" +#include "ivect.h" +#include +namespace python = boost::python; + +namespace { + +# include "dvect_conversions.cpp" +# include "ivect_conversions.cpp" + + vects::ivect dvect_as_ivect(const vects::dvect& dv) + { + vects::ivect iv(dv.size()); + vects::ivect::iterator iviter = iv.begin(); + for (int i = 0; i < dv.size(); i++) iviter[i] = static_cast(dv[i]); + return iv; + } +} + +BOOST_PYTHON_MODULE_INIT(dvect) +{ + try + { + python::module_builder this_module("dvect"); + + python::class_builder dvect_class(this_module, "dvect"); + python::export_converters(dvect_class); + + python::import_converters ivect_converters("ivect", "ivect"); + + dvect_class.def(python::constructor()); + dvect_class.def(&vects::dvect::as_tuple, "as_tuple"); + dvect_class.def(dvect_as_ivect, "as_ivect"); + +# include "dvect_defs.cpp" +# include "ivect_defs.cpp" + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/dvect.h b/example/dvect.h new file mode 100644 index 00000000..8ffe7b50 --- /dev/null +++ b/example/dvect.h @@ -0,0 +1,32 @@ +#ifndef DVECT_H +#define DVECT_H + +#include +#include + +namespace vects { + + struct dvect : public std::vector + { + dvect() : std::vector() {} + dvect(size_t n) : std::vector(n) {} + dvect(boost::python::tuple tuple) : std::vector(tuple.size()) + { + std::vector::iterator v_it = begin(); + for (int i = 0; i < tuple.size(); i++) + v_it[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), + boost::python::type()); + } + + boost::python::tuple as_tuple() const + { + boost::python::tuple t(size()); + for (int i = 0; i < size(); i++) + t.set_item(i, + boost::python::ref(BOOST_PYTHON_CONVERSION::to_python((*this)[i]))); + return t; + } + }; +} + +#endif // DVECT_H diff --git a/example/dvect_conversions.cpp b/example/dvect_conversions.cpp new file mode 100644 index 00000000..21527243 --- /dev/null +++ b/example/dvect_conversions.cpp @@ -0,0 +1,51 @@ + // basics first: const reference converters + boost::python::tuple const_dvect_reference_as_tuple(const vects::dvect& dv) + { + return dv.as_tuple(); + } + + // to_python smart pointer conversions + std::auto_ptr dvect_as_auto_ptr(const vects::dvect& dv) + { + return std::auto_ptr(new vects::dvect(dv)); + } + boost::shared_ptr dvect_as_shared_ptr(const vects::dvect& dv) + { + return boost::shared_ptr(new vects::dvect(dv)); + } + + // smart pointers passed by value + boost::python::ref auto_ptr_value_dvect_as_tuple(std::auto_ptr dv) + { + if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return dv->as_tuple().reference(); + } + boost::python::ref shared_ptr_value_dvect_as_tuple(boost::shared_ptr dv) + { + if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return dv->as_tuple().reference(); + } + + // smart pointers passed by reference + boost::python::ref auto_ptr_reference_dvect_as_tuple(std::auto_ptr& dv) + { + if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return dv->as_tuple().reference(); + } + boost::python::ref shared_ptr_reference_dvect_as_tuple(boost::shared_ptr& dv) + { + if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return dv->as_tuple().reference(); + } + + // smart pointers passed by const reference + boost::python::ref auto_ptr_const_reference_dvect_as_tuple(const std::auto_ptr& dv) + { + if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return dv->as_tuple().reference(); + } + boost::python::ref shared_ptr_const_reference_dvect_as_tuple(const boost::shared_ptr& dv) + { + if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return dv->as_tuple().reference(); + } diff --git a/example/dvect_defs.cpp b/example/dvect_defs.cpp new file mode 100644 index 00000000..2739b219 --- /dev/null +++ b/example/dvect_defs.cpp @@ -0,0 +1,13 @@ + this_module.def(dvect_as_auto_ptr, "dvect_as_auto_ptr"); + this_module.def(dvect_as_shared_ptr, "dvect_as_shared_ptr"); + + this_module.def(const_dvect_reference_as_tuple, "const_dvect_reference_as_tuple"); + + this_module.def(auto_ptr_value_dvect_as_tuple, "auto_ptr_value_dvect_as_tuple"); + this_module.def(shared_ptr_value_dvect_as_tuple, "shared_ptr_value_dvect_as_tuple"); + + this_module.def(auto_ptr_reference_dvect_as_tuple, "auto_ptr_reference_dvect_as_tuple"); + this_module.def(shared_ptr_reference_dvect_as_tuple, "shared_ptr_reference_dvect_as_tuple"); + + this_module.def(auto_ptr_const_reference_dvect_as_tuple, "auto_ptr_const_reference_dvect_as_tuple"); + this_module.def(shared_ptr_const_reference_dvect_as_tuple, "shared_ptr_const_reference_dvect_as_tuple"); diff --git a/example/ivect.cpp b/example/ivect.cpp new file mode 100644 index 00000000..db1c0ec3 --- /dev/null +++ b/example/ivect.cpp @@ -0,0 +1,45 @@ +// Example by Ralf W. Grosse-Kunstleve +// See root/libs/python/doc/cross_module.html for an introduction. + +#include "dvect.h" +#include "ivect.h" +#include +namespace python = boost::python; + +namespace { + +# include "dvect_conversions.cpp" +# include "ivect_conversions.cpp" + + vects::dvect ivect_as_dvect(const vects::ivect& iv) + { + vects::dvect dv(iv.size()); + vects::dvect::iterator dviter = dv.begin(); + for (int i = 0; i < iv.size(); i++) dviter[i] = static_cast(iv[i]); + return dv; + } +} + +BOOST_PYTHON_MODULE_INIT(ivect) +{ + try + { + python::module_builder this_module("ivect"); + + python::class_builder ivect_class(this_module, "ivect"); + python::export_converters(ivect_class); + + python::import_converters dvect_converters("dvect", "dvect"); + + ivect_class.def(python::constructor()); + ivect_class.def(&vects::ivect::as_tuple, "as_tuple"); + ivect_class.def(ivect_as_dvect, "as_dvect"); + +# include "dvect_defs.cpp" +# include "ivect_defs.cpp" + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/noncopyable.h b/example/noncopyable.h new file mode 100644 index 00000000..de7b3672 --- /dev/null +++ b/example/noncopyable.h @@ -0,0 +1,14 @@ +#ifndef NONCOPYABLE_H +#define NONCOPYABLE_H + +class store +{ + private: + store(const store&) { } // Disable the copy constructor. + int number; + public: + store(const int i) : number(i) { } + int recall() const { return number; } +}; + +#endif // NONCOPYABLE_H diff --git a/example/noncopyable_export.cpp b/example/noncopyable_export.cpp new file mode 100644 index 00000000..794b1200 --- /dev/null +++ b/example/noncopyable_export.cpp @@ -0,0 +1,25 @@ +// Example by Ralf W. Grosse-Kunstleve +// See root/libs/python/doc/cross_module.html for an introduction. + +#include +namespace python = boost::python; + +#include "noncopyable.h" + +BOOST_PYTHON_MODULE_INIT(noncopyable_export) +{ + try + { + python::module_builder this_module("noncopyable_export"); + + python::class_builder store_class(this_module, "store"); + python::export_converters_noncopyable(store_class); + + store_class.def(python::constructor()); + store_class.def(&store::recall, "recall"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/noncopyable_import.cpp b/example/noncopyable_import.cpp new file mode 100644 index 00000000..ea2477be --- /dev/null +++ b/example/noncopyable_import.cpp @@ -0,0 +1,42 @@ +// Example by Ralf W. Grosse-Kunstleve +// See root/libs/python/doc/cross_module.html for an introduction. + +#include +namespace python = boost::python; + +#include "noncopyable.h" + +namespace { // Avoid cluttering the global namespace. + + // A function with store objects as both input and output parameters. + // Because the copy constructor is disabled, we cannot pass a store + // object by value. Instead, we pass a smart pointer. + std::auto_ptr add_stores(const store& s1, const store& s2) + { + int sum = s1.recall() + s2.recall(); + std::auto_ptr ss = std::auto_ptr(new store(sum)); + return ss; + } +} + +BOOST_PYTHON_MODULE_INIT(noncopyable_import) +{ + try + { + python::module_builder this_module("noncopyable_import"); + + python::import_converters + dvect_converters("noncopyable_export", "store"); + + // Imagine all the additional classes with member functions + // that have store objects as input and output parameters. + // Lots and lots of them. + // However, to keep this example simple, we only define a + // module-level function. + this_module.def(add_stores, "add_stores"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/pickle1.cpp b/example/pickle1.cpp new file mode 100644 index 00000000..cdd78989 --- /dev/null +++ b/example/pickle1.cpp @@ -0,0 +1,64 @@ +// Example by Ralf W. Grosse-Kunstleve + +/* + This example shows how to make an Extension Class "pickleable". + + The world class below can be fully restored by passing the + appropriate argument to the constructor. Therefore it is sufficient + to define the pickle interface method __getinitargs__. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include + +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class world + { + private: + std::string country; + int secret_number; + public: + world(const std::string& country) : secret_number(0) { + this->country = country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + }; + + // Support for pickle. + python::ref world_getinitargs(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_country()); + return result.reference(); + } +} + +BOOST_PYTHON_MODULE_INIT(pickle1) +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("pickle1"); + + // Create the Python type object for our extension class. + python::class_builder world_class(this_module, "world"); + + // Add the __init__ function. + world_class.def(python::constructor()); + // Add a regular member function. + world_class.def(&world::greet, "greet"); + + // Support for pickle. + world_class.def(world_getinitargs, "__getinitargs__"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/pickle2.cpp b/example/pickle2.cpp new file mode 100644 index 00000000..d6aa3201 --- /dev/null +++ b/example/pickle2.cpp @@ -0,0 +1,100 @@ +// Example by Ralf W. Grosse-Kunstleve + +/* + This example shows how to make an Extension Class "pickleable". + + The world class below contains member data (secret_number) that + cannot be restored by any of the constructors. Therefore it is + necessary to provide the __getstate__/__setstate__ pair of pickle + interface methods. + + For simplicity, the __dict__ is not included in the result of + __getstate__. This is not generally recommended, but a valid + approach if it is anticipated that the object's __dict__ will + always be empty. Note that safety guard are provided to catch the + cases where this assumption is not true. + + pickle3.cpp shows how to include the object's __dict__ in the + result of __getstate__. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include + +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class world + { + public: + world(const std::string& country) : secret_number(0) { + this->country = country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + void set_secret_number(int number) { secret_number = number; } + int get_secret_number() const { return secret_number; } + private: + std::string country; + int secret_number; + }; + + // Support for pickle. + + using BOOST_PYTHON_CONVERSION::from_python; + + python::ref world_getinitargs(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_country()); + return result.reference(); // returning the reference avoids the copying. + } + + python::ref world_getstate(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_secret_number()); + return result.reference(); // returning the reference avoids the copying. + } + + void world_setstate(world& w, python::tuple state) { + if (state.size() != 1) { + PyErr_SetString(PyExc_ValueError, + "Unexpected argument in call to __setstate__."); + throw python::error_already_set(); + } + int number = from_python(state[0].get(), python::type()); + if (number != 42) + w.set_secret_number(number); + } +} + +BOOST_PYTHON_MODULE_INIT(pickle2) +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("pickle2"); + + // Create the Python type object for our extension class. + python::class_builder world_class(this_module, "world"); + + // Add the __init__ function. + world_class.def(python::constructor()); + // Add a regular member function. + world_class.def(&world::greet, "greet"); + world_class.def(&world::get_secret_number, "get_secret_number"); + world_class.def(&world::set_secret_number, "set_secret_number"); + + // Support for pickle. + world_class.def(world_getinitargs, "__getinitargs__"); + world_class.def(world_getstate, "__getstate__"); + world_class.def(world_setstate, "__setstate__"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/pickle3.cpp b/example/pickle3.cpp new file mode 100644 index 00000000..bfa7dc54 --- /dev/null +++ b/example/pickle3.cpp @@ -0,0 +1,150 @@ +// Example by Ralf W. Grosse-Kunstleve + +/* + This example shows how to make an Extension Class "pickleable". + + The world class below contains member data (secret_number) that + cannot be restored by any of the constructors. Therefore it is + necessary to provide the __getstate__/__setstate__ pair of pickle + interface methods. + + The object's __dict__ is included in the result of __getstate__. + This requires more code (compare with pickle2.cpp), but is + unavoidable if the object's __dict__ is not always empty. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include + +#include +namespace python = boost::python; + +namespace boost { namespace python { + + ref getattr(PyObject* o, const std::string& attr_name) { + return ref(PyObject_GetAttrString(o, const_cast(attr_name.c_str()))); + } + ref getattr(const ref& r, const std::string& attr_name) { + return getattr(r.get(), attr_name); + } + +}} + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class world + { + public: + world(const std::string& country) : secret_number(0) { + this->country = country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + void set_secret_number(int number) { secret_number = number; } + int get_secret_number() const { return secret_number; } + private: + std::string country; + int secret_number; + }; + + // Support for pickle. + python::ref world_getinitargs(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_country()); + return result.reference(); // returning the reference avoids the copying. + } + + python::ref world_getstate(python::tuple const & args, + python::dictionary const & keywords); + + PyObject* world_setstate(python::tuple const & args, + python::dictionary const & keywords); +} + +BOOST_PYTHON_MODULE_INIT(pickle3) +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("pickle3"); + + // Create the Python type object for our extension class. + python::class_builder world_class(this_module, "world"); + + // Add the __init__ function. + world_class.def(python::constructor()); + // Add a regular member function. + world_class.def(&world::greet, "greet"); + world_class.def(&world::get_secret_number, "get_secret_number"); + world_class.def(&world::set_secret_number, "set_secret_number"); + + // Support for pickle. + world_class.def(world_getinitargs, "__getinitargs__"); + world_class.def_raw(world_getstate, "__getstate__"); + world_class.def_raw(world_setstate, "__setstate__"); + world_class.getstate_manages_dict(); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} + +namespace { + + using BOOST_PYTHON_CONVERSION::from_python; + using boost::python::type; + using boost::python::ref; + using boost::python::tuple; + using boost::python::list; + using boost::python::dictionary; + using boost::python::getattr; + + ref world_getstate(tuple const & args, dictionary const & keywords) + { + if(args.size() != 1 || keywords.size() != 0) { + PyErr_SetString(PyExc_TypeError, "wrong number of arguments"); + throw boost::python::argument_error(); + } + const world& w = from_python(args[0].get(), type()); + ref mydict = getattr(args[0], "__dict__"); + tuple result(2); + // store the object's __dict__ + result.set_item(0, mydict); + // store the internal state of the C++ object + result.set_item(1, w.get_secret_number()); + return result.reference(); // returning the reference avoids the copying. + } + + PyObject* world_setstate(tuple const & args, dictionary const & keywords) + { + if(args.size() != 2 || keywords.size() != 0) { + PyErr_SetString(PyExc_TypeError, "wrong number of arguments"); + throw boost::python::argument_error(); + } + world& w = from_python(args[0].get(), type()); + ref mydict = getattr(args[0], "__dict__"); + tuple state = from_python(args[1].get(), type()); + if (state.size() != 2) { + PyErr_SetString(PyExc_ValueError, + "Unexpected argument in call to __setstate__."); + throw python::error_already_set(); + } + // restore the object's __dict__ + dictionary odict = from_python(mydict.get(), type()); + const dictionary& pdict = from_python(state[0].get(), type()); + list pkeys(pdict.keys()); + for (int i = 0; i < pkeys.size(); i++) { + ref k(pkeys[i]); + //odict[k] = pdict[k]; // XXX memory leak! + odict[k] = pdict.get_item(k); // this does not leak. + } + // restore the internal state of the C++ object + int number = from_python(state[1].get(), type()); + if (number != 42) + w.set_secret_number(number); + return python::detail::none(); + } +} diff --git a/example/simple_vector.cpp b/example/simple_vector.cpp new file mode 100644 index 00000000..5ac0767b --- /dev/null +++ b/example/simple_vector.cpp @@ -0,0 +1,103 @@ +// Example by Ralf W. Grosse-Kunstleve + +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // A wrapper is used to define additional constructors. + // + struct vector_double_wrapper: std::vector + { + // Tell the compiler how to convert a base class object to + // this wrapper object. + vector_double_wrapper(PyObject*, const std::vector& vd) + : std::vector(vd) {} + + vector_double_wrapper(PyObject* self) + : std::vector() {} + + vector_double_wrapper(PyObject* self, int n) + : std::vector(n) {} + + vector_double_wrapper(PyObject* self, python::tuple tuple) + : std::vector(tuple.size()) + { + std::vector::iterator vd = begin(); + for (int i = 0; i < tuple.size(); i++) + vd[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), + python::type()); + } + }; + + double getitem(const std::vector& vd, std::size_t key) { + return vd[key]; + } + + void setitem(std::vector& vd, std::size_t key, double d) { + std::vector::iterator vditer = vd.begin(); + vditer[key] = d; + } + + void delitem(std::vector& vd, std::size_t key) { + std::vector::iterator vditer = vd.begin(); + vd.erase(&vditer[key]); + } + + // Convert vector_double to a regular Python tuple. + // + python::tuple as_tuple(const std::vector& vd) + { + python::tuple t(vd.size()); + for (int i = 0; i < vd.size(); i++) t.set_item(i, + python::ref(BOOST_PYTHON_CONVERSION::to_python(vd[i]))); + return t; + } + + // Function returning a vector_double object to Python. + // + std::vector foo(int n) + { + std::vector vd(n); + std::vector::iterator vditer = vd.begin(); + for (int i = 0; i < n; i++) vditer[i] = double(i); + return vd; + } + + // Same as foo(), but avoid copying on return. + // + std::auto_ptr > bar(int n) + { + std::auto_ptr > vdptr(new std::vector(n)); + std::vector::iterator vditer = vdptr->begin(); + for (int i = 0; i < n; i++) vditer[i] = double(10 * i); + return vdptr; + } +} + +BOOST_PYTHON_MODULE_INIT(simple_vector) +{ + try + { + python::module_builder this_module("simple_vector"); + + python::class_builder, vector_double_wrapper> + vector_double(this_module, "vector_double"); + + 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__"); + vector_double.def(setitem, "__setitem__"); + vector_double.def(delitem, "__delitem__"); + vector_double.def(as_tuple, "as_tuple"); + + this_module.def(foo, "foo"); + this_module.def(bar, "bar"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/test_do_it_yourself_converters.py b/example/test_do_it_yourself_converters.py new file mode 100644 index 00000000..e256c614 --- /dev/null +++ b/example/test_do_it_yourself_converters.py @@ -0,0 +1,22 @@ +r'''>>> import do_it_yourself_converters + >>> ixset = do_it_yourself_converters.IndexingSet() + >>> ixset.add((1,2,3)) + >>> ixset.add((4,5,6)) + >>> ixset.add((7,8,9)) + >>> print ixset.get(0) + (1, 2, 3) + >>> print ixset.get(1) + (4, 5, 6) + >>> print ixset.get(2) + (7, 8, 9) +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_do_it_yourself_converters + doctest.testmod(test_do_it_yourself_converters) + +if __name__ == '__main__': + run() diff --git a/example/test_pickle1.py b/example/test_pickle1.py new file mode 100644 index 00000000..05696d4a --- /dev/null +++ b/example/test_pickle1.py @@ -0,0 +1,31 @@ +r'''>>> import pickle1 + >>> import re + >>> import pickle + >>> pickle1.world.__module__ + 'pickle1' + >>> pickle1.world.__safe_for_unpickling__ + 1 + >>> pickle1.world.__reduce__() + 'world' + >>> assert re.match( + ... "\(, \('Hello',\)\)", + ... repr(pickle1.world('Hello').__reduce__())) + >>> + >>> wd = pickle1.world('California') + >>> pstr = pickle.dumps(wd) + >>> wl = pickle.loads(pstr) + >>> print wd.greet() + Hello from California! + >>> print wl.greet() + Hello from California! +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_pickle1 + doctest.testmod(test_pickle1) + +if __name__ == '__main__': + run() diff --git a/example/test_pickle2.py b/example/test_pickle2.py new file mode 100644 index 00000000..463befa6 --- /dev/null +++ b/example/test_pickle2.py @@ -0,0 +1,45 @@ +r'''>>> import pickle2 + >>> import re + >>> import pickle + >>> pickle2.world.__module__ + 'pickle2' + >>> pickle2.world.__safe_for_unpickling__ + 1 + >>> pickle2.world.__reduce__() + 'world' + >>> assert re.match( + ... "\(, \('Hello',\), \(0,\)\)", + ... repr(pickle2.world('Hello').__reduce__())) + >>> + >>> for number in (24, 42): + ... wd = pickle2.world('California') + ... wd.set_secret_number(number) + ... pstr = pickle.dumps(wd) + ... wl = pickle.loads(pstr) + ... print wd.greet(), wd.get_secret_number() + ... print wl.greet(), wl.get_secret_number() + Hello from California! 24 + Hello from California! 24 + Hello from California! 42 + Hello from California! 0 + +# Now show that the __dict__ is not taken care of. + >>> wd = pickle2.world('California') + >>> wd.x = 1 + >>> wd.__dict__ + {'x': 1} + >>> try: pstr = pickle.dumps(wd) + ... except RuntimeError, err: print err[0] + ... + Incomplete pickle support (__getstate_manages_dict__ not set) +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_pickle2 + doctest.testmod(test_pickle2) + +if __name__ == '__main__': + run() diff --git a/example/test_pickle3.py b/example/test_pickle3.py new file mode 100644 index 00000000..b964f1a2 --- /dev/null +++ b/example/test_pickle3.py @@ -0,0 +1,38 @@ +r'''>>> import pickle3 + >>> import re + >>> import pickle + >>> pickle3.world.__module__ + 'pickle3' + >>> pickle3.world.__safe_for_unpickling__ + 1 + >>> pickle3.world.__reduce__() + 'world' + >>> assert re.match( + ... "\(, \('Hello',\), \(\{\}, 0\)\)", + ... repr(pickle3.world('Hello').__reduce__())) + >>> + >>> for number in (24, 42): + ... wd = pickle3.world('California') + ... wd.set_secret_number(number) + ... wd.x = 2 * number + ... wd.y = 'y' * number + ... wd.z = 3. * number + ... pstr = pickle.dumps(wd) + ... wl = pickle.loads(pstr) + ... print wd.greet(), wd.get_secret_number(), wd.__dict__ + ... print wl.greet(), wl.get_secret_number(), wl.__dict__ + Hello from California! 24 {'z': 72.0, 'x': 48, 'y': 'yyyyyyyyyyyyyyyyyyyyyyyy'} + Hello from California! 24 {'z': 72.0, 'x': 48, 'y': 'yyyyyyyyyyyyyyyyyyyyyyyy'} + Hello from California! 42 {'z': 126.0, 'x': 84, 'y': 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'} + Hello from California! 0 {'z': 126.0, 'x': 84, 'y': 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'} +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_pickle3 + doctest.testmod(test_pickle3) + +if __name__ == '__main__': + run() diff --git a/example/test_simple_vector.py b/example/test_simple_vector.py new file mode 100644 index 00000000..a19e205b --- /dev/null +++ b/example/test_simple_vector.py @@ -0,0 +1,35 @@ +r'''>>> import simple_vector + >>> v=simple_vector.vector_double() + >>> print v.as_tuple() + () + >>> v=simple_vector.vector_double(5) + >>> print v.as_tuple() + (0.0, 0.0, 0.0, 0.0, 0.0) + >>> print len(v) + 5 + >>> v=simple_vector.vector_double((3,4,5)) + >>> print v.as_tuple() + (3.0, 4.0, 5.0) + >>> print v[1] + 4.0 + >>> v[1] = 40 + >>> print v.as_tuple() + (3.0, 40.0, 5.0) + >>> del v[1] + >>> print v.as_tuple() + (3.0, 5.0) + >>> print simple_vector.foo(11).as_tuple() + (0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0) + >>> print simple_vector.bar(12).as_tuple() + (0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0) +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_simple_vector + doctest.testmod(test_simple_vector) + +if __name__ == '__main__': + run() From ef7c4379572ef0f9758a4c1c5add34616a8c0757 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 19:31:00 +0000 Subject: [PATCH 118/154] moved from branch ralf_grosse_kunstleve to trunk [SVN r9817] --- example/ivect.h | 32 ++++++++ example/ivect_conversions.cpp | 51 +++++++++++++ example/ivect_defs.cpp | 13 ++++ example/test_cross_module.py | 139 ++++++++++++++++++++++++++++++++++ example/tst_dvect1.py | 20 +++++ example/tst_dvect2.py | 98 ++++++++++++++++++++++++ example/tst_ivect1.py | 20 +++++ example/tst_ivect2.py | 98 ++++++++++++++++++++++++ example/tst_noncopyable.py | 16 ++++ 9 files changed, 487 insertions(+) create mode 100644 example/ivect.h create mode 100644 example/ivect_conversions.cpp create mode 100644 example/ivect_defs.cpp create mode 100644 example/test_cross_module.py create mode 100644 example/tst_dvect1.py create mode 100644 example/tst_dvect2.py create mode 100644 example/tst_ivect1.py create mode 100644 example/tst_ivect2.py create mode 100644 example/tst_noncopyable.py diff --git a/example/ivect.h b/example/ivect.h new file mode 100644 index 00000000..a0187307 --- /dev/null +++ b/example/ivect.h @@ -0,0 +1,32 @@ +#ifndef IVECT_H +#define IVECT_H + +#include +#include + +namespace vects { + + struct ivect : public std::vector + { + ivect() : std::vector() {} + ivect(size_t n) : std::vector(n) {} + ivect(boost::python::tuple tuple) : std::vector(tuple.size()) + { + std::vector::iterator v_it = begin(); + for (int i = 0; i < tuple.size(); i++) + v_it[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), + boost::python::type()); + } + + boost::python::tuple as_tuple() const + { + boost::python::tuple t(size()); + for (int i = 0; i < size(); i++) + t.set_item(i, + boost::python::ref(BOOST_PYTHON_CONVERSION::to_python((*this)[i]))); + return t; + } + }; +} + +#endif // IVECT_H diff --git a/example/ivect_conversions.cpp b/example/ivect_conversions.cpp new file mode 100644 index 00000000..4f59573d --- /dev/null +++ b/example/ivect_conversions.cpp @@ -0,0 +1,51 @@ + // basics first: const reference converters + boost::python::tuple const_ivect_reference_as_tuple(const vects::ivect& iv) + { + return iv.as_tuple(); + } + + // to_python smart pointer conversions + std::auto_ptr ivect_as_auto_ptr(const vects::ivect& iv) + { + return std::auto_ptr(new vects::ivect(iv)); + } + boost::shared_ptr ivect_as_shared_ptr(const vects::ivect& iv) + { + return boost::shared_ptr(new vects::ivect(iv)); + } + + // smart pointers passed by value + boost::python::ref auto_ptr_value_ivect_as_tuple(std::auto_ptr iv) + { + if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return iv->as_tuple().reference(); + } + boost::python::ref shared_ptr_value_ivect_as_tuple(boost::shared_ptr iv) + { + if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return iv->as_tuple().reference(); + } + + // smart pointers passed by reference + boost::python::ref auto_ptr_reference_ivect_as_tuple(std::auto_ptr& iv) + { + if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return iv->as_tuple().reference(); + } + boost::python::ref shared_ptr_reference_ivect_as_tuple(boost::shared_ptr& iv) + { + if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return iv->as_tuple().reference(); + } + + // smart pointers passed by const reference + boost::python::ref auto_ptr_const_reference_ivect_as_tuple(const std::auto_ptr& iv) + { + if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return iv->as_tuple().reference(); + } + boost::python::ref shared_ptr_const_reference_ivect_as_tuple(const boost::shared_ptr& iv) + { + if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count); + return iv->as_tuple().reference(); + } diff --git a/example/ivect_defs.cpp b/example/ivect_defs.cpp new file mode 100644 index 00000000..811c243d --- /dev/null +++ b/example/ivect_defs.cpp @@ -0,0 +1,13 @@ + this_module.def(ivect_as_auto_ptr, "ivect_as_auto_ptr"); + this_module.def(ivect_as_shared_ptr, "ivect_as_shared_ptr"); + + this_module.def(const_ivect_reference_as_tuple, "const_ivect_reference_as_tuple"); + + this_module.def(auto_ptr_value_ivect_as_tuple, "auto_ptr_value_ivect_as_tuple"); + this_module.def(shared_ptr_value_ivect_as_tuple, "shared_ptr_value_ivect_as_tuple"); + + this_module.def(auto_ptr_reference_ivect_as_tuple, "auto_ptr_reference_ivect_as_tuple"); + this_module.def(shared_ptr_reference_ivect_as_tuple, "shared_ptr_reference_ivect_as_tuple"); + + this_module.def(auto_ptr_const_reference_ivect_as_tuple, "auto_ptr_const_reference_ivect_as_tuple"); + this_module.def(shared_ptr_const_reference_ivect_as_tuple, "shared_ptr_const_reference_ivect_as_tuple"); diff --git a/example/test_cross_module.py b/example/test_cross_module.py new file mode 100644 index 00000000..81057f23 --- /dev/null +++ b/example/test_cross_module.py @@ -0,0 +1,139 @@ +r'''>>> import tst_noncopyable + >>> tst_noncopyable.f() + 1 + 2 + 3 + >>> import tst_dvect1 + >>> tst_dvect1.f() + (1.0, 2.0, 3.0, 4.0, 5.0) + (1, 2, 3, 4, 5) + (1, 2, 3, 4, 5) + (1, 2, 3, 4, 5) + (1, 2, 3, 4, 5) + (1, 2, 3, 4, 5) + (1, 2, 3, 4, 5) + >>> import tst_ivect1 + >>> tst_ivect1.f() + (1, 2, 3, 4, 5) + (1.0, 2.0, 3.0, 4.0, 5.0) + (1.0, 2.0, 3.0, 4.0, 5.0) + (1.0, 2.0, 3.0, 4.0, 5.0) + (1.0, 2.0, 3.0, 4.0, 5.0) + (1.0, 2.0, 3.0, 4.0, 5.0) + (1.0, 2.0, 3.0, 4.0, 5.0) + >>> import sys + >>> if ("--broken-auto-ptr" in sys.argv): + ... broken_auto_ptr = 1 + ... else: + ... broken_auto_ptr = 0 + >>> import tst_dvect2 + >>> tst_dvect2.f(broken_auto_ptr) + 1. auto_ptr_value_ivect_as_tuple + (1, 2, 3, 4, 5) + 2. auto_ptr_value_ivect_as_tuple + None + 1. auto_ptr_value_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 2. auto_ptr_value_dvect_as_tuple + None + 1. shared_ptr_value_ivect_as_tuple + (1, 2, 3, 4, 5) + 2. shared_ptr_value_ivect_as_tuple + (1, 2, 3, 4, 5) + 1. shared_ptr_value_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 2. shared_ptr_value_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 1. auto_ptr_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 2. auto_ptr_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 1. auto_ptr_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 2. auto_ptr_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 1. shared_ptr_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 2. shared_ptr_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 1. shared_ptr_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 2. shared_ptr_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 1. auto_ptr_const_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 2. auto_ptr_const_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 1. auto_ptr_const_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 2. auto_ptr_const_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 1. shared_ptr_const_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 2. shared_ptr_const_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 1. shared_ptr_const_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 2. shared_ptr_const_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + >>> import tst_ivect2 + >>> tst_ivect2.f(broken_auto_ptr) + 1. auto_ptr_value_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 2. auto_ptr_value_dvect_as_tuple + None + 1. auto_ptr_value_ivect_as_tuple + (1, 2, 3, 4, 5) + 2. auto_ptr_value_ivect_as_tuple + None + 1. shared_ptr_value_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 2. shared_ptr_value_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 1. shared_ptr_value_ivect_as_tuple + (1, 2, 3, 4, 5) + 2. shared_ptr_value_ivect_as_tuple + (1, 2, 3, 4, 5) + 1. auto_ptr_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 2. auto_ptr_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 1. auto_ptr_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 2. auto_ptr_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 1. shared_ptr_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 2. shared_ptr_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 1. shared_ptr_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 2. shared_ptr_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 1. auto_ptr_const_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 2. auto_ptr_const_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 1. auto_ptr_const_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 2. auto_ptr_const_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 1. shared_ptr_const_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 2. shared_ptr_const_reference_dvect_as_tuple + (1.0, 2.0, 3.0, 4.0, 5.0) + 1. shared_ptr_const_reference_ivect_as_tuple + (1, 2, 3, 4, 5) + 2. shared_ptr_const_reference_ivect_as_tuple + (1, 2, 3, 4, 5) +''' + +def run(args = None): + if args is not None: + import sys + sys.argv = args + import doctest, test_cross_module + doctest.testmod(test_cross_module) + +if __name__ == '__main__': + run() diff --git a/example/tst_dvect1.py b/example/tst_dvect1.py new file mode 100644 index 00000000..22315528 --- /dev/null +++ b/example/tst_dvect1.py @@ -0,0 +1,20 @@ +def f(): + import dvect + dv = dvect.dvect((1,2,3,4,5)) + print dv.as_tuple() + iv = dv.as_ivect() + print iv.as_tuple() + print dvect.const_ivect_reference_as_tuple(iv) + aiv = dvect.ivect_as_auto_ptr(iv) + print dvect.const_ivect_reference_as_tuple(aiv) + siv = dvect.ivect_as_shared_ptr(iv) + print dvect.const_ivect_reference_as_tuple(siv) + print aiv.as_tuple() + print siv.as_tuple() + +if (__name__ == "__main__"): + import sys, string + n = 1 + if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) + for i in xrange(n): + f() diff --git a/example/tst_dvect2.py b/example/tst_dvect2.py new file mode 100644 index 00000000..539e0b88 --- /dev/null +++ b/example/tst_dvect2.py @@ -0,0 +1,98 @@ +def f(broken_auto_ptr): + import dvect + import ivect + # + dv = dvect.dvect((1,2,3,4,5)) + iv = dv.as_ivect() + # + aiv = dvect.ivect_as_auto_ptr(iv) + print '1. auto_ptr_value_ivect_as_tuple' + print ivect.auto_ptr_value_ivect_as_tuple(aiv) + print '2. auto_ptr_value_ivect_as_tuple' + if (not broken_auto_ptr): + print ivect.auto_ptr_value_ivect_as_tuple(aiv) + else: + print None + # + adv = dvect.dvect_as_auto_ptr(dv) + print '1. auto_ptr_value_dvect_as_tuple' + print ivect.auto_ptr_value_dvect_as_tuple(adv) + print '2. auto_ptr_value_dvect_as_tuple' + if (not broken_auto_ptr): + print ivect.auto_ptr_value_dvect_as_tuple(adv) + else: + print None + # + siv = dvect.ivect_as_shared_ptr(iv) + print '1. shared_ptr_value_ivect_as_tuple' + print ivect.shared_ptr_value_ivect_as_tuple(siv) + print '2. shared_ptr_value_ivect_as_tuple' + print ivect.shared_ptr_value_ivect_as_tuple(siv) + # + sdv = dvect.dvect_as_shared_ptr(dv) + print '1. shared_ptr_value_dvect_as_tuple' + print ivect.shared_ptr_value_dvect_as_tuple(sdv) + print '2. shared_ptr_value_dvect_as_tuple' + print ivect.shared_ptr_value_dvect_as_tuple(sdv) + # + aiv = dvect.ivect_as_auto_ptr(iv) + print '1. auto_ptr_reference_ivect_as_tuple' + print ivect.auto_ptr_reference_ivect_as_tuple(aiv) + print '2. auto_ptr_reference_ivect_as_tuple' + print ivect.auto_ptr_reference_ivect_as_tuple(aiv) + # + adv = dvect.dvect_as_auto_ptr(dv) + print '1. auto_ptr_reference_dvect_as_tuple' + print ivect.auto_ptr_reference_dvect_as_tuple(adv) + print '2. auto_ptr_reference_dvect_as_tuple' + print ivect.auto_ptr_reference_dvect_as_tuple(adv) + # + siv = dvect.ivect_as_shared_ptr(iv) + print '1. shared_ptr_reference_ivect_as_tuple' + print ivect.shared_ptr_reference_ivect_as_tuple(siv) + print '2. shared_ptr_reference_ivect_as_tuple' + print ivect.shared_ptr_reference_ivect_as_tuple(siv) + # + sdv = dvect.dvect_as_shared_ptr(dv) + print '1. shared_ptr_reference_dvect_as_tuple' + print ivect.shared_ptr_reference_dvect_as_tuple(sdv) + print '2. shared_ptr_reference_dvect_as_tuple' + print ivect.shared_ptr_reference_dvect_as_tuple(sdv) + # + aiv = dvect.ivect_as_auto_ptr(iv) + print '1. auto_ptr_const_reference_ivect_as_tuple' + print ivect.auto_ptr_const_reference_ivect_as_tuple(aiv) + print '2. auto_ptr_const_reference_ivect_as_tuple' + print ivect.auto_ptr_const_reference_ivect_as_tuple(aiv) + # + adv = dvect.dvect_as_auto_ptr(dv) + print '1. auto_ptr_const_reference_dvect_as_tuple' + print ivect.auto_ptr_const_reference_dvect_as_tuple(adv) + print '2. auto_ptr_const_reference_dvect_as_tuple' + print ivect.auto_ptr_const_reference_dvect_as_tuple(adv) + # + siv = dvect.ivect_as_shared_ptr(iv) + print '1. shared_ptr_const_reference_ivect_as_tuple' + print ivect.shared_ptr_const_reference_ivect_as_tuple(siv) + print '2. shared_ptr_const_reference_ivect_as_tuple' + print ivect.shared_ptr_const_reference_ivect_as_tuple(siv) + # + sdv = dvect.dvect_as_shared_ptr(dv) + print '1. shared_ptr_const_reference_dvect_as_tuple' + print ivect.shared_ptr_const_reference_dvect_as_tuple(sdv) + print '2. shared_ptr_const_reference_dvect_as_tuple' + print ivect.shared_ptr_const_reference_dvect_as_tuple(sdv) + +if (__name__ == "__main__"): + import sys, string + broken_auto_ptr = 0 + n = 1 + if (len(sys.argv) > 1): + if (sys.argv[1] == "--broken-auto-ptr"): + broken_auto_ptr = 1 + if (len(sys.argv) > 2): + n = string.atoi(sys.argv[2]) + else: + n = string.atoi(sys.argv[1]) + for i in xrange(n): + f(broken_auto_ptr) diff --git a/example/tst_ivect1.py b/example/tst_ivect1.py new file mode 100644 index 00000000..7369fdbf --- /dev/null +++ b/example/tst_ivect1.py @@ -0,0 +1,20 @@ +def f(): + import ivect + iv = ivect.ivect((1,2,3,4,5)) + print iv.as_tuple() + dv = iv.as_dvect() + print dv.as_tuple() + print ivect.const_dvect_reference_as_tuple(dv) + adv = ivect.dvect_as_auto_ptr(dv) + print ivect.const_dvect_reference_as_tuple(adv) + sdv = ivect.dvect_as_shared_ptr(dv) + print ivect.const_dvect_reference_as_tuple(sdv) + print adv.as_tuple() + print sdv.as_tuple() + +if (__name__ == "__main__"): + import sys, string + n = 1 + if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) + for i in xrange(n): + f() diff --git a/example/tst_ivect2.py b/example/tst_ivect2.py new file mode 100644 index 00000000..6ffd2826 --- /dev/null +++ b/example/tst_ivect2.py @@ -0,0 +1,98 @@ +def f(broken_auto_ptr): + import ivect + import dvect + # + iv = ivect.ivect((1,2,3,4,5)) + dv = iv.as_dvect() + # + adv = ivect.dvect_as_auto_ptr(dv) + print '1. auto_ptr_value_dvect_as_tuple' + print dvect.auto_ptr_value_dvect_as_tuple(adv) + print '2. auto_ptr_value_dvect_as_tuple' + if (not broken_auto_ptr): + print dvect.auto_ptr_value_dvect_as_tuple(adv) + else: + print None + # + aiv = ivect.ivect_as_auto_ptr(iv) + print '1. auto_ptr_value_ivect_as_tuple' + print dvect.auto_ptr_value_ivect_as_tuple(aiv) + print '2. auto_ptr_value_ivect_as_tuple' + if (not broken_auto_ptr): + print dvect.auto_ptr_value_ivect_as_tuple(aiv) + else: + print None + # + sdv = ivect.dvect_as_shared_ptr(dv) + print '1. shared_ptr_value_dvect_as_tuple' + print dvect.shared_ptr_value_dvect_as_tuple(sdv) + print '2. shared_ptr_value_dvect_as_tuple' + print dvect.shared_ptr_value_dvect_as_tuple(sdv) + # + siv = ivect.ivect_as_shared_ptr(iv) + print '1. shared_ptr_value_ivect_as_tuple' + print dvect.shared_ptr_value_ivect_as_tuple(siv) + print '2. shared_ptr_value_ivect_as_tuple' + print dvect.shared_ptr_value_ivect_as_tuple(siv) + # + adv = ivect.dvect_as_auto_ptr(dv) + print '1. auto_ptr_reference_dvect_as_tuple' + print dvect.auto_ptr_reference_dvect_as_tuple(adv) + print '2. auto_ptr_reference_dvect_as_tuple' + print dvect.auto_ptr_reference_dvect_as_tuple(adv) + # + aiv = ivect.ivect_as_auto_ptr(iv) + print '1. auto_ptr_reference_ivect_as_tuple' + print dvect.auto_ptr_reference_ivect_as_tuple(aiv) + print '2. auto_ptr_reference_ivect_as_tuple' + print dvect.auto_ptr_reference_ivect_as_tuple(aiv) + # + sdv = ivect.dvect_as_shared_ptr(dv) + print '1. shared_ptr_reference_dvect_as_tuple' + print dvect.shared_ptr_reference_dvect_as_tuple(sdv) + print '2. shared_ptr_reference_dvect_as_tuple' + print dvect.shared_ptr_reference_dvect_as_tuple(sdv) + # + siv = ivect.ivect_as_shared_ptr(iv) + print '1. shared_ptr_reference_ivect_as_tuple' + print dvect.shared_ptr_reference_ivect_as_tuple(siv) + print '2. shared_ptr_reference_ivect_as_tuple' + print dvect.shared_ptr_reference_ivect_as_tuple(siv) + # + adv = ivect.dvect_as_auto_ptr(dv) + print '1. auto_ptr_const_reference_dvect_as_tuple' + print dvect.auto_ptr_const_reference_dvect_as_tuple(adv) + print '2. auto_ptr_const_reference_dvect_as_tuple' + print dvect.auto_ptr_const_reference_dvect_as_tuple(adv) + # + aiv = ivect.ivect_as_auto_ptr(iv) + print '1. auto_ptr_const_reference_ivect_as_tuple' + print dvect.auto_ptr_const_reference_ivect_as_tuple(aiv) + print '2. auto_ptr_const_reference_ivect_as_tuple' + print dvect.auto_ptr_const_reference_ivect_as_tuple(aiv) + # + sdv = ivect.dvect_as_shared_ptr(dv) + print '1. shared_ptr_const_reference_dvect_as_tuple' + print dvect.shared_ptr_const_reference_dvect_as_tuple(sdv) + print '2. shared_ptr_const_reference_dvect_as_tuple' + print dvect.shared_ptr_const_reference_dvect_as_tuple(sdv) + # + siv = ivect.ivect_as_shared_ptr(iv) + print '1. shared_ptr_const_reference_ivect_as_tuple' + print dvect.shared_ptr_const_reference_ivect_as_tuple(siv) + print '2. shared_ptr_const_reference_ivect_as_tuple' + print dvect.shared_ptr_const_reference_ivect_as_tuple(siv) + +if (__name__ == "__main__"): + import sys, string + broken_auto_ptr = 0 + n = 1 + if (len(sys.argv) > 1): + if (sys.argv[1] == "--broken-auto-ptr"): + broken_auto_ptr = 1 + if (len(sys.argv) > 2): + n = string.atoi(sys.argv[2]) + else: + n = string.atoi(sys.argv[1]) + for i in xrange(n): + f(broken_auto_ptr) diff --git a/example/tst_noncopyable.py b/example/tst_noncopyable.py new file mode 100644 index 00000000..155910a5 --- /dev/null +++ b/example/tst_noncopyable.py @@ -0,0 +1,16 @@ +def f(): + import noncopyable_export + import noncopyable_import + s1 = noncopyable_export.store(1) + print s1.recall() + s2 = noncopyable_export.store(2) + print s2.recall() + s3 = noncopyable_import.add_stores(s1, s2) + print s3.recall() + +if (__name__ == "__main__"): + import sys, string + n = 1 + if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) + for i in xrange(n): + f() From b5a86a904507dff5777e8aa49b471808a11a5988 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 19:38:20 +0000 Subject: [PATCH 119/154] cross_module mods [SVN r9819] --- build/como.mak | 11 +++++++---- build/gcc.mak | 36 +++++++++++++++++++++++++----------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/build/como.mak b/build/como.mak index 581eefea..8f05e309 100644 --- a/build/como.mak +++ b/build/como.mak @@ -1,10 +1,12 @@ # Revision History: +# 17 Apr 01 include cross-module support, compile getting_started1 (R.W. Grosse-Kunstleve) UNTESTED! # 06 Mar 01 Fixed typo in use of "PYTHON_LIB" (Dave Abrahams) # 04 Mar 01 Changed library name to libboost_python.a (David Abrahams) LIBSRC = \ classes.cpp \ conversions.cpp \ + cross_module.cpp \ extension_class.cpp \ functions.cpp \ init_function.cpp \ @@ -34,11 +36,12 @@ endif | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \ [ -s $@ ] || rm -f $@ -example1: example1.o libboost_python.a - como-dyn-link -o ../example/hellomodule.$(MODULE_EXTENSION) $(PYTHON_LIB) example1.o -L. -lboost_python - python ../example/test_example1.py +getting_started1: getting_started1.o libboost_python.a + como-dyn-link -o ../example/getting_started1.$(MODULE_EXTENSION) $(PYTHON_LIB) getting_started1.o -L. -lboost_python + ln -s ../test/doctest.py ../example + python ../example/test_getting_started1.py -example1.o: ../example/example1.cpp +getting_started1.o: ../example/getting_started1.cpp como --pic $(INC) -o $*.o -c $< clean: diff --git a/build/gcc.mak b/build/gcc.mak index f71185e0..ce718f2b 100644 --- a/build/gcc.mak +++ b/build/gcc.mak @@ -1,5 +1,7 @@ # Revision History +# 17 Apr 01 include cross-module support, compile getting_started1 (R.W. Grosse-Kunstleve) +# 17 Apr 01 build shared library (patch provided by Dan Nuffer) # 04 Mar 01 Changed library name to libboost_python.a, various cleanups, # attempted Cygwin compatibility. Still needs testing on Linux # (David Abrahams) @@ -8,6 +10,7 @@ LIBSRC = \ classes.cpp \ conversions.cpp \ + cross_module.cpp \ extension_class.cpp \ functions.cpp \ init_function.cpp \ @@ -18,7 +21,7 @@ LIBSRC = \ LIBOBJ = $(LIBSRC:.cpp=.o) OBJ = $(LIBOBJ) -PYTHON_INC=$(ROOT)/usr/local/include/python2.0 +LIBNAME = libboost_python # libpython2.0.dll ifeq "$(OS)" "Windows_NT" @@ -26,13 +29,18 @@ ROOT=c:/cygnus INC = -Ic:/cygnus/usr/include/g++-3 -Ic:/cygnus/usr/include -Ic:/boost -I$(PYTHON_INC) MODULE_EXTENSION=dll PYTHON_LIB=c:/cygnus/usr/local/lib/python2.0/config/libpython2.0.dll.a +SHARED_LIB = $(LIBNAME).dll else -INC = -I$(PYTHON_INC) +PYTHON_INC=$(ROOT)/usr/local/Python-2.0/include/python2.0 +BOOST_INC=../../.. +INC = -I$(BOOST_INC) -I$(PYTHON_INC) MODULE_EXTENSION=so +VERSION=1 +SHARED_LIB = $(LIBNAME).so.$(VERSION) endif %.o: ../src/%.cpp - g++ -fPIC -Wall -W $(INC) -o $*.o -c $< + g++ -fPIC -Wall -W $(INC) $(CXXFLAGS) -o $*.o -c $< %.d: ../src/%.cpp @echo creating $@ @@ -43,7 +51,9 @@ endif PYTHON = python -test: comprehensive.o libboost_python.a +all: test $(SHARED_LIB) getting_started1 + +test: comprehensive.o $(LIBNAME).a $(SHARED_LIB) g++ $(CXXFLAGS) -shared -o ../test/boost_python_test.$(MODULE_EXTENSION) comprehensive.o -L. -lboost_python $(PYTHON_LIB) $(PYTHON) ../test/comprehensive.py @@ -51,20 +61,24 @@ comprehensive.o: ../test/comprehensive.cpp g++ $(CXXFLAGS) --template-depth-32 -fPIC -Wall -W $(INC) -o $*.o -c $< -example1: example1.o libboost_python.a - g++ $(CXXFLAGS) -shared -o ../example/hellomodule.$(MODULE_EXTENSION) example1.o -L. -lboost_python $(PYTHON_LIB) - $(PYTHON) ../example/test_example1.py +getting_started1: getting_started1.o $(LIBNAME).a + g++ $(CXXFLAGS) -shared -o ../example/getting_started1.$(MODULE_EXTENSION) getting_started1.o -L. -lboost_python $(PYTHON_LIB) + ln -s ../test/doctest.py ../example + $(PYTHON) ../example/test_getting_started1.py -example1.o: ../example/example1.cpp +getting_started1.o: ../example/getting_started1.cpp g++ $(CXXFLAGS) --template-depth-32 -fPIC -Wall -W $(INC) -o $*.o -c $< clean: rm -rf *.o *.$(MODULE_EXTENSION) *.a *.d *.pyc *.bak a.out -libboost_python.a: $(LIBOBJ) - rm -f libboost_python.a - ar cq libboost_python.a $(LIBOBJ) +$(LIBNAME).a: $(LIBOBJ) + rm -f $@ + ar cqs $@ $(LIBOBJ) + +$(SHARED_LIB): $(LIBOBJ) + g++ $(CXXFLAGS) -shared -o $@ -Wl,--soname=$(LIBNAME).$(MODULE_EXTENSION) DEP = $(OBJ:.o=.d) From 0c954dde270cb59e7a6093aee5ce36eb8fd7de55 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 19:42:35 +0000 Subject: [PATCH 120/154] moved from branch ralf_grosse_kunstleve to trunk [SVN r9820] --- build/filemgr.py | 135 ++++++++++++++++++++++++ build/irix_CC.mak | 165 ++++++++++++++++++++++++++++++ build/linux_gcc.mak | 191 +++++++++++++++++----------------- build/mingw32.mak | 242 +++++++++++++++++++++----------------------- build/tru64_cxx.mak | 186 ++++++++++++++++++---------------- build/vc60.mak | 133 ++++++++++++++++++++++++ 6 files changed, 740 insertions(+), 312 deletions(-) create mode 100644 build/filemgr.py create mode 100644 build/irix_CC.mak create mode 100644 build/vc60.mak diff --git a/build/filemgr.py b/build/filemgr.py new file mode 100644 index 00000000..fa674f18 --- /dev/null +++ b/build/filemgr.py @@ -0,0 +1,135 @@ +# Revision history: +# 12 Apr 01 use os.path, shutil +# Initial version: R.W. Grosse-Kunstleve + +bpl_src = "/libs/python/src" +bpl_tst = "/libs/python/test" +bpl_exa = "/libs/python/example" +files = ( +bpl_src + "/classes.cpp", +bpl_src + "/conversions.cpp", +bpl_src + "/extension_class.cpp", +bpl_src + "/functions.cpp", +bpl_src + "/init_function.cpp", +bpl_src + "/module_builder.cpp", +bpl_src + "/objects.cpp", +bpl_src + "/types.cpp", +bpl_src + "/cross_module.cpp", +bpl_tst + "/comprehensive.cpp", +bpl_tst + "/comprehensive.hpp", +bpl_tst + "/comprehensive.py", +bpl_tst + "/doctest.py", +bpl_exa + "/abstract.cpp", +bpl_exa + "/getting_started1.cpp", +bpl_exa + "/getting_started2.cpp", +bpl_exa + "/getting_started3.cpp", +bpl_exa + "/simple_vector.cpp", +bpl_exa + "/do_it_yourself_converters.cpp", +bpl_exa + "/pickle1.cpp", +bpl_exa + "/pickle2.cpp", +bpl_exa + "/pickle3.cpp", +bpl_exa + "/test_abstract.py", +bpl_exa + "/test_getting_started1.py", +bpl_exa + "/test_getting_started2.py", +bpl_exa + "/test_getting_started3.py", +bpl_exa + "/test_simple_vector.py", +bpl_exa + "/test_do_it_yourself_converters.py", +bpl_exa + "/test_pickle1.py", +bpl_exa + "/test_pickle2.py", +bpl_exa + "/test_pickle3.py", +bpl_exa + "/noncopyable.h", +bpl_exa + "/noncopyable_export.cpp", +bpl_exa + "/noncopyable_import.cpp", +bpl_exa + "/dvect.h", +bpl_exa + "/dvect.cpp", +bpl_exa + "/dvect_conversions.cpp", +bpl_exa + "/dvect_defs.cpp", +bpl_exa + "/ivect.h", +bpl_exa + "/ivect.cpp", +bpl_exa + "/ivect_conversions.cpp", +bpl_exa + "/ivect_defs.cpp", +bpl_exa + "/tst_noncopyable.py", +bpl_exa + "/tst_dvect1.py", +bpl_exa + "/tst_dvect2.py", +bpl_exa + "/tst_ivect1.py", +bpl_exa + "/tst_ivect2.py", +bpl_exa + "/test_cross_module.py", +) + +defs = ( +"boost_python_test", +"abstract", +"getting_started1", +"getting_started2", +"getting_started3", +"simple_vector", +"do_it_yourself_converters", +"pickle1", +"pickle2", +"pickle3", +"noncopyable_export", +"noncopyable_import", +"ivect", +"dvect", +) + +if (__name__ == "__main__"): + + import sys, os, shutil + + path = sys.argv[1] + mode = sys.argv[2] + if (not mode in ("softlinks", "unlink", "cp", "rm", "copy", "del")): + raise RuntimeError, \ + "usage: python filemgr.py path " + + if (mode in ("cp", "copy")): + for fn in files: + f = os.path.basename(fn) + print "Copying: " + f + shutil.copy(path + fn, ".") + + elif (mode == "softlinks"): + for fn in files: + f = os.path.basename(fn) + if (os.path.exists(f)): + print "File exists: " + f + else: + print "Linking: " + f + os.symlink(path + fn, f) + + elif (mode in ("rm", "del")): + for fn in files: + f = os.path.basename(fn) + if (os.path.exists(f)): + print "Removing: " + f + try: os.unlink(f) + except: pass + + elif (mode == "unlink"): + for fn in files: + f = os.path.basename(fn) + if (os.path.exists(f)): + if (os.path.islink(f)): + print "Unlinking: " + f + try: os.unlink(f) + except: pass + else: + print "Not a softlink: " + f + + if (mode in ("softlinks", "cp", "copy")): + for d in defs: + fn = d + ".def" + print "Creating: " + fn + f = open(fn, "w") + f.write("EXPORTS\n") + f.write("\tinit" + d + "\n") + f.close() + + if (mode in ("unlink", "rm", "del")): + for d in defs: + fn = d + ".def" + if (os.path.exists(fn)): + print "Removing: " + fn + try: os.unlink(fn) + except: pass diff --git a/build/irix_CC.mak b/build/irix_CC.mak new file mode 100644 index 00000000..88d374d8 --- /dev/null +++ b/build/irix_CC.mak @@ -0,0 +1,165 @@ +# Usage: +# +# Create a new empty directory anywhere (preferably not in the boost tree). +# Copy this Makefile to that new directory and rename it to "Makefile" +# Adjust the pathnames below. +# +# make softlinks Create softlinks to source code and tests +# make Compile all sources +# make test Run doctest tests +# make clean Remove all object files +# make unlink Remove softlinks +# +# Revision history: +# 12 Apr 01 new macro ROOT to simplify configuration (R.W. Grosse-Kunstleve) +# Initial version: R.W. Grosse-Kunstleve + +ROOT=$(HOME) +BOOST=$(ROOT)/boost + +PYEXE=/usr/local/Python-1.5.2/bin/python +PYINC=-I/usr/local/Python-1.5.2/include/python1.5 +#PYEXE=/usr/local/Python-2.0/bin/python +#PYINC=-I/usr/local/Python-2.0/include/python2.0 +STLPORTINC=-I$(BOOST)/boost/compatibility/cpp_c_headers + +STDOPTS= +WARNOPTS=-woff 1001,1234,1682 +OPTOPTS=-g + +CPP=CC -LANG:std -n32 -mips4 +CPPOPTS=$(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \ + $(STDOPTS) $(WARNOPTS) $(OPTOPTS) +MAKEDEP=-M + +LD=CC -LANG:std -n32 -mips4 +LDOPTS=-shared + +OBJ=classes.o conversions.o extension_class.o functions.o \ + init_function.o module_builder.o \ + objects.o types.o cross_module.o +DEPOBJ=$(OBJ) \ + comprehensive.o \ + abstract.o \ + getting_started1.o getting_started2.o getting_started3.o \ + simple_vector.o \ + do_it_yourself_converters.o \ + pickle1.o pickle2.o pickle3.o \ + noncopyable_export.o noncopyable_import.o \ + ivect.o dvect.o + +.SUFFIXES: .o .cpp + +all: libboost_python.a \ + boost_python_test.so \ + abstract.so \ + getting_started1.so getting_started2.so getting_started3.so \ + simple_vector.so \ + do_it_yourself_converters.so \ + pickle1.so pickle2.so pickle3.so \ + noncopyable_export.so noncopyable_import.so \ + ivect.so dvect.so + +libboost_python.a: $(OBJ) + rm -f libboost_python.a + $(CPP) -ar -o libboost_python.a $(OBJ) + +boost_python_test.so: $(OBJ) comprehensive.o + $(LD) $(LDOPTS) $(OBJ) comprehensive.o -o boost_python_test.so -lm + +abstract.so: $(OBJ) abstract.o + $(LD) $(LDOPTS) $(OBJ) abstract.o -o abstract.so + +getting_started1.so: $(OBJ) getting_started1.o + $(LD) $(LDOPTS) $(OBJ) getting_started1.o -o getting_started1.so + +getting_started2.so: $(OBJ) getting_started2.o + $(LD) $(LDOPTS) $(OBJ) getting_started2.o -o getting_started2.so + +getting_started3.so: $(OBJ) getting_started3.o + $(LD) $(LDOPTS) $(OBJ) getting_started3.o -o getting_started3.so + +simple_vector.so: $(OBJ) simple_vector.o + $(LD) $(LDOPTS) $(OBJ) simple_vector.o -o simple_vector.so + +do_it_yourself_converters.so: $(OBJ) do_it_yourself_converters.o + $(LD) $(LDOPTS) $(OBJ) do_it_yourself_converters.o -o do_it_yourself_converters.so + +pickle1.so: $(OBJ) pickle1.o + $(LD) $(LDOPTS) $(OBJ) pickle1.o -o pickle1.so + +pickle2.so: $(OBJ) pickle2.o + $(LD) $(LDOPTS) $(OBJ) pickle2.o -o pickle2.so + +pickle3.so: $(OBJ) pickle3.o + $(LD) $(LDOPTS) $(OBJ) pickle3.o -o pickle3.so + +noncopyable_export.so: $(OBJ) noncopyable_export.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \ + noncopyable_export.o -o noncopyable_export.so + +noncopyable_import.so: $(OBJ) noncopyable_import.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \ + noncopyable_import.o -o noncopyable_import.so + +ivect.so: $(OBJ) ivect.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) ivect.o -o ivect.so + +dvect.so: $(OBJ) dvect.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) dvect.o -o dvect.so + +.cpp.o: + $(CPP) $(CPPOPTS) -c $*.cpp + +test: + $(PYEXE) comprehensive.py + $(PYEXE) test_abstract.py + $(PYEXE) test_getting_started1.py + $(PYEXE) test_getting_started2.py + $(PYEXE) test_getting_started3.py + $(PYEXE) test_simple_vector.py + $(PYEXE) test_do_it_yourself_converters.py + $(PYEXE) test_pickle1.py + $(PYEXE) test_pickle2.py + $(PYEXE) test_pickle3.py + $(PYEXE) test_cross_module.py + +clean: + rm -f $(OBJ) libboost_python.a libboost_python.a.input + rm -f comprehensive.o boost_python_test.so + rm -f abstract.o abstract.so + rm -f getting_started1.o getting_started1.so + rm -f getting_started2.o getting_started2.so + rm -f getting_started3.o getting_started3.so + rm -f simple_vector.o simple_vector.so + rm -f do_it_yourself_converters.o do_it_yourself_converters.so + rm -f pickle1.o pickle1.so + rm -f pickle2.o pickle2.so + rm -f pickle3.o pickle3.so + rm -f noncopyable_export.o noncopyable_export.so + rm -f noncopyable_import.o noncopyable_import.so + rm -f ivect.o ivect.so + rm -f dvect.o dvect.so + rm -f so_locations *.pyc + rm -rf ii_files + +softlinks: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) softlinks + +unlink: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) unlink + +cp: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) cp + +rm: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) rm + +depend: + @ cat Makefile.nodepend; \ + for obj in $(DEPOBJ); \ + do \ + bn=`echo "$$obj" | cut -d. -f1`; \ + $(CPP) $(CPPOPTS) $(MAKEDEP) "$$bn".cpp; \ + done + diff --git a/build/linux_gcc.mak b/build/linux_gcc.mak index a07bb5da..9be8f1cb 100644 --- a/build/linux_gcc.mak +++ b/build/linux_gcc.mak @@ -2,110 +2,64 @@ # # Create a new empty directory anywhere (preferably not in the boost tree). # Copy this Makefile to that new directory and rename it to "Makefile" -# Set the BOOST pathname below. +# Adjust the pathnames below. # # make softlinks Create softlinks to source code and tests # make Compile all sources # make test Run doctest tests # make clean Remove all object files # make unlink Remove softlinks +# +# Revision history: +# 12 Apr 01 new macro ROOT to simplify configuration (R.W. Grosse-Kunstleve) +# Initial version: R.W. Grosse-Kunstleve -BOOST= /net/cci/rwgk/boost +ROOT=$(HOME) +BOOST=$(ROOT)/boost -PYEXE= /usr/local/Python-1.5.2/bin/python -PYINC= -I/usr/local/Python-1.5.2/include/python1.5 -#PYEXE= /usr/local/Python-2.0/bin/python -#PYINC= -I/usr/local/Python-2.0/include/python2.0 -#STLPORTINC= -I/usr/local/STLport-4.1b3/stlport -#STLPORTOPTS= \ -# -D__USE_STD_IOSTREAM \ -# -D__STL_NO_SGI_IOSTREAMS \ -# -D__STL_USE_NATIVE_STRING \ -# -D__STL_NO_NEW_C_HEADERS \ -# -D_RWSTD_COMPILE_INSTANTIATE=1 -#STLPORTINC= -I/usr/local/STLport-4.1b4/stlport -#STLPORTOPTS= -D__NO_USE_STD_IOSTREAM -D__STL_NO_SGI_IOSTREAMS -#STLPORTINC= -I/net/cci/xp/C++_C_headers +PYEXE=/usr/bin/python +PYINC=-I/usr/include/python1.5 +#PYEXE=/usr/local/Python-1.5.2/bin/python +#PYINC=-I/usr/local/Python-1.5.2/include/python1.5 +#PYEXE=/usr/local/Python-2.0/bin/python +#PYINC=-I/usr/local/Python-2.0/include/python2.0 -STDOPTS= -ftemplate-depth-21 +STDOPTS=-ftemplate-depth-21 WARNOPTS= -# use -msg_display_number to obtain integer tags for -msg_disable +OPTOPTS=-g -CPP= g++ -CPPOPTS= $(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \ - $(STDOPTS) $(WARNOPTS) -g -MAKEDEP= -M +CPP=g++ +CPPOPTS=$(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \ + $(STDOPTS) $(WARNOPTS) $(OPTOPTS) +MAKEDEP=-M -LD= g++ -LDOPTS= -shared +LD=g++ +LDOPTS=-shared -#HIDDEN= -hidden - -BPL_SRC = $(BOOST)/libs/python/src -BPL_TST = $(BOOST)/libs/python/test -BPL_EXA = $(BOOST)/libs/python/example -SOFTLINKS = \ -$(BPL_SRC)/classes.cpp \ -$(BPL_SRC)/conversions.cpp \ -$(BPL_SRC)/extension_class.cpp \ -$(BPL_SRC)/functions.cpp \ -$(BPL_SRC)/init_function.cpp \ -$(BPL_SRC)/module_builder.cpp \ -$(BPL_SRC)/objects.cpp \ -$(BPL_SRC)/types.cpp \ -$(BPL_TST)/comprehensive.cpp \ -$(BPL_TST)/comprehensive.hpp \ -$(BPL_TST)/comprehensive.py \ -$(BPL_TST)/doctest.py \ -$(BPL_EXA)/abstract.cpp \ -$(BPL_EXA)/getting_started1.cpp \ -$(BPL_EXA)/getting_started2.cpp \ -$(BPL_EXA)/getting_started3.cpp \ -$(BPL_EXA)/getting_started4.cpp \ -$(BPL_EXA)/getting_started5.cpp \ -$(BPL_EXA)/test_abstract.py \ -$(BPL_EXA)/test_getting_started1.py \ -$(BPL_EXA)/test_getting_started2.py \ -$(BPL_EXA)/test_getting_started3.py \ -$(BPL_EXA)/test_getting_started4.py \ -$(BPL_EXA)/test_getting_started5.py - -OBJ = classes.o conversions.o extension_class.o functions.o \ - init_function.o module_builder.o \ - objects.o types.o -DEPOBJ= $(OBJ) comprehensive.o abstract.o \ - getting_started1.o getting_started2.o getting_started3.o \ - getting_started4.o getting_started5.o +OBJ=classes.o conversions.o extension_class.o functions.o \ + init_function.o module_builder.o \ + objects.o types.o cross_module.o +DEPOBJ=$(OBJ) \ + comprehensive.o \ + abstract.o \ + getting_started1.o getting_started2.o getting_started3.o \ + simple_vector.o \ + do_it_yourself_converters.o \ + pickle1.o pickle2.o pickle3.o \ + noncopyable_export.o noncopyable_import.o \ + ivect.o dvect.o .SUFFIXES: .o .cpp -all: libboost_python.a boost_python_test.so abstract.so \ +all: libboost_python.a \ + boost_python_test.so \ + abstract.so \ getting_started1.so getting_started2.so getting_started3.so \ - getting_started4.so getting_started5.so - -softlinks: - @ for pn in $(SOFTLINKS); \ - do \ - bn=`basename "$$pn"`; \ - if [ ! -e "$$bn" ]; then \ - echo "ln -s $$pn ."; \ - ln -s "$$pn" .; \ - else \ - echo "info: no softlink created (file exists): $$bn"; \ - fi; \ - done - -unlink: - @ for pn in $(SOFTLINKS); \ - do \ - bn=`basename "$$pn"`; \ - if [ -L "$$bn" ]; then \ - echo "rm $$bn"; \ - rm "$$bn"; \ - elif [ -e "$$bn" ]; then \ - echo "info: not a softlink: $$bn"; \ - fi; \ - done + simple_vector.so \ + do_it_yourself_converters.so \ + pickle1.so pickle2.so pickle3.so \ + noncopyable_export.so noncopyable_import.so \ + ivect.so dvect.so libboost_python.a: $(OBJ) rm -f libboost_python.a @@ -126,11 +80,34 @@ getting_started2.so: $(OBJ) getting_started2.o getting_started3.so: $(OBJ) getting_started3.o $(LD) $(LDOPTS) $(OBJ) getting_started3.o -o getting_started3.so -getting_started4.so: $(OBJ) getting_started4.o - $(LD) $(LDOPTS) $(OBJ) getting_started4.o -o getting_started4.so +simple_vector.so: $(OBJ) simple_vector.o + $(LD) $(LDOPTS) $(OBJ) simple_vector.o -o simple_vector.so -getting_started5.so: $(OBJ) getting_started5.o - $(LD) $(LDOPTS) $(OBJ) getting_started5.o -o getting_started5.so +do_it_yourself_converters.so: $(OBJ) do_it_yourself_converters.o + $(LD) $(LDOPTS) $(OBJ) do_it_yourself_converters.o -o do_it_yourself_converters.so + +pickle1.so: $(OBJ) pickle1.o + $(LD) $(LDOPTS) $(OBJ) pickle1.o -o pickle1.so + +pickle2.so: $(OBJ) pickle2.o + $(LD) $(LDOPTS) $(OBJ) pickle2.o -o pickle2.so + +pickle3.so: $(OBJ) pickle3.o + $(LD) $(LDOPTS) $(OBJ) pickle3.o -o pickle3.so + +noncopyable_export.so: $(OBJ) noncopyable_export.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \ + noncopyable_export.o -o noncopyable_export.so + +noncopyable_import.so: $(OBJ) noncopyable_import.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \ + noncopyable_import.o -o noncopyable_import.so + +ivect.so: $(OBJ) ivect.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) ivect.o -o ivect.so + +dvect.so: $(OBJ) dvect.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) dvect.o -o dvect.so .cpp.o: $(CPP) $(CPPOPTS) -c $*.cpp @@ -141,8 +118,12 @@ test: $(PYEXE) test_getting_started1.py $(PYEXE) test_getting_started2.py $(PYEXE) test_getting_started3.py - $(PYEXE) test_getting_started4.py - $(PYEXE) test_getting_started5.py + $(PYEXE) test_simple_vector.py + $(PYEXE) test_do_it_yourself_converters.py + $(PYEXE) test_pickle1.py + $(PYEXE) test_pickle2.py + $(PYEXE) test_pickle3.py + $(PYEXE) test_cross_module.py clean: rm -f $(OBJ) libboost_python.a libboost_python.a.input @@ -151,10 +132,28 @@ clean: rm -f getting_started1.o getting_started1.so rm -f getting_started2.o getting_started2.so rm -f getting_started3.o getting_started3.so - rm -f getting_started4.o getting_started4.so - rm -f getting_started5.o getting_started5.so + rm -f simple_vector.o simple_vector.so + rm -f do_it_yourself_converters.o do_it_yourself_converters.so + rm -f pickle1.o pickle1.so + rm -f pickle2.o pickle2.so + rm -f pickle3.o pickle3.so + rm -f noncopyable_export.o noncopyable_export.so + rm -f noncopyable_import.o noncopyable_import.so + rm -f ivect.o ivect.so + rm -f dvect.o dvect.so rm -f so_locations *.pyc - rm -rf cxx_repository + +softlinks: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) softlinks + +unlink: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) unlink + +cp: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) cp + +rm: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) rm depend: @ cat Makefile.nodepend; \ diff --git a/build/mingw32.mak b/build/mingw32.mak index 014af132..98a26735 100644 --- a/build/mingw32.mak +++ b/build/mingw32.mak @@ -1,18 +1,14 @@ # Usage: # -# Create a new empty directory anywhere (preferably not in the boost tree). -# Copy this Makefile to that new directory and rename it to "Makefile" -# Set the BOOST_* pathnames below. +# make copy Copy the sources and tests +# make Compile all sources +# make test Run doctest tests +# make clean Remove all object files +# make del Remove the sources and tests # -# The idea is that the build directory is on a Unix filesystem that -# is mounted on a PC using SAMBA. Use this makefile under both Unix -# and Windows: -# -# Unix: make softlinks Create softlinks to source code and tests -# Win: make Compile all sources -# Win: make test Run doctest tests -# Unix: make clean Remove all object files -# Unix: make unlink Remove softlinks +# Revision history: +# 12 Apr 01 new macro ROOT to simplify configuration (R.W. Grosse-Kunstleve) +# Initial version: R.W. Grosse-Kunstleve # To install mingw32, follow instructions at: # http://starship.python.net/crew/kernr/mingw32/Notes.html @@ -31,117 +27,49 @@ # Could this be fixed with compiler options? # -fhuge-objects looks interesting, but requires recompiling the C++ library. # (what exactly does that mean?) -# -fvtable-thunks eliminates the compiler warning, -# but "import boost_python_test" still causes a crash. +# -fvtable-thunks eliminates the compiler warning, but +# "import boost_python_test" still causes a crash. -BOOST_UNIX= /net/cci/rwgk/boost -BOOST_WIN= "L:\boost" +ROOT=L: +BOOST_WIN="$(ROOT)\boost" +BOOST_UNIX=$(HOME)/boost -PYEXE= "C:\Program files\Python\python.exe" -PYINC= -I"C:\usr\include\python1.5" -PYLIB= "C:\usr\lib\libpython15.a" +PYEXE="C:\Program files\Python\python.exe" +PYINC=-I"C:\usr\include\python1.5" +PYLIB="C:\usr\lib\libpython15.a" -STDOPTS= -ftemplate-depth-21 +STDOPTS=-ftemplate-depth-21 WARNOPTS= +OPTOPTS=-g -CPP= g++ -CPPOPTS= $(STLPORTINC) $(STLPORTOPTS) -I$(BOOST_WIN) $(PYINC) \ - $(STDOPTS) $(WARNOPTS) -g +CPP=g++ +CPPOPTS=$(STLPORTINC) $(STLPORTOPTS) -I$(BOOST_WIN) $(PYINC) \ + $(STDOPTS) $(WARNOPTS) $(OPTOPTS) -LD= g++ -LDOPTS= -shared +LD=g++ +LDOPTS=-shared -BPL_SRC = $(BOOST_UNIX)/libs/python/src -BPL_TST = $(BOOST_UNIX)/libs/python/test -BPL_EXA = $(BOOST_UNIX)/libs/python/example -SOFTLINKS = \ -$(BPL_SRC)/classes.cpp \ -$(BPL_SRC)/conversions.cpp \ -$(BPL_SRC)/extension_class.cpp \ -$(BPL_SRC)/functions.cpp \ -$(BPL_SRC)/init_function.cpp \ -$(BPL_SRC)/module_builder.cpp \ -$(BPL_SRC)/objects.cpp \ -$(BPL_SRC)/types.cpp \ -$(BPL_TST)/comprehensive.cpp \ -$(BPL_TST)/comprehensive.hpp \ -$(BPL_TST)/comprehensive.py \ -$(BPL_TST)/doctest.py \ -$(BPL_EXA)/abstract.cpp \ -$(BPL_EXA)/getting_started1.cpp \ -$(BPL_EXA)/getting_started2.cpp \ -$(BPL_EXA)/getting_started3.cpp \ -$(BPL_EXA)/getting_started4.cpp \ -$(BPL_EXA)/getting_started5.cpp \ -$(BPL_EXA)/passing_char.cpp \ -$(BPL_EXA)/test_abstract.py \ -$(BPL_EXA)/test_getting_started1.py \ -$(BPL_EXA)/test_getting_started2.py \ -$(BPL_EXA)/test_getting_started3.py \ -$(BPL_EXA)/test_getting_started4.py \ -$(BPL_EXA)/test_getting_started5.py - -DEFS= \ -boost_python_test \ -abstract \ -getting_started1 \ -getting_started2 \ -getting_started3 \ -getting_started4 \ -getting_started5 - -OBJ = classes.o conversions.o extension_class.o functions.o \ - init_function.o module_builder.o \ - objects.o types.o +OBJ=classes.o conversions.o extension_class.o functions.o \ + init_function.o module_builder.o \ + objects.o types.o cross_module.o .SUFFIXES: .o .cpp -all: libboost_python.a boost_python_test.pyd abstract.pyd \ +all: libboost_python.a \ + abstract.pyd \ getting_started1.pyd getting_started2.pyd getting_started3.pyd \ - getting_started4.pyd getting_started5.pyd - -softlinks: defs - @ for pn in $(SOFTLINKS); \ - do \ - bn=`basename "$$pn"`; \ - if [ ! -e "$$bn" ]; then \ - echo "ln -s $$pn ."; \ - ln -s "$$pn" .; \ - else \ - echo "info: no softlink created (file exists): $$bn"; \ - fi; \ - done - -unlink: rmdefs - @ for pn in $(SOFTLINKS); \ - do \ - bn=`basename "$$pn"`; \ - if [ -L "$$bn" ]; then \ - echo "rm $$bn"; \ - rm "$$bn"; \ - elif [ -e "$$bn" ]; then \ - echo "info: not a softlink: $$bn"; \ - fi; \ - done - -defs: - @ for def in $(DEFS); \ - do \ - echo "EXPORTS\n\tinit$$def" > $$def.def; \ - done - -rmdefs: - @ for def in $(DEFS); \ - do \ - rm $$def.def; \ - done + simple_vector.pyd \ + do_it_yourself_converters.pyd \ + pickle1.pyd pickle2.pyd pickle3.pyd \ + noncopyable_export.pyd noncopyable_import.pyd \ + ivect.pyd dvect.pyd libboost_python.a: $(OBJ) del libboost_python.a ar r libboost_python.a $(OBJ) -DLLWRAPOPTS= -s --driver-name g++ -s - --entry _DllMainCRTStartup@12 --target=i386-mingw32 +DLLWRAPOPTS=-s --driver-name g++ -s \ + --entry _DllMainCRTStartup@12 --target=i386-mingw32 boost_python_test.pyd: $(OBJ) comprehensive.o dllwrap $(DLLWRAPOPTS) \ @@ -173,38 +101,96 @@ getting_started3.pyd: $(OBJ) getting_started3.o --def getting_started3.def \ $(OBJ) getting_started3.o $(PYLIB) -getting_started4.pyd: $(OBJ) getting_started4.o +simple_vector.pyd: $(OBJ) simple_vector.o dllwrap $(DLLWRAPOPTS) \ - --dllname getting_started4.pyd \ - --def getting_started4.def \ - $(OBJ) getting_started4.o $(PYLIB) + --dllname simple_vector.pyd \ + --def simple_vector.def \ + $(OBJ) simple_vector.o $(PYLIB) -getting_started5.pyd: $(OBJ) getting_started5.o +do_it_yourself_converters.pyd: $(OBJ) do_it_yourself_converters.o dllwrap $(DLLWRAPOPTS) \ - --dllname getting_started5.pyd \ - --def getting_started5.def \ - $(OBJ) getting_started5.o $(PYLIB) + --dllname do_it_yourself_converters.pyd \ + --def do_it_yourself_converters.def \ + $(OBJ) do_it_yourself_converters.o $(PYLIB) + +pickle1.pyd: $(OBJ) pickle1.o + dllwrap $(DLLWRAPOPTS) \ + --dllname pickle1.pyd \ + --def pickle1.def \ + $(OBJ) pickle1.o $(PYLIB) + +pickle2.pyd: $(OBJ) pickle2.o + dllwrap $(DLLWRAPOPTS) \ + --dllname pickle2.pyd \ + --def pickle2.def \ + $(OBJ) pickle2.o $(PYLIB) + +pickle3.pyd: $(OBJ) pickle3.o + dllwrap $(DLLWRAPOPTS) \ + --dllname pickle3.pyd \ + --def pickle3.def \ + $(OBJ) pickle3.o $(PYLIB) + +noncopyable_export.pyd: $(OBJ) noncopyable_export.o + dllwrap $(DLLWRAPOPTS) \ + --dllname noncopyable_export.pyd \ + --def noncopyable_export.def \ + $(OBJ) noncopyable_export.o $(PYLIB) + +noncopyable_import.pyd: $(OBJ) noncopyable_import.o + dllwrap $(DLLWRAPOPTS) \ + --dllname noncopyable_import.pyd \ + --def noncopyable_import.def \ + $(OBJ) noncopyable_import.o $(PYLIB) + +ivect.pyd: $(OBJ) ivect.o + dllwrap $(DLLWRAPOPTS) \ + --dllname ivect.pyd \ + --def ivect.def \ + $(OBJ) ivect.o $(PYLIB) + +dvect.pyd: $(OBJ) dvect.o + dllwrap $(DLLWRAPOPTS) \ + --dllname dvect.pyd \ + --def dvect.def \ + $(OBJ) dvect.o $(PYLIB) .cpp.o: $(CPP) $(CPPOPTS) -c $*.cpp test: - $(PYEXE) comprehensive.py +# $(PYEXE) comprehensive.py $(PYEXE) test_abstract.py $(PYEXE) test_getting_started1.py $(PYEXE) test_getting_started2.py $(PYEXE) test_getting_started3.py - $(PYEXE) test_getting_started4.py - $(PYEXE) test_getting_started5.py + $(PYEXE) test_simple_vector.py + $(PYEXE) test_do_it_yourself_converters.py + $(PYEXE) test_pickle1.py + $(PYEXE) test_pickle2.py + $(PYEXE) test_pickle3.py + $(PYEXE) test_cross_module.py clean: - rm -f $(OBJ) libboost_python.a libboost_python.a.input - rm -f comprehensive.o boost_python_test.pyd - rm -f abstract.o abstract.pyd - rm -f getting_started1.o getting_started1.pyd - rm -f getting_started2.o getting_started2.pyd - rm -f getting_started3.o getting_started3.pyd - rm -f getting_started4.o getting_started4.pyd - rm -f getting_started5.o getting_started5.pyd - rm -f so_locations *.pyc - rm -rf cxx_repository + del *.o + del *.a + del *.pyd + del *.pyc + +softlinks: + python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) softlinks + +unlink: + python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) unlink + +cp: + python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) cp + +rm: + python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) rm + +copy: + $(PYEXE) $(BOOST_WIN)\libs\python\build\filemgr.py $(BOOST_WIN) copy + +del: + $(PYEXE) $(BOOST_WIN)\libs\python\build\filemgr.py $(BOOST_WIN) del diff --git a/build/tru64_cxx.mak b/build/tru64_cxx.mak index 3fd584b7..41f7a554 100644 --- a/build/tru64_cxx.mak +++ b/build/tru64_cxx.mak @@ -2,110 +2,74 @@ # # Create a new empty directory anywhere (preferably not in the boost tree). # Copy this Makefile to that new directory and rename it to "Makefile" -# Set the BOOST pathname below. +# Adjust the pathnames below. # # make softlinks Create softlinks to source code and tests # make Compile all sources # make test Run doctest tests # make clean Remove all object files # make unlink Remove softlinks +# +# Revision history: +# 12 Apr 01 new macro ROOT to simplify configuration (R.W. Grosse-Kunstleve) +# Initial version: R.W. Grosse-Kunstleve -BOOST= /net/cci/rwgk/boost +ROOT=$(HOME) +BOOST=$(ROOT)/boost -PYEXE= /usr/local/Python-1.5.2/bin/python -PYINC= -I/usr/local/Python-1.5.2/include/python1.5 -#PYEXE= /usr/local/Python-2.0/bin/python -#PYINC= -I/usr/local/Python-2.0/include/python2.0 -#STLPORTINC= -I/usr/local/STLport-4.1b3/stlport +PYEXE=/usr/local/Python-1.5.2/bin/python +PYINC=-I/usr/local/Python-1.5.2/include/python1.5 +#PYEXE=/usr/local/Python-2.0/bin/python +#PYINC=-I/usr/local/Python-2.0/include/python2.0 +#STLPORTINC=-I/usr/local/STLport-4.1b3/stlport +#STLPORTINC=-I/usr/local/STLport-4.1b4/stlport #STLPORTOPTS= \ # -D__USE_STD_IOSTREAM \ # -D__STL_NO_SGI_IOSTREAMS \ # -D__STL_USE_NATIVE_STRING \ # -D__STL_NO_NEW_C_HEADERS \ # -D_RWSTD_COMPILE_INSTANTIATE=1 -#STLPORTINC= -I/usr/local/STLport-4.1b4/stlport -#STLPORTOPTS= -D__NO_USE_STD_IOSTREAM -D__STL_NO_SGI_IOSTREAMS -STLPORTINC= -I/net/cci/xp/C++_C_headers +STLPORTINC=-I$(BOOST)/boost/compatibility/cpp_c_headers -STDOPTS= -std strict_ansi -WARNOPTS= -msg_disable 186,450,1115 +STDOPTS=-std strict_ansi # use -msg_display_number to obtain integer tags for -msg_disable +WARNOPTS=-msg_disable 186,450,1115 +OPTOPTS=-g -CPP= cxx -CPPOPTS= $(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \ - $(STDOPTS) $(WARNOPTS) -g -MAKEDEP= -Em +CPP=cxx +CPPOPTS=$(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \ + $(STDOPTS) $(WARNOPTS) $(OPTOPTS) +MAKEDEP=-Em -LD= cxx -LDOPTS= -shared -expect_unresolved 'Py*' -expect_unresolved '_Py*' +LD=cxx +LDOPTS=-shared -expect_unresolved 'Py*' -expect_unresolved '_Py*' -#HIDDEN= -hidden +#HIDDEN=-hidden -BPL_SRC = $(BOOST)/libs/python/src -BPL_TST = $(BOOST)/libs/python/test -BPL_EXA = $(BOOST)/libs/python/example -SOFTLINKS = \ -$(BPL_SRC)/classes.cpp \ -$(BPL_SRC)/conversions.cpp \ -$(BPL_SRC)/extension_class.cpp \ -$(BPL_SRC)/functions.cpp \ -$(BPL_SRC)/init_function.cpp \ -$(BPL_SRC)/module_builder.cpp \ -$(BPL_SRC)/objects.cpp \ -$(BPL_SRC)/types.cpp \ -$(BPL_TST)/comprehensive.cpp \ -$(BPL_TST)/comprehensive.hpp \ -$(BPL_TST)/comprehensive.py \ -$(BPL_TST)/doctest.py \ -$(BPL_EXA)/abstract.cpp \ -$(BPL_EXA)/getting_started1.cpp \ -$(BPL_EXA)/getting_started2.cpp \ -$(BPL_EXA)/getting_started3.cpp \ -$(BPL_EXA)/getting_started4.cpp \ -$(BPL_EXA)/getting_started5.cpp \ -$(BPL_EXA)/test_abstract.py \ -$(BPL_EXA)/test_getting_started1.py \ -$(BPL_EXA)/test_getting_started2.py \ -$(BPL_EXA)/test_getting_started3.py \ -$(BPL_EXA)/test_getting_started4.py \ -$(BPL_EXA)/test_getting_started5.py - -OBJ = classes.o conversions.o extension_class.o functions.o \ - init_function.o module_builder.o \ - objects.o types.o -DEPOBJ= $(OBJ) comprehensive.o abstract.o \ - getting_started1.o getting_started2.o getting_started3.o \ - getting_started4.o getting_started5.o +OBJ=classes.o conversions.o extension_class.o functions.o \ + init_function.o module_builder.o \ + objects.o types.o cross_module.o +DEPOBJ=$(OBJ) \ + comprehensive.o \ + abstract.o \ + getting_started1.o getting_started2.o getting_started3.o \ + simple_vector.o \ + do_it_yourself_converters.o \ + pickle1.o pickle2.o pickle3.o \ + noncopyable_export.o noncopyable_import.o \ + ivect.o dvect.o .SUFFIXES: .o .cpp -all: libboost_python.a boost_python_test.so abstract.so \ +all: libboost_python.a \ + boost_python_test.so \ + abstract.so \ getting_started1.so getting_started2.so getting_started3.so \ - getting_started4.so getting_started5.so - -softlinks: - @ for pn in $(SOFTLINKS); \ - do \ - bn=`basename "$$pn"`; \ - if [ ! -e "$$bn" ]; then \ - echo "ln -s $$pn ."; \ - ln -s "$$pn" .; \ - else \ - echo "info: no softlink created (file exists): $$bn"; \ - fi; \ - done - -unlink: - @ for pn in $(SOFTLINKS); \ - do \ - bn=`basename "$$pn"`; \ - if [ -L "$$bn" ]; then \ - echo "rm $$bn"; \ - rm "$$bn"; \ - elif [ -e "$$bn" ]; then \ - echo "info: not a softlink: $$bn"; \ - fi; \ - done + simple_vector.so \ + do_it_yourself_converters.so \ + pickle1.so pickle2.so pickle3.so \ + noncopyable_export.so noncopyable_import.so \ + ivect.so dvect.so libboost_python.a: $(OBJ) rm -f libboost_python.a @@ -130,11 +94,34 @@ getting_started2.so: $(OBJ) getting_started2.o getting_started3.so: $(OBJ) getting_started3.o $(LD) $(LDOPTS) $(OBJ) getting_started3.o -o getting_started3.so -getting_started4.so: $(OBJ) getting_started4.o - $(LD) $(LDOPTS) $(OBJ) getting_started4.o -o getting_started4.so +simple_vector.so: $(OBJ) simple_vector.o + $(LD) $(LDOPTS) $(OBJ) simple_vector.o -o simple_vector.so -getting_started5.so: $(OBJ) getting_started5.o - $(LD) $(LDOPTS) $(OBJ) getting_started5.o -o getting_started5.so +do_it_yourself_converters.so: $(OBJ) do_it_yourself_converters.o + $(LD) $(LDOPTS) $(OBJ) do_it_yourself_converters.o -o do_it_yourself_converters.so + +pickle1.so: $(OBJ) pickle1.o + $(LD) $(LDOPTS) $(OBJ) pickle1.o -o pickle1.so + +pickle2.so: $(OBJ) pickle2.o + $(LD) $(LDOPTS) $(OBJ) pickle2.o -o pickle2.so + +pickle3.so: $(OBJ) pickle3.o + $(LD) $(LDOPTS) $(OBJ) pickle3.o -o pickle3.so + +noncopyable_export.so: $(OBJ) noncopyable_export.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \ + noncopyable_export.o -o noncopyable_export.so + +noncopyable_import.so: $(OBJ) noncopyable_import.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) \ + noncopyable_import.o -o noncopyable_import.so + +ivect.so: $(OBJ) ivect.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) ivect.o -o ivect.so + +dvect.so: $(OBJ) dvect.o + $(LD) $(LDOPTS) $(OBJ) $(HIDDEN) dvect.o -o dvect.so .cpp.o: $(CPP) $(CPPOPTS) -c $*.cpp @@ -145,8 +132,12 @@ test: $(PYEXE) test_getting_started1.py $(PYEXE) test_getting_started2.py $(PYEXE) test_getting_started3.py - $(PYEXE) test_getting_started4.py - $(PYEXE) test_getting_started5.py + $(PYEXE) test_simple_vector.py + $(PYEXE) test_do_it_yourself_converters.py + $(PYEXE) test_pickle1.py + $(PYEXE) test_pickle2.py + $(PYEXE) test_pickle3.py + $(PYEXE) test_cross_module.py clean: rm -f $(OBJ) libboost_python.a libboost_python.a.input @@ -155,11 +146,30 @@ clean: rm -f getting_started1.o getting_started1.so rm -f getting_started2.o getting_started2.so rm -f getting_started3.o getting_started3.so - rm -f getting_started4.o getting_started4.so - rm -f getting_started5.o getting_started5.so + rm -f simple_vector.o simple_vector.so + rm -f do_it_yourself_converters.o do_it_yourself_converters.so + rm -f pickle1.o pickle1.so + rm -f pickle2.o pickle2.so + rm -f pickle3.o pickle3.so + rm -f noncopyable_export.o noncopyable_export.so + rm -f noncopyable_import.o noncopyable_import.so + rm -f ivect.o ivect.so + rm -f dvect.o dvect.so rm -f so_locations *.pyc rm -rf cxx_repository +softlinks: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) softlinks + +unlink: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) unlink + +cp: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) cp + +rm: + $(PYEXE) $(BOOST)/libs/python/build/filemgr.py $(BOOST) rm + depend: @ cat Makefile.nodepend; \ for obj in $(DEPOBJ); \ diff --git a/build/vc60.mak b/build/vc60.mak new file mode 100644 index 00000000..64e0b9df --- /dev/null +++ b/build/vc60.mak @@ -0,0 +1,133 @@ +# Usage: +# +# make copy Copy the sources and tests +# make Compile all sources +# make test Run doctest tests +# make clean Remove all object files +# make del Remove the sources and tests +# +# Revision history: +# 12 Apr 01 new macro ROOT to simplify configuration (R.W. Grosse-Kunstleve) +# Initial version: R.W. Grosse-Kunstleve + +ROOT=L: +BOOST_WIN="$(ROOT)\boost" +BOOST_UNIX=$(HOME)/boost + +PYEXE="C:\Program files\Python\python.exe" +PYINC=/I"C:\Program files\Python\include" +PYLIB="C:\Program files\Python\libs\python15.lib" + +STDOPTS=/nologo /MD /GR /GX /Zm200 +WARNOPTS= +OPTOPTS= + +CPP=cl.exe +CPPOPTS=$(STLPORTINC) $(STLPORTOPTS) /I$(BOOST_WIN) $(PYINC) \ + $(STDOPTS) $(WARNOPTS) $(OPTOPTS) + +LD=link.exe +LDOPTS=/nologo /dll /incremental:no + +OBJ=classes.obj conversions.obj extension_class.obj functions.obj \ + init_function.obj module_builder.obj \ + objects.obj types.obj cross_module.obj + +.SUFFIXES: .obj .cpp + +all: boost_python.lib \ + boost_python_test.pyd \ + abstract.pyd \ + getting_started1.pyd getting_started2.pyd getting_started3.pyd \ + simple_vector.pyd \ + do_it_yourself_converters.pyd \ + pickle1.pyd pickle2.pyd pickle3.pyd \ + noncopyable_export.pyd noncopyable_import.pyd \ + ivect.pyd dvect.pyd + +boost_python.lib: $(OBJ) + $(LD) -lib /nologo /out:boost_python.lib $(OBJ) + +boost_python_test.pyd: $(OBJ) comprehensive.obj + $(LD) $(LDOPTS) $(OBJ) comprehensive.obj $(PYLIB) /export:initboost_python_test /out:"boost_python_test.pyd" + +abstract.pyd: $(OBJ) abstract.obj + $(LD) $(LDOPTS) $(OBJ) abstract.obj $(PYLIB) /export:initabstract /out:"abstract.pyd" + +getting_started1.pyd: $(OBJ) getting_started1.obj + $(LD) $(LDOPTS) $(OBJ) getting_started1.obj $(PYLIB) /export:initgetting_started1 /out:"getting_started1.pyd" + +getting_started2.pyd: $(OBJ) getting_started2.obj + $(LD) $(LDOPTS) $(OBJ) getting_started2.obj $(PYLIB) /export:initgetting_started2 /out:"getting_started2.pyd" + +getting_started3.pyd: $(OBJ) getting_started3.obj + $(LD) $(LDOPTS) $(OBJ) getting_started3.obj $(PYLIB) /export:initgetting_started3 /out:"getting_started3.pyd" + +simple_vector.pyd: $(OBJ) simple_vector.obj + $(LD) $(LDOPTS) $(OBJ) simple_vector.obj $(PYLIB) /export:initsimple_vector /out:"simple_vector.pyd" + +do_it_yourself_converters.pyd: $(OBJ) do_it_yourself_converters.obj + $(LD) $(LDOPTS) $(OBJ) do_it_yourself_converters.obj $(PYLIB) /export:initdo_it_yourself_converters /out:"do_it_yourself_converters.pyd" + +pickle1.pyd: $(OBJ) pickle1.obj + $(LD) $(LDOPTS) $(OBJ) pickle1.obj $(PYLIB) /export:initpickle1 /out:"pickle1.pyd" + +pickle2.pyd: $(OBJ) pickle2.obj + $(LD) $(LDOPTS) $(OBJ) pickle2.obj $(PYLIB) /export:initpickle2 /out:"pickle2.pyd" + +pickle3.pyd: $(OBJ) pickle3.obj + $(LD) $(LDOPTS) $(OBJ) pickle3.obj $(PYLIB) /export:initpickle3 /out:"pickle3.pyd" + +noncopyable_export.pyd: $(OBJ) noncopyable_export.obj + $(LD) $(LDOPTS) $(OBJ) noncopyable_export.obj $(PYLIB) /export:initnoncopyable_export /out:"noncopyable_export.pyd" + +noncopyable_import.pyd: $(OBJ) noncopyable_import.obj + $(LD) $(LDOPTS) $(OBJ) noncopyable_import.obj $(PYLIB) /export:initnoncopyable_import /out:"noncopyable_import.pyd" + +ivect.pyd: $(OBJ) ivect.obj + $(LD) $(LDOPTS) $(OBJ) ivect.obj $(PYLIB) /export:initivect /out:"ivect.pyd" + +dvect.pyd: $(OBJ) dvect.obj + $(LD) $(LDOPTS) $(OBJ) dvect.obj $(PYLIB) /export:initdvect /out:"dvect.pyd" + +.cpp.obj: + $(CPP) $(CPPOPTS) /c $*.cpp + +test: + $(PYEXE) comprehensive.py --broken-auto-ptr + $(PYEXE) test_abstract.py + $(PYEXE) test_getting_started1.py + $(PYEXE) test_getting_started2.py + $(PYEXE) test_getting_started3.py + $(PYEXE) test_simple_vector.py + $(PYEXE) test_do_it_yourself_converters.py + $(PYEXE) test_pickle1.py + $(PYEXE) test_pickle2.py + $(PYEXE) test_pickle3.py + $(PYEXE) test_cross_module.py --broken-auto-ptr + +clean: + del *.obj + del *.lib + del *.exp + del *.idb + del *.pyd + del *.pyc + +softlinks: + python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) softlinks + +unlink: + python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) unlink + +cp: + python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) cp + +rm: + python $(BOOST_UNIX)/libs/python/build/filemgr.py $(BOOST_UNIX) rm + +copy: + $(PYEXE) $(BOOST_WIN)\libs\python\build\filemgr.py $(BOOST_WIN) copy + +del: + $(PYEXE) $(BOOST_WIN)\libs\python\build\filemgr.py $(BOOST_WIN) del From fde432601aae5fc1ca29e1ba10b763622af6ab76 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 19:46:15 +0000 Subject: [PATCH 121/154] workaround for irix_CC problem. [SVN r9821] --- test/comprehensive.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/comprehensive.cpp b/test/comprehensive.cpp index 7699b01f..aa2d9886 100644 --- a/test/comprehensive.cpp +++ b/test/comprehensive.cpp @@ -15,6 +15,10 @@ #include // for pow() #include +#if defined(sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 +inline double pow(int x, int y) { return pow(static_cast(x), y); } +#endif + namespace bpl_test { FooCallback::FooCallback(PyObject* self, int x) From fa7b6591cf72da6d1d14d90dcb4b702cf9d325af Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 19:49:42 +0000 Subject: [PATCH 122/154] moved from branch ralf_grosse_kunstleve to trunk (was cross_module_dependencies.html) [SVN r9822] --- doc/cross_module.html | 336 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 doc/cross_module.html diff --git a/doc/cross_module.html b/doc/cross_module.html new file mode 100644 index 00000000..08c39bfe --- /dev/null +++ b/doc/cross_module.html @@ -0,0 +1,336 @@ + + +Cross-extension-module dependencies + +
        + +c++boost.gif (8819 bytes) + +
        +

        Cross-extension-module dependencies

        + +It is good programming practice to organize large projects as modules +that interact with each other via well defined interfaces. With +Boost.Python it is possible to reflect this organization at the C++ +level at the Python level. This is, each logical C++ module can be +organized as a separate Python extension module. + +

        +At first sight this might seem natural and straightforward. However, it +is a fairly complex problem to establish cross-extension-module +dependencies while maintaining the same ease of use Boost.Python +provides for classes that are wrapped in the same extension module. To +a large extent this complexity can be hidden from the author of a +Boost.Python extension module, but not entirely. + +


        +

        The recipe

        + +Suppose there is an extension module that exposes certain instances of +the C++ std::vector template library such that it can be used +from Python in the following manner: + +
        +import std_vector
        +v = std_vector.double([1, 2, 3, 4])
        +v.push_back(5)
        +v.size()
        +
        + +Suppose the std_vector module is done well and reflects all +C++ functions that are useful at the Python level, for all C++ built-in +data types (std_vector.int, std_vector.long, etc.). + +

        +Suppose further that there is statistic module with a C++ class that +has constructors or member functions that use or return a +std::vector. For example: + +

        +class xy {
        +  public:
        +    xy(const std::vector<double>& x, const std::vector<double>& y) : m_x(x), m_y(y) {}
        +    const std::vector<double>& x() const { return m_x; }
        +    const std::vector<double>& y() const { return m_y; }
        +    double correlation();
        +  private:
        +    std::vector<double> m_x;
        +    std::vector<double> m_y;
        +}
        +
        + +What is more natural than reusing the std_vector extension +module to expose these constructors or functions to Python? + +

        +Unfortunately, what seems natural needs a little work in both the +std_vector and the statistics module. + +

        +In the std_vector extension module, +std::vector<double> is exposed to Python in the usual +way with the class_builder<> template. To also enable the +automatic conversion of std::vector<double> function +arguments or return values in other Boost.Python C++ modules, the +converters that convert a std::vector<double> C++ object +to a Python object and vice versa (i.e. the to_python() and +from_python() template functions) have to be exported. For +example: + +

        +  #include <boost/python/cross_module.hpp>
        +  //...
        +  class_builder<std::vector<double> > v_double(std_vector_module, "double");
        +  export_converters(v_double);
        +
        + +In the extension module that wraps class xy we can now import +these converters with the import_converters<> template. +For example: + +
        +  #include <boost/python/cross_module.hpp>
        +  //...
        +  import_converters<std::vector<double> > v_double_converters("std_vector", "double");
        +
        + +That is all. All the attributes that are defined for +std_vector.double in the std_vector Boost.Python +module will be available for the returned objects of xy.x() +and xy.y(). Similarly, the constructor for xy will +accept objects that were created by the std_vectormodule. + +
        +

        Placement of import_converters<> template instantiations

        + +import_converts<> can be viewed as a drop-in replacement +for class_wrapper<>, and the recommendations for the +placement of class_wrapper<> template instantiations +also apply to to import_converts<>. In particular, it is +important that an instantiation of class_wrapper<> is +visible to any code which wraps a C++ function with a T, +T*, const T&, etc. parameter or return value. +Therefore you may want to group all class_wrapper<> and +import_converts<> instantiations at the top of your +module's init function, then def() the member functions later +to avoid problems with inter-class dependencies. + +
        +

        Non-copyable types

        + +export_converters() instantiates C++ template functions that +invoke the copy constructor of the wrapped type. For a type that is +non-copyable this will result in compile-time error messages. In such a +case, export_converters_noncopyable() can be used to export +the converters that do not involve the copy constructor of the wrapped +type. For example: + +
        +class_builder<store> py_store(your_module, "store");
        +export_converters_noncopyable(py_store);
        +
        + +The corresponding import_converters<> statement does not +need any special attention: + +
        +import_converters<store> py_store("noncopyable_export", "store");
        +
        + +
        +

        Python module search path

        + +The std_vector and statistics modules can now be used +in the following way: + +
        +import std_vector
        +import statistics
        +x = std_vector.double([1, 2, 3, 4])
        +y = std_vector.double([2, 4, 6, 8])
        +xy = statistics.xy(x, y)
        +xy.correlation()
        +
        + +In this example it is clear that Python has to be able to find both the +std_vector and the statistics extension module. In +other words, both extension modules need to be in the Python module +search path (sys.path). + +

        +The situation is not always this obvious. Suppose the +statistics module has a random() function that +returns a vector of random numbers with a given length: + +

        +import statistics
        +x = statistics.random(5)
        +y = statistics.random(5)
        +xy = statistics.xy(x, y)
        +xy.correlation()
        +
        + +A naive user will not easily anticipate that the std_vector +module is used to pass the x and y vectors around. If +the std_vector module is in the Python module search path, +this form of ignorance is of no harm. On the contrary, we are glad +that we do not have to bother the user with details like this. + +

        +If the std_vector module is not in the Python module search +path, a Python exception will be raised: + +

        +Traceback (innermost last):
        +  File "foo.py", line 2, in ?
        +    x = statistics.random(5)
        +ImportError: No module named std_vector
        +
        + +As is the case with any system of a non-trivial complexity, it is +important that the setup is consistent and complete. + +
        +

        Two-way module dependencies

        + +Boost.Python supports two-way module dependencies. This is best +illustrated by a simple example. + +

        +Suppose there is a module ivect that implements vectors of +integers, and a similar module dvect that implements vectors +of doubles. We want to be able do convert an integer vector to a double +vector and vice versa. For example: + +

        +import ivect
        +iv = ivect.ivect((1,2,3,4,5))
        +dv = iv.as_dvect()
        +
        + +The last expression will implicitly import the dvect module in +order to enable the conversion of the C++ representation of +dvect to a Python object. The analogous is possible for a +dvect: + +
        +import dvect
        +dv = dvect.dvect((1,2,3,4,5))
        +iv = dv.as_ivect()
        +
        + +Now the ivect module is imported implicitly. + +

        +Note that the two-way dependencies are possible because the +dependencies are resolved only when needed. This is, the initialization +of the ivect module does not rely on the dvect +module, and vice versa. Only if as_dvect() or +as_ivect() is actually invoked will the corresponding module +be implicitly imported. This also means that, for example, the +dvect module does not have to be available at all if +as_dvect() is never used. + +


        +

        Clarification of compile-time and link-time dependencies

        + +Boost.Python's support for resolving cross-module dependencies at +runtime does not imply that compile-time dependencies are eliminated. +For example, the statistics extension module in the example above will +need to #include <vector>. This is immediately obvious +from the definition of class xy. + +

        +If a library is wrapped that consists of both header files and compiled +components (e.g. libdvect.a, dvect.lib, etc.), both +the Boost.Python extension module with the +export_converters() statement and the module with the +import_converters<> statement need to be linked against +the object library. Ideally one would build a shared library (e.g. +libdvect.so, dvect.dll, etc.). However, this +introduces the issue of having to configure the search path for the +dynamic loading correctly. For small libraries it is therefore often +more convenient to ignore the fact that the object files are loaded +into memory more than once. + +


        +

        Summary of motivation for cross-module support

        + +The main purpose of Boost.Python's cross-module support is to allow for +a modular system layout. With this support it is straightforward to +reflect C++ code organization at the Python level. Without the +cross-module support, a multi-purpose module like std_vector +would be impractical because the entire wrapper code would somehow have +to be duplicated in all extension modules that use it, making them +harder to maintain and harder to build. + +

        +Another motivation for the cross-module support is that two extension +modules that wrap the same class cannot both be imported into Python. +For example, if there are two modules A and B that +both wrap a given class X, this will work: + +

        +import A
        +x = A.X()
        +
        + +This will also work: + +
        +import B
        +x = B.X()
        +
        + +However, this will fail: + +
        +import A
        +import B
        +python: /net/cci/rwgk/boost/boost/python/detail/extension_class.hpp:866:
        +static void boost::python::detail::class_registry<X>::register_class(boost::python::detail::extension_class_base *):
        +Assertion `static_class_object == 0' failed.
        +Abort
        +
        + +A good solution is to wrap class X only once. Depending on the +situation, this could be done by module A or B, or an +additional small extension module that only wraps and exports +class X. + +

        +Finally, there can be important psychological or political reasons for +using the cross-module support. If a group of classes is lumped +together with many others in a huge module, the authors will have +difficulties in being identified with their work. The situation is +much more transparent if the work is represented by a module with a +recognizable name. This is not just a question of strong egos, but also +of getting credit and funding. + +


        +

        Why not use export_converters() universally?

        + +There is some overhead associated with the Boost.Python cross-module +support. Depending on the platform, the size of the code generated by +export_converters() is roughly 10%-20% of that generated +by class_builder<>. For a large extension module with +many wrapped classes, this could mean a significant difference. +Therefore the general recommendation is to use +export_converters() only for classes that are likely to +be used as function arguments or return values in other modules. + +
        +© Copyright Ralf W. Grosse-Kunstleve 2001. Permission to copy, +use, modify, sell and distribute this document is granted provided this +copyright notice appears in all copies. This document is provided "as +is" without express or implied warranty, and with no claim as to its +suitability for any purpose. + +

        +Updated: April 2001 + +

        From 38ac4fe84938e5a211d54b20fb912c1969f34aa3 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 19:51:30 +0000 Subject: [PATCH 123/154] cross-module mods [SVN r9823] --- doc/index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/index.html b/doc/index.html index c6e0722e..5ec32a6b 100644 --- a/doc/index.html +++ b/doc/index.html @@ -134,6 +134,8 @@ among others.
      • Pickle Support +
      • Cross-Extension-Module Dependencies +
      • Wrapping Enums
      • Pointers and Smart Pointers From 62b90206e842edce572c4ac10af9f9716a4f9173 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 19:52:44 +0000 Subject: [PATCH 124/154] More organized presentation. [SVN r9824] --- doc/building.html | 279 +++++++++++++++++++++++++--------------------- 1 file changed, 151 insertions(+), 128 deletions(-) diff --git a/doc/building.html b/doc/building.html index 2a8c9cae..f9458c42 100644 --- a/doc/building.html +++ b/doc/building.html @@ -5,153 +5,176 @@ Building an Extension Module
        -

        c++boost.gif (8819 bytes)Building an Extension Module

        The build process for Boost is currently undergoing some evolution, and, it is to be hoped, improvement. The following facts may help: +


        + Makefiles for various platforms and a Visual Studio project + reside in the Boost subdirectory libs/python/build. + Build targets include: +
          -
        • - Makefiles for various platforms reside in the Boost subdirectory - libs/python/build: +
        • The boost_python library for static linking with your + extension module. On the various Unices, this library will be + called libboost_python.a. When using Visual C++, the + library will be called boost_python.lib. -
            -
          • como.mak (Comeau C++ on Linux) +

            +

          • A comprehensive test of Boost.Python features. This test builds + a Boost.Python extension module, then runs Python to import the + module, and runs a series of tests on it using doctest. Source code for the module + and tests is available in the Boost subdirectory + libs/python/test. -
          • linux_gcc.mak (GCC on - Linux/Unix) +

            +

          • Various examples from the Boost subdirectory + libs/python/example. + All these examples include a doctest modeled + on the comprehensive test above. -
          • gcc.mak (older makefile for GCC - on Linux/Unix. Deprecated.) - -
          • mingw32.mak - (highly-specialized makefile for mingw32 (Win32-targeted) GCC. Read - the header comment). - -
          • tru64_cxx.mak (Compaq - Alpha). -
          -
          - -
        • - A project workspace for Microsoft Visual Studio is provided at libs/python/build/build.dsw. The - include paths for this project may need to be changed for your - installation. They currently assume that python has been installed at - c:\tools\python. Three configurations of all targets are - supported: - -
            -
          • Release (optimization, -DNDEBUG) - -
          • Debug (no optimization -D_DEBUG) - -
          • DebugPython (no optimization, -D_DEBUG - -DBOOST_DEBUG_PYTHON) -
          - -

          When extension modules are built with Visual C++ using - -D_DEBUG, Python defaults to force linking with a - special debugging version of the Python DLL. Since this debug DLL - isn't supplied with the default Python installation for Windows, - Boost.Python uses boost/python/detail/wrap_python.hpp - to temporarily undefine _DEBUG when Python.h is - #included. - -

          If you want the extra runtime checks available with the debugging - version of the library, #define BOOST_DEBUG_PYTHON to - re-enable library forcing, and link with the DebugPython version of - boost_python.lib. You'll need to get the debugging version - of the Python executable (python_d.exe) and DLL - (python20_d.dll or python15_d.dll). The Python - sources include project files for building these. If you download them, change the name of the - top-level directory to src, and install it under - c:\tools\python, the workspace supplied by Boost.Python will - be able to use it without modification. Just open - c:\tools\python\src\pcbuild\pcbuild.dsw and invoke "build - all" to generate all the debugging targets. - -

          If you do not #define BOOST_DEBUG_PYTHON, be sure that - any source files #include <boost/python/detail/wrap_python.hpp> - instead of the usual Python.h, or you will have link - incompatibilities.
          -
          - - -

        • - The makefiles and Visual Studio project can all build at least the - following: - -
            -
          • The boost_python library for static linking with your - extension module. On the various Unices, this library will be - called libboost_python.a. On Win32 platforms, the library - will be called boost_python.lib. - -
          • A comprehensive test of Boost.Python features. This test builds - a Boost.Python extension module, then runs Python to import the - module, and runs a series of tests on it using doctest. Source code for the module - and tests is available in the Boost subdirectory - libs/python/test.
            - - -
          • Various examples from the Boost subdirectory - libs/python/example. Which examples are built currently - depends on the platform. The most up-to-date examples are - getting_startedn.cpp from Ralf W. - Grosse-Kunstleve. All these examples include a doctest modeled - on the comprehensive test above.
            -
            - -
          - -
        • - If your platform isn't directly supported, you can build a static - library from the following source files (in the Boost subdirectory - libs/python/src), or compile them directly and link the - resulting objects into your extension module: - -
        -

        Next: Wrapping Enums Previous: + There is a group of makefiles with support for simultaneous + compilation on multiple platforms and a consistent set of + features that build the boost_python library for static + linking, the comprehensive test, and all examples in + libs/python/example: + +

        + Usage of these makefiles is described here. + +
        + There is another group of makefiles for GNU make. + These makefiles are less redundant than the makefiles + in the group above, + but the list of compilation targets is not as complete + and there is no support for simultaneous compilation + on multiple platforms. + + + +
        + A project workspace for Microsoft Visual Studio is provided at libs/python/build/build.dsw. The + include paths for this project may need to be changed for your + installation. They currently assume that python has been installed at + c:\tools\python. Three configurations of all targets are + supported: + +
          +
        • Release (optimization, -DNDEBUG) + +
        • Debug (no optimization -D_DEBUG) + +
        • DebugPython (no optimization, -D_DEBUG + -DBOOST_DEBUG_PYTHON) +
        + +

        When extension modules are built with Visual C++ using + -D_DEBUG, Python defaults to force linking with a + special debugging version of the Python DLL. Since this debug DLL + isn't supplied with the default Python installation for Windows, + Boost.Python uses boost/python/detail/wrap_python.hpp + to temporarily undefine _DEBUG when Python.h is + #included. + +

        If you want the extra runtime checks available with the debugging + version of the library, #define BOOST_DEBUG_PYTHON to + re-enable library forcing, and link with the DebugPython version of + boost_python.lib. You'll need to get the debugging version + of the Python executable (python_d.exe) and DLL + (python20_d.dll or python15_d.dll). The Python + sources include project files for building these. If you download them, change the name of the + top-level directory to src, and install it under + c:\tools\python, the workspace supplied by Boost.Python will + be able to use it without modification. Just open + c:\tools\python\src\pcbuild\pcbuild.dsw and invoke "build + all" to generate all the debugging targets. + +

        If you do not #define BOOST_DEBUG_PYTHON, be sure that + any source files #include <boost/python/detail/wrap_python.hpp> + instead of the usual Python.h, or you will have link + incompatibilities.
        + +


        + If your platform isn't directly supported, you can build a static + library from the following source files (in the Boost subdirectory + libs/python/src), or compile them directly and link the + resulting objects into your extension module: + + + +
        + Next: Wrapping Enums Previous: A Peek Under the Hood Up: Top +

        © Copyright David Abrahams 2000. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided ``as is'' without express or implied warranty, and with no claim as to its suitability for any purpose. -

        Updated: Mar 6, 2001 +

        Updated: Apr 17, 2001 (R.W. Grosse-Kunstleve)

        - From ad4b0fff565fb36c827f20357de54255dc365d3d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 19:55:11 +0000 Subject: [PATCH 125/154] moved from branch ralf_grosse_kunstleve to trunk [SVN r9825] --- doc/pickle.html | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/doc/pickle.html b/doc/pickle.html index 842112d3..994a78ab 100644 --- a/doc/pickle.html +++ b/doc/pickle.html @@ -227,11 +227,38 @@ Both __getinitargs__ and __getstate__ are not defined.

      -

      Example

      +

      Examples

      -An example that shows how to configure pickle support is available in the -boost/lib/python/example directory -(getting_started3.cpp). +There are three files in boost/libs/python/example that +show how so provide pickle support. + +

      pickle1.cpp

      + + The C++ class in this example can be fully restored by passing the + appropriate argument to the constructor. Therefore it is sufficient + to define the pickle interface method __getinitargs__. + +

      pickle2.cpp

      + + The C++ class in this example contains member data that cannot be + restored by any of the constructors. Therefore it is necessary to + provide the __getstate__/__setstate__ pair of + pickle interface methods. + +

      + For simplicity, the __dict__ is not included in the result + of __getstate__. This is not generally recommended, but a + valid approach if it is anticipated that the object's + __dict__ will always be empty. Note that the safety guards + will catch the cases where this assumption is violated. + +

      pickle3.cpp

      + + This example is similar to pickle2.cpp. However, the + object's __dict__ is included in the result of + __getstate__. This requires more code but is unavoidable + if the object's __dict__ is not always empty.
      © Copyright Ralf W. Grosse-Kunstleve 2001. Permission to copy, @@ -241,5 +268,5 @@ is" without express or implied warranty, and with no claim as to its suitability for any purpose.

      -Updated: March 10, 2001 +Updated: March 21, 2001 From da83f20a283d943ed9fa42317109d3d0c3af14ec Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 20:02:20 +0000 Subject: [PATCH 126/154] stray getting_started3 references removed. [SVN r9826] --- build/filemgr.py | 3 --- build/irix_CC.mak | 9 ++------- build/linux_gcc.mak | 9 ++------- build/mingw32.mak | 9 +-------- build/tru64_cxx.mak | 9 ++------- build/vc60.mak | 6 +----- 6 files changed, 8 insertions(+), 37 deletions(-) diff --git a/build/filemgr.py b/build/filemgr.py index fa674f18..d8310f6d 100644 --- a/build/filemgr.py +++ b/build/filemgr.py @@ -22,7 +22,6 @@ bpl_tst + "/doctest.py", bpl_exa + "/abstract.cpp", bpl_exa + "/getting_started1.cpp", bpl_exa + "/getting_started2.cpp", -bpl_exa + "/getting_started3.cpp", bpl_exa + "/simple_vector.cpp", bpl_exa + "/do_it_yourself_converters.cpp", bpl_exa + "/pickle1.cpp", @@ -31,7 +30,6 @@ bpl_exa + "/pickle3.cpp", bpl_exa + "/test_abstract.py", bpl_exa + "/test_getting_started1.py", bpl_exa + "/test_getting_started2.py", -bpl_exa + "/test_getting_started3.py", bpl_exa + "/test_simple_vector.py", bpl_exa + "/test_do_it_yourself_converters.py", bpl_exa + "/test_pickle1.py", @@ -61,7 +59,6 @@ defs = ( "abstract", "getting_started1", "getting_started2", -"getting_started3", "simple_vector", "do_it_yourself_converters", "pickle1", diff --git a/build/irix_CC.mak b/build/irix_CC.mak index 88d374d8..5894ff51 100644 --- a/build/irix_CC.mak +++ b/build/irix_CC.mak @@ -41,7 +41,7 @@ OBJ=classes.o conversions.o extension_class.o functions.o \ DEPOBJ=$(OBJ) \ comprehensive.o \ abstract.o \ - getting_started1.o getting_started2.o getting_started3.o \ + getting_started1.o getting_started2.o \ simple_vector.o \ do_it_yourself_converters.o \ pickle1.o pickle2.o pickle3.o \ @@ -53,7 +53,7 @@ DEPOBJ=$(OBJ) \ all: libboost_python.a \ boost_python_test.so \ abstract.so \ - getting_started1.so getting_started2.so getting_started3.so \ + getting_started1.so getting_started2.so \ simple_vector.so \ do_it_yourself_converters.so \ pickle1.so pickle2.so pickle3.so \ @@ -76,9 +76,6 @@ getting_started1.so: $(OBJ) getting_started1.o getting_started2.so: $(OBJ) getting_started2.o $(LD) $(LDOPTS) $(OBJ) getting_started2.o -o getting_started2.so -getting_started3.so: $(OBJ) getting_started3.o - $(LD) $(LDOPTS) $(OBJ) getting_started3.o -o getting_started3.so - simple_vector.so: $(OBJ) simple_vector.o $(LD) $(LDOPTS) $(OBJ) simple_vector.o -o simple_vector.so @@ -116,7 +113,6 @@ test: $(PYEXE) test_abstract.py $(PYEXE) test_getting_started1.py $(PYEXE) test_getting_started2.py - $(PYEXE) test_getting_started3.py $(PYEXE) test_simple_vector.py $(PYEXE) test_do_it_yourself_converters.py $(PYEXE) test_pickle1.py @@ -130,7 +126,6 @@ clean: rm -f abstract.o abstract.so rm -f getting_started1.o getting_started1.so rm -f getting_started2.o getting_started2.so - rm -f getting_started3.o getting_started3.so rm -f simple_vector.o simple_vector.so rm -f do_it_yourself_converters.o do_it_yourself_converters.so rm -f pickle1.o pickle1.so diff --git a/build/linux_gcc.mak b/build/linux_gcc.mak index 9be8f1cb..9cd2b5de 100644 --- a/build/linux_gcc.mak +++ b/build/linux_gcc.mak @@ -42,7 +42,7 @@ OBJ=classes.o conversions.o extension_class.o functions.o \ DEPOBJ=$(OBJ) \ comprehensive.o \ abstract.o \ - getting_started1.o getting_started2.o getting_started3.o \ + getting_started1.o getting_started2.o \ simple_vector.o \ do_it_yourself_converters.o \ pickle1.o pickle2.o pickle3.o \ @@ -54,7 +54,7 @@ DEPOBJ=$(OBJ) \ all: libboost_python.a \ boost_python_test.so \ abstract.so \ - getting_started1.so getting_started2.so getting_started3.so \ + getting_started1.so getting_started2.so \ simple_vector.so \ do_it_yourself_converters.so \ pickle1.so pickle2.so pickle3.so \ @@ -77,9 +77,6 @@ getting_started1.so: $(OBJ) getting_started1.o getting_started2.so: $(OBJ) getting_started2.o $(LD) $(LDOPTS) $(OBJ) getting_started2.o -o getting_started2.so -getting_started3.so: $(OBJ) getting_started3.o - $(LD) $(LDOPTS) $(OBJ) getting_started3.o -o getting_started3.so - simple_vector.so: $(OBJ) simple_vector.o $(LD) $(LDOPTS) $(OBJ) simple_vector.o -o simple_vector.so @@ -117,7 +114,6 @@ test: $(PYEXE) test_abstract.py $(PYEXE) test_getting_started1.py $(PYEXE) test_getting_started2.py - $(PYEXE) test_getting_started3.py $(PYEXE) test_simple_vector.py $(PYEXE) test_do_it_yourself_converters.py $(PYEXE) test_pickle1.py @@ -131,7 +127,6 @@ clean: rm -f abstract.o abstract.so rm -f getting_started1.o getting_started1.so rm -f getting_started2.o getting_started2.so - rm -f getting_started3.o getting_started3.so rm -f simple_vector.o simple_vector.so rm -f do_it_yourself_converters.o do_it_yourself_converters.so rm -f pickle1.o pickle1.so diff --git a/build/mingw32.mak b/build/mingw32.mak index 98a26735..0a16f332 100644 --- a/build/mingw32.mak +++ b/build/mingw32.mak @@ -57,7 +57,7 @@ OBJ=classes.o conversions.o extension_class.o functions.o \ all: libboost_python.a \ abstract.pyd \ - getting_started1.pyd getting_started2.pyd getting_started3.pyd \ + getting_started1.pyd getting_started2.pyd \ simple_vector.pyd \ do_it_yourself_converters.pyd \ pickle1.pyd pickle2.pyd pickle3.pyd \ @@ -95,12 +95,6 @@ getting_started2.pyd: $(OBJ) getting_started2.o --def getting_started2.def \ $(OBJ) getting_started2.o $(PYLIB) -getting_started3.pyd: $(OBJ) getting_started3.o - dllwrap $(DLLWRAPOPTS) \ - --dllname getting_started3.pyd \ - --def getting_started3.def \ - $(OBJ) getting_started3.o $(PYLIB) - simple_vector.pyd: $(OBJ) simple_vector.o dllwrap $(DLLWRAPOPTS) \ --dllname simple_vector.pyd \ @@ -163,7 +157,6 @@ test: $(PYEXE) test_abstract.py $(PYEXE) test_getting_started1.py $(PYEXE) test_getting_started2.py - $(PYEXE) test_getting_started3.py $(PYEXE) test_simple_vector.py $(PYEXE) test_do_it_yourself_converters.py $(PYEXE) test_pickle1.py diff --git a/build/tru64_cxx.mak b/build/tru64_cxx.mak index 41f7a554..21a8126e 100644 --- a/build/tru64_cxx.mak +++ b/build/tru64_cxx.mak @@ -52,7 +52,7 @@ OBJ=classes.o conversions.o extension_class.o functions.o \ DEPOBJ=$(OBJ) \ comprehensive.o \ abstract.o \ - getting_started1.o getting_started2.o getting_started3.o \ + getting_started1.o getting_started2.o \ simple_vector.o \ do_it_yourself_converters.o \ pickle1.o pickle2.o pickle3.o \ @@ -64,7 +64,7 @@ DEPOBJ=$(OBJ) \ all: libboost_python.a \ boost_python_test.so \ abstract.so \ - getting_started1.so getting_started2.so getting_started3.so \ + getting_started1.so getting_started2.so \ simple_vector.so \ do_it_yourself_converters.so \ pickle1.so pickle2.so pickle3.so \ @@ -91,9 +91,6 @@ getting_started1.so: $(OBJ) getting_started1.o getting_started2.so: $(OBJ) getting_started2.o $(LD) $(LDOPTS) $(OBJ) getting_started2.o -o getting_started2.so -getting_started3.so: $(OBJ) getting_started3.o - $(LD) $(LDOPTS) $(OBJ) getting_started3.o -o getting_started3.so - simple_vector.so: $(OBJ) simple_vector.o $(LD) $(LDOPTS) $(OBJ) simple_vector.o -o simple_vector.so @@ -131,7 +128,6 @@ test: $(PYEXE) test_abstract.py $(PYEXE) test_getting_started1.py $(PYEXE) test_getting_started2.py - $(PYEXE) test_getting_started3.py $(PYEXE) test_simple_vector.py $(PYEXE) test_do_it_yourself_converters.py $(PYEXE) test_pickle1.py @@ -145,7 +141,6 @@ clean: rm -f abstract.o abstract.so rm -f getting_started1.o getting_started1.so rm -f getting_started2.o getting_started2.so - rm -f getting_started3.o getting_started3.so rm -f simple_vector.o simple_vector.so rm -f do_it_yourself_converters.o do_it_yourself_converters.so rm -f pickle1.o pickle1.so diff --git a/build/vc60.mak b/build/vc60.mak index 64e0b9df..f0016075 100644 --- a/build/vc60.mak +++ b/build/vc60.mak @@ -38,7 +38,7 @@ OBJ=classes.obj conversions.obj extension_class.obj functions.obj \ all: boost_python.lib \ boost_python_test.pyd \ abstract.pyd \ - getting_started1.pyd getting_started2.pyd getting_started3.pyd \ + getting_started1.pyd getting_started2.pyd \ simple_vector.pyd \ do_it_yourself_converters.pyd \ pickle1.pyd pickle2.pyd pickle3.pyd \ @@ -60,9 +60,6 @@ getting_started1.pyd: $(OBJ) getting_started1.obj getting_started2.pyd: $(OBJ) getting_started2.obj $(LD) $(LDOPTS) $(OBJ) getting_started2.obj $(PYLIB) /export:initgetting_started2 /out:"getting_started2.pyd" -getting_started3.pyd: $(OBJ) getting_started3.obj - $(LD) $(LDOPTS) $(OBJ) getting_started3.obj $(PYLIB) /export:initgetting_started3 /out:"getting_started3.pyd" - simple_vector.pyd: $(OBJ) simple_vector.obj $(LD) $(LDOPTS) $(OBJ) simple_vector.obj $(PYLIB) /export:initsimple_vector /out:"simple_vector.pyd" @@ -98,7 +95,6 @@ test: $(PYEXE) test_abstract.py $(PYEXE) test_getting_started1.py $(PYEXE) test_getting_started2.py - $(PYEXE) test_getting_started3.py $(PYEXE) test_simple_vector.py $(PYEXE) test_do_it_yourself_converters.py $(PYEXE) test_pickle1.py From c3215d0ba5b3b75e2e6f42e37b5e8ad592fb57c3 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 17 Apr 2001 21:30:05 +0000 Subject: [PATCH 127/154] enhancement [SVN r9827] --- example/README | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/example/README b/example/README index 34b50d61..35d822d5 100644 --- a/example/README +++ b/example/README @@ -1,6 +1,24 @@ To get started with the Boost Python Library, use the examples -getting_started?.cpp and abstract.cpp. +getting_started1.cpp and getting_started2.cpp. + +Examples for providing pickle support can be found in: + pickle1.cpp + pickle2.cpp + pickle3.cpp +See also: libs/python/doc/pickle.html + +Other advanced concepts are introduced by: + abstract.cpp + simple_vector.cpp + do_it_yourself_converters.cpp + +Examples for the cross-module support are provided by: + noncopyable_export.cpp + noncopyable_import.cpp + dvect.cpp + ivect.cpp +See also: libs/python/doc/cross_module.html The files example1.cpp and rwgk1.cpp are obsolete. They are only -included because the makefiles in the build directory still refer to -them. This will be fixed later. +included because the Visual Studio project in the build directory still +refers to them. From ebb0145256b4247bf270d6442b669773153d487c Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 18 Apr 2001 01:23:50 +0000 Subject: [PATCH 128/154] trying to clean cvs attic mess... [SVN r9828] --- example/simple_vector.cpp | 103 -------------------------------------- 1 file changed, 103 deletions(-) delete mode 100644 example/simple_vector.cpp diff --git a/example/simple_vector.cpp b/example/simple_vector.cpp deleted file mode 100644 index 5ac0767b..00000000 --- a/example/simple_vector.cpp +++ /dev/null @@ -1,103 +0,0 @@ -// Example by Ralf W. Grosse-Kunstleve - -#include -namespace python = boost::python; - -namespace { // Avoid cluttering the global namespace. - - // A wrapper is used to define additional constructors. - // - struct vector_double_wrapper: std::vector - { - // Tell the compiler how to convert a base class object to - // this wrapper object. - vector_double_wrapper(PyObject*, const std::vector& vd) - : std::vector(vd) {} - - vector_double_wrapper(PyObject* self) - : std::vector() {} - - vector_double_wrapper(PyObject* self, int n) - : std::vector(n) {} - - vector_double_wrapper(PyObject* self, python::tuple tuple) - : std::vector(tuple.size()) - { - std::vector::iterator vd = begin(); - for (int i = 0; i < tuple.size(); i++) - vd[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), - python::type()); - } - }; - - double getitem(const std::vector& vd, std::size_t key) { - return vd[key]; - } - - void setitem(std::vector& vd, std::size_t key, double d) { - std::vector::iterator vditer = vd.begin(); - vditer[key] = d; - } - - void delitem(std::vector& vd, std::size_t key) { - std::vector::iterator vditer = vd.begin(); - vd.erase(&vditer[key]); - } - - // Convert vector_double to a regular Python tuple. - // - python::tuple as_tuple(const std::vector& vd) - { - python::tuple t(vd.size()); - for (int i = 0; i < vd.size(); i++) t.set_item(i, - python::ref(BOOST_PYTHON_CONVERSION::to_python(vd[i]))); - return t; - } - - // Function returning a vector_double object to Python. - // - std::vector foo(int n) - { - std::vector vd(n); - std::vector::iterator vditer = vd.begin(); - for (int i = 0; i < n; i++) vditer[i] = double(i); - return vd; - } - - // Same as foo(), but avoid copying on return. - // - std::auto_ptr > bar(int n) - { - std::auto_ptr > vdptr(new std::vector(n)); - std::vector::iterator vditer = vdptr->begin(); - for (int i = 0; i < n; i++) vditer[i] = double(10 * i); - return vdptr; - } -} - -BOOST_PYTHON_MODULE_INIT(simple_vector) -{ - try - { - python::module_builder this_module("simple_vector"); - - python::class_builder, vector_double_wrapper> - vector_double(this_module, "vector_double"); - - 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__"); - vector_double.def(setitem, "__setitem__"); - vector_double.def(delitem, "__delitem__"); - vector_double.def(as_tuple, "as_tuple"); - - this_module.def(foo, "foo"); - this_module.def(bar, "bar"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} From 22024e7c1f8b7f8d2b92ad9ea0f2ce9307451e94 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 18 Apr 2001 01:24:34 +0000 Subject: [PATCH 129/154] trying to clean cvs attic mess... [SVN r9829] --- example/simple_vector.cpp | 103 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 example/simple_vector.cpp diff --git a/example/simple_vector.cpp b/example/simple_vector.cpp new file mode 100644 index 00000000..5ac0767b --- /dev/null +++ b/example/simple_vector.cpp @@ -0,0 +1,103 @@ +// Example by Ralf W. Grosse-Kunstleve + +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // A wrapper is used to define additional constructors. + // + struct vector_double_wrapper: std::vector + { + // Tell the compiler how to convert a base class object to + // this wrapper object. + vector_double_wrapper(PyObject*, const std::vector& vd) + : std::vector(vd) {} + + vector_double_wrapper(PyObject* self) + : std::vector() {} + + vector_double_wrapper(PyObject* self, int n) + : std::vector(n) {} + + vector_double_wrapper(PyObject* self, python::tuple tuple) + : std::vector(tuple.size()) + { + std::vector::iterator vd = begin(); + for (int i = 0; i < tuple.size(); i++) + vd[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(), + python::type()); + } + }; + + double getitem(const std::vector& vd, std::size_t key) { + return vd[key]; + } + + void setitem(std::vector& vd, std::size_t key, double d) { + std::vector::iterator vditer = vd.begin(); + vditer[key] = d; + } + + void delitem(std::vector& vd, std::size_t key) { + std::vector::iterator vditer = vd.begin(); + vd.erase(&vditer[key]); + } + + // Convert vector_double to a regular Python tuple. + // + python::tuple as_tuple(const std::vector& vd) + { + python::tuple t(vd.size()); + for (int i = 0; i < vd.size(); i++) t.set_item(i, + python::ref(BOOST_PYTHON_CONVERSION::to_python(vd[i]))); + return t; + } + + // Function returning a vector_double object to Python. + // + std::vector foo(int n) + { + std::vector vd(n); + std::vector::iterator vditer = vd.begin(); + for (int i = 0; i < n; i++) vditer[i] = double(i); + return vd; + } + + // Same as foo(), but avoid copying on return. + // + std::auto_ptr > bar(int n) + { + std::auto_ptr > vdptr(new std::vector(n)); + std::vector::iterator vditer = vdptr->begin(); + for (int i = 0; i < n; i++) vditer[i] = double(10 * i); + return vdptr; + } +} + +BOOST_PYTHON_MODULE_INIT(simple_vector) +{ + try + { + python::module_builder this_module("simple_vector"); + + python::class_builder, vector_double_wrapper> + vector_double(this_module, "vector_double"); + + 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__"); + vector_double.def(setitem, "__setitem__"); + vector_double.def(delitem, "__delitem__"); + vector_double.def(as_tuple, "as_tuple"); + + this_module.def(foo, "foo"); + this_module.def(bar, "bar"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} From dc462cdc1f1fd22a97a69eda4b2a3cc97bb8bd7a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 18 Apr 2001 01:27:51 +0000 Subject: [PATCH 130/154] cleaning up cvs attic mess [SVN r9830] --- example/do_it_yourself_converters.cpp | 128 ---------------------- example/dvect.cpp | 45 -------- example/ivect.cpp | 45 -------- example/noncopyable_export.cpp | 25 ----- example/noncopyable_import.cpp | 42 -------- example/pickle1.cpp | 64 ----------- example/pickle2.cpp | 100 ----------------- example/pickle3.cpp | 150 -------------------------- example/tst_dvect1.py | 20 ---- example/tst_ivect1.py | 20 ---- example/tst_noncopyable.py | 16 --- 11 files changed, 655 deletions(-) delete mode 100644 example/do_it_yourself_converters.cpp delete mode 100644 example/dvect.cpp delete mode 100644 example/ivect.cpp delete mode 100644 example/noncopyable_export.cpp delete mode 100644 example/noncopyable_import.cpp delete mode 100644 example/pickle1.cpp delete mode 100644 example/pickle2.cpp delete mode 100644 example/pickle3.cpp delete mode 100644 example/tst_dvect1.py delete mode 100644 example/tst_ivect1.py delete mode 100644 example/tst_noncopyable.py diff --git a/example/do_it_yourself_converters.cpp b/example/do_it_yourself_converters.cpp deleted file mode 100644 index 6d2d2d6a..00000000 --- a/example/do_it_yourself_converters.cpp +++ /dev/null @@ -1,128 +0,0 @@ -// Example by Ralf W. Grosse-Kunstleve -/* - - This example shows how to convert a class from and to native - Python objects, such as tuples. - - We do not want to expose the helper class MillerIndex as an - Extension Class. However, in order to simplify the wrapper code, - we want to define from_python() and to_python() functions for - class MillerIndex. - - Consider the alternatives: - - - Expose MillerIndex as an Extension Class. - We need a constructor MillerIndex(python::tuple). - Python function calls become more complex: - foo(MillerIndex((1,2,3)) instead of foo((1,2,3)) - We need a method such as MillerIndex().as_tuple(). - - - Define a wrapper function for each function that we - want to expose, e.g.: - void add(const IndexingSet& ixset, const python::tuple PyMIx) - - The first alternative introduces a new type that the user has to - deal with. Other modules using Miller indices might organize them in - different ways, for example to increase runtime efficiency for - important procedures. This means, the user has to know how to - convert between the different kinds of Miller index representations. - This can quickly become a nuisance. Relying on native Python data - structures minimizes the number of special types the user has to - learn and convert. Of course, this argument is only valid for - small and relatively simply classes. - - If there are many member functions with MillerIndex arguments, the - second alternative is impractical, and concentrating the conversion - mechanism in one central place is essential for code - maintainability. An added benefit is that more convenient (smarter) - conversion functions can be provided without cluttering the rest of - the wrapper code. - - */ - -#include -#include -#include -namespace python = boost::python; - -namespace { // Avoid cluttering the global namespace. - - // The helper class. - // - class MillerIndex { - public: - int v[3]; - }; - - // The main class. Imagine that there are MANY member functions - // like add() and get(). - // - class IndexingSet { - private: - std::vector VMIx; - public: - void add(const MillerIndex& MIx) { VMIx.push_back(MIx); } - MillerIndex get(std::size_t i) const { return VMIx[i]; } - }; -} - -BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE - - // Convert a Python tuple to a MillerIndex object. - // - MillerIndex from_python(PyObject* p, python::type) - { - python::tuple tup - = python::tuple(python::ref(p, python::ref::increment_count)); - if (tup.size() != 3) { - PyErr_SetString(PyExc_ValueError, - "expecting exactly 3 values in tuple."); - throw python::error_already_set(); - } - MillerIndex result; - for (int i = 0; i < 3; i++) - result.v[i] = from_python(tup[i].get(), python::type()); - return result; - } - - // Similar conversion for MillerIndex objects passed by value. - // Not actually used, but included to show the principle. - // - MillerIndex from_python(PyObject* p, python::type) - { - return from_python(p, python::type()); - } - - // Convert a MillerIndex object to a Python tuple. - // - PyObject* to_python(const MillerIndex& hkl) - { - python::tuple result(3); - for (int i = 0; i < 3; i++) - result.set_item(i, python::ref(to_python(hkl.v[i]))); - return result.reference().release(); - } - -BOOST_PYTHON_END_CONVERSION_NAMESPACE - -BOOST_PYTHON_MODULE_INIT(do_it_yourself_converters) -{ - try - { - // Create an object representing this extension module. - python::module_builder this_module("do_it_yourself_converters"); - - // Create the Python type object for our extension class. - python::class_builder ixset_class(this_module, "IndexingSet"); - - // Add the __init__ function. - ixset_class.def(python::constructor<>()); - // Add the member functions. - ixset_class.def(&IndexingSet::add, "add"); - ixset_class.def(&IndexingSet::get, "get"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/dvect.cpp b/example/dvect.cpp deleted file mode 100644 index da6b35a3..00000000 --- a/example/dvect.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Example by Ralf W. Grosse-Kunstleve -// See root/libs/python/doc/cross_module.html for an introduction. - -#include "dvect.h" -#include "ivect.h" -#include -namespace python = boost::python; - -namespace { - -# include "dvect_conversions.cpp" -# include "ivect_conversions.cpp" - - vects::ivect dvect_as_ivect(const vects::dvect& dv) - { - vects::ivect iv(dv.size()); - vects::ivect::iterator iviter = iv.begin(); - for (int i = 0; i < dv.size(); i++) iviter[i] = static_cast(dv[i]); - return iv; - } -} - -BOOST_PYTHON_MODULE_INIT(dvect) -{ - try - { - python::module_builder this_module("dvect"); - - python::class_builder dvect_class(this_module, "dvect"); - python::export_converters(dvect_class); - - python::import_converters ivect_converters("ivect", "ivect"); - - dvect_class.def(python::constructor()); - dvect_class.def(&vects::dvect::as_tuple, "as_tuple"); - dvect_class.def(dvect_as_ivect, "as_ivect"); - -# include "dvect_defs.cpp" -# include "ivect_defs.cpp" - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/ivect.cpp b/example/ivect.cpp deleted file mode 100644 index db1c0ec3..00000000 --- a/example/ivect.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Example by Ralf W. Grosse-Kunstleve -// See root/libs/python/doc/cross_module.html for an introduction. - -#include "dvect.h" -#include "ivect.h" -#include -namespace python = boost::python; - -namespace { - -# include "dvect_conversions.cpp" -# include "ivect_conversions.cpp" - - vects::dvect ivect_as_dvect(const vects::ivect& iv) - { - vects::dvect dv(iv.size()); - vects::dvect::iterator dviter = dv.begin(); - for (int i = 0; i < iv.size(); i++) dviter[i] = static_cast(iv[i]); - return dv; - } -} - -BOOST_PYTHON_MODULE_INIT(ivect) -{ - try - { - python::module_builder this_module("ivect"); - - python::class_builder ivect_class(this_module, "ivect"); - python::export_converters(ivect_class); - - python::import_converters dvect_converters("dvect", "dvect"); - - ivect_class.def(python::constructor()); - ivect_class.def(&vects::ivect::as_tuple, "as_tuple"); - ivect_class.def(ivect_as_dvect, "as_dvect"); - -# include "dvect_defs.cpp" -# include "ivect_defs.cpp" - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/noncopyable_export.cpp b/example/noncopyable_export.cpp deleted file mode 100644 index 794b1200..00000000 --- a/example/noncopyable_export.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Example by Ralf W. Grosse-Kunstleve -// See root/libs/python/doc/cross_module.html for an introduction. - -#include -namespace python = boost::python; - -#include "noncopyable.h" - -BOOST_PYTHON_MODULE_INIT(noncopyable_export) -{ - try - { - python::module_builder this_module("noncopyable_export"); - - python::class_builder store_class(this_module, "store"); - python::export_converters_noncopyable(store_class); - - store_class.def(python::constructor()); - store_class.def(&store::recall, "recall"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/noncopyable_import.cpp b/example/noncopyable_import.cpp deleted file mode 100644 index ea2477be..00000000 --- a/example/noncopyable_import.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// Example by Ralf W. Grosse-Kunstleve -// See root/libs/python/doc/cross_module.html for an introduction. - -#include -namespace python = boost::python; - -#include "noncopyable.h" - -namespace { // Avoid cluttering the global namespace. - - // A function with store objects as both input and output parameters. - // Because the copy constructor is disabled, we cannot pass a store - // object by value. Instead, we pass a smart pointer. - std::auto_ptr add_stores(const store& s1, const store& s2) - { - int sum = s1.recall() + s2.recall(); - std::auto_ptr ss = std::auto_ptr(new store(sum)); - return ss; - } -} - -BOOST_PYTHON_MODULE_INIT(noncopyable_import) -{ - try - { - python::module_builder this_module("noncopyable_import"); - - python::import_converters - dvect_converters("noncopyable_export", "store"); - - // Imagine all the additional classes with member functions - // that have store objects as input and output parameters. - // Lots and lots of them. - // However, to keep this example simple, we only define a - // module-level function. - this_module.def(add_stores, "add_stores"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/pickle1.cpp b/example/pickle1.cpp deleted file mode 100644 index cdd78989..00000000 --- a/example/pickle1.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// Example by Ralf W. Grosse-Kunstleve - -/* - This example shows how to make an Extension Class "pickleable". - - The world class below can be fully restored by passing the - appropriate argument to the constructor. Therefore it is sufficient - to define the pickle interface method __getinitargs__. - - For more information refer to boost/libs/python/doc/pickle.html. - */ - -#include - -#include -namespace python = boost::python; - -namespace { // Avoid cluttering the global namespace. - - // A friendly class. - class world - { - private: - std::string country; - int secret_number; - public: - world(const std::string& country) : secret_number(0) { - this->country = country; - } - std::string greet() const { return "Hello from " + country + "!"; } - std::string get_country() const { return country; } - }; - - // Support for pickle. - python::ref world_getinitargs(const world& w) { - python::tuple result(1); - result.set_item(0, w.get_country()); - return result.reference(); - } -} - -BOOST_PYTHON_MODULE_INIT(pickle1) -{ - try - { - // Create an object representing this extension module. - python::module_builder this_module("pickle1"); - - // Create the Python type object for our extension class. - python::class_builder world_class(this_module, "world"); - - // Add the __init__ function. - world_class.def(python::constructor()); - // Add a regular member function. - world_class.def(&world::greet, "greet"); - - // Support for pickle. - world_class.def(world_getinitargs, "__getinitargs__"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/pickle2.cpp b/example/pickle2.cpp deleted file mode 100644 index d6aa3201..00000000 --- a/example/pickle2.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// Example by Ralf W. Grosse-Kunstleve - -/* - This example shows how to make an Extension Class "pickleable". - - The world class below contains member data (secret_number) that - cannot be restored by any of the constructors. Therefore it is - necessary to provide the __getstate__/__setstate__ pair of pickle - interface methods. - - For simplicity, the __dict__ is not included in the result of - __getstate__. This is not generally recommended, but a valid - approach if it is anticipated that the object's __dict__ will - always be empty. Note that safety guard are provided to catch the - cases where this assumption is not true. - - pickle3.cpp shows how to include the object's __dict__ in the - result of __getstate__. - - For more information refer to boost/libs/python/doc/pickle.html. - */ - -#include - -#include -namespace python = boost::python; - -namespace { // Avoid cluttering the global namespace. - - // A friendly class. - class world - { - public: - world(const std::string& country) : secret_number(0) { - this->country = country; - } - std::string greet() const { return "Hello from " + country + "!"; } - std::string get_country() const { return country; } - void set_secret_number(int number) { secret_number = number; } - int get_secret_number() const { return secret_number; } - private: - std::string country; - int secret_number; - }; - - // Support for pickle. - - using BOOST_PYTHON_CONVERSION::from_python; - - python::ref world_getinitargs(const world& w) { - python::tuple result(1); - result.set_item(0, w.get_country()); - return result.reference(); // returning the reference avoids the copying. - } - - python::ref world_getstate(const world& w) { - python::tuple result(1); - result.set_item(0, w.get_secret_number()); - return result.reference(); // returning the reference avoids the copying. - } - - void world_setstate(world& w, python::tuple state) { - if (state.size() != 1) { - PyErr_SetString(PyExc_ValueError, - "Unexpected argument in call to __setstate__."); - throw python::error_already_set(); - } - int number = from_python(state[0].get(), python::type()); - if (number != 42) - w.set_secret_number(number); - } -} - -BOOST_PYTHON_MODULE_INIT(pickle2) -{ - try - { - // Create an object representing this extension module. - python::module_builder this_module("pickle2"); - - // Create the Python type object for our extension class. - python::class_builder world_class(this_module, "world"); - - // Add the __init__ function. - world_class.def(python::constructor()); - // Add a regular member function. - world_class.def(&world::greet, "greet"); - world_class.def(&world::get_secret_number, "get_secret_number"); - world_class.def(&world::set_secret_number, "set_secret_number"); - - // Support for pickle. - world_class.def(world_getinitargs, "__getinitargs__"); - world_class.def(world_getstate, "__getstate__"); - world_class.def(world_setstate, "__setstate__"); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} diff --git a/example/pickle3.cpp b/example/pickle3.cpp deleted file mode 100644 index bfa7dc54..00000000 --- a/example/pickle3.cpp +++ /dev/null @@ -1,150 +0,0 @@ -// Example by Ralf W. Grosse-Kunstleve - -/* - This example shows how to make an Extension Class "pickleable". - - The world class below contains member data (secret_number) that - cannot be restored by any of the constructors. Therefore it is - necessary to provide the __getstate__/__setstate__ pair of pickle - interface methods. - - The object's __dict__ is included in the result of __getstate__. - This requires more code (compare with pickle2.cpp), but is - unavoidable if the object's __dict__ is not always empty. - - For more information refer to boost/libs/python/doc/pickle.html. - */ - -#include - -#include -namespace python = boost::python; - -namespace boost { namespace python { - - ref getattr(PyObject* o, const std::string& attr_name) { - return ref(PyObject_GetAttrString(o, const_cast(attr_name.c_str()))); - } - ref getattr(const ref& r, const std::string& attr_name) { - return getattr(r.get(), attr_name); - } - -}} - -namespace { // Avoid cluttering the global namespace. - - // A friendly class. - class world - { - public: - world(const std::string& country) : secret_number(0) { - this->country = country; - } - std::string greet() const { return "Hello from " + country + "!"; } - std::string get_country() const { return country; } - void set_secret_number(int number) { secret_number = number; } - int get_secret_number() const { return secret_number; } - private: - std::string country; - int secret_number; - }; - - // Support for pickle. - python::ref world_getinitargs(const world& w) { - python::tuple result(1); - result.set_item(0, w.get_country()); - return result.reference(); // returning the reference avoids the copying. - } - - python::ref world_getstate(python::tuple const & args, - python::dictionary const & keywords); - - PyObject* world_setstate(python::tuple const & args, - python::dictionary const & keywords); -} - -BOOST_PYTHON_MODULE_INIT(pickle3) -{ - try - { - // Create an object representing this extension module. - python::module_builder this_module("pickle3"); - - // Create the Python type object for our extension class. - python::class_builder world_class(this_module, "world"); - - // Add the __init__ function. - world_class.def(python::constructor()); - // Add a regular member function. - world_class.def(&world::greet, "greet"); - world_class.def(&world::get_secret_number, "get_secret_number"); - world_class.def(&world::set_secret_number, "set_secret_number"); - - // Support for pickle. - world_class.def(world_getinitargs, "__getinitargs__"); - world_class.def_raw(world_getstate, "__getstate__"); - world_class.def_raw(world_setstate, "__setstate__"); - world_class.getstate_manages_dict(); - } - catch(...) - { - python::handle_exception(); // Deal with the exception for Python - } -} - -namespace { - - using BOOST_PYTHON_CONVERSION::from_python; - using boost::python::type; - using boost::python::ref; - using boost::python::tuple; - using boost::python::list; - using boost::python::dictionary; - using boost::python::getattr; - - ref world_getstate(tuple const & args, dictionary const & keywords) - { - if(args.size() != 1 || keywords.size() != 0) { - PyErr_SetString(PyExc_TypeError, "wrong number of arguments"); - throw boost::python::argument_error(); - } - const world& w = from_python(args[0].get(), type()); - ref mydict = getattr(args[0], "__dict__"); - tuple result(2); - // store the object's __dict__ - result.set_item(0, mydict); - // store the internal state of the C++ object - result.set_item(1, w.get_secret_number()); - return result.reference(); // returning the reference avoids the copying. - } - - PyObject* world_setstate(tuple const & args, dictionary const & keywords) - { - if(args.size() != 2 || keywords.size() != 0) { - PyErr_SetString(PyExc_TypeError, "wrong number of arguments"); - throw boost::python::argument_error(); - } - world& w = from_python(args[0].get(), type()); - ref mydict = getattr(args[0], "__dict__"); - tuple state = from_python(args[1].get(), type()); - if (state.size() != 2) { - PyErr_SetString(PyExc_ValueError, - "Unexpected argument in call to __setstate__."); - throw python::error_already_set(); - } - // restore the object's __dict__ - dictionary odict = from_python(mydict.get(), type()); - const dictionary& pdict = from_python(state[0].get(), type()); - list pkeys(pdict.keys()); - for (int i = 0; i < pkeys.size(); i++) { - ref k(pkeys[i]); - //odict[k] = pdict[k]; // XXX memory leak! - odict[k] = pdict.get_item(k); // this does not leak. - } - // restore the internal state of the C++ object - int number = from_python(state[1].get(), type()); - if (number != 42) - w.set_secret_number(number); - return python::detail::none(); - } -} diff --git a/example/tst_dvect1.py b/example/tst_dvect1.py deleted file mode 100644 index 22315528..00000000 --- a/example/tst_dvect1.py +++ /dev/null @@ -1,20 +0,0 @@ -def f(): - import dvect - dv = dvect.dvect((1,2,3,4,5)) - print dv.as_tuple() - iv = dv.as_ivect() - print iv.as_tuple() - print dvect.const_ivect_reference_as_tuple(iv) - aiv = dvect.ivect_as_auto_ptr(iv) - print dvect.const_ivect_reference_as_tuple(aiv) - siv = dvect.ivect_as_shared_ptr(iv) - print dvect.const_ivect_reference_as_tuple(siv) - print aiv.as_tuple() - print siv.as_tuple() - -if (__name__ == "__main__"): - import sys, string - n = 1 - if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) - for i in xrange(n): - f() diff --git a/example/tst_ivect1.py b/example/tst_ivect1.py deleted file mode 100644 index 7369fdbf..00000000 --- a/example/tst_ivect1.py +++ /dev/null @@ -1,20 +0,0 @@ -def f(): - import ivect - iv = ivect.ivect((1,2,3,4,5)) - print iv.as_tuple() - dv = iv.as_dvect() - print dv.as_tuple() - print ivect.const_dvect_reference_as_tuple(dv) - adv = ivect.dvect_as_auto_ptr(dv) - print ivect.const_dvect_reference_as_tuple(adv) - sdv = ivect.dvect_as_shared_ptr(dv) - print ivect.const_dvect_reference_as_tuple(sdv) - print adv.as_tuple() - print sdv.as_tuple() - -if (__name__ == "__main__"): - import sys, string - n = 1 - if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) - for i in xrange(n): - f() diff --git a/example/tst_noncopyable.py b/example/tst_noncopyable.py deleted file mode 100644 index 155910a5..00000000 --- a/example/tst_noncopyable.py +++ /dev/null @@ -1,16 +0,0 @@ -def f(): - import noncopyable_export - import noncopyable_import - s1 = noncopyable_export.store(1) - print s1.recall() - s2 = noncopyable_export.store(2) - print s2.recall() - s3 = noncopyable_import.add_stores(s1, s2) - print s3.recall() - -if (__name__ == "__main__"): - import sys, string - n = 1 - if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) - for i in xrange(n): - f() From cbff11296bcbf7c486019db142cc9ba46560b20a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 18 Apr 2001 01:29:23 +0000 Subject: [PATCH 131/154] cleaning up cvs attic mess [SVN r9831] --- example/do_it_yourself_converters.cpp | 128 ++++++++++++++++++++++ example/dvect.cpp | 45 ++++++++ example/ivect.cpp | 45 ++++++++ example/noncopyable_export.cpp | 25 +++++ example/noncopyable_import.cpp | 42 ++++++++ example/pickle1.cpp | 64 +++++++++++ example/pickle2.cpp | 100 +++++++++++++++++ example/pickle3.cpp | 150 ++++++++++++++++++++++++++ example/tst_dvect1.py | 20 ++++ example/tst_ivect1.py | 20 ++++ example/tst_noncopyable.py | 16 +++ 11 files changed, 655 insertions(+) create mode 100644 example/do_it_yourself_converters.cpp create mode 100644 example/dvect.cpp create mode 100644 example/ivect.cpp create mode 100644 example/noncopyable_export.cpp create mode 100644 example/noncopyable_import.cpp create mode 100644 example/pickle1.cpp create mode 100644 example/pickle2.cpp create mode 100644 example/pickle3.cpp create mode 100644 example/tst_dvect1.py create mode 100644 example/tst_ivect1.py create mode 100644 example/tst_noncopyable.py diff --git a/example/do_it_yourself_converters.cpp b/example/do_it_yourself_converters.cpp new file mode 100644 index 00000000..6d2d2d6a --- /dev/null +++ b/example/do_it_yourself_converters.cpp @@ -0,0 +1,128 @@ +// Example by Ralf W. Grosse-Kunstleve +/* + + This example shows how to convert a class from and to native + Python objects, such as tuples. + + We do not want to expose the helper class MillerIndex as an + Extension Class. However, in order to simplify the wrapper code, + we want to define from_python() and to_python() functions for + class MillerIndex. + + Consider the alternatives: + + - Expose MillerIndex as an Extension Class. + We need a constructor MillerIndex(python::tuple). + Python function calls become more complex: + foo(MillerIndex((1,2,3)) instead of foo((1,2,3)) + We need a method such as MillerIndex().as_tuple(). + + - Define a wrapper function for each function that we + want to expose, e.g.: + void add(const IndexingSet& ixset, const python::tuple PyMIx) + + The first alternative introduces a new type that the user has to + deal with. Other modules using Miller indices might organize them in + different ways, for example to increase runtime efficiency for + important procedures. This means, the user has to know how to + convert between the different kinds of Miller index representations. + This can quickly become a nuisance. Relying on native Python data + structures minimizes the number of special types the user has to + learn and convert. Of course, this argument is only valid for + small and relatively simply classes. + + If there are many member functions with MillerIndex arguments, the + second alternative is impractical, and concentrating the conversion + mechanism in one central place is essential for code + maintainability. An added benefit is that more convenient (smarter) + conversion functions can be provided without cluttering the rest of + the wrapper code. + + */ + +#include +#include +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // The helper class. + // + class MillerIndex { + public: + int v[3]; + }; + + // The main class. Imagine that there are MANY member functions + // like add() and get(). + // + class IndexingSet { + private: + std::vector VMIx; + public: + void add(const MillerIndex& MIx) { VMIx.push_back(MIx); } + MillerIndex get(std::size_t i) const { return VMIx[i]; } + }; +} + +BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE + + // Convert a Python tuple to a MillerIndex object. + // + MillerIndex from_python(PyObject* p, python::type) + { + python::tuple tup + = python::tuple(python::ref(p, python::ref::increment_count)); + if (tup.size() != 3) { + PyErr_SetString(PyExc_ValueError, + "expecting exactly 3 values in tuple."); + throw python::error_already_set(); + } + MillerIndex result; + for (int i = 0; i < 3; i++) + result.v[i] = from_python(tup[i].get(), python::type()); + return result; + } + + // Similar conversion for MillerIndex objects passed by value. + // Not actually used, but included to show the principle. + // + MillerIndex from_python(PyObject* p, python::type) + { + return from_python(p, python::type()); + } + + // Convert a MillerIndex object to a Python tuple. + // + PyObject* to_python(const MillerIndex& hkl) + { + python::tuple result(3); + for (int i = 0; i < 3; i++) + result.set_item(i, python::ref(to_python(hkl.v[i]))); + return result.reference().release(); + } + +BOOST_PYTHON_END_CONVERSION_NAMESPACE + +BOOST_PYTHON_MODULE_INIT(do_it_yourself_converters) +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("do_it_yourself_converters"); + + // Create the Python type object for our extension class. + python::class_builder ixset_class(this_module, "IndexingSet"); + + // Add the __init__ function. + ixset_class.def(python::constructor<>()); + // Add the member functions. + ixset_class.def(&IndexingSet::add, "add"); + ixset_class.def(&IndexingSet::get, "get"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/dvect.cpp b/example/dvect.cpp new file mode 100644 index 00000000..da6b35a3 --- /dev/null +++ b/example/dvect.cpp @@ -0,0 +1,45 @@ +// Example by Ralf W. Grosse-Kunstleve +// See root/libs/python/doc/cross_module.html for an introduction. + +#include "dvect.h" +#include "ivect.h" +#include +namespace python = boost::python; + +namespace { + +# include "dvect_conversions.cpp" +# include "ivect_conversions.cpp" + + vects::ivect dvect_as_ivect(const vects::dvect& dv) + { + vects::ivect iv(dv.size()); + vects::ivect::iterator iviter = iv.begin(); + for (int i = 0; i < dv.size(); i++) iviter[i] = static_cast(dv[i]); + return iv; + } +} + +BOOST_PYTHON_MODULE_INIT(dvect) +{ + try + { + python::module_builder this_module("dvect"); + + python::class_builder dvect_class(this_module, "dvect"); + python::export_converters(dvect_class); + + python::import_converters ivect_converters("ivect", "ivect"); + + dvect_class.def(python::constructor()); + dvect_class.def(&vects::dvect::as_tuple, "as_tuple"); + dvect_class.def(dvect_as_ivect, "as_ivect"); + +# include "dvect_defs.cpp" +# include "ivect_defs.cpp" + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/ivect.cpp b/example/ivect.cpp new file mode 100644 index 00000000..db1c0ec3 --- /dev/null +++ b/example/ivect.cpp @@ -0,0 +1,45 @@ +// Example by Ralf W. Grosse-Kunstleve +// See root/libs/python/doc/cross_module.html for an introduction. + +#include "dvect.h" +#include "ivect.h" +#include +namespace python = boost::python; + +namespace { + +# include "dvect_conversions.cpp" +# include "ivect_conversions.cpp" + + vects::dvect ivect_as_dvect(const vects::ivect& iv) + { + vects::dvect dv(iv.size()); + vects::dvect::iterator dviter = dv.begin(); + for (int i = 0; i < iv.size(); i++) dviter[i] = static_cast(iv[i]); + return dv; + } +} + +BOOST_PYTHON_MODULE_INIT(ivect) +{ + try + { + python::module_builder this_module("ivect"); + + python::class_builder ivect_class(this_module, "ivect"); + python::export_converters(ivect_class); + + python::import_converters dvect_converters("dvect", "dvect"); + + ivect_class.def(python::constructor()); + ivect_class.def(&vects::ivect::as_tuple, "as_tuple"); + ivect_class.def(ivect_as_dvect, "as_dvect"); + +# include "dvect_defs.cpp" +# include "ivect_defs.cpp" + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/noncopyable_export.cpp b/example/noncopyable_export.cpp new file mode 100644 index 00000000..794b1200 --- /dev/null +++ b/example/noncopyable_export.cpp @@ -0,0 +1,25 @@ +// Example by Ralf W. Grosse-Kunstleve +// See root/libs/python/doc/cross_module.html for an introduction. + +#include +namespace python = boost::python; + +#include "noncopyable.h" + +BOOST_PYTHON_MODULE_INIT(noncopyable_export) +{ + try + { + python::module_builder this_module("noncopyable_export"); + + python::class_builder store_class(this_module, "store"); + python::export_converters_noncopyable(store_class); + + store_class.def(python::constructor()); + store_class.def(&store::recall, "recall"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/noncopyable_import.cpp b/example/noncopyable_import.cpp new file mode 100644 index 00000000..ea2477be --- /dev/null +++ b/example/noncopyable_import.cpp @@ -0,0 +1,42 @@ +// Example by Ralf W. Grosse-Kunstleve +// See root/libs/python/doc/cross_module.html for an introduction. + +#include +namespace python = boost::python; + +#include "noncopyable.h" + +namespace { // Avoid cluttering the global namespace. + + // A function with store objects as both input and output parameters. + // Because the copy constructor is disabled, we cannot pass a store + // object by value. Instead, we pass a smart pointer. + std::auto_ptr add_stores(const store& s1, const store& s2) + { + int sum = s1.recall() + s2.recall(); + std::auto_ptr ss = std::auto_ptr(new store(sum)); + return ss; + } +} + +BOOST_PYTHON_MODULE_INIT(noncopyable_import) +{ + try + { + python::module_builder this_module("noncopyable_import"); + + python::import_converters + dvect_converters("noncopyable_export", "store"); + + // Imagine all the additional classes with member functions + // that have store objects as input and output parameters. + // Lots and lots of them. + // However, to keep this example simple, we only define a + // module-level function. + this_module.def(add_stores, "add_stores"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/pickle1.cpp b/example/pickle1.cpp new file mode 100644 index 00000000..cdd78989 --- /dev/null +++ b/example/pickle1.cpp @@ -0,0 +1,64 @@ +// Example by Ralf W. Grosse-Kunstleve + +/* + This example shows how to make an Extension Class "pickleable". + + The world class below can be fully restored by passing the + appropriate argument to the constructor. Therefore it is sufficient + to define the pickle interface method __getinitargs__. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include + +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class world + { + private: + std::string country; + int secret_number; + public: + world(const std::string& country) : secret_number(0) { + this->country = country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + }; + + // Support for pickle. + python::ref world_getinitargs(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_country()); + return result.reference(); + } +} + +BOOST_PYTHON_MODULE_INIT(pickle1) +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("pickle1"); + + // Create the Python type object for our extension class. + python::class_builder world_class(this_module, "world"); + + // Add the __init__ function. + world_class.def(python::constructor()); + // Add a regular member function. + world_class.def(&world::greet, "greet"); + + // Support for pickle. + world_class.def(world_getinitargs, "__getinitargs__"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/pickle2.cpp b/example/pickle2.cpp new file mode 100644 index 00000000..d6aa3201 --- /dev/null +++ b/example/pickle2.cpp @@ -0,0 +1,100 @@ +// Example by Ralf W. Grosse-Kunstleve + +/* + This example shows how to make an Extension Class "pickleable". + + The world class below contains member data (secret_number) that + cannot be restored by any of the constructors. Therefore it is + necessary to provide the __getstate__/__setstate__ pair of pickle + interface methods. + + For simplicity, the __dict__ is not included in the result of + __getstate__. This is not generally recommended, but a valid + approach if it is anticipated that the object's __dict__ will + always be empty. Note that safety guard are provided to catch the + cases where this assumption is not true. + + pickle3.cpp shows how to include the object's __dict__ in the + result of __getstate__. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include + +#include +namespace python = boost::python; + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class world + { + public: + world(const std::string& country) : secret_number(0) { + this->country = country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + void set_secret_number(int number) { secret_number = number; } + int get_secret_number() const { return secret_number; } + private: + std::string country; + int secret_number; + }; + + // Support for pickle. + + using BOOST_PYTHON_CONVERSION::from_python; + + python::ref world_getinitargs(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_country()); + return result.reference(); // returning the reference avoids the copying. + } + + python::ref world_getstate(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_secret_number()); + return result.reference(); // returning the reference avoids the copying. + } + + void world_setstate(world& w, python::tuple state) { + if (state.size() != 1) { + PyErr_SetString(PyExc_ValueError, + "Unexpected argument in call to __setstate__."); + throw python::error_already_set(); + } + int number = from_python(state[0].get(), python::type()); + if (number != 42) + w.set_secret_number(number); + } +} + +BOOST_PYTHON_MODULE_INIT(pickle2) +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("pickle2"); + + // Create the Python type object for our extension class. + python::class_builder world_class(this_module, "world"); + + // Add the __init__ function. + world_class.def(python::constructor()); + // Add a regular member function. + world_class.def(&world::greet, "greet"); + world_class.def(&world::get_secret_number, "get_secret_number"); + world_class.def(&world::set_secret_number, "set_secret_number"); + + // Support for pickle. + world_class.def(world_getinitargs, "__getinitargs__"); + world_class.def(world_getstate, "__getstate__"); + world_class.def(world_setstate, "__setstate__"); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} diff --git a/example/pickle3.cpp b/example/pickle3.cpp new file mode 100644 index 00000000..bfa7dc54 --- /dev/null +++ b/example/pickle3.cpp @@ -0,0 +1,150 @@ +// Example by Ralf W. Grosse-Kunstleve + +/* + This example shows how to make an Extension Class "pickleable". + + The world class below contains member data (secret_number) that + cannot be restored by any of the constructors. Therefore it is + necessary to provide the __getstate__/__setstate__ pair of pickle + interface methods. + + The object's __dict__ is included in the result of __getstate__. + This requires more code (compare with pickle2.cpp), but is + unavoidable if the object's __dict__ is not always empty. + + For more information refer to boost/libs/python/doc/pickle.html. + */ + +#include + +#include +namespace python = boost::python; + +namespace boost { namespace python { + + ref getattr(PyObject* o, const std::string& attr_name) { + return ref(PyObject_GetAttrString(o, const_cast(attr_name.c_str()))); + } + ref getattr(const ref& r, const std::string& attr_name) { + return getattr(r.get(), attr_name); + } + +}} + +namespace { // Avoid cluttering the global namespace. + + // A friendly class. + class world + { + public: + world(const std::string& country) : secret_number(0) { + this->country = country; + } + std::string greet() const { return "Hello from " + country + "!"; } + std::string get_country() const { return country; } + void set_secret_number(int number) { secret_number = number; } + int get_secret_number() const { return secret_number; } + private: + std::string country; + int secret_number; + }; + + // Support for pickle. + python::ref world_getinitargs(const world& w) { + python::tuple result(1); + result.set_item(0, w.get_country()); + return result.reference(); // returning the reference avoids the copying. + } + + python::ref world_getstate(python::tuple const & args, + python::dictionary const & keywords); + + PyObject* world_setstate(python::tuple const & args, + python::dictionary const & keywords); +} + +BOOST_PYTHON_MODULE_INIT(pickle3) +{ + try + { + // Create an object representing this extension module. + python::module_builder this_module("pickle3"); + + // Create the Python type object for our extension class. + python::class_builder world_class(this_module, "world"); + + // Add the __init__ function. + world_class.def(python::constructor()); + // Add a regular member function. + world_class.def(&world::greet, "greet"); + world_class.def(&world::get_secret_number, "get_secret_number"); + world_class.def(&world::set_secret_number, "set_secret_number"); + + // Support for pickle. + world_class.def(world_getinitargs, "__getinitargs__"); + world_class.def_raw(world_getstate, "__getstate__"); + world_class.def_raw(world_setstate, "__setstate__"); + world_class.getstate_manages_dict(); + } + catch(...) + { + python::handle_exception(); // Deal with the exception for Python + } +} + +namespace { + + using BOOST_PYTHON_CONVERSION::from_python; + using boost::python::type; + using boost::python::ref; + using boost::python::tuple; + using boost::python::list; + using boost::python::dictionary; + using boost::python::getattr; + + ref world_getstate(tuple const & args, dictionary const & keywords) + { + if(args.size() != 1 || keywords.size() != 0) { + PyErr_SetString(PyExc_TypeError, "wrong number of arguments"); + throw boost::python::argument_error(); + } + const world& w = from_python(args[0].get(), type()); + ref mydict = getattr(args[0], "__dict__"); + tuple result(2); + // store the object's __dict__ + result.set_item(0, mydict); + // store the internal state of the C++ object + result.set_item(1, w.get_secret_number()); + return result.reference(); // returning the reference avoids the copying. + } + + PyObject* world_setstate(tuple const & args, dictionary const & keywords) + { + if(args.size() != 2 || keywords.size() != 0) { + PyErr_SetString(PyExc_TypeError, "wrong number of arguments"); + throw boost::python::argument_error(); + } + world& w = from_python(args[0].get(), type()); + ref mydict = getattr(args[0], "__dict__"); + tuple state = from_python(args[1].get(), type()); + if (state.size() != 2) { + PyErr_SetString(PyExc_ValueError, + "Unexpected argument in call to __setstate__."); + throw python::error_already_set(); + } + // restore the object's __dict__ + dictionary odict = from_python(mydict.get(), type()); + const dictionary& pdict = from_python(state[0].get(), type()); + list pkeys(pdict.keys()); + for (int i = 0; i < pkeys.size(); i++) { + ref k(pkeys[i]); + //odict[k] = pdict[k]; // XXX memory leak! + odict[k] = pdict.get_item(k); // this does not leak. + } + // restore the internal state of the C++ object + int number = from_python(state[1].get(), type()); + if (number != 42) + w.set_secret_number(number); + return python::detail::none(); + } +} diff --git a/example/tst_dvect1.py b/example/tst_dvect1.py new file mode 100644 index 00000000..22315528 --- /dev/null +++ b/example/tst_dvect1.py @@ -0,0 +1,20 @@ +def f(): + import dvect + dv = dvect.dvect((1,2,3,4,5)) + print dv.as_tuple() + iv = dv.as_ivect() + print iv.as_tuple() + print dvect.const_ivect_reference_as_tuple(iv) + aiv = dvect.ivect_as_auto_ptr(iv) + print dvect.const_ivect_reference_as_tuple(aiv) + siv = dvect.ivect_as_shared_ptr(iv) + print dvect.const_ivect_reference_as_tuple(siv) + print aiv.as_tuple() + print siv.as_tuple() + +if (__name__ == "__main__"): + import sys, string + n = 1 + if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) + for i in xrange(n): + f() diff --git a/example/tst_ivect1.py b/example/tst_ivect1.py new file mode 100644 index 00000000..7369fdbf --- /dev/null +++ b/example/tst_ivect1.py @@ -0,0 +1,20 @@ +def f(): + import ivect + iv = ivect.ivect((1,2,3,4,5)) + print iv.as_tuple() + dv = iv.as_dvect() + print dv.as_tuple() + print ivect.const_dvect_reference_as_tuple(dv) + adv = ivect.dvect_as_auto_ptr(dv) + print ivect.const_dvect_reference_as_tuple(adv) + sdv = ivect.dvect_as_shared_ptr(dv) + print ivect.const_dvect_reference_as_tuple(sdv) + print adv.as_tuple() + print sdv.as_tuple() + +if (__name__ == "__main__"): + import sys, string + n = 1 + if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) + for i in xrange(n): + f() diff --git a/example/tst_noncopyable.py b/example/tst_noncopyable.py new file mode 100644 index 00000000..155910a5 --- /dev/null +++ b/example/tst_noncopyable.py @@ -0,0 +1,16 @@ +def f(): + import noncopyable_export + import noncopyable_import + s1 = noncopyable_export.store(1) + print s1.recall() + s2 = noncopyable_export.store(2) + print s2.recall() + s3 = noncopyable_import.add_stores(s1, s2) + print s3.recall() + +if (__name__ == "__main__"): + import sys, string + n = 1 + if (len(sys.argv) > 1): n = string.atoi(sys.argv[1]) + for i in xrange(n): + f() From 349b9bb2bf2f5dbc9b2365752b4d516d4ed62147 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 18 Apr 2001 19:13:11 +0000 Subject: [PATCH 132/154] use reserved symbol for detecting sgi [SVN r9835] --- test/comprehensive.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/comprehensive.cpp b/test/comprehensive.cpp index aa2d9886..410bd243 100644 --- a/test/comprehensive.cpp +++ b/test/comprehensive.cpp @@ -15,7 +15,7 @@ #include // for pow() #include -#if defined(sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 +#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 inline double pow(int x, int y) { return pow(static_cast(x), y); } #endif From fb8d9edfdfda1999bffd73c3e3dcb9cd626a039b Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Wed, 25 Apr 2001 00:24:50 +0000 Subject: [PATCH 133/154] Change all eGroups references to YahooGroups [SVN r9979] --- doc/index.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/index.html b/doc/index.html index 5ec32a6b..f636e7a8 100644 --- a/doc/index.html +++ b/doc/index.html @@ -1,6 +1,5 @@ - The Boost Python Library (Boost.Python) @@ -154,7 +153,7 @@ among others.

      Questions should be directed to the boost mailing list. + "http://www.yahoogroups.com/list/boost">the boost mailing list.

      © Copyright David Abrahams 2001. Permission to copy, use, modify, From 00b4f09e8abc953f106663bf316bad837af4ec82 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 5 May 2001 01:06:33 +0000 Subject: [PATCH 134/154] Check indices passed to __getitem__, __setitem__, __delitem__ [SVN r10009] --- build/irix_CC.mak | 2 +- example/simple_vector.cpp | 8 ++++++++ example/test_simple_vector.py | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/build/irix_CC.mak b/build/irix_CC.mak index 5894ff51..0436ef8a 100644 --- a/build/irix_CC.mak +++ b/build/irix_CC.mak @@ -24,7 +24,7 @@ PYINC=-I/usr/local/Python-1.5.2/include/python1.5 STLPORTINC=-I$(BOOST)/boost/compatibility/cpp_c_headers STDOPTS= -WARNOPTS=-woff 1001,1234,1682 +WARNOPTS=-woff 1001,1183,1234,1682 OPTOPTS=-g CPP=CC -LANG:std -n32 -mips4 diff --git a/example/simple_vector.cpp b/example/simple_vector.cpp index 5ac0767b..8f30121b 100644 --- a/example/simple_vector.cpp +++ b/example/simple_vector.cpp @@ -30,16 +30,24 @@ namespace { // Avoid cluttering the global namespace. } }; + void raise_vector_IndexError() { + PyErr_SetString(PyExc_IndexError, "IndexError: vector index out of range"); + throw python::error_already_set(); + } + double getitem(const std::vector& vd, std::size_t key) { + if (key < 0 || key >= vd.size()) raise_vector_IndexError(); return vd[key]; } void setitem(std::vector& vd, std::size_t key, double d) { + if (key < 0 || key >= vd.size()) raise_vector_IndexError(); std::vector::iterator vditer = vd.begin(); vditer[key] = d; } void delitem(std::vector& vd, std::size_t key) { + if (key < 0 || key >= vd.size()) raise_vector_IndexError(); std::vector::iterator vditer = vd.begin(); vd.erase(&vditer[key]); } diff --git a/example/test_simple_vector.py b/example/test_simple_vector.py index a19e205b..ca38d715 100644 --- a/example/test_simple_vector.py +++ b/example/test_simple_vector.py @@ -15,6 +15,11 @@ r'''>>> import simple_vector >>> v[1] = 40 >>> print v.as_tuple() (3.0, 40.0, 5.0) + >>> for e in v: + ... print e + 3.0 + 40.0 + 5.0 >>> del v[1] >>> print v.as_tuple() (3.0, 5.0) From 25320cd0e02bb14b058fa51fc2e2bc6e29000435 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 14 May 2001 21:43:34 +0000 Subject: [PATCH 135/154] Removed: unnecessary key < 0 test. [SVN r10113] --- build/irix_CC.mak | 2 +- example/simple_vector.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/irix_CC.mak b/build/irix_CC.mak index 0436ef8a..5894ff51 100644 --- a/build/irix_CC.mak +++ b/build/irix_CC.mak @@ -24,7 +24,7 @@ PYINC=-I/usr/local/Python-1.5.2/include/python1.5 STLPORTINC=-I$(BOOST)/boost/compatibility/cpp_c_headers STDOPTS= -WARNOPTS=-woff 1001,1183,1234,1682 +WARNOPTS=-woff 1001,1234,1682 OPTOPTS=-g CPP=CC -LANG:std -n32 -mips4 diff --git a/example/simple_vector.cpp b/example/simple_vector.cpp index 8f30121b..2b3aa290 100644 --- a/example/simple_vector.cpp +++ b/example/simple_vector.cpp @@ -31,23 +31,23 @@ namespace { // Avoid cluttering the global namespace. }; void raise_vector_IndexError() { - PyErr_SetString(PyExc_IndexError, "IndexError: vector index out of range"); + PyErr_SetString(PyExc_IndexError, "vector index out of range"); throw python::error_already_set(); } double getitem(const std::vector& vd, std::size_t key) { - if (key < 0 || key >= vd.size()) raise_vector_IndexError(); + if (key >= vd.size()) raise_vector_IndexError(); return vd[key]; } void setitem(std::vector& vd, std::size_t key, double d) { - if (key < 0 || key >= vd.size()) raise_vector_IndexError(); + if (key >= vd.size()) raise_vector_IndexError(); std::vector::iterator vditer = vd.begin(); vditer[key] = d; } void delitem(std::vector& vd, std::size_t key) { - if (key < 0 || key >= vd.size()) raise_vector_IndexError(); + if (key >= vd.size()) raise_vector_IndexError(); std::vector::iterator vditer = vd.begin(); vd.erase(&vditer[key]); } From d04f613c419c0b726d6f5d28b5e48d9ee3dff4e4 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Fri, 18 May 2001 15:12:30 +0000 Subject: [PATCH 136/154] Fix up internal links [SVN r10122] --- doc/overriding.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/overriding.html b/doc/overriding.html index af458d79..02665be5 100644 --- a/doc/overriding.html +++ b/doc/overriding.html @@ -47,17 +47,17 @@ class hello PyObject* argument. The initial argument should be stored in the self data member described above. -

    • If the class being wrapped is ever returned by +
    • If the class being wrapped is ever returned by value from a wrapped function, be sure you do the same for the T's copy constructor: you'll need a constructor taking arguments (PyObject*, const T&). -
    • An implementation of each virtual function you may +
    • An implementation of each virtual function you may wish to override in Python which uses callback<return-type>::call_method(self, "name", args...) to call the Python override. -
    • For each non-pure virtual function meant to be +
    • For each non-pure virtual function meant to be overridable from Python, a static member function (or a free function) taking a reference or pointer to the T as the first parameter and which forwards any additional parameters neccessary to the default @@ -211,5 +211,5 @@ href="http://cs.calvin.edu/c++/C++Standard-Nov97/basic.html#basic.def.odr">ODR - Updated: Mar 6, 2001 + Updated: Mar 21, 2001 From 188597ecaf2968d6811d0272dc4cbc09e8d77023 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 24 May 2001 08:28:46 +0000 Subject: [PATCH 137/154] fixes tested with vc60, tru64cxx, irixCC, gcc2952 [SVN r10208] --- include/boost/python/callback.hpp | 440 ++++++++++++------------- include/boost/python/caller.hpp | 68 ++-- include/boost/python/detail/config.hpp | 23 +- 3 files changed, 264 insertions(+), 267 deletions(-) diff --git a/include/boost/python/callback.hpp b/include/boost/python/callback.hpp index 7240b5b7..b9e850c6 100644 --- a/include/boost/python/callback.hpp +++ b/include/boost/python/callback.hpp @@ -46,7 +46,7 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1) { - ref p1(to_python(a1)); + ref p1(to_python(search_namespace, a1)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(O)"), p1.get())); @@ -57,7 +57,7 @@ struct callback template static R call(PyObject* self, const A1& a1) { - ref p1(to_python(a1)); + ref p1(to_python(search_namespace, a1)); ref result(PyEval_CallFunction(self, const_cast("(O)"), p1.get())); detail::callback_adjust_refcount(result.get(), type()); @@ -67,8 +67,8 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OO)"), p1.get(), @@ -80,8 +80,8 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); ref result(PyEval_CallFunction(self, const_cast("(OO)"), p1.get(), p2.get())); @@ -92,9 +92,9 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOO)"), p1.get(), @@ -107,9 +107,9 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); ref result(PyEval_CallFunction(self, const_cast("(OOO)"), p1.get(), p2.get(), @@ -121,10 +121,10 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOO)"), p1.get(), @@ -138,10 +138,10 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); ref result(PyEval_CallFunction(self, const_cast("(OOOO)"), p1.get(), p2.get(), @@ -154,11 +154,11 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOO)"), p1.get(), @@ -173,11 +173,11 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); ref result(PyEval_CallFunction(self, const_cast("(OOOOO)"), p1.get(), p2.get(), @@ -191,12 +191,12 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOO)"), p1.get(), @@ -212,12 +212,12 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOO)"), p1.get(), p2.get(), @@ -232,13 +232,13 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOO)"), p1.get(), @@ -255,13 +255,13 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOO)"), p1.get(), p2.get(), @@ -277,14 +277,14 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); - ref p8(to_python(a8)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); + ref p8(to_python(search_namespace, a8)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOOO)"), p1.get(), @@ -302,14 +302,14 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); - ref p8(to_python(a8)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); + ref p8(to_python(search_namespace, a8)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOO)"), p1.get(), p2.get(), @@ -326,15 +326,15 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); - ref p8(to_python(a8)); - ref p9(to_python(a9)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); + ref p8(to_python(search_namespace, a8)); + ref p9(to_python(search_namespace, a9)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOOOO)"), p1.get(), @@ -353,15 +353,15 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); - ref p8(to_python(a8)); - ref p9(to_python(a9)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); + ref p8(to_python(search_namespace, a8)); + ref p9(to_python(search_namespace, a9)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOOO)"), p1.get(), p2.get(), @@ -379,16 +379,16 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); - ref p8(to_python(a8)); - ref p9(to_python(a9)); - ref p10(to_python(a10)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); + ref p8(to_python(search_namespace, a8)); + ref p9(to_python(search_namespace, a9)); + ref p10(to_python(search_namespace, a10)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOOOOO)"), p1.get(), @@ -408,16 +408,16 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); - ref p8(to_python(a8)); - ref p9(to_python(a9)); - ref p10(to_python(a10)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); + ref p8(to_python(search_namespace, a8)); + ref p9(to_python(search_namespace, a9)); + ref p10(to_python(search_namespace, a10)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOOOO)"), p1.get(), p2.get(), @@ -455,7 +455,7 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1) { - ref p1(to_python(a1)); + ref p1(to_python(search_namespace, a1)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(O)"), p1.get())); @@ -464,7 +464,7 @@ struct callback template static void call(PyObject* self, const A1& a1) { - ref p1(to_python(a1)); + ref p1(to_python(search_namespace, a1)); ref result(PyEval_CallFunction(self, const_cast("(O)"), p1.get())); } @@ -472,8 +472,8 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OO)"), p1.get(), @@ -483,8 +483,8 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); ref result(PyEval_CallFunction(self, const_cast("(OO)"), p1.get(), p2.get())); @@ -493,9 +493,9 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOO)"), p1.get(), @@ -506,9 +506,9 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); ref result(PyEval_CallFunction(self, const_cast("(OOO)"), p1.get(), p2.get(), @@ -518,10 +518,10 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOO)"), p1.get(), @@ -533,10 +533,10 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); ref result(PyEval_CallFunction(self, const_cast("(OOOO)"), p1.get(), p2.get(), @@ -547,11 +547,11 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOO)"), p1.get(), @@ -564,11 +564,11 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); ref result(PyEval_CallFunction(self, const_cast("(OOOOO)"), p1.get(), p2.get(), @@ -580,12 +580,12 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOO)"), p1.get(), @@ -599,12 +599,12 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOO)"), p1.get(), p2.get(), @@ -617,13 +617,13 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOO)"), p1.get(), @@ -638,13 +638,13 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOO)"), p1.get(), p2.get(), @@ -658,14 +658,14 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); - ref p8(to_python(a8)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); + ref p8(to_python(search_namespace, a8)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOOO)"), p1.get(), @@ -681,14 +681,14 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); - ref p8(to_python(a8)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); + ref p8(to_python(search_namespace, a8)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOO)"), p1.get(), p2.get(), @@ -703,15 +703,15 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); - ref p8(to_python(a8)); - ref p9(to_python(a9)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); + ref p8(to_python(search_namespace, a8)); + ref p9(to_python(search_namespace, a9)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOOOO)"), p1.get(), @@ -728,15 +728,15 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); - ref p8(to_python(a8)); - ref p9(to_python(a9)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); + ref p8(to_python(search_namespace, a8)); + ref p9(to_python(search_namespace, a9)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOOO)"), p1.get(), p2.get(), @@ -752,16 +752,16 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); - ref p8(to_python(a8)); - ref p9(to_python(a9)); - ref p10(to_python(a10)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); + ref p8(to_python(search_namespace, a8)); + ref p9(to_python(search_namespace, a9)); + ref p10(to_python(search_namespace, a10)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOOOOO)"), p1.get(), @@ -779,16 +779,16 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) { - ref p1(to_python(a1)); - ref p2(to_python(a2)); - ref p3(to_python(a3)); - ref p4(to_python(a4)); - ref p5(to_python(a5)); - ref p6(to_python(a6)); - ref p7(to_python(a7)); - ref p8(to_python(a8)); - ref p9(to_python(a9)); - ref p10(to_python(a10)); + ref p1(to_python(search_namespace, a1)); + ref p2(to_python(search_namespace, a2)); + ref p3(to_python(search_namespace, a3)); + ref p4(to_python(search_namespace, a4)); + ref p5(to_python(search_namespace, a5)); + ref p6(to_python(search_namespace, a6)); + ref p7(to_python(search_namespace, a7)); + ref p8(to_python(search_namespace, a8)); + ref p9(to_python(search_namespace, a9)); + ref p10(to_python(search_namespace, a10)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOOOO)"), p1.get(), p2.get(), diff --git a/include/boost/python/caller.hpp b/include/boost/python/caller.hpp index 35b2d618..86820233 100644 --- a/include/boost/python/caller.hpp +++ b/include/boost/python/caller.hpp @@ -30,7 +30,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("O"), &self)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)()); + return to_python(search_namespace, (target.*pmf)()); } template @@ -40,7 +40,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OO"), &self, &a1)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()))); + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()))); } template @@ -51,7 +51,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOO"), &self, &a1, &a2)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()))); } @@ -64,7 +64,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOO"), &self, &a1, &a2, &a3)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()))); } @@ -79,7 +79,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOO"), &self, &a1, &a2, &a3, &a4)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()))); @@ -96,7 +96,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &self, &a1, &a2, &a3, &a4, &a5)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -115,7 +115,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -136,7 +136,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -159,7 +159,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -184,7 +184,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -211,7 +211,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -230,7 +230,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("O"), &self)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)()); + return to_python(search_namespace, (target.*pmf)()); } template @@ -240,7 +240,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OO"), &self, &a1)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()))); + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()))); } template @@ -251,7 +251,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOO"), &self, &a1, &a2)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()))); } @@ -264,7 +264,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOO"), &self, &a1, &a2, &a3)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()))); } @@ -279,7 +279,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOO"), &self, &a1, &a2, &a3, &a4)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()))); @@ -296,7 +296,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &self, &a1, &a2, &a3, &a4, &a5)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -315,7 +315,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -336,7 +336,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -359,7 +359,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -384,7 +384,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -411,7 +411,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) return 0; T& target = from_python(self, type()); - return to_python((target.*pmf)(from_python(a1, type()), + return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -427,7 +427,7 @@ struct caller static PyObject* call(R (*f)(), PyObject* args, PyObject* /* keywords */ ) { if (!PyArg_ParseTuple(args, const_cast(""))) return 0; - return to_python(f()); + return to_python(search_namespace, f()); } template @@ -435,7 +435,7 @@ struct caller PyObject* a1; if (!PyArg_ParseTuple(args, const_cast("O"), &a1)) return 0; - return to_python(f(from_python(a1, type()))); + return to_python(search_namespace, f(from_python(a1, type()))); } template @@ -444,7 +444,7 @@ struct caller PyObject* a2; if (!PyArg_ParseTuple(args, const_cast("OO"), &a1, &a2)) return 0; - return to_python(f(from_python(a1, type()), + return to_python(search_namespace, f(from_python(a1, type()), from_python(a2, type()))); } @@ -455,7 +455,7 @@ struct caller PyObject* a3; if (!PyArg_ParseTuple(args, const_cast("OOO"), &a1, &a2, &a3)) return 0; - return to_python(f(from_python(a1, type()), + return to_python(search_namespace, f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()))); } @@ -468,7 +468,7 @@ struct caller PyObject* a4; if (!PyArg_ParseTuple(args, const_cast("OOOO"), &a1, &a2, &a3, &a4)) return 0; - return to_python(f(from_python(a1, type()), + return to_python(search_namespace, f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()))); @@ -483,7 +483,7 @@ struct caller PyObject* a5; if (!PyArg_ParseTuple(args, const_cast("OOOOO"), &a1, &a2, &a3, &a4, &a5)) return 0; - return to_python(f(from_python(a1, type()), + return to_python(search_namespace, f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -500,7 +500,7 @@ struct caller PyObject* a6; if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6)) return 0; - return to_python(f(from_python(a1, type()), + return to_python(search_namespace, f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -519,7 +519,7 @@ struct caller PyObject* a7; if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7)) return 0; - return to_python(f(from_python(a1, type()), + return to_python(search_namespace, f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -540,7 +540,7 @@ struct caller PyObject* a8; if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) return 0; - return to_python(f(from_python(a1, type()), + return to_python(search_namespace, f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -563,7 +563,7 @@ struct caller PyObject* a9; if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) return 0; - return to_python(f(from_python(a1, type()), + return to_python(search_namespace, f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -588,7 +588,7 @@ struct caller PyObject* a10; if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) return 0; - return to_python(f(from_python(a1, type()), + return to_python(search_namespace, f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -615,7 +615,7 @@ struct caller PyObject* a11; if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10, &a11)) return 0; - return to_python(f(from_python(a1, type()), + return to_python(search_namespace, f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), diff --git a/include/boost/python/detail/config.hpp b/include/boost/python/detail/config.hpp index 9792695e..348bcc39 100644 --- a/include/boost/python/detail/config.hpp +++ b/include/boost/python/detail/config.hpp @@ -15,19 +15,6 @@ # include # include -# ifdef BOOST_NO_OPERATORS_IN_NAMESPACE - // A gcc bug forces some symbols into the global namespace -# define BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE -# define BOOST_PYTHON_END_CONVERSION_NAMESPACE -# define BOOST_PYTHON_CONVERSION -# define BOOST_PYTHON_IMPORT_CONVERSION(x) using ::x -# else -# define BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE namespace boost { namespace python { -# define BOOST_PYTHON_END_CONVERSION_NAMESPACE }} // namespace boost::python -# define BOOST_PYTHON_CONVERSION boost::python -# define BOOST_PYTHON_IMPORT_CONVERSION(x) void never_defined() // so we can follow the macro with a ';' -# endif - # if defined(BOOST_MSVC) # if _MSC_VER <= 1200 # define BOOST_MSVC6_OR_EARLIER 1 @@ -37,6 +24,16 @@ # endif +# if defined(BOOST_PYTHON_USE_FRIEND_KOENIG_LOOKUP) +// for compilers that support Koenig lookup +# define BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE namespace boost { namespace python { +# define BOOST_PYTHON_END_CONVERSION_NAMESPACE }} // namespace boost::python +# else +// for compilers that do not support Koenig lookup for friend functions +# define BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE +# define BOOST_PYTHON_END_CONVERSION_NAMESPACE +# endif + // Work around the broken library implementation/strict ansi checking on some // EDG-based compilers (e.g. alpha), which incorrectly warn that the result of // offsetof() is not an integer constant expression. From 294254efbb4539e93fb86249e7c92a5377191b88 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 24 May 2001 08:43:56 +0000 Subject: [PATCH 138/154] Fix accident: restore main version. [SVN r10209] --- include/boost/python/callback.hpp | 440 +++++++++++++++--------------- include/boost/python/caller.hpp | 68 ++--- 2 files changed, 254 insertions(+), 254 deletions(-) diff --git a/include/boost/python/callback.hpp b/include/boost/python/callback.hpp index b9e850c6..7240b5b7 100644 --- a/include/boost/python/callback.hpp +++ b/include/boost/python/callback.hpp @@ -46,7 +46,7 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1) { - ref p1(to_python(search_namespace, a1)); + ref p1(to_python(a1)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(O)"), p1.get())); @@ -57,7 +57,7 @@ struct callback template static R call(PyObject* self, const A1& a1) { - ref p1(to_python(search_namespace, a1)); + ref p1(to_python(a1)); ref result(PyEval_CallFunction(self, const_cast("(O)"), p1.get())); detail::callback_adjust_refcount(result.get(), type()); @@ -67,8 +67,8 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OO)"), p1.get(), @@ -80,8 +80,8 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); ref result(PyEval_CallFunction(self, const_cast("(OO)"), p1.get(), p2.get())); @@ -92,9 +92,9 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOO)"), p1.get(), @@ -107,9 +107,9 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); ref result(PyEval_CallFunction(self, const_cast("(OOO)"), p1.get(), p2.get(), @@ -121,10 +121,10 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOO)"), p1.get(), @@ -138,10 +138,10 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); ref result(PyEval_CallFunction(self, const_cast("(OOOO)"), p1.get(), p2.get(), @@ -154,11 +154,11 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOO)"), p1.get(), @@ -173,11 +173,11 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); ref result(PyEval_CallFunction(self, const_cast("(OOOOO)"), p1.get(), p2.get(), @@ -191,12 +191,12 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOO)"), p1.get(), @@ -212,12 +212,12 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOO)"), p1.get(), p2.get(), @@ -232,13 +232,13 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOO)"), p1.get(), @@ -255,13 +255,13 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOO)"), p1.get(), p2.get(), @@ -277,14 +277,14 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); - ref p8(to_python(search_namespace, a8)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOOO)"), p1.get(), @@ -302,14 +302,14 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); - ref p8(to_python(search_namespace, a8)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOO)"), p1.get(), p2.get(), @@ -326,15 +326,15 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); - ref p8(to_python(search_namespace, a8)); - ref p9(to_python(search_namespace, a9)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOOOO)"), p1.get(), @@ -353,15 +353,15 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); - ref p8(to_python(search_namespace, a8)); - ref p9(to_python(search_namespace, a9)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOOO)"), p1.get(), p2.get(), @@ -379,16 +379,16 @@ struct callback template static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); - ref p8(to_python(search_namespace, a8)); - ref p9(to_python(search_namespace, a9)); - ref p10(to_python(search_namespace, a10)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); + ref p10(to_python(a10)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOOOOO)"), p1.get(), @@ -408,16 +408,16 @@ struct callback template static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); - ref p8(to_python(search_namespace, a8)); - ref p9(to_python(search_namespace, a9)); - ref p10(to_python(search_namespace, a10)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); + ref p10(to_python(a10)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOOOO)"), p1.get(), p2.get(), @@ -455,7 +455,7 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1) { - ref p1(to_python(search_namespace, a1)); + ref p1(to_python(a1)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(O)"), p1.get())); @@ -464,7 +464,7 @@ struct callback template static void call(PyObject* self, const A1& a1) { - ref p1(to_python(search_namespace, a1)); + ref p1(to_python(a1)); ref result(PyEval_CallFunction(self, const_cast("(O)"), p1.get())); } @@ -472,8 +472,8 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OO)"), p1.get(), @@ -483,8 +483,8 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); ref result(PyEval_CallFunction(self, const_cast("(OO)"), p1.get(), p2.get())); @@ -493,9 +493,9 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOO)"), p1.get(), @@ -506,9 +506,9 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); ref result(PyEval_CallFunction(self, const_cast("(OOO)"), p1.get(), p2.get(), @@ -518,10 +518,10 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOO)"), p1.get(), @@ -533,10 +533,10 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); ref result(PyEval_CallFunction(self, const_cast("(OOOO)"), p1.get(), p2.get(), @@ -547,11 +547,11 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOO)"), p1.get(), @@ -564,11 +564,11 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); ref result(PyEval_CallFunction(self, const_cast("(OOOOO)"), p1.get(), p2.get(), @@ -580,12 +580,12 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOO)"), p1.get(), @@ -599,12 +599,12 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOO)"), p1.get(), p2.get(), @@ -617,13 +617,13 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOO)"), p1.get(), @@ -638,13 +638,13 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOO)"), p1.get(), p2.get(), @@ -658,14 +658,14 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); - ref p8(to_python(search_namespace, a8)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOOO)"), p1.get(), @@ -681,14 +681,14 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); - ref p8(to_python(search_namespace, a8)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOO)"), p1.get(), p2.get(), @@ -703,15 +703,15 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); - ref p8(to_python(search_namespace, a8)); - ref p9(to_python(search_namespace, a9)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOOOO)"), p1.get(), @@ -728,15 +728,15 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); - ref p8(to_python(search_namespace, a8)); - ref p9(to_python(search_namespace, a9)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOOO)"), p1.get(), p2.get(), @@ -752,16 +752,16 @@ struct callback template static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); - ref p8(to_python(search_namespace, a8)); - ref p9(to_python(search_namespace, a9)); - ref p10(to_python(search_namespace, a10)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); + ref p10(to_python(a10)); ref result(PyEval_CallMethod(self, const_cast(name), const_cast("(OOOOOOOOOO)"), p1.get(), @@ -779,16 +779,16 @@ struct callback template static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) { - ref p1(to_python(search_namespace, a1)); - ref p2(to_python(search_namespace, a2)); - ref p3(to_python(search_namespace, a3)); - ref p4(to_python(search_namespace, a4)); - ref p5(to_python(search_namespace, a5)); - ref p6(to_python(search_namespace, a6)); - ref p7(to_python(search_namespace, a7)); - ref p8(to_python(search_namespace, a8)); - ref p9(to_python(search_namespace, a9)); - ref p10(to_python(search_namespace, a10)); + ref p1(to_python(a1)); + ref p2(to_python(a2)); + ref p3(to_python(a3)); + ref p4(to_python(a4)); + ref p5(to_python(a5)); + ref p6(to_python(a6)); + ref p7(to_python(a7)); + ref p8(to_python(a8)); + ref p9(to_python(a9)); + ref p10(to_python(a10)); ref result(PyEval_CallFunction(self, const_cast("(OOOOOOOOOO)"), p1.get(), p2.get(), diff --git a/include/boost/python/caller.hpp b/include/boost/python/caller.hpp index 86820233..35b2d618 100644 --- a/include/boost/python/caller.hpp +++ b/include/boost/python/caller.hpp @@ -30,7 +30,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("O"), &self)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)()); + return to_python((target.*pmf)()); } template @@ -40,7 +40,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OO"), &self, &a1)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()))); + return to_python((target.*pmf)(from_python(a1, type()))); } template @@ -51,7 +51,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOO"), &self, &a1, &a2)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()))); } @@ -64,7 +64,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOO"), &self, &a1, &a2, &a3)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()))); } @@ -79,7 +79,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOO"), &self, &a1, &a2, &a3, &a4)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()))); @@ -96,7 +96,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &self, &a1, &a2, &a3, &a4, &a5)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -115,7 +115,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -136,7 +136,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -159,7 +159,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -184,7 +184,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -211,7 +211,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -230,7 +230,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("O"), &self)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)()); + return to_python((target.*pmf)()); } template @@ -240,7 +240,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OO"), &self, &a1)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()))); + return to_python((target.*pmf)(from_python(a1, type()))); } template @@ -251,7 +251,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOO"), &self, &a1, &a2)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()))); } @@ -264,7 +264,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOO"), &self, &a1, &a2, &a3)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()))); } @@ -279,7 +279,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOO"), &self, &a1, &a2, &a3, &a4)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()))); @@ -296,7 +296,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &self, &a1, &a2, &a3, &a4, &a5)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -315,7 +315,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -336,7 +336,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -359,7 +359,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -384,7 +384,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -411,7 +411,7 @@ struct caller if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &self, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) return 0; T& target = from_python(self, type()); - return to_python(search_namespace, (target.*pmf)(from_python(a1, type()), + return to_python((target.*pmf)(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -427,7 +427,7 @@ struct caller static PyObject* call(R (*f)(), PyObject* args, PyObject* /* keywords */ ) { if (!PyArg_ParseTuple(args, const_cast(""))) return 0; - return to_python(search_namespace, f()); + return to_python(f()); } template @@ -435,7 +435,7 @@ struct caller PyObject* a1; if (!PyArg_ParseTuple(args, const_cast("O"), &a1)) return 0; - return to_python(search_namespace, f(from_python(a1, type()))); + return to_python(f(from_python(a1, type()))); } template @@ -444,7 +444,7 @@ struct caller PyObject* a2; if (!PyArg_ParseTuple(args, const_cast("OO"), &a1, &a2)) return 0; - return to_python(search_namespace, f(from_python(a1, type()), + return to_python(f(from_python(a1, type()), from_python(a2, type()))); } @@ -455,7 +455,7 @@ struct caller PyObject* a3; if (!PyArg_ParseTuple(args, const_cast("OOO"), &a1, &a2, &a3)) return 0; - return to_python(search_namespace, f(from_python(a1, type()), + return to_python(f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()))); } @@ -468,7 +468,7 @@ struct caller PyObject* a4; if (!PyArg_ParseTuple(args, const_cast("OOOO"), &a1, &a2, &a3, &a4)) return 0; - return to_python(search_namespace, f(from_python(a1, type()), + return to_python(f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()))); @@ -483,7 +483,7 @@ struct caller PyObject* a5; if (!PyArg_ParseTuple(args, const_cast("OOOOO"), &a1, &a2, &a3, &a4, &a5)) return 0; - return to_python(search_namespace, f(from_python(a1, type()), + return to_python(f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -500,7 +500,7 @@ struct caller PyObject* a6; if (!PyArg_ParseTuple(args, const_cast("OOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6)) return 0; - return to_python(search_namespace, f(from_python(a1, type()), + return to_python(f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -519,7 +519,7 @@ struct caller PyObject* a7; if (!PyArg_ParseTuple(args, const_cast("OOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7)) return 0; - return to_python(search_namespace, f(from_python(a1, type()), + return to_python(f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -540,7 +540,7 @@ struct caller PyObject* a8; if (!PyArg_ParseTuple(args, const_cast("OOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8)) return 0; - return to_python(search_namespace, f(from_python(a1, type()), + return to_python(f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -563,7 +563,7 @@ struct caller PyObject* a9; if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9)) return 0; - return to_python(search_namespace, f(from_python(a1, type()), + return to_python(f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -588,7 +588,7 @@ struct caller PyObject* a10; if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10)) return 0; - return to_python(search_namespace, f(from_python(a1, type()), + return to_python(f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), @@ -615,7 +615,7 @@ struct caller PyObject* a11; if (!PyArg_ParseTuple(args, const_cast("OOOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10, &a11)) return 0; - return to_python(search_namespace, f(from_python(a1, type()), + return to_python(f(from_python(a1, type()), from_python(a2, type()), from_python(a3, type()), from_python(a4, type()), From 66da2339d4abfa1820d6a0320fc6f98e1bc92a5e Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 24 May 2001 08:51:05 +0000 Subject: [PATCH 139/154] Fix accident: restore main version. [SVN r10210] --- include/boost/python/detail/config.hpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/include/boost/python/detail/config.hpp b/include/boost/python/detail/config.hpp index 348bcc39..9792695e 100644 --- a/include/boost/python/detail/config.hpp +++ b/include/boost/python/detail/config.hpp @@ -15,6 +15,19 @@ # include # include +# ifdef BOOST_NO_OPERATORS_IN_NAMESPACE + // A gcc bug forces some symbols into the global namespace +# define BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE +# define BOOST_PYTHON_END_CONVERSION_NAMESPACE +# define BOOST_PYTHON_CONVERSION +# define BOOST_PYTHON_IMPORT_CONVERSION(x) using ::x +# else +# define BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE namespace boost { namespace python { +# define BOOST_PYTHON_END_CONVERSION_NAMESPACE }} // namespace boost::python +# define BOOST_PYTHON_CONVERSION boost::python +# define BOOST_PYTHON_IMPORT_CONVERSION(x) void never_defined() // so we can follow the macro with a ';' +# endif + # if defined(BOOST_MSVC) # if _MSC_VER <= 1200 # define BOOST_MSVC6_OR_EARLIER 1 @@ -24,16 +37,6 @@ # endif -# if defined(BOOST_PYTHON_USE_FRIEND_KOENIG_LOOKUP) -// for compilers that support Koenig lookup -# define BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE namespace boost { namespace python { -# define BOOST_PYTHON_END_CONVERSION_NAMESPACE }} // namespace boost::python -# else -// for compilers that do not support Koenig lookup for friend functions -# define BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE -# define BOOST_PYTHON_END_CONVERSION_NAMESPACE -# endif - // Work around the broken library implementation/strict ansi checking on some // EDG-based compilers (e.g. alpha), which incorrectly warn that the result of // offsetof() is not an integer constant expression. From 29a855813d307864ee96d5f45f63582d24d846ca Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 28 May 2001 20:14:25 +0000 Subject: [PATCH 140/154] fixed typo [SVN r10240] --- doc/pointers.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/pointers.html b/doc/pointers.html index fdbee797..00f7bb41 100644 --- a/doc/pointers.html +++ b/doc/pointers.html @@ -85,7 +85,7 @@ code before the last Python reference to it disappears: BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround PyObject* to_python(Foo* p) { - return boost::python::python_extension_class_converters<Foo>::ptr_to_python(p); + return boost::python::python_extension_class_converters<Foo>::ptr_to_python(p); } PyObject* to_python(const Foo* p) From 7a71cea92a4ecbc59a4072b8d083f2fb9680942e Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 18 Jun 2001 12:11:46 +0000 Subject: [PATCH 141/154] updated ILU links thanks to Scott Langley [SVN r10355] --- doc/comparisons.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/comparisons.html b/doc/comparisons.html index 6f082d51..57cec744 100644 --- a/doc/comparisons.html +++ b/doc/comparisons.html @@ -112,10 +112,10 @@ that.''
      -Paul Dubois

      ILU

      ILU + href="ftp://ftp.parc.xerox.com/pub/ilu/ilu.html">ILU is a very ambitious project which tries to describe a module's interface (types and functions) in terms of an Interface + href="ftp://ftp.parc.xerox.com/pub/ilu/2.0b1/manual-html/manual_2.html">Interface Specification Language (ISL) so that it can be uniformly interfaced to a wide range of computer languages, including Common Lisp, C++, C, Modula-3, and Python. ILU can parse the ISL to generate a C++ language From 91f0728b5598b144df3a87f236f6512c5dae459d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 21 Jun 2001 20:46:26 +0000 Subject: [PATCH 142/154] Minor fix, thanks to Jens Maurer. [SVN r10377] --- example/simple_vector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/simple_vector.cpp b/example/simple_vector.cpp index 2b3aa290..3499c8f7 100644 --- a/example/simple_vector.cpp +++ b/example/simple_vector.cpp @@ -49,7 +49,7 @@ namespace { // Avoid cluttering the global namespace. void delitem(std::vector& vd, std::size_t key) { if (key >= vd.size()) raise_vector_IndexError(); std::vector::iterator vditer = vd.begin(); - vd.erase(&vditer[key]); + vd.erase(vditer + key); } // Convert vector_double to a regular Python tuple. From 8b88e9f7272e8d0041deaca23b017193615cb849 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 21 Jun 2001 20:49:41 +0000 Subject: [PATCH 143/154] define changed to enable Silicon Graphics gcc compilation. [SVN r10378] --- test/comprehensive.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/comprehensive.cpp b/test/comprehensive.cpp index 410bd243..427ed2d8 100644 --- a/test/comprehensive.cpp +++ b/test/comprehensive.cpp @@ -15,7 +15,9 @@ #include // for pow() #include -#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 +#if defined(__sgi) \ + && ( (defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730) \ + && !defined(__GNUC__)) inline double pow(int x, int y) { return pow(static_cast(x), y); } #endif From 7c33a46a76dc7174317644e90e0aabfd52718b59 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Thu, 21 Jun 2001 23:38:42 +0000 Subject: [PATCH 144/154] A small fix for Borland [SVN r10389] --- src/classes.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/classes.cpp b/src/classes.cpp index c609eeef..8755bb34 100644 --- a/src/classes.cpp +++ b/src/classes.cpp @@ -203,7 +203,8 @@ namespace detail { } if (!BOOST_CSTD_::strcmp(name, "__reduce__")) { - ref target(as_object(this), ref::increment_count); + PyObject* self = as_object(this); + ref target(self, ref::increment_count); return bound_function::create(target, global_class_reduce()); } @@ -808,7 +809,7 @@ namespace detail { // Enable the special handler for methods of the given name, if any. void enable_named_method(boost::python::detail::class_base* type_obj, const char* name) { - const std::size_t num_enablers = sizeof(enablers) / sizeof(enablers[0]); + const std::size_t num_enablers = PY_ARRAY_LENGTH(enablers); // Make sure this ends with "__" since we'll only compare the head of the // string. This is done to make the __getattr____/__setattr____ From 1364b97b881185c8ea231c146679fbce172532b1 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Thu, 21 Jun 2001 23:39:30 +0000 Subject: [PATCH 145/154] A small Borland fix [SVN r10390] --- include/boost/python/detail/init_function.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/python/detail/init_function.hpp b/include/boost/python/detail/init_function.hpp index f4b24fa6..c0c50272 100644 --- a/include/boost/python/detail/init_function.hpp +++ b/include/boost/python/detail/init_function.hpp @@ -73,7 +73,8 @@ namespace detail { struct parameter_traits { private: - typedef const_ref_selector::value> selector; + enum { is_ref = boost::is_reference::value }; + typedef const_ref_selector selector; public: typedef typename selector::template const_ref::type const_reference; }; From 081150b477dfbd5dce9d3a7faaa0d12fce9380e9 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Thu, 21 Jun 2001 23:40:04 +0000 Subject: [PATCH 146/154] Quick Borland fix [SVN r10391] --- include/boost/python/detail/types.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/python/detail/types.hpp b/include/boost/python/detail/types.hpp index ee33ce04..5f0c8f97 100644 --- a/include/boost/python/detail/types.hpp +++ b/include/boost/python/detail/types.hpp @@ -375,8 +375,12 @@ PyObject* reprable::instance_repr(PyObject* obj) const // This macro gets the length of an array as a compile-time constant, and will // fail to compile if the parameter is a pointer. +#ifdef __BORLANDC__ // smart implementation doesn't work for borland; maybe someone knows a workaround? +# define PY_ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0])) +#else # define PY_ARRAY_LENGTH(a) \ (sizeof(::boost::python::detail::countof_validate(a, &(a))) ? sizeof(a) / sizeof((a)[0]) : 0) +#endif template inline void countof_validate(T* const, T* const*); From 88372000b5b4348610e4e5440de4e9a8d4b5f29d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 22 Jun 2001 00:49:58 +0000 Subject: [PATCH 147/154] fixes due to Jens Maurer (merged from branch boost_python_friend_fixes) [SVN r10395] --- build/linux_gcc.mak | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/linux_gcc.mak b/build/linux_gcc.mak index 9cd2b5de..5971ca61 100644 --- a/build/linux_gcc.mak +++ b/build/linux_gcc.mak @@ -17,14 +17,14 @@ ROOT=$(HOME) BOOST=$(ROOT)/boost -PYEXE=/usr/bin/python +PYEXE=PYTHONPATH=. /usr/bin/python PYINC=-I/usr/include/python1.5 #PYEXE=/usr/local/Python-1.5.2/bin/python #PYINC=-I/usr/local/Python-1.5.2/include/python1.5 #PYEXE=/usr/local/Python-2.0/bin/python #PYINC=-I/usr/local/Python-2.0/include/python2.0 -STDOPTS=-ftemplate-depth-21 +STDOPTS=-fPIC -ftemplate-depth-21 WARNOPTS= OPTOPTS=-g @@ -33,7 +33,7 @@ CPPOPTS=$(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \ $(STDOPTS) $(WARNOPTS) $(OPTOPTS) MAKEDEP=-M -LD=g++ +LD=$(CPP) LDOPTS=-shared OBJ=classes.o conversions.o extension_class.o functions.o \ From 4328ae1d8d86607807d5e649d4e0d9135a4d07bf Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Fri, 22 Jun 2001 22:36:00 +0000 Subject: [PATCH 148/154] Updates for Boost.Build [SVN r10403] --- example/test_abstract.py | 5 +++-- example/test_cross_module.py | 5 +++-- example/test_do_it_yourself_converters.py | 5 +++-- example/test_example1.py | 5 +++-- example/test_getting_started1.py | 5 +++-- example/test_getting_started2.py | 6 ++++-- example/test_pickle1.py | 6 ++++-- example/test_pickle2.py | 6 ++++-- example/test_pickle3.py | 5 +++-- example/test_rwgk1.py | 6 ++++-- example/test_simple_vector.py | 6 ++++-- test/comprehensive.py | 4 ++-- 12 files changed, 40 insertions(+), 24 deletions(-) diff --git a/example/test_abstract.py b/example/test_abstract.py index dda8aaa7..a48aff1b 100644 --- a/example/test_abstract.py +++ b/example/test_abstract.py @@ -17,7 +17,8 @@ def run(args = None): import sys sys.argv = args import doctest, test_abstract - doctest.testmod(test_abstract) + return doctest.testmod(test_abstract) if __name__ == '__main__': - run() + import sys + sys.exit(run()[0]) diff --git a/example/test_cross_module.py b/example/test_cross_module.py index 81057f23..86c1be0e 100644 --- a/example/test_cross_module.py +++ b/example/test_cross_module.py @@ -133,7 +133,8 @@ def run(args = None): import sys sys.argv = args import doctest, test_cross_module - doctest.testmod(test_cross_module) + return doctest.testmod(test_cross_module) if __name__ == '__main__': - run() + import sys + sys.exit(run()) diff --git a/example/test_do_it_yourself_converters.py b/example/test_do_it_yourself_converters.py index e256c614..17240750 100644 --- a/example/test_do_it_yourself_converters.py +++ b/example/test_do_it_yourself_converters.py @@ -16,7 +16,8 @@ def run(args = None): import sys sys.argv = args import doctest, test_do_it_yourself_converters - doctest.testmod(test_do_it_yourself_converters) + return doctest.testmod(test_do_it_yourself_converters) if __name__ == '__main__': - run() + import sys + sys.exit(run()[0]) diff --git a/example/test_example1.py b/example/test_example1.py index 0e3a9a18..3a30cb5b 100644 --- a/example/test_example1.py +++ b/example/test_example1.py @@ -44,7 +44,8 @@ def run(args = None): import sys sys.argv = args import doctest, test_example1 - doctest.testmod(test_example1) + return doctest.testmod(test_example1) if __name__ == '__main__': - run() + import sys + sys.exit(run()[0]) diff --git a/example/test_getting_started1.py b/example/test_getting_started1.py index 7daf65af..cd8fb59e 100644 --- a/example/test_getting_started1.py +++ b/example/test_getting_started1.py @@ -11,7 +11,8 @@ def run(args = None): import sys sys.argv = args import doctest, test_getting_started1 - doctest.testmod(test_getting_started1) + return doctest.testmod(test_getting_started1) if __name__ == '__main__': - run() + import sys + sys.exit(run()[0]) diff --git a/example/test_getting_started2.py b/example/test_getting_started2.py index 49cf765d..ccfaa4f1 100644 --- a/example/test_getting_started2.py +++ b/example/test_getting_started2.py @@ -23,7 +23,9 @@ def run(args = None): import sys sys.argv = args import doctest, test_getting_started2 - doctest.testmod(test_getting_started2) + return doctest.testmod(test_getting_started2) if __name__ == '__main__': - run() + import sys + sys.exit(run()[0]) + diff --git a/example/test_pickle1.py b/example/test_pickle1.py index 05696d4a..48c76a5f 100644 --- a/example/test_pickle1.py +++ b/example/test_pickle1.py @@ -25,7 +25,9 @@ def run(args = None): import sys sys.argv = args import doctest, test_pickle1 - doctest.testmod(test_pickle1) + return doctest.testmod(test_pickle1) if __name__ == '__main__': - run() + import sys + sys.exit(run()[0]) + diff --git a/example/test_pickle2.py b/example/test_pickle2.py index 463befa6..bafa9875 100644 --- a/example/test_pickle2.py +++ b/example/test_pickle2.py @@ -39,7 +39,9 @@ def run(args = None): import sys sys.argv = args import doctest, test_pickle2 - doctest.testmod(test_pickle2) + return doctest.testmod(test_pickle2) if __name__ == '__main__': - run() + import sys + sys.exit(run()[0]) + diff --git a/example/test_pickle3.py b/example/test_pickle3.py index b964f1a2..36da735d 100644 --- a/example/test_pickle3.py +++ b/example/test_pickle3.py @@ -32,7 +32,8 @@ def run(args = None): import sys sys.argv = args import doctest, test_pickle3 - doctest.testmod(test_pickle3) + return doctest.testmod(test_pickle3) if __name__ == '__main__': - run() + import sys + sys.exit(run()[0]) diff --git a/example/test_rwgk1.py b/example/test_rwgk1.py index 87298875..631eea3e 100644 --- a/example/test_rwgk1.py +++ b/example/test_rwgk1.py @@ -11,7 +11,9 @@ def run(args = None): import sys sys.argv = args import doctest, test_rwgk1 - doctest.testmod(test_rwgk1) + return doctest.testmod(test_rwgk1) if __name__ == '__main__': - run() + import sys + sys.exit(run()[0]) + diff --git a/example/test_simple_vector.py b/example/test_simple_vector.py index ca38d715..c6a2cd59 100644 --- a/example/test_simple_vector.py +++ b/example/test_simple_vector.py @@ -34,7 +34,9 @@ def run(args = None): import sys sys.argv = args import doctest, test_simple_vector - doctest.testmod(test_simple_vector) + return doctest.testmod(test_simple_vector) if __name__ == '__main__': - run() + import sys + sys.exit(run()[0]) + diff --git a/test/comprehensive.py b/test/comprehensive.py index c1424d25..06a191af 100644 --- a/test/comprehensive.py +++ b/test/comprehensive.py @@ -1188,7 +1188,7 @@ def run(args = None): if args is not None: sys.argv = args import doctest, comprehensive - doctest.testmod(comprehensive) + return doctest.testmod(comprehensive) if __name__ == '__main__': - run() + sys.exit(run()[0]) From ff2b37f6e374d6c9b594747ffa1eaa267b9ca952 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Fri, 29 Jun 2001 03:57:34 +0000 Subject: [PATCH 149/154] Fix so it compiles with Cygwin [SVN r10480] --- include/boost/python/detail/config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/python/detail/config.hpp b/include/boost/python/detail/config.hpp index 9792695e..b6075368 100644 --- a/include/boost/python/detail/config.hpp +++ b/include/boost/python/detail/config.hpp @@ -57,7 +57,7 @@ # define BOOST_CSTD_ std # endif -#ifdef _WIN32 +#if defined(_WIN32) || defined(__CYGWIN__) # define BOOST_PYTHON_MODULE_INIT(name) extern "C" __declspec(dllexport) void init##name() #else # define BOOST_PYTHON_MODULE_INIT(name) extern "C" void init##name() From a32dedd16c8998faad1aa7cd31f57de4d4e5ecee Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Fri, 29 Jun 2001 20:30:58 +0000 Subject: [PATCH 150/154] updates for Python2.1 [SVN r10485] --- test/comprehensive.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/test/comprehensive.py b/test/comprehensive.py index 06a191af..013fae96 100644 --- a/test/comprehensive.py +++ b/test/comprehensive.py @@ -19,10 +19,13 @@ Load up the extension module Automatic checking of the number and type of arguments. Foo's constructor takes a single long parameter. - >>> ext = Foo() - Traceback (innermost last): - File "", line 1, in ? - TypeError: function requires exactly 1 argument; 0 given + >>> try: + ... ext = Foo() + ... except TypeError, err: + ... assert re.match(r'function .* exactly 1 argument;? \(?0 given\)?', + ... str(err)) + ... else: + ... print 'no exception' >>> try: ext = Foo('foo') ... except TypeError, err: @@ -1014,9 +1017,12 @@ test inheritB2 -2 >>> str(i) '2' - >>> j = i/i - Traceback (innermost last): - TypeError: bad operand type(s) for / + >>> try: j = i/i + ... except TypeError, err: + ... assert re.match(r'(bad|unsupported) operand type\(s\) for /', + ... str(err)) + ... else: print 'no exception' + >>> j = abs(i) Traceback (innermost last): TypeError: bad operand type for abs() From 884b59a0b308f448b63f856ea6b56af7a99106c5 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 2 Jul 2001 00:16:28 +0000 Subject: [PATCH 151/154] Added JIT debugging hooks [SVN r10507] --- example/dvect.cpp | 11 +++++++++++ example/ivect.cpp | 11 +++++++++++ example/noncopyable_export.cpp | 10 ++++++++++ example/noncopyable_import.cpp | 10 ++++++++++ 4 files changed, 42 insertions(+) diff --git a/example/dvect.cpp b/example/dvect.cpp index da6b35a3..4d109c96 100644 --- a/example/dvect.cpp +++ b/example/dvect.cpp @@ -20,6 +20,16 @@ namespace { } } +# ifdef BOOST_MSVC // fixes for JIT debugging +# include +extern "C" void structured_exception_translator(unsigned int, EXCEPTION_POINTERS*) +{ + throw; +} +extern "C" void (*old_translator)(unsigned int, EXCEPTION_POINTERS*) + = _set_se_translator(structured_exception_translator); +# endif + BOOST_PYTHON_MODULE_INIT(dvect) { try @@ -43,3 +53,4 @@ BOOST_PYTHON_MODULE_INIT(dvect) python::handle_exception(); // Deal with the exception for Python } } + diff --git a/example/ivect.cpp b/example/ivect.cpp index db1c0ec3..848d693e 100644 --- a/example/ivect.cpp +++ b/example/ivect.cpp @@ -20,6 +20,16 @@ namespace { } } +# ifdef BOOST_MSVC // fixes for JIT debugging +# include +extern "C" void structured_exception_translator(unsigned int, EXCEPTION_POINTERS*) +{ + throw; +} +extern "C" void (*old_translator)(unsigned int, EXCEPTION_POINTERS*) + = _set_se_translator(structured_exception_translator); +# endif + BOOST_PYTHON_MODULE_INIT(ivect) { try @@ -43,3 +53,4 @@ BOOST_PYTHON_MODULE_INIT(ivect) python::handle_exception(); // Deal with the exception for Python } } + diff --git a/example/noncopyable_export.cpp b/example/noncopyable_export.cpp index 794b1200..b118abb8 100644 --- a/example/noncopyable_export.cpp +++ b/example/noncopyable_export.cpp @@ -6,6 +6,16 @@ namespace python = boost::python; #include "noncopyable.h" +# ifdef BOOST_MSVC // fixes for JIT debugging +# include +extern "C" void structured_exception_translator(unsigned int, EXCEPTION_POINTERS*) +{ + throw; +} +extern "C" void (*old_translator)(unsigned int, EXCEPTION_POINTERS*) + = _set_se_translator(structured_exception_translator); +# endif + BOOST_PYTHON_MODULE_INIT(noncopyable_export) { try diff --git a/example/noncopyable_import.cpp b/example/noncopyable_import.cpp index ea2477be..66c6457d 100644 --- a/example/noncopyable_import.cpp +++ b/example/noncopyable_import.cpp @@ -19,6 +19,16 @@ namespace { // Avoid cluttering the global namespace. } } +# ifdef BOOST_MSVC // fixes for JIT debugging +# include +extern "C" void structured_exception_translator(unsigned int, EXCEPTION_POINTERS*) +{ + throw; +} +extern "C" void (*old_translator)(unsigned int, EXCEPTION_POINTERS*) + = _set_se_translator(structured_exception_translator); +# endif + BOOST_PYTHON_MODULE_INIT(noncopyable_import) { try From e504c3cd466326b11d40c363a67c89e356049db5 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 2 Jul 2001 00:16:53 +0000 Subject: [PATCH 152/154] Made it a little more immune to command-line argument ordering [SVN r10508] --- example/tst_dvect2.py | 20 +++++++++++++------- example/tst_ivect2.py | 20 +++++++++++++------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/example/tst_dvect2.py b/example/tst_dvect2.py index 539e0b88..2e72bf8b 100644 --- a/example/tst_dvect2.py +++ b/example/tst_dvect2.py @@ -87,12 +87,18 @@ if (__name__ == "__main__"): import sys, string broken_auto_ptr = 0 n = 1 - if (len(sys.argv) > 1): - if (sys.argv[1] == "--broken-auto-ptr"): - broken_auto_ptr = 1 - if (len(sys.argv) > 2): - n = string.atoi(sys.argv[2]) - else: - n = string.atoi(sys.argv[1]) + + if len(sys.argv) > 1: + argv = [] + + for x in sys.argv: + if x != '--broken_auto_ptr': + argv.append(x) + broken_auto_ptr = argv != sys.argv + sys.argv = argv + + if len(sys.argv) > 1: + n = string.atoi(sys.argv[1]) + for i in xrange(n): f(broken_auto_ptr) diff --git a/example/tst_ivect2.py b/example/tst_ivect2.py index 6ffd2826..e7607151 100644 --- a/example/tst_ivect2.py +++ b/example/tst_ivect2.py @@ -87,12 +87,18 @@ if (__name__ == "__main__"): import sys, string broken_auto_ptr = 0 n = 1 - if (len(sys.argv) > 1): - if (sys.argv[1] == "--broken-auto-ptr"): - broken_auto_ptr = 1 - if (len(sys.argv) > 2): - n = string.atoi(sys.argv[2]) - else: - n = string.atoi(sys.argv[1]) + + if len(sys.argv) > 1: + argv = [] + + for x in sys.argv: + if x != '--broken_auto_ptr': + argv.append(x) + broken_auto_ptr = argv != sys.argv + sys.argv = argv + + if len(sys.argv) > 1: + n = string.atoi(sys.argv[1]) + for i in xrange(n): f(broken_auto_ptr) From 76c6adf1cfe57835c6fa264296820739cd1ef7b6 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Tue, 3 Jul 2001 12:43:12 +0000 Subject: [PATCH 153/154] --broken_auto_ptr -> --broken-auto-ptr [SVN r10511] --- example/tst_dvect2.py | 2 +- example/tst_ivect2.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/tst_dvect2.py b/example/tst_dvect2.py index 2e72bf8b..90d381a7 100644 --- a/example/tst_dvect2.py +++ b/example/tst_dvect2.py @@ -92,7 +92,7 @@ if (__name__ == "__main__"): argv = [] for x in sys.argv: - if x != '--broken_auto_ptr': + if x != '--broken-auto-ptr': argv.append(x) broken_auto_ptr = argv != sys.argv sys.argv = argv diff --git a/example/tst_ivect2.py b/example/tst_ivect2.py index e7607151..a9e6aeef 100644 --- a/example/tst_ivect2.py +++ b/example/tst_ivect2.py @@ -92,7 +92,7 @@ if (__name__ == "__main__"): argv = [] for x in sys.argv: - if x != '--broken_auto_ptr': + if x != '--broken-auto-ptr': argv.append(x) broken_auto_ptr = argv != sys.argv sys.argv = argv From 606898f5691a641a695d806941ad7c08d0a204f6 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 6 Jul 2001 07:31:39 +0000 Subject: [PATCH 154/154] tiny trivial fix. [SVN r10547] --- example/test_cross_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/test_cross_module.py b/example/test_cross_module.py index 86c1be0e..c5e2bef6 100644 --- a/example/test_cross_module.py +++ b/example/test_cross_module.py @@ -137,4 +137,4 @@ def run(args = None): if __name__ == '__main__': import sys - sys.exit(run()) + sys.exit(run()[0])