2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-26 06:42:27 +00:00

Compare commits

..

39 Commits

Author SHA1 Message Date
Ralf W. Grosse-Kunstleve
8824572893 get ready to move to trunk
[SVN r9818]
2001-04-17 19:37:40 +00:00
Ralf W. Grosse-Kunstleve
4bb2668733 copyright
[SVN r9811]
2001-04-17 18:37:37 +00:00
Ralf W. Grosse-Kunstleve
01aa63e5f1 Motivation: Assertion 'static_class_object == 0' failed.
[SVN r9809]
2001-04-17 02:22:39 +00:00
Ralf W. Grosse-Kunstleve
237ae8a322 Use default python.
[SVN r9757]
2001-04-11 00:30:49 +00:00
Ralf W. Grosse-Kunstleve
0183d777d2 Better comments.
[SVN r9756]
2001-04-11 00:29:24 +00:00
Ralf W. Grosse-Kunstleve
176beb3b47 uniform python_import_extension_class_converters
[SVN r9755]
2001-04-10 23:04:02 +00:00
Ralf W. Grosse-Kunstleve
77626967d6 unique sig, import
[SVN r9754]
2001-04-10 21:35:31 +00:00
Ralf W. Grosse-Kunstleve
d2115b21d7 unique sig, export
[SVN r9753]
2001-04-10 19:30:21 +00:00
Ralf W. Grosse-Kunstleve
38492e4e7e -all ld option removed.
[SVN r9721]
2001-04-05 14:35:06 +00:00
nobody
e2580e5c60 This commit was manufactured by cvs2svn to create branch
'ralf_grosse_kunstleve'.

[SVN r9690]
2001-04-01 13:47:26 +00:00
Ralf W. Grosse-Kunstleve
e87c03643f meaningless const removed.
[SVN r9637]
2001-03-23 09:15:25 +00:00
Ralf W. Grosse-Kunstleve
7367d79a09 build boost_python.lib
[SVN r9636]
2001-03-23 05:29:13 +00:00
Ralf W. Grosse-Kunstleve
cd45d594aa Pointers to new examples.
[SVN r9627]
2001-03-21 22:34:00 +00:00
Ralf W. Grosse-Kunstleve
8771eded6d Minor fixes.
[SVN r9626]
2001-03-21 22:33:28 +00:00
Ralf W. Grosse-Kunstleve
b96393a7e8 --broken-auto-ptr switch for VC++ 6.0
[SVN r9625]
2001-03-21 20:00:23 +00:00
Ralf W. Grosse-Kunstleve
66e3c67398 Files renamed to *simple_vector*, *do_it_yourself_converters*
[SVN r9624]
2001-03-21 02:39:01 +00:00
nobody
34bc55e21a This commit was manufactured by cvs2svn to create branch
'ralf_grosse_kunstleve'.

[SVN r9622]
2001-03-21 02:33:28 +00:00
Ralf W. Grosse-Kunstleve
61978881ba Much more extensive testing of import_converters.
[SVN r9620]
2001-03-21 01:22:21 +00:00
Ralf W. Grosse-Kunstleve
8631427d4e Much more extensive testing of import_converters.
[SVN r9618]
2001-03-21 01:11:03 +00:00
Ralf W. Grosse-Kunstleve
82edce6450 Now using BOOST_PYTHON_MODULE_INIT.
[SVN r9617]
2001-03-21 01:09:17 +00:00
Ralf W. Grosse-Kunstleve
1c454c4116 Return type for smart ptr values fixed.
[SVN r9614]
2001-03-21 01:02:24 +00:00
Ralf W. Grosse-Kunstleve
6dc5ef02b5 BOOST_PYTHON_TRU64_CXX_PROBLEM define
[SVN r9613]
2001-03-20 14:49:26 +00:00
Ralf W. Grosse-Kunstleve
feadcfe0a2 New export_converters() interface.
[SVN r9604]
2001-03-20 02:44:20 +00:00
nobody
e21d518511 This commit was manufactured by cvs2svn to create branch
'ralf_grosse_kunstleve'.

[SVN r9603]
2001-03-20 02:16:09 +00:00
Ralf W. Grosse-Kunstleve
f2b763c2e1 VC++ 6.0 makefile; filemgr.py used by all ralf_grosse_kunstleve makefiles.
[SVN r9602]
2001-03-20 02:16:08 +00:00
Ralf W. Grosse-Kunstleve
028a3b9750 VC++ 6.0 fixes and misc. other modifications.
[SVN r9601]
2001-03-20 02:13:28 +00:00
Ralf W. Grosse-Kunstleve
e8c9229704 Renamed to cross_module.cpp
[SVN r9598]
2001-03-20 02:03:44 +00:00
Ralf W. Grosse-Kunstleve
ffc29171e3 Renamed to cross_module.hpp
[SVN r9597]
2001-03-20 02:02:38 +00:00
Ralf W. Grosse-Kunstleve
bc54113bef Revert to main reference.hpp. VC6 cannot handle, get<T>().
[SVN r9593]
2001-03-19 22:40:08 +00:00
Ralf W. Grosse-Kunstleve
ff3120a52c free getattr()
[SVN r9554]
2001-03-14 05:27:13 +00:00
Ralf W. Grosse-Kunstleve
9e41737b68 More comments.
[SVN r9553]
2001-03-13 00:24:38 +00:00
Ralf W. Grosse-Kunstleve
33aac2ec83 New pickle1,2,3 examples.
[SVN r9552]
2001-03-13 00:05:43 +00:00
nobody
fd563fbf3c This commit was manufactured by cvs2svn to create branch
'ralf_grosse_kunstleve'.

[SVN r9550]
2001-03-13 00:01:07 +00:00
Ralf W. Grosse-Kunstleve
419a323483 reference.get<T>(); reference.getattr(attr_name);
[SVN r9548]
2001-03-12 23:54:18 +00:00
Ralf W. Grosse-Kunstleve
a0ebc5f25e Mods to address David's remarks.
[SVN r9469]
2001-03-07 00:09:23 +00:00
Ralf W. Grosse-Kunstleve
e1a600aba9 SPECIAL_PYCVTSOBJECT removed for now.
[SVN r9468]
2001-03-06 23:08:29 +00:00
Ralf W. Grosse-Kunstleve
0561d5e363 x_class_builder rules etc. added to Makefiles.
[SVN r9461]
2001-03-06 02:52:30 +00:00
Ralf W. Grosse-Kunstleve
4d007528a7 (incomplete) adaptation to new vers of class python_extension_class_converters.
[SVN r9460]
2001-03-06 02:51:03 +00:00
nobody
667ec238a5 This commit was manufactured by cvs2svn to create branch
'ralf_grosse_kunstleve'.

[SVN r9458]
2001-03-06 02:44:33 +00:00
39 changed files with 4214 additions and 180 deletions

135
build/filemgr.py Normal file
View File

@@ -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 <softlinks|unlink|cp|rm|copy|del>"
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

165
build/irix_CC.mak Normal file
View File

@@ -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

165
build/linux_gcc.mak Normal file
View File

@@ -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/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
WARNOPTS=
OPTOPTS=-g
CPP=g++
CPPOPTS=$(STLPORTINC) $(STLPORTOPTS) -I$(BOOST) $(PYINC) \
$(STDOPTS) $(WARNOPTS) $(OPTOPTS)
MAKEDEP=-M
LD=g++
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
ar r 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
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

196
build/mingw32.mak Normal file
View File

@@ -0,0 +1,196 @@
# 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
# 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<bpl_test::Derived1>'
# 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 boost_python_test" still causes a crash.
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"
STDOPTS=-ftemplate-depth-21
WARNOPTS=
OPTOPTS=-g
CPP=g++
CPPOPTS=$(STLPORTINC) $(STLPORTOPTS) -I$(BOOST_WIN) $(PYINC) \
$(STDOPTS) $(WARNOPTS) $(OPTOPTS)
LD=g++
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
.SUFFIXES: .o .cpp
all: libboost_python.a \
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
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
boost_python_test.pyd: $(OBJ) comprehensive.o
dllwrap $(DLLWRAPOPTS) \
--dllname boost_python_test.pyd \
--def boost_python_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)
simple_vector.pyd: $(OBJ) simple_vector.o
dllwrap $(DLLWRAPOPTS) \
--dllname simple_vector.pyd \
--def simple_vector.def \
$(OBJ) simple_vector.o $(PYLIB)
do_it_yourself_converters.pyd: $(OBJ) do_it_yourself_converters.o
dllwrap $(DLLWRAPOPTS) \
--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) 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:
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

180
build/tru64_cxx.mak Normal file
View File

@@ -0,0 +1,180 @@
# 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/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$(BOOST)/boost/compatibility/cpp_c_headers
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) $(OPTOPTS)
MAKEDEP=-Em
LD=cxx
LDOPTS=-shared -expect_unresolved 'Py*' -expect_unresolved '_Py*'
#HIDDEN=-hidden
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
cd cxx_repository; \
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
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 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); \
do \
bn=`echo "$$obj" | cut -d. -f1`; \
$(CPP) $(CPPOPTS) $(MAKEDEP) "$$bn".cpp; \
done

133
build/vc60.mak Normal file
View File

@@ -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

View File

@@ -0,0 +1,336 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>Cross-extension-module dependencies</title>
<div>
<img src="../../../c++boost.gif"
alt="c++boost.gif (8819 bytes)"
align="center"
width="277" height="86">
<hr>
<h1>Cross-extension-module dependencies</h1>
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.
<p>
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.
<hr>
<h2>The recipe</h2>
Suppose there is an extension module that exposes certain instances of
the C++ <tt>std::vector</tt> template library such that it can be used
from Python in the following manner:
<pre>
import std_vector
v = std_vector.double([1, 2, 3, 4])
v.push_back(5)
v.size()
</pre>
Suppose the <tt>std_vector</tt> module is done well and reflects all
C++ functions that are useful at the Python level, for all C++ built-in
data types (<tt>std_vector.int</tt>, <tt>std_vector.long</tt>, etc.).
<p>
Suppose further that there is statistic module with a C++ class that
has constructors or member functions that use or return a
<tt>std::vector</tt>. For example:
<pre>
class xy {
public:
xy(const std::vector&lt;double&gt;&amp; x, const std::vector&lt;double&gt;&amp; y) : m_x(x), m_y(y) {}
const std::vector&lt;double&gt;&amp; x() const { return m_x; }
const std::vector&lt;double&gt;&amp; y() const { return m_y; }
double correlation();
private:
std::vector&lt;double&gt; m_x;
std::vector&lt;double&gt; m_y;
}
</pre>
What is more natural than reusing the <tt>std_vector</tt> extension
module to expose these constructors or functions to Python?
<p>
Unfortunately, what seems natural needs a little work in both the
<tt>std_vector</tt> and the <tt>statistics</tt> module.
<p>
In the <tt>std_vector</tt> extension module,
<tt>std::vector&lt;double&gt;</tt> is exposed to Python in the usual
way with the <tt>class_builder&lt;&gt;</tt> template. To also enable the
automatic conversion of <tt>std::vector&lt;double&gt;</tt> function
arguments or return values in other Boost.Python C++ modules, the
converters that convert a <tt>std::vector&lt;double&gt;</tt> C++ object
to a Python object and vice versa (i.e. the <tt>to_python()</tt> and
<tt>from_python()</tt> template functions) have to be exported. For
example:
<pre>
#include &lt;boost/python/cross_module.hpp&gt;
//...
class_builder&lt;std::vector&lt;double&gt; &gt; v_double(std_vector_module, &quot;double&quot;);
export_converters(v_double);
</pre>
In the extension module that wraps <tt>class xy</tt> we can now import
these converters with the <tt>import_converters&lt;&gt;</tt> template.
For example:
<pre>
#include &lt;boost/python/cross_module.hpp&gt;
//...
import_converters&lt;std::vector&lt;double&gt; &gt; v_double_converters(&quot;std_vector&quot;, &quot;double&quot;);
</pre>
That is all. All the attributes that are defined for
<tt>std_vector.double</tt> in the <tt>std_vector</tt> Boost.Python
module will be available for the returned objects of <tt>xy.x()</tt>
and <tt>xy.y()</tt>. Similarly, the constructor for <tt>xy</tt> will
accept objects that were created by the <tt>std_vector</tt>module.
<hr>
<h2>Placement of <tt>import_converters&lt;&gt;</tt> template instantiations</h2>
<tt>import_converts&lt;&gt;</tt> can be viewed as a drop-in replacement
for <tt>class_wrapper&lt;&gt;</tt>, and the recommendations for the
placement of <tt>class_wrapper&lt;&gt;</tt> template instantiations
also apply to to <tt>import_converts&lt;&gt;</tt>. In particular, it is
important that an instantiation of <tt>class_wrapper&lt;&gt;</tt> is
visible to any code which wraps a C++ function with a <tt>T</tt>,
<tt>T*</tt>, const <tt>T&amp;</tt>, etc. parameter or return value.
Therefore you may want to group all <tt>class_wrapper&lt;&gt;</tt> and
<tt>import_converts&lt;&gt;</tt> instantiations at the top of your
module's init function, then <tt>def()</tt> the member functions later
to avoid problems with inter-class dependencies.
<hr>
<h2>Non-copyable types</h2>
<tt>export_converters()</tt> 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, <tt>export_converters_noncopyable()</tt> can be used to export
the converters that do not involve the copy constructor of the wrapped
type. For example:
<pre>
class_builder&lt;store&gt; py_store(your_module, &quot;store&quot;);
export_converters_noncopyable(py_store);
</pre>
The corresponding <tt>import_converters&lt;&gt;</tt> statement does not
need any special attention:
<pre>
import_converters&lt;store&gt; py_store(&quot;noncopyable_export&quot;, &quot;store&quot;);
</pre>
<hr>
<h2>Python module search path</h2>
The <tt>std_vector</tt> and <tt>statistics</tt> modules can now be used
in the following way:
<pre>
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()
</pre>
In this example it is clear that Python has to be able to find both the
<tt>std_vector</tt> and the <tt>statistics</tt> extension module. In
other words, both extension modules need to be in the Python module
search path (<tt>sys.path</tt>).
<p>
The situation is not always this obvious. Suppose the
<tt>statistics</tt> module has a <tt>random()</tt> function that
returns a vector of random numbers with a given length:
<pre>
import statistics
x = statistics.random(5)
y = statistics.random(5)
xy = statistics.xy(x, y)
xy.correlation()
</pre>
A naive user will not easily anticipate that the <tt>std_vector</tt>
module is used to pass the <tt>x</tt> and <tt>y</tt> vectors around. If
the <tt>std_vector</tt> 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.
<p>
If the <tt>std_vector</tt> module is not in the Python module search
path, a Python exception will be raised:
<pre>
Traceback (innermost last):
File &quot;foo.py&quot;, line 2, in ?
x = statistics.random(5)
ImportError: No module named std_vector
</pre>
As is the case with any system of a non-trivial complexity, it is
important that the setup is consistent and complete.
<hr>
<h2>Two-way module dependencies</h2>
Boost.Python supports two-way module dependencies. This is best
illustrated by a simple example.
<p>
Suppose there is a module <tt>ivect</tt> that implements vectors of
integers, and a similar module <tt>dvect</tt> that implements vectors
of doubles. We want to be able do convert an integer vector to a double
vector and vice versa. For example:
<pre>
import ivect
iv = ivect.ivect((1,2,3,4,5))
dv = iv.as_dvect()
</pre>
The last expression will implicitly import the <tt>dvect</tt> module in
order to enable the conversion of the C++ representation of
<tt>dvect</tt> to a Python object. The analogous is possible for a
<tt>dvect</tt>:
<pre>
import dvect
dv = dvect.dvect((1,2,3,4,5))
iv = dv.as_ivect()
</pre>
Now the <tt>ivect</tt> module is imported implicitly.
<p>
Note that the two-way dependencies are possible because the
dependencies are resolved only when needed. This is, the initialization
of the <tt>ivect</tt> module does not rely on the <tt>dvect</tt>
module, and vice versa. Only if <tt>as_dvect()</tt> or
<tt>as_ivect()</tt> is actually invoked will the corresponding module
be implicitly imported. This also means that, for example, the
<tt>dvect</tt> module does not have to be available at all if
<tt>as_dvect()</tt> is never used.
<hr>
<h2>Clarification of compile-time and link-time dependencies</h2>
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 <tt>#include &lt;vector&gt;</tt>. This is immediately obvious
from the definition of <tt>class xy</tt>.
<p>
If a library is wrapped that consists of both header files and compiled
components (e.g. <tt>libdvect.a</tt>, <tt>dvect.lib</tt>, etc.), both
the Boost.Python extension module with the
<tt>export_converters()</tt> statement and the module with the
<tt>import_converters&lt;&gt;</tt> statement need to be linked against
the object library. Ideally one would build a shared library (e.g.
<tt>libdvect.so</tt>, <tt>dvect.dll</tt>, 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.
<hr>
<h2>Summary of motivation for cross-module support</h2>
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 <tt>std_vector</tt>
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.
<p>
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 <tt>A</tt> and <tt>B</tt> that
both wrap a given <tt>class X</tt>, this will work:
<pre>
import A
x = A.X()
</pre>
This will also work:
<pre>
import B
x = B.X()
</pre>
However, this will fail:
<pre>
import A
import B
python: /net/cci/rwgk/boost/boost/python/detail/extension_class.hpp:866:
static void boost::python::detail::class_registry&lt;X&gt;::register_class(boost::python::detail::extension_class_base *):
Assertion `static_class_object == 0' failed.
Abort
</pre>
A good solution is to wrap <tt>class X</tt> only once. Depending on the
situation, this could be done by module <tt>A</tt> or <tt>B</tt>, or an
additional small extension module that only wraps and exports
<tt>class X</tt>.
<p>
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.
<hr>
<h2>Why not use <tt>export_converters()</tt> universally?</h2>
There is some overhead associated with the Boost.Python cross-module
support. Depending on the platform, the size of the code generated by
<tt>export_converters()</tt> is roughly 10%-20% of that generated
by <tt>class_builder&lt;&gt;</tt>. For a large extension module with
many wrapped classes, this could mean a significant difference.
Therefore the general recommendation is to use
<tt>export_converters()</tt> only for classes that are likely to
be used as function arguments or return values in other modules.
<hr>
&copy; 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.
<p>
Updated: April 2001
</div>

272
doc/pickle.html Normal file
View File

@@ -0,0 +1,272 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>Boost.Python Pickle Support</title>
<div>
<img src="../../../c++boost.gif"
alt="c++boost.gif (8819 bytes)"
align="center"
width="277" height="86">
<hr>
<h1>Boost.Python Pickle Support</h1>
Pickle is a Python module for object serialization, also known
as persistence, marshalling, or flattening.
<p>
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.
<p>
The Boost Python Library supports the pickle module by emulating the
interface implemented by Jim Fulton's ExtensionClass module that is
included in the
<a href="http://www.zope.org/"
>ZOPE</a>
distribution.
This interface is similar to that for regular Python classes as
described in detail in the
<a href="http://www.python.org/doc/current/lib/module-pickle.html"
>Python Library Reference for pickle.</a>
<hr>
<h2>The Boost.Python Pickle Interface</h2>
At the user level, the Boost.Python pickle interface involves three special
methods:
<dl>
<dt>
<strong><tt>__getinitargs__</tt></strong>
<dd>
When an instance of a Boost.Python extension class is pickled, the
pickler tests if the instance has a <tt>__getinitargs__</tt> 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.
<p>
If <tt>__getinitargs__</tt> is not defined, the class constructor
will be called without arguments.
<p>
<dt>
<strong><tt>__getstate__</tt></strong>
<dd>
When an instance of a Boost.Python extension class is pickled, the
pickler tests if the instance has a <tt>__getstate__</tt> method.
This method should return a Python object representing the state of
the instance.
<p>
If <tt>__getstate__</tt> is not defined, the instance's
<tt>__dict__</tt> is pickled (if it is not empty).
<p>
<dt>
<strong><tt>__setstate__</tt></strong>
<dd>
When an instance of a Boost.Python extension class is restored by the
unpickler, it is first constructed using the result of
<tt>__getinitargs__</tt> as arguments (see above). Subsequently the
unpickler tests if the new instance has a <tt>__setstate__</tt>
method. If so, this method is called with the result of
<tt>__getstate__</tt> (a Python object) as the argument.
<p>
If <tt>__setstate__</tt> is not defined, the result of
<tt>__getstate__</tt> must be a Python dictionary. The items of this
dictionary are added to the instance's <tt>__dict__</tt>.
</dl>
If both <tt>__getstate__</tt> and <tt>__setstate__</tt> are defined,
the Python object returned by <tt>__getstate__</tt> need not be a
dictionary. The <tt>__getstate__</tt> and <tt>__setstate__</tt> methods
can do what they want.
<hr>
<h2>Pitfalls and Safety Guards</h2>
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:
<dl>
<dt>
<strong>Pitfall 1:</strong>
Both <tt>__getinitargs__</tt> and <tt>__getstate__</tt> are not defined.
<dd>
In this situation the unpickler calls the class constructor without
arguments and then adds the <tt>__dict__</tt> that was pickled by
default to that of the new instance.
<p>
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
<tt>__getinitargs__</tt> and <tt>__getstate__</tt> are not defined,
Boost.Python tests if the class has an attribute
<tt>__dict_defines_state__</tt>. An exception is raised if this
attribute is not defined:
<pre>
RuntimeError: Incomplete pickle support (__dict_defines_state__ not set)
</pre>
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.:
<pre>
class_builder&lt;your_class&gt; py_your_class(your_module, "your_class");
py_your_class.dict_defines_state();
</pre>
It is also possible to override the safety guard at the Python level.
E.g.:
<pre>
import your_bpl_module
class your_class(your_bpl_module.your_class):
__dict_defines_state__ = 1
</pre>
<p>
<dt>
<strong>Pitfall 2:</strong>
<tt>__getstate__</tt> is defined and the instance's <tt>__dict__</tt> is not empty.
<dd>
The author of a Boost.Python extension class might provide a
<tt>__getstate__</tt> method without considering the possibilities
that:
<p>
<ul>
<li>
his class is used in Python as a base class. Most likely the
<tt>__dict__</tt> of instances of the derived class needs to be
pickled in order to restore the instances correctly.
<p>
<li>
the user adds items to the instance's <tt>__dict__</tt> directly.
Again, the <tt>__dict__</tt> of the instance then needs to be
pickled.
</ul>
<p>
To alert the user to this highly unobvious problem, a safety guard is
provided. If <tt>__getstate__</tt> is defined and the instance's
<tt>__dict__</tt> is not empty, Boost.Python tests if the class has
an attribute <tt>__getstate_manages_dict__</tt>. An exception is
raised if this attribute is not defined:
<pre>
RuntimeError: Incomplete pickle support (__getstate_manages_dict__ not set)
</pre>
To resolve this problem, it should first be established that the
<tt>__getstate__</tt> and <tt>__setstate__</tt> methods manage the
instances's <tt>__dict__</tt> 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++:
<pre>
class_builder&lt;your_class&gt; py_your_class(your_module, "your_class");
py_your_class.getstate_manages_dict();
</pre>
In Python:
<pre>
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
</pre>
</dl>
<hr>
<h2>Practical Advice</h2>
<ul>
<li>
Avoid using <tt>__getstate__</tt> if the instance can also be
reconstructed by way of <tt>__getinitargs__</tt>. This automatically
avoids Pitfall 2.
<p>
<li>
If <tt>__getstate__</tt> is required, include the instance's
<tt>__dict__</tt> in the Python object that is returned.
</ul>
<hr>
<h2>Examples</h2>
There are three files in <tt>boost/libs/python/example</tt> that
show how so provide pickle support.
<h3><a href="../example/pickle1.cpp"><tt>pickle1.cpp</tt></a></h3>
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 <tt>__getinitargs__</tt>.
<h3><a href="../example/pickle2.cpp"><tt>pickle2.cpp</tt></a></h3>
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 <tt>__getstate__</tt>/<tt>__setstate__</tt> pair of
pickle interface methods.
<p>
For simplicity, the <tt>__dict__</tt> is not included in the result
of <tt>__getstate__</tt>. This is not generally recommended, but a
valid approach if it is anticipated that the object's
<tt>__dict__</tt> will always be empty. Note that the safety guards
will catch the cases where this assumption is violated.
<h3><a href="../example/pickle3.cpp"><tt>pickle3.cpp</tt></a></h3>
This example is similar to <a
href="../example/pickle2.cpp"><tt>pickle2.cpp</tt></a>. However, the
object's <tt>__dict__</tt> is included in the result of
<tt>__getstate__</tt>. This requires more code but is unavoidable
if the object's <tt>__dict__</tt> is not always empty.
<hr>
&copy; 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.
<p>
Updated: March 21, 2001
</div>

View File

@@ -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 <string>
#include <vector>
#include <boost/python/class_builder.hpp>
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<MillerIndex> 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<const MillerIndex&>)
{
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<int>());
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<MillerIndex>)
{
return from_python(p, python::type<const MillerIndex&>());
}
// 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<IndexingSet> 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
}
}

42
example/dvect.cpp Normal file
View File

@@ -0,0 +1,42 @@
#include "dvect.h"
#include "ivect.h"
#include <boost/python/cross_module.hpp>
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<int>(dv[i]);
return iv;
}
}
BOOST_PYTHON_MODULE_INIT(dvect)
{
try
{
python::module_builder this_module("dvect");
python::class_builder<vects::dvect> dvect_class(this_module, "dvect");
python::export_converters(dvect_class);
python::import_converters<vects::ivect> ivect_converters("ivect", "ivect");
dvect_class.def(python::constructor<python::tuple>());
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
}
}

32
example/dvect.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef DVECT_H
#define DVECT_H
#include <vector>
#include <boost/python/class_builder.hpp>
namespace vects {
struct dvect : public std::vector<double>
{
dvect() : std::vector<double>() {}
dvect(size_t n) : std::vector<double>(n) {}
dvect(boost::python::tuple tuple) : std::vector<double>(tuple.size())
{
std::vector<double>::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<double>());
}
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

View File

@@ -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<vects::dvect> dvect_as_auto_ptr(const vects::dvect& dv)
{
return std::auto_ptr<vects::dvect>(new vects::dvect(dv));
}
boost::shared_ptr<vects::dvect> dvect_as_shared_ptr(const vects::dvect& dv)
{
return boost::shared_ptr<vects::dvect>(new vects::dvect(dv));
}
// smart pointers passed by value
boost::python::ref auto_ptr_value_dvect_as_tuple(std::auto_ptr<vects::dvect> 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<vects::dvect> 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<vects::dvect>& 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<vects::dvect>& 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<vects::dvect>& 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<vects::dvect>& dv)
{
if (dv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count);
return dv->as_tuple().reference();
}

13
example/dvect_defs.cpp Normal file
View File

@@ -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");

42
example/ivect.cpp Normal file
View File

@@ -0,0 +1,42 @@
#include "dvect.h"
#include "ivect.h"
#include <boost/python/cross_module.hpp>
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<double>(iv[i]);
return dv;
}
}
BOOST_PYTHON_MODULE_INIT(ivect)
{
try
{
python::module_builder this_module("ivect");
python::class_builder<vects::ivect> ivect_class(this_module, "ivect");
python::export_converters(ivect_class);
python::import_converters<vects::dvect> dvect_converters("dvect", "dvect");
ivect_class.def(python::constructor<python::tuple>());
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
}
}

32
example/ivect.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef IVECT_H
#define IVECT_H
#include <vector>
#include <boost/python/class_builder.hpp>
namespace vects {
struct ivect : public std::vector<int>
{
ivect() : std::vector<int>() {}
ivect(size_t n) : std::vector<int>(n) {}
ivect(boost::python::tuple tuple) : std::vector<int>(tuple.size())
{
std::vector<int>::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<int>());
}
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

View File

@@ -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<vects::ivect> ivect_as_auto_ptr(const vects::ivect& iv)
{
return std::auto_ptr<vects::ivect>(new vects::ivect(iv));
}
boost::shared_ptr<vects::ivect> ivect_as_shared_ptr(const vects::ivect& iv)
{
return boost::shared_ptr<vects::ivect>(new vects::ivect(iv));
}
// smart pointers passed by value
boost::python::ref auto_ptr_value_ivect_as_tuple(std::auto_ptr<vects::ivect> 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<vects::ivect> 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<vects::ivect>& 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<vects::ivect>& 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<vects::ivect>& 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<vects::ivect>& iv)
{
if (iv.get() == 0) return boost::python::ref(Py_None, boost::python::ref::increment_count);
return iv->as_tuple().reference();
}

13
example/ivect_defs.cpp Normal file
View File

@@ -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");

14
example/noncopyable.h Normal file
View File

@@ -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

View File

@@ -0,0 +1,22 @@
#include <boost/python/cross_module.hpp>
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> store_class(this_module, "store");
python::export_converters_noncopyable(store_class);
store_class.def(python::constructor<int>());
store_class.def(&store::recall, "recall");
}
catch(...)
{
python::handle_exception(); // Deal with the exception for Python
}
}

View File

@@ -0,0 +1,39 @@
#include <boost/python/cross_module.hpp>
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<store> add_stores(const store& s1, const store& s2)
{
int sum = s1.recall() + s2.recall();
std::auto_ptr<store> ss = std::auto_ptr<store>(new store(sum));
return ss;
}
}
BOOST_PYTHON_MODULE_INIT(noncopyable_import)
{
try
{
python::module_builder this_module("noncopyable_import");
python::import_converters<store>
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
}
}

62
example/pickle1.cpp Normal file
View File

@@ -0,0 +1,62 @@
/*
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 <string>
#include <boost/python/class_builder.hpp>
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> world_class(this_module, "world");
// Add the __init__ function.
world_class.def(python::constructor<std::string>());
// 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
}
}

98
example/pickle2.cpp Normal file
View File

@@ -0,0 +1,98 @@
/*
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 <string>
#include <boost/python/class_builder.hpp>
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<int>());
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> world_class(this_module, "world");
// Add the __init__ function.
world_class.def(python::constructor<std::string>());
// 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
}
}

148
example/pickle3.cpp Normal file
View File

@@ -0,0 +1,148 @@
/*
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 <string>
#include <boost/python/class_builder.hpp>
namespace python = boost::python;
namespace boost { namespace python {
ref getattr(PyObject* o, const std::string& attr_name) {
return ref(PyObject_GetAttrString(o, const_cast<char*>(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> world_class(this_module, "world");
// Add the __init__ function.
world_class.def(python::constructor<std::string>());
// 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<const world&>());
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<world&>());
ref mydict = getattr(args[0], "__dict__");
tuple state = from_python(args[1].get(), type<tuple>());
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<dictionary>());
const dictionary& pdict = from_python(state[0].get(), type<const dictionary&>());
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<int>());
if (number != 42)
w.set_secret_number(number);
return python::detail::none();
}
}

101
example/simple_vector.cpp Normal file
View File

@@ -0,0 +1,101 @@
#include <boost/python/class_builder.hpp>
namespace python = boost::python;
namespace { // Avoid cluttering the global namespace.
// A wrapper is used to define additional constructors.
//
struct vector_double_wrapper: std::vector<double>
{
// Tell the compiler how to convert a base class object to
// this wrapper object.
vector_double_wrapper(PyObject*, const std::vector<double>& vd)
: std::vector<double>(vd) {}
vector_double_wrapper(PyObject* self)
: std::vector<double>() {}
vector_double_wrapper(PyObject* self, int n)
: std::vector<double>(n) {}
vector_double_wrapper(PyObject* self, python::tuple tuple)
: std::vector<double>(tuple.size())
{
std::vector<double>::iterator vd = begin();
for (int i = 0; i < tuple.size(); i++)
vd[i] = BOOST_PYTHON_CONVERSION::from_python(tuple[i].get(),
python::type<double>());
}
};
double getitem(const std::vector<double>& vd, std::size_t key) {
return vd[key];
}
void setitem(std::vector<double>& vd, std::size_t key, double d) {
std::vector<double>::iterator vditer = vd.begin();
vditer[key] = d;
}
void delitem(std::vector<double>& vd, std::size_t key) {
std::vector<double>::iterator vditer = vd.begin();
vd.erase(&vditer[key]);
}
// Convert vector_double to a regular Python tuple.
//
python::tuple as_tuple(const std::vector<double>& 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<double> foo(int n)
{
std::vector<double> vd(n);
std::vector<double>::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<std::vector<double> > bar(int n)
{
std::auto_ptr<std::vector<double> > vdptr(new std::vector<double>(n));
std::vector<double>::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<std::vector<double>, vector_double_wrapper>
vector_double(this_module, "vector_double");
vector_double.def(python::constructor<>());
vector_double.def(python::constructor<const int>());
vector_double.def(python::constructor<python::tuple>());
vector_double.def(&std::vector<double>::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
}
}

1
example/swap_iv_dv.sh Normal file
View File

@@ -0,0 +1 @@
sed 's/iv/xv/g' $1 | sed 's/dv/iv/g' | sed 's/xv/dv/g'

View File

@@ -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()

31
example/test_pickle1.py Normal file
View File

@@ -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(
... "\(<extension class pickle1.world at [0-9a-fA-FxX]+>, \('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()

45
example/test_pickle2.py Normal file
View File

@@ -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(
... "\(<extension class pickle2.world at [0-9a-fA-FxX]+>, \('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()

38
example/test_pickle3.py Normal file
View File

@@ -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(
... "\(<extension class pickle3.world at [0-9a-fA-FxX]+>, \('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()

View File

@@ -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()

23
example/tst_dvect1.py Normal file
View File

@@ -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()

98
example/tst_dvect2.py Normal file
View File

@@ -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)

23
example/tst_ivect1.py Normal file
View File

@@ -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()

98
example/tst_ivect2.py Normal file
View File

@@ -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)

View File

@@ -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()

View File

@@ -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 <boost/python/class_builder.hpp>
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 T> class import_extension_class;
}}}
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
/* This class template is instantiated by import_converters<T>.
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 T>
class python_import_extension_class_converters
{
public:
friend python_import_extension_class_converters py_extension_class_converters(boost::python::type<T>, bool sig = false) {
return python_import_extension_class_converters();
}
PyObject* to_python(const T& x) const {
return boost::python::detail::import_extension_class<T>::get_converters()->to_python(x);
}
friend T* from_python(PyObject* p, boost::python::type<T*> t, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_Ts(p, t);
}
friend const T* from_python(PyObject* p, boost::python::type<const T*> t, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_cTs(p, t);
}
friend const T* from_python(PyObject* p, boost::python::type<const T*const&> t, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_cTscr(p, t);
}
friend T* from_python(PyObject* p, boost::python::type<T* const&> t, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_Tscr(p, t);
}
friend T& from_python(PyObject* p, boost::python::type<T&> t, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_Tr(p, t);
}
friend const T& from_python(PyObject* p, boost::python::type<const T&> t, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_cTr(p, t);
}
friend const T& from_python(PyObject* p, boost::python::type<T> t, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_T(p, t);
}
friend std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<std::auto_ptr<T>&> t, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_aTr(p, t);
}
friend std::auto_ptr<T> from_python(PyObject* p, boost::python::type<std::auto_ptr<T> > t, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_aT(p, t);
}
friend const std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<const std::auto_ptr<T>&> t, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_caTr(p, t);
}
friend PyObject* to_python(std::auto_ptr<T> x, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->to_python(x);
}
friend boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<boost::shared_ptr<T>&> t, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_sTr(p, t);
}
friend const boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<boost::shared_ptr<T> > t, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_sT(p, t);
}
friend const boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<const boost::shared_ptr<T>&> t, bool sig = false) {
return boost::python::detail::import_extension_class<T>::get_converters()->from_python_csTr(p, t);
}
friend PyObject* to_python(boost::shared_ptr<T> x, bool sig = false) {
return boost::python::detail::import_extension_class<T>::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 <class T>
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*> t) = 0;
virtual const T* from_python_cTs(PyObject* p, boost::python::type<const T*> t) = 0;
virtual const T* from_python_cTscr(PyObject* p, boost::python::type<const T*const&> t) = 0;
virtual T* from_python_Tscr(PyObject* p, boost::python::type<T* const&> t) = 0;
virtual T& from_python_Tr(PyObject* p, boost::python::type<T&> t) = 0;
virtual const T& from_python_cTr(PyObject* p, boost::python::type<const T&> t) = 0;
virtual const T& from_python_T(PyObject* p, boost::python::type<T> t) = 0;
virtual std::auto_ptr<T>& from_python_aTr(PyObject* p, boost::python::type<std::auto_ptr<T>&> t) = 0;
virtual std::auto_ptr<T> from_python_aT(PyObject* p, boost::python::type<std::auto_ptr<T> > t) = 0;
virtual const std::auto_ptr<T>& from_python_caTr(PyObject* p, boost::python::type<const std::auto_ptr<T>&> t) = 0;
virtual PyObject* to_python(std::auto_ptr<T> x) = 0;
virtual boost::shared_ptr<T>& from_python_sTr(PyObject* p, boost::python::type<boost::shared_ptr<T>&> t) = 0;
virtual const boost::shared_ptr<T>& from_python_sT(PyObject* p, boost::python::type<boost::shared_ptr<T> > t) = 0;
virtual const boost::shared_ptr<T>& from_python_csTr(PyObject* p, boost::python::type<const boost::shared_ptr<T>&> t) = 0;
virtual PyObject* to_python(boost::shared_ptr<T> x) = 0;
};
// Converters to be used if T is not copyable.
template <class T>
struct export_converter_object_noncopyable : export_converter_object_base<T>
{
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*> t) {
return BOOST_PYTHON_CONVERSION::from_python(p, t);
}
virtual const T* from_python_cTs(PyObject* p, boost::python::type<const T*> t) {
return BOOST_PYTHON_CONVERSION::from_python(p, t);
}
virtual const T* from_python_cTscr(PyObject* p, boost::python::type<const T*const&> t) {
return BOOST_PYTHON_CONVERSION::from_python(p, t);
}
virtual T* from_python_Tscr(PyObject* p, boost::python::type<T* const&> t) {
return BOOST_PYTHON_CONVERSION::from_python(p, t);
}
virtual T& from_python_Tr(PyObject* p, boost::python::type<T&> t) {
return BOOST_PYTHON_CONVERSION::from_python(p, t);
}
virtual const T& from_python_cTr(PyObject* p, boost::python::type<const T&> t) {
return BOOST_PYTHON_CONVERSION::from_python(p, t);
}
virtual const T& from_python_T(PyObject* p, boost::python::type<T> t) {
return BOOST_PYTHON_CONVERSION::from_python(p, t);
}
virtual std::auto_ptr<T>& from_python_aTr(PyObject* p, boost::python::type<std::auto_ptr<T>&> t) {
return BOOST_PYTHON_CONVERSION::from_python(p, t);
}
virtual std::auto_ptr<T> from_python_aT(PyObject* p, boost::python::type<std::auto_ptr<T> > t) {
return BOOST_PYTHON_CONVERSION::from_python(p, t);
}
virtual const std::auto_ptr<T>& from_python_caTr(PyObject* p, boost::python::type<const std::auto_ptr<T>&> t) {
return BOOST_PYTHON_CONVERSION::from_python(p, t);
}
virtual PyObject* to_python(std::auto_ptr<T> x) {
return BOOST_PYTHON_CONVERSION::to_python(x);
}
virtual boost::shared_ptr<T>& from_python_sTr(PyObject* p, boost::python::type<boost::shared_ptr<T>&> t) {
return BOOST_PYTHON_CONVERSION::from_python(p, t);
}
virtual const boost::shared_ptr<T>& from_python_sT(PyObject* p, boost::python::type<boost::shared_ptr<T> > t) {
return BOOST_PYTHON_CONVERSION::from_python(p, t);
}
virtual const boost::shared_ptr<T>& from_python_csTr(PyObject* p, boost::python::type<const boost::shared_ptr<T>&> t) {
return BOOST_PYTHON_CONVERSION::from_python(p, t);
}
virtual PyObject* to_python(boost::shared_ptr<T> x) {
return BOOST_PYTHON_CONVERSION::to_python(x);
}
};
// The addditional to_python() converter that can be used if T is copyable.
template <class T>
struct export_converter_object : export_converter_object_noncopyable<T>
{
virtual PyObject* to_python(const T& x) {
return BOOST_PYTHON_CONVERSION::py_extension_class_converters(boost::python::type<T>()).to_python(x);
}
};
namespace detail {
/* This class template is instantiated by import_converters<T>.
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 T>
class import_extension_class
: public python_import_extension_class_converters<T>
{
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<T>* get_converters();
private:
static std::string m_module;
static std::string m_py_class;
static boost::python::export_converter_object_base<T>* imported_converters;
};
template <class T> std::string import_extension_class<T>::m_module;
template <class T> std::string import_extension_class<T>::m_py_class;
template <class T>
boost::python::export_converter_object_base<T>*
import_extension_class<T>::imported_converters = 0;
template <class T>
boost::python::export_converter_object_base<T>*
import_extension_class<T>::get_converters() {
if (imported_converters == 0) {
void* cobject
= import_converter_object(m_module, m_py_class,
converters_attribute_name);
imported_converters
= static_cast<boost::python::export_converter_object_base<T>*>(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 <class T, class U>
void export_converters(class_builder<T, U>& cb)
{
static export_converter_object<T> export_cvts;
cb.add(
ref(PyCObject_FromVoidPtr(reinterpret_cast<void*>(&export_cvts), NULL)),
detail::converters_attribute_name);
}
// Implementation of export_converters_noncopyable().
template <class T, class U>
void export_converters_noncopyable(class_builder<T, U>& cb)
{
static export_converter_object_noncopyable<T> export_cvts;
cb.add(
ref(PyCObject_FromVoidPtr(reinterpret_cast<void*>(&export_cvts), NULL)),
detail::converters_attribute_name);
}
// Implementation of import_converters<T>.
template <class T>
class import_converters
: python_import_extension_class_converters<T> // 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<T>(module, py_class))
{ }
private:
boost::shared_ptr<detail::import_extension_class<T> > m_class;
};
}} // namespace boost::python
#endif // CROSS_MODULE_HPP

View File

@@ -0,0 +1,915 @@
// (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 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_
# include <boost/python/detail/config.hpp>
# include <boost/python/classes.hpp>
# include <vector>
# include <boost/python/detail/none.hpp>
# include <boost/python/objects.hpp>
# include <boost/python/detail/functions.hpp>
# include <memory>
# include <boost/python/detail/init_function.hpp>
# include <typeinfo>
# include <boost/smart_ptr.hpp>
# include <boost/type_traits.hpp>
namespace boost { namespace python {
// forward declarations
template <long which, class operand> struct operators;
template <class T> struct left_operand;
template <class T> struct right_operand;
enum without_downcast_t { without_downcast };
namespace detail {
// forward declarations
class extension_instance;
class extension_class_base;
template <class T> class instance_holder;
template <class T, class U> class instance_value_holder;
template <class ref, class T> class instance_ptr_holder;
template <class Specified> struct operand_select;
template <long> struct choose_op;
template <long> struct choose_rop;
template <long> struct choose_unary_op;
template <long> struct define_operator;
meta_class<extension_instance>* extension_meta_class();
extension_instance* get_extension_instance(PyObject* p);
void report_missing_instance_data(extension_instance*, class_t<extension_instance>*, const std::type_info&);
void report_missing_ptr_data(extension_instance*, class_t<extension_instance>*, const std::type_info&);
void report_missing_class_object(const std::type_info&);
void report_released_smart_pointer(const std::type_info&);
template <class T>
T* check_non_null(T* p)
{
if (p == 0)
report_released_smart_pointer(typeid(T));
return p;
}
template <class Held> 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<extension_instance>
{
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<base_class_info> const& base_classes() const = 0;
virtual std::vector<derived_class_info> const& derived_classes() const = 0;
protected:
friend struct add_operator_base;
void add_method(reference<function> 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 T>
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<base_class_info> const& base_classes();
static std::vector<derived_class_info> const& derived_classes();
private:
static extension_class_base* static_class_object;
static std::vector<base_class_info> static_base_class_info;
static std::vector<derived_class_info> static_derived_class_info;
};
template <bool is_pointer>
struct is_null_helper
{
template <class Ptr>
static bool test(Ptr x) { return x == 0; }
};
template <>
struct is_null_helper<false>
{
template <class Ptr>
static bool test(const Ptr& x) { return x.get() == 0; }
};
template <class Ptr>
bool is_null(const Ptr& x)
{
return is_null_helper<(is_pointer<Ptr>::value)>::test(x);
}
}}} // 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<T>.
template <class T, class U = boost::python::detail::held_instance<T> >
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<T>, bool sig = false)
{
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<boost::python::detail::extension_instance> result(create_instance());
result->add_implementation(
std::auto_ptr<boost::python::detail::instance_holder_base>(
new boost::python::detail::instance_value_holder<T,U>(result.get(), x)));
return result.release();
}
friend
T* non_null_from_python(PyObject* obj, boost::python::type<T*>)
{
// 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<boost::python::detail::instance_holder_base*>::const_iterator iterator;
for (iterator p = self->wrapped_objects().begin();
p != self->wrapped_objects().end(); ++p)
{
boost::python::detail::instance_holder<T>* held = dynamic_cast<boost::python::detail::instance_holder<T>*>(*p);
if (held != 0)
return held->target();
// see extclass.cpp for an explanation of try_class_conversions()
void* target = boost::python::detail::class_registry<T>::class_object()->try_class_conversions(*p);
if(target)
return static_cast<T*>(target);
}
boost::python::detail::report_missing_instance_data(self, boost::python::detail::class_registry<T>::class_object(), typeid(T));
throw boost::python::argument_error();
}
// Convert to T*
friend T* from_python(PyObject* obj, boost::python::type<T*>, bool sig = false)
{
if (obj == Py_None)
return 0;
else
return non_null_from_python(obj, boost::python::type<T*>());
}
// Extract from obj a mutable reference to the PtrType object which is holding a T.
template <class PtrType>
static PtrType& smart_ptr_reference(PyObject* obj, boost::python::type<PtrType>)
{
// 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<boost::python::detail::instance_holder_base*>::const_iterator iterator;
for (iterator p = self->wrapped_objects().begin();
p != self->wrapped_objects().end(); ++p)
{
boost::python::detail::instance_ptr_holder<PtrType, T>* held =
dynamic_cast<boost::python::detail::instance_ptr_holder<PtrType, T>*>(*p);
if (held != 0)
return held->ptr();
}
boost::python::detail::report_missing_ptr_data(self, boost::python::detail::class_registry<T>::class_object(), typeid(T));
throw boost::python::argument_error();
}
// 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 <class PtrType>
static PtrType& smart_ptr_value(PyObject* obj, boost::python::type<PtrType>)
{
if (obj == Py_None)
{
static PtrType null_ptr;
return null_ptr;
}
return smart_ptr_reference(obj, boost::python::type<PtrType>());
}
template <class PtrType>
static PyObject* smart_ptr_to_python(PtrType x)
{
if (boost::python::detail::is_null(x))
{
return boost::python::detail::none();
}
boost::python::reference<boost::python::detail::extension_instance> result(create_instance());
result->add_implementation(
std::auto_ptr<boost::python::detail::instance_holder_base>(
new boost::python::detail::instance_ptr_holder<PtrType,T>(x)));
return result.release();
}
static boost::python::reference<boost::python::detail::extension_instance> create_instance()
{
PyTypeObject* class_object = boost::python::detail::class_registry<T>::class_object();
if (class_object == 0)
boost::python::detail::report_missing_class_object(typeid(T));
return boost::python::reference<boost::python::detail::extension_instance>(
new boost::python::detail::extension_instance(class_object));
}
// Convert to const T*
friend const T* from_python(PyObject* p, boost::python::type<const T*>, bool sig = false)
{ return from_python(p, boost::python::type<T*>()); }
// Convert to const T* const&
friend const T* from_python(PyObject* p, boost::python::type<const T*const&>, bool sig = false)
{ return from_python(p, boost::python::type<const T*>()); }
// Convert to T* const&
friend T* from_python(PyObject* p, boost::python::type<T* const&>, bool sig = false)
{ return from_python(p, boost::python::type<T*>()); }
// Convert to T&
friend T& from_python(PyObject* p, boost::python::type<T&>, bool sig = false)
{ return *boost::python::detail::check_non_null(non_null_from_python(p, boost::python::type<T*>())); }
// Convert to const T&
friend const T& from_python(PyObject* p, boost::python::type<const T&>, bool sig = false)
{ return from_python(p, boost::python::type<T&>()); }
// Convert to T
friend const T& from_python(PyObject* p, boost::python::type<T>, bool sig = false)
{ return from_python(p, boost::python::type<T&>()); }
friend std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<std::auto_ptr<T>&>, bool sig = false)
{ return smart_ptr_reference(p, boost::python::type<std::auto_ptr<T> >()); }
friend std::auto_ptr<T> from_python(PyObject* p, boost::python::type<std::auto_ptr<T> >, bool sig = false)
{ return smart_ptr_value(p, boost::python::type<std::auto_ptr<T> >()); }
friend const std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<const std::auto_ptr<T>&>, bool sig = false)
{ return smart_ptr_value(p, boost::python::type<std::auto_ptr<T> >()); }
friend PyObject* to_python(std::auto_ptr<T> x, bool sig = false)
{ return smart_ptr_to_python(x); }
friend boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<boost::shared_ptr<T>&>, bool sig = false)
{ return smart_ptr_reference(p, boost::python::type<boost::shared_ptr<T> >()); }
friend const boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<boost::shared_ptr<T> >, bool sig = false)
{ return smart_ptr_value(p, boost::python::type<boost::shared_ptr<T> >()); }
friend const boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<const boost::shared_ptr<T>&>, bool sig = false)
{ return smart_ptr_value(p, boost::python::type<boost::shared_ptr<T> >()); }
friend PyObject* to_python(boost::shared_ptr<T> x, bool sig = false)
{ return smart_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 <class T>
PyObject* to_python(const T& x)
{
return py_extension_class_converters(boost::python::type<T>()).to_python(x);
}
BOOST_PYTHON_END_CONVERSION_NAMESPACE
namespace boost { namespace python {
BOOST_PYTHON_IMPORT_CONVERSION(python_extension_class_converters);
namespace detail {
template <class T> 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 <class From, class To>
struct define_conversion
{
static void* upcast_ptr(void* v)
{
return static_cast<To*>(static_cast<From*>(v));
}
static void* downcast_ptr(void* v)
{
return dynamic_cast<To*>(static_cast<From*>(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<extension_instance> 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 T, class U = held_instance<T> >
class extension_class
: public python_extension_class_converters<T, U>, // 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 <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
inline void def(constructor<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>)
// The following incantation builds a signature1, signature2,... object. It
// should _all_ get optimized away.
{ add_constructor(
prepend(type<A1>::id(),
prepend(type<A2>::id(),
prepend(type<A3>::id(),
prepend(type<A4>::id(),
prepend(type<A5>::id(),
prepend(type<A6>::id(),
prepend(type<A7>::id(),
prepend(type<A8>::id(),
prepend(type<A9>::id(),
prepend(type<A10>::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 <long which, class Operand>
inline void def(operators<which,Operand>)
{
typedef typename operand_select<Operand>::template wrapped<T>::type true_operand;
def_operators(operators<which,true_operand>());
}
// 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<int const&>());
// 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<int const&>());
template <long which, class Left, class Right>
inline void def(operators<which,Left>, right_operand<Right> r)
{
typedef typename operand_select<Left>::template wrapped<T>::type true_left;
def_operators(operators<which,true_left>(), 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<int const&>());
// 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<int const&>());
template <long which, class Left, class Right>
inline void def(operators<which,Right>, left_operand<Left> l)
{
typedef typename operand_select<Right>::template wrapped<T>::type true_right;
def_operators(operators<which,true_right>(), 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 <class Fn>
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 <class Fn>
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 <class Fn, class DefaultFn>
inline void def(Fn fn, const char* name, DefaultFn default_fn)
{
this->add_method(new_virtual_function(type<T>(), fn, default_fn), name);
}
// Provide a function which implements x.<name>, reading from the given
// member (pm) of the T obj
template <class MemberType>
inline void def_getter(MemberType T::*pm, const char* name)
{
this->add_getter_method(new getter_function<T, MemberType>(pm), name);
}
// Provide a function which implements assignment to x.<name>, writing to
// the given member (pm) of the T obj
template <class MemberType>
inline void def_setter(MemberType T::*pm, const char* name)
{
this->add_setter_method(new setter_function<T, MemberType>(pm), name);
}
// Expose the given member (pm) of the T obj as a read-only attribute
template <class MemberType>
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 <class MemberType>
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 <class S, class V>
void declare_base(extension_class<S, V>* base)
{
// see extclass.cpp for an explanation of why we need to register
// conversion functions
base_class_info baseInfo(base,
&define_conversion<S, T>::downcast_ptr);
class_registry<T>::register_base_class(baseInfo);
add_base(ref(as_object(base), ref::increment_count));
derived_class_info derivedInfo(this,
&define_conversion<T, S>::upcast_ptr);
class_registry<S>::register_derived_class(derivedInfo);
}
// declare the given class a base class of this one and register
// only up conversion function
template <class S, class V>
void declare_base(extension_class<S, V>* 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<T>::register_base_class(baseInfo);
add_base(ref(as_object(base), ref::increment_count));
derived_class_info derivedInfo(this,
&define_conversion<T, S>::upcast_ptr);
class_registry<S>::register_derived_class(derivedInfo);
}
private: // types
typedef instance_value_holder<T,U> holder;
private: // extension_class_base virtual function implementations
std::vector<base_class_info> const& base_classes() const;
std::vector<derived_class_info> const& derived_classes() const;
void* extract_object_from_holder(instance_holder_base* v) const;
private: // Utility functions
template <long which, class Operand>
inline void def_operators(operators<which,Operand>)
{
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<Operand>::add(this);
choose_op<(which & op_sub)>::template args<Operand>::add(this);
choose_op<(which & op_mul)>::template args<Operand>::add(this);
choose_op<(which & op_div)>::template args<Operand>::add(this);
choose_op<(which & op_mod)>::template args<Operand>::add(this);
choose_op<(which & op_divmod)>::template args<Operand>::add(this);
choose_op<(which & op_pow)>::template args<Operand>::add(this);
choose_op<(which & op_lshift)>::template args<Operand>::add(this);
choose_op<(which & op_rshift)>::template args<Operand>::add(this);
choose_op<(which & op_and)>::template args<Operand>::add(this);
choose_op<(which & op_xor)>::template args<Operand>::add(this);
choose_op<(which & op_or)>::template args<Operand>::add(this);
choose_unary_op<(which & op_neg)>::template args<Operand>::add(this);
choose_unary_op<(which & op_pos)>::template args<Operand>::add(this);
choose_unary_op<(which & op_abs)>::template args<Operand>::add(this);
choose_unary_op<(which & op_invert)>::template args<Operand>::add(this);
choose_unary_op<(which & op_int)>::template args<Operand>::add(this);
choose_unary_op<(which & op_long)>::template args<Operand>::add(this);
choose_unary_op<(which & op_float)>::template args<Operand>::add(this);
choose_op<(which & op_cmp)>::template args<Operand>::add(this);
choose_unary_op<(which & op_str)>::template args<Operand>::add(this);
}
template <long which, class Left, class Right>
inline void def_operators(operators<which,Left>, right_operand<Right>)
{
def_standard_coerce();
choose_op<(which & op_add)>::template args<Left,Right>::add(this);
choose_op<(which & op_sub)>::template args<Left,Right>::add(this);
choose_op<(which & op_mul)>::template args<Left,Right>::add(this);
choose_op<(which & op_div)>::template args<Left,Right>::add(this);
choose_op<(which & op_mod)>::template args<Left,Right>::add(this);
choose_op<(which & op_divmod)>::template args<Left,Right>::add(this);
choose_op<(which & op_pow)>::template args<Left,Right>::add(this);
choose_op<(which & op_lshift)>::template args<Left,Right>::add(this);
choose_op<(which & op_rshift)>::template args<Left,Right>::add(this);
choose_op<(which & op_and)>::template args<Left,Right>::add(this);
choose_op<(which & op_xor)>::template args<Left,Right>::add(this);
choose_op<(which & op_or)>::template args<Left,Right>::add(this);
choose_op<(which & op_cmp)>::template args<Left,Right>::add(this);
}
template <long which, class Left, class Right>
inline void def_operators(operators<which,Right>, left_operand<Left>)
{
def_standard_coerce();
choose_rop<(which & op_add)>::template args<Left,Right>::add(this);
choose_rop<(which & op_sub)>::template args<Left,Right>::add(this);
choose_rop<(which & op_mul)>::template args<Left,Right>::add(this);
choose_rop<(which & op_div)>::template args<Left,Right>::add(this);
choose_rop<(which & op_mod)>::template args<Left,Right>::add(this);
choose_rop<(which & op_divmod)>::template args<Left,Right>::add(this);
choose_rop<(which & op_pow)>::template args<Left,Right>::add(this);
choose_rop<(which & op_lshift)>::template args<Left,Right>::add(this);
choose_rop<(which & op_rshift)>::template args<Left,Right>::add(this);
choose_rop<(which & op_and)>::template args<Left,Right>::add(this);
choose_rop<(which & op_xor)>::template args<Left,Right>::add(this);
choose_rop<(which & op_or)>::template args<Left,Right>::add(this);
choose_rop<(which & op_cmp)>::template args<Left,Right>::add(this);
}
template <class signature>
void add_constructor(signature sig)
{
this->add_constructor_object(init_function<holder>::create(sig));
}
};
// A simple wrapper over a T which allows us to use extension_class<T> with a
// single template parameter only. See extension_class<T>, above.
template <class Held>
class held_instance : public Held
{
// There are no member functions: we want to avoid inadvertently overriding
// any virtual functions in Held.
public:
held_instance(PyObject*) : Held() {}
template <class A1>
held_instance(PyObject*, A1 a1) : Held(a1) {}
template <class A1, class A2>
held_instance(PyObject*, A1 a1, A2 a2) : Held(a1, a2) {}
template <class A1, class A2, class A3>
held_instance(PyObject*, A1 a1, A2 a2, A3 a3) : Held(a1, a2, a3) {}
template <class A1, class A2, class A3, class A4>
held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4) : Held(a1, a2, a3, a4) {}
template <class A1, class A2, class A3, class A4, class A5>
held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : Held(a1, a2, a3, a4, a5) {}
template <class A1, class A2, class A3, class A4, class A5, class A6>
held_instance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : Held(a1, a2, a3, a4, a5, a6) {}
template <class A1, class A2, class A3, class A4, class A5, class A6, class 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 <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class 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 <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class 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 <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class 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
// 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 Held>
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 Held, class Wrapper>
class instance_value_holder : public instance_holder<Held>
{
public:
Held* target() { return &m_held; }
Wrapper* value_target() { return &m_held; }
instance_value_holder(extension_instance* p) :
m_held(p) {}
template <class A1>
instance_value_holder(extension_instance* p, A1 a1) :
m_held(p, a1) {}
template <class A1, class A2>
instance_value_holder(extension_instance* p, A1 a1, A2 a2) :
m_held(p, a1, a2) {}
template <class A1, class A2, class A3>
instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3) :
m_held(p, a1, a2, a3) {}
template <class A1, class A2, class A3, class A4>
instance_value_holder(extension_instance* p, A1 a1, A2 a2, A3 a3, A4 a4) :
m_held(p, a1, a2, a3, a4) {}
template <class A1, class A2, class A3, class A4, class A5>
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 <class A1, class A2, class A3, class A4, class A5, class A6>
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 <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
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 <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
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 <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
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 <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
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; }
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<HeldType> and PtrType == boost::shared_ptr<HeldType>.
template <class PtrType, class HeldType>
class instance_ptr_holder : public instance_holder<HeldType>
{
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<instance_holder_base> holder);
typedef std::vector<instance_holder_base*> held_objects;
const held_objects& wrapped_objects() const
{ return m_wrapped_objects; }
private:
held_objects m_wrapped_objects;
};
//
// Template function implementations
//
template <class T, class U>
extension_class<T, U>::extension_class()
: extension_class_base(typeid(T).name())
{
class_registry<T>::register_class(this);
}
template <class T, class U>
extension_class<T, U>::extension_class(const char* name)
: extension_class_base(name)
{
class_registry<T>::register_class(this);
}
template <class T, class U>
void extension_class<T, U>::def_standard_coerce()
{
ref coerce_fct = dict().get_item(string("__coerce__"));
if(coerce_fct.get() == 0) // not yet defined
this->def(&standard_coerce, "__coerce__");
}
template <class T, class U>
inline
std::vector<base_class_info> const&
extension_class<T, U>::base_classes() const
{
return class_registry<T>::base_classes();
}
template <class T, class U>
inline
std::vector<derived_class_info> const&
extension_class<T, U>::derived_classes() const
{
return class_registry<T>::derived_classes();
}
template <class T, class U>
void* extension_class<T, U>::extract_object_from_holder(instance_holder_base* v) const
{
instance_holder<T>* held = dynamic_cast<instance_holder<T>*>(v);
if(held)
return held->target();
return 0;
}
template <class T, class U>
extension_class<T, U>::~extension_class()
{
class_registry<T>::unregister_class(this);
}
template <class T>
inline void class_registry<T>::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 <class T>
inline void class_registry<T>::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 <class T>
void class_registry<T>::register_base_class(base_class_info const& i)
{
static_base_class_info.push_back(i);
}
template <class T>
void class_registry<T>::register_derived_class(derived_class_info const& i)
{
static_derived_class_info.push_back(i);
}
template <class T>
std::vector<base_class_info> const& class_registry<T>::base_classes()
{
return static_base_class_info;
}
template <class T>
std::vector<derived_class_info> const& class_registry<T>::derived_classes()
{
return static_derived_class_info;
}
//
// Static data member declaration.
//
template <class T>
extension_class_base* class_registry<T>::static_class_object;
template <class T>
std::vector<base_class_info> class_registry<T>::static_base_class_info;
template <class T>
std::vector<derived_class_info> class_registry<T>::static_derived_class_info;
}}} // namespace boost::python::detail
#endif // EXTENSION_CLASS_DWA052000_H_

View File

@@ -1,180 +0,0 @@
23 October 2003
Fixed bug where a class would appear more than one in the generated code.
6 October 2003
Fixed bug reported by Niall Douglas (using his patch) about UniqueInt not
appearing correctly with --multiple.
Added precompiled header support on windows systems (using #pragma hdrstop).
Suggested by Niall Douglas.
Fixed a bug with -I directive and AllFromHeader. Reported by Scott Snyder.
4 October 2003
Added return_self, thanks for Niall Douglas for pointing out that it was
missing.
Added --file-list, where you can pass a file where the pyste files are listed
one per line. Also suggested by Niall Douglas.
Documentation has been finally updated, after a long wait. Please let me know
if you spot any mistake!
2 October 2003
Scott Snyder found a typo in ClassExporter that prevented -= and *= operators
from being exported. Thanks Scott!
20 September 2003
Added return_by_value in the list of policies supported. Thanks to Niall
Douglas for the remainder.
19 September 2003
Better support for unnamed enums, plus they are by default exported to the
parent's namespace. Normal enums can have the same behaviour using the function
export_values on the Enum object. Feature requested by Niall Douglas.
10 September 2003
A new variable is accessible in the Pyste files: INTERFACE_FILE contains the
full path of the pyste file.
4 September 2003
Now it is possible to override protected and private pure virtual functions
in Python, as requested by Roman Yakovenko.
23 August 2003
Fixed bug where some Imports where not writing their include files.
Now whenever the declarations change, the cache files are rebuilt
automatically.
19 August 2003
Fixed a bug related to the generation of the bases<> template.
17 August 2003
Added support for insertion of user code in the generated code.
16 August 2003
Applied a patch by Gottfried Ganssauge that adds exception specifiers to
wrapper functions and pointer declarations. Thanks a lot Gottfried!!
Applied a patch by Prabhu Ramachandran that fixes ae problem with the
pure virtual method generation. Thanks again Prabhu!
10 August 2003
Support for incremental generation of the code has been added. This changes
how --multiple works; documentation of this new feature will follow. Thanks
to Prabhu Ramachandran, that saw the need for this feature and discussed a
solution.
Automatically convert \ to / in Windows systems before passing the paths to
gccxml.
Fixed a bug reported by Prabhu Ramachandran, where in some classes the virtual
methods were being definied incorrectly. Thanks a lot Prabhu!
7 July 2003
Applied 2 patches by Prabhu Ramachandran: a fix in the new --multiple method,
and two new functions "hold_with_shared_ptr" and its counterpart for auto_ptr.
Thanks a lot Prabhu!
Fixed a bug where the macro BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID was being
called multiple times for the same type.
Thanks to Gottfried Ganßauge for reporting this!
Fixed bug where using AllFromHeader didn't use bases<> when exporting
hierarchies.
Fixed the staticmethod bug.
5 July 2003
Changed how --multiple works: now it generates one cpp file for each pyste
file, makeing easier to integrate Pyste with build systems.
4 July 2003
Applied patch that solved a bug in ClassExporter and added a distutils install
script (install/setup.py), both contributed by Prabhu Ramachandran.
Thanks Prabhu!
2 July 2003
Jim Wilson found a bug where types like "char**" were being interpreted as
"char*". Thanks Jim!
16 June 2003
Thanks to discussions with David Abrahams and Roman Sulzhyk, some behaviours
have changed:
- If you export a derived class without exporting its base classes, the derived
class will explicitly export the bases's methods and attributes. Before, if
you were interested in the bases's methods, you had to export the base
classes too.
- Added a new function, no_override. When a member function is specified as
"no_override", no virtual wrappers are generated for it, improving
performance and letting the code more clean.
- There was a bug in which the policy of virtual member functions was being
ignored (patch by Roman Sulzhyk).
Thanks again to Roman Sulzhyk for the patches and discussion in the c++-sig.
4 June 2003
Major improvements in memory usage.
3 June 2003
Appliced a patch from Giulio Eulisse that allows unnamed enumerations to be
exported with an AllFromHeader construct. Thanks a lot Giulio!
2 June 2003
Added a new construct, add_method. See documentation.
23 May 2003
Support for global variables added.
Various bug fixes.
08 May 2003
Fixed bug where in a certain cases the GCCXMLParser would end up with multiple
declarations of the same class
22 Apr 2003
- Now shows a warning when the user tries to export a forward-declared class.
Forward-declared classes are ignored by the AllFromHeader construct.
- Fixed a bug where classes, functions and enums where being exported, even if
excluded from a AllFromHeader construct.
16 Apr 2003
Added a more generic (but ugly) code to declare the smart pointer converters.
07 Apr 2003
- Removed the warnings about forward declarations: it was not accurate enough.
Another strategy must be thought of.
- Fixed bug in the --multiple mode, where the order of the class instantiations
could end up wrong.
- Lots of fixes in the documentation, pointed out by Dirk Gerrits. Thanks Dirk!
- Fixed support for the return_opaque_pointer policy (the support macro was not
being declared).
06 Apr 2003
Support for the improved static data members support of Boost.Python.
05 Apr 2003
New option for generating the bindings: --multiple.
02 Apr 2003
Forward declarations are now detected and a warning is generated.
24 Mar 2003
Default policy for functions/methods that return const T& is now
return_value_policy<copy_const_reference>().
22 Mar 2003
Exporting virtual methods of the base classes in the derived classes too.
21 Mar 2003
Added manual support for boost::shared_ptr and std::auto_ptr (see doc).
19 Mar 2003
Added support for int, double, float and long operators acting as expected in
python.
14 Mar 2003
Fixed bug: Wrappers for protected and virtual methods were not being generated.

87
src/cross_module.cpp Normal file
View File

@@ -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 <boost/python/cross_module.hpp>
namespace python = boost::python;
# include <stdio.h> // MSVC6.0SP4 does not know std::fprintf
# include <string.h> // 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<char*>(module_name.c_str()));
PyObject* py_class = PyDict_GetItemString(module_dict, const_cast<char*>(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<char*>(err.c_str()));
throw python::import_error();
}
python::ref c_obj(PyObject_GetAttrString(py_class, const_cast<char*>(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<char*>(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<char*>(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