mirror of
https://github.com/boostorg/python.git
synced 2026-01-25 06:22:15 +00:00
Compare commits
2 Commits
svn-branch
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8934fa00f | ||
|
|
fcf452e24a |
@@ -1,216 +0,0 @@
|
|||||||
# Microsoft Developer Studio Project File - Name="bpl_static" - Package Owner=<4>
|
|
||||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
|
||||||
# ** DO NOT EDIT **
|
|
||||||
|
|
||||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
|
||||||
|
|
||||||
CFG=bpl_static - Win32 Debug
|
|
||||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
|
||||||
!MESSAGE use the Export Makefile command and run
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "bpl_static.mak".
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE You can specify a configuration when running NMAKE
|
|
||||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "bpl_static.mak" CFG="bpl_static - Win32 Debug"
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE Possible choices for configuration are:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE "bpl_static - Win32 Release" (based on "Win32 (x86) Static Library")
|
|
||||||
!MESSAGE "bpl_static - Win32 Debug" (based on "Win32 (x86) Static Library")
|
|
||||||
!MESSAGE
|
|
||||||
|
|
||||||
# Begin Project
|
|
||||||
# PROP AllowPerConfigDependencies 0
|
|
||||||
# PROP Scc_ProjName ""
|
|
||||||
# PROP Scc_LocalPath ""
|
|
||||||
CPP=cl.exe
|
|
||||||
RSC=rc.exe
|
|
||||||
|
|
||||||
!IF "$(CFG)" == "bpl_static - Win32 Release"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 0
|
|
||||||
# PROP BASE Output_Dir "Release"
|
|
||||||
# PROP BASE Intermediate_Dir "Release"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 0
|
|
||||||
# PROP Output_Dir "Release"
|
|
||||||
# PROP Intermediate_Dir "Release"
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
|
||||||
# ADD CPP /nologo /MD /W4 /WX /GR /GX /O2 /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /c
|
|
||||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LIB32=link.exe -lib
|
|
||||||
# ADD BASE LIB32 /nologo
|
|
||||||
# ADD LIB32 /nologo
|
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "bpl_static - Win32 Debug"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 1
|
|
||||||
# PROP BASE Output_Dir "Debug"
|
|
||||||
# PROP BASE Intermediate_Dir "Debug"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 1
|
|
||||||
# PROP Output_Dir "Debug"
|
|
||||||
# PROP Intermediate_Dir "Debug"
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
|
||||||
# ADD CPP /nologo /MDd /W4 /WX /Gm /GR /GX /ZI /Od /I "..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c
|
|
||||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LIB32=link.exe -lib
|
|
||||||
# ADD BASE LIB32 /nologo
|
|
||||||
# ADD LIB32 /nologo
|
|
||||||
|
|
||||||
!ENDIF
|
|
||||||
|
|
||||||
# Begin Target
|
|
||||||
|
|
||||||
# Name "bpl_static - Win32 Release"
|
|
||||||
# Name "bpl_static - Win32 Debug"
|
|
||||||
# Begin Group "Source Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\src\classes.cpp
|
|
||||||
# ADD CPP /W3
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\src\conversions.cpp
|
|
||||||
# ADD CPP /W3
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\src\extension_class.cpp
|
|
||||||
# ADD CPP /W3
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\src\functions.cpp
|
|
||||||
# ADD CPP /W3
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\src\init_function.cpp
|
|
||||||
# ADD CPP /W3
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\src\module_builder.cpp
|
|
||||||
# ADD CPP /W3
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\src\objects.cpp
|
|
||||||
# ADD CPP /W3
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\src\types.cpp
|
|
||||||
# ADD CPP /W3
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Header Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\detail\base_object.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\callback.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\caller.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\detail\cast.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\class_builder.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\classes.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\detail\config.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\conversions.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\errors.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\detail\extension_class.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\detail\functions.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\detail\init_function.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\module_builder.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\detail\none.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\objects.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\operators.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\reference.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\detail\signatures.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\detail\singleton.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\detail\types.hpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\boost\python\detail\wrap_python.hpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# End Target
|
|
||||||
# End Project
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
|
||||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "bpl_static"=.\bpl_static.dsp - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "example1"=.\example1\example1.dsp - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
Begin Project Dependency
|
|
||||||
Project_Dep_Name bpl_static
|
|
||||||
End Project Dependency
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "rwgk1"=.\rwgk1\rwgk1.dsp - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
Begin Project Dependency
|
|
||||||
Project_Dep_Name bpl_static
|
|
||||||
End Project Dependency
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "test"=.\test\test.dsp - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
Begin Project Dependency
|
|
||||||
Project_Dep_Name bpl_static
|
|
||||||
End Project Dependency
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Global:
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<3>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
BIN
build/build.opt
BIN
build/build.opt
Binary file not shown.
@@ -1,51 +0,0 @@
|
|||||||
LIBSRC = \
|
|
||||||
classes.cpp \
|
|
||||||
conversions.cpp \
|
|
||||||
extension_class.cpp \
|
|
||||||
functions.cpp \
|
|
||||||
init_function.cpp \
|
|
||||||
module_builder.cpp \
|
|
||||||
objects.cpp \
|
|
||||||
types.cpp
|
|
||||||
|
|
||||||
LIBOBJ = $(LIBSRC:.cpp=.o)
|
|
||||||
OBJ = $(LIBOBJ)
|
|
||||||
|
|
||||||
|
|
||||||
ifeq "$(OS)" "Windows_NT"
|
|
||||||
PYTHON_LIB=c:/tools/python/libs/python15.lib
|
|
||||||
INC = -Ic:/cygnus/usr/include/g++-3 -Ic:/cygnus/usr/include -Ic:/boost -Ic:/tools/python/include
|
|
||||||
MODULE_EXTENSION=dll
|
|
||||||
else
|
|
||||||
INC = -I/usr/local/include/python1.5
|
|
||||||
MODULE_EXTENSION=so
|
|
||||||
endif
|
|
||||||
|
|
||||||
%.o: ../src/%.cpp
|
|
||||||
como --pic $(INC) -o $*.o -c $<
|
|
||||||
|
|
||||||
%.d: ../src/%.cpp
|
|
||||||
@echo creating $@
|
|
||||||
@set -e; como -M $(INC) -c $< \
|
|
||||||
| sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
|
|
||||||
[ -s $@ ] || rm -f $@
|
|
||||||
|
|
||||||
example1: example1.o libpycpp.a
|
|
||||||
como-dyn-link -o ../example/hellomodule.$(MODULE_EXTENSION) $(PYHTON_LIB) example1.o -L. -lpycpp
|
|
||||||
python ../example/test_example1.py
|
|
||||||
|
|
||||||
example1.o: ../example/example1.cpp
|
|
||||||
como --pic $(INC) -o $*.o -c $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf *.o *.$(MODULE_EXTENSION) *.a *.d *.pyc *.bak a.out
|
|
||||||
|
|
||||||
libpycpp.a: $(LIBOBJ)
|
|
||||||
rm -f libpycpp.a
|
|
||||||
ar cq libpycpp.a $(LIBOBJ)
|
|
||||||
|
|
||||||
DEP = $(OBJ:.o=.d)
|
|
||||||
|
|
||||||
ifneq "$(MAKECMDGOALS)" "clean"
|
|
||||||
include $(DEP)
|
|
||||||
endif
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
# Microsoft Developer Studio Project File - Name="example1" - Package Owner=<4>
|
|
||||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
|
||||||
# ** DO NOT EDIT **
|
|
||||||
|
|
||||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
|
||||||
|
|
||||||
CFG=example1 - Win32 Debug
|
|
||||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
|
||||||
!MESSAGE use the Export Makefile command and run
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "example1.mak".
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE You can specify a configuration when running NMAKE
|
|
||||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "example1.mak" CFG="example1 - Win32 Debug"
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE Possible choices for configuration are:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE "example1 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
|
||||||
!MESSAGE "example1 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
|
||||||
!MESSAGE
|
|
||||||
|
|
||||||
# Begin Project
|
|
||||||
# PROP AllowPerConfigDependencies 0
|
|
||||||
# PROP Scc_ProjName ""
|
|
||||||
# PROP Scc_LocalPath ""
|
|
||||||
CPP=cl.exe
|
|
||||||
MTL=midl.exe
|
|
||||||
RSC=rc.exe
|
|
||||||
|
|
||||||
!IF "$(CFG)" == "example1 - Win32 Release"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 0
|
|
||||||
# PROP BASE Output_Dir "Release"
|
|
||||||
# PROP BASE Intermediate_Dir "Release"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 0
|
|
||||||
# PROP Output_Dir "Release"
|
|
||||||
# PROP Intermediate_Dir "Release"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /c
|
|
||||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /c
|
|
||||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
|
||||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
|
||||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
|
||||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"Release/hello.dll" /libpath:"c:\tools\python\libs"
|
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "example1 - Win32 Debug"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 1
|
|
||||||
# PROP BASE Output_Dir "Debug"
|
|
||||||
# PROP BASE Intermediate_Dir "Debug"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 1
|
|
||||||
# PROP Output_Dir "Debug"
|
|
||||||
# PROP Intermediate_Dir "Debug"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c
|
|
||||||
# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE1_EXPORTS" /YX /FD /GZ /c
|
|
||||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
|
||||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
|
||||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
|
||||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"Debug/hello.dll" /pdbtype:sept /libpath:"c:\tools\python\libs"
|
|
||||||
|
|
||||||
!ENDIF
|
|
||||||
|
|
||||||
# Begin Target
|
|
||||||
|
|
||||||
# Name "example1 - Win32 Release"
|
|
||||||
# Name "example1 - Win32 Debug"
|
|
||||||
# Begin Group "Source Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\example\example1.cpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Header Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Resource Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
|
||||||
# End Group
|
|
||||||
# End Target
|
|
||||||
# End Project
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
LIBSRC = \
|
|
||||||
classes.cpp \
|
|
||||||
conversions.cpp \
|
|
||||||
extension_class.cpp \
|
|
||||||
functions.cpp \
|
|
||||||
init_function.cpp \
|
|
||||||
module_builder.cpp \
|
|
||||||
objects.cpp \
|
|
||||||
types.cpp
|
|
||||||
|
|
||||||
LIBOBJ = $(LIBSRC:.cpp=.o)
|
|
||||||
OBJ = $(LIBOBJ)
|
|
||||||
|
|
||||||
|
|
||||||
ifeq "$(OS)" "Windows_NT"
|
|
||||||
PYTHON_LIB=c:/tools/python/libs/python15.lib
|
|
||||||
INC = -Ic:/cygnus/usr/include/g++-3 -Ic:/cygnus/usr/include -Ic:/boost -Ic:/tools/python/include
|
|
||||||
MODULE_EXTENSION=dll
|
|
||||||
else
|
|
||||||
INC = -I/usr/local/include/python1.5
|
|
||||||
MODULE_EXTENSION=so
|
|
||||||
endif
|
|
||||||
|
|
||||||
%.o: ../src/%.cpp
|
|
||||||
g++ -fPIC -Wall -W $(INC) -o $*.o -c $<
|
|
||||||
|
|
||||||
%.d: ../src/%.cpp
|
|
||||||
@echo creating $@
|
|
||||||
@set -e; g++ -M $(INC) -c $< \
|
|
||||||
| sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
|
|
||||||
[ -s $@ ] || rm -f $@
|
|
||||||
|
|
||||||
|
|
||||||
example1: example1.o libpycpp.a
|
|
||||||
g++ -shared -o ../example/hellomodule.$(MODULE_EXTENSION) $(PYHTON_LIB) example1.o -L. -lpycpp
|
|
||||||
python ../example/test_example1.py
|
|
||||||
|
|
||||||
example1.o: ../example/example1.cpp
|
|
||||||
g++ -fPIC -Wall -W $(INC) -o $*.o -c $<
|
|
||||||
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf *.o *.$(MODULE_EXTENSION) *.a *.d *.pyc *.bak a.out
|
|
||||||
|
|
||||||
libpycpp.a: $(LIBOBJ)
|
|
||||||
rm -f libpycpp.a
|
|
||||||
ar cq libpycpp.a $(LIBOBJ)
|
|
||||||
|
|
||||||
DEP = $(OBJ:.o=.d)
|
|
||||||
|
|
||||||
ifneq "$(MAKECMDGOALS)" "clean"
|
|
||||||
include $(DEP)
|
|
||||||
endif
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
# Microsoft Developer Studio Project File - Name="rwgk1" - Package Owner=<4>
|
|
||||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
|
||||||
# ** DO NOT EDIT **
|
|
||||||
|
|
||||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
|
||||||
|
|
||||||
CFG=rwgk1 - Win32 Debug
|
|
||||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
|
||||||
!MESSAGE use the Export Makefile command and run
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "rwgk1.mak".
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE You can specify a configuration when running NMAKE
|
|
||||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "rwgk1.mak" CFG="rwgk1 - Win32 Debug"
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE Possible choices for configuration are:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE "rwgk1 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
|
||||||
!MESSAGE "rwgk1 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
|
||||||
!MESSAGE
|
|
||||||
|
|
||||||
# Begin Project
|
|
||||||
# PROP AllowPerConfigDependencies 0
|
|
||||||
# PROP Scc_ProjName ""
|
|
||||||
# PROP Scc_LocalPath ""
|
|
||||||
CPP=cl.exe
|
|
||||||
MTL=midl.exe
|
|
||||||
RSC=rc.exe
|
|
||||||
|
|
||||||
!IF "$(CFG)" == "rwgk1 - Win32 Release"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 0
|
|
||||||
# PROP BASE Output_Dir "Release"
|
|
||||||
# PROP BASE Intermediate_Dir "Release"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 0
|
|
||||||
# PROP Output_Dir "Release"
|
|
||||||
# PROP Intermediate_Dir "Release"
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /c
|
|
||||||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /c
|
|
||||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
|
||||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
|
||||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
|
||||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /libpath:"c:\tools\python\libs"
|
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "rwgk1 - Win32 Debug"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 1
|
|
||||||
# PROP BASE Output_Dir "Debug"
|
|
||||||
# PROP BASE Intermediate_Dir "Debug"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 1
|
|
||||||
# PROP Output_Dir "Debug"
|
|
||||||
# PROP Intermediate_Dir "Debug"
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c
|
|
||||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "RWGK1_EXPORTS" /YX /FD /GZ /c
|
|
||||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
|
||||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
|
||||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
|
||||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs"
|
|
||||||
|
|
||||||
!ENDIF
|
|
||||||
|
|
||||||
# Begin Target
|
|
||||||
|
|
||||||
# Name "rwgk1 - Win32 Release"
|
|
||||||
# Name "rwgk1 - Win32 Debug"
|
|
||||||
# Begin Group "Source Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\example\rwgk1.cpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Header Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Resource Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
|
||||||
# End Group
|
|
||||||
# End Target
|
|
||||||
# End Project
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
# Microsoft Developer Studio Project File - Name="test" - Package Owner=<4>
|
|
||||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
|
||||||
# ** DO NOT EDIT **
|
|
||||||
|
|
||||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
|
||||||
|
|
||||||
CFG=test - Win32 Debug
|
|
||||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
|
||||||
!MESSAGE use the Export Makefile command and run
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "test.mak".
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE You can specify a configuration when running NMAKE
|
|
||||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "test.mak" CFG="test - Win32 Debug"
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE Possible choices for configuration are:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE "test - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
|
||||||
!MESSAGE "test - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
|
||||||
!MESSAGE
|
|
||||||
|
|
||||||
# Begin Project
|
|
||||||
# PROP AllowPerConfigDependencies 0
|
|
||||||
# PROP Scc_ProjName ""
|
|
||||||
# PROP Scc_LocalPath ""
|
|
||||||
CPP=cl.exe
|
|
||||||
MTL=midl.exe
|
|
||||||
RSC=rc.exe
|
|
||||||
|
|
||||||
!IF "$(CFG)" == "test - Win32 Release"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 0
|
|
||||||
# PROP BASE Output_Dir "Release"
|
|
||||||
# PROP BASE Intermediate_Dir "Release"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 0
|
|
||||||
# PROP Output_Dir "Release"
|
|
||||||
# PROP Intermediate_Dir "Release"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /c
|
|
||||||
# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /Zm200 /c
|
|
||||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
|
||||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
|
||||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
|
||||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /libpath:"c:\tools\python\libs"
|
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "test - Win32 Debug"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 1
|
|
||||||
# PROP BASE Output_Dir "Debug"
|
|
||||||
# PROP BASE Intermediate_Dir "Debug"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 1
|
|
||||||
# PROP Output_Dir "Debug"
|
|
||||||
# PROP Intermediate_Dir "Debug"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /c
|
|
||||||
# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "..\..\..\.." /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TEST_EXPORTS" /YX /FD /GZ /Zm200 /c
|
|
||||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
|
||||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
|
||||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
|
||||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"c:\tools\python\libs"
|
|
||||||
# SUBTRACT LINK32 /pdb:none
|
|
||||||
|
|
||||||
!ENDIF
|
|
||||||
|
|
||||||
# Begin Target
|
|
||||||
|
|
||||||
# Name "test - Win32 Release"
|
|
||||||
# Name "test - Win32 Debug"
|
|
||||||
# Begin Group "Source Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\test\comprehensive.cpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Header Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\test\comprehensive.hpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Resource Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
|
||||||
# End Group
|
|
||||||
# End Target
|
|
||||||
# End Project
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
#
|
|
||||||
# Tested with:
|
|
||||||
# Compaq C++ V6.2-024 for Digital UNIX V5.0 (Rev. 910)
|
|
||||||
#
|
|
||||||
# Python 1.5.2 was installed without any customizations.
|
|
||||||
# boost_all.zip vers. 1.18.1 was unpacked using unzip -aa and not modified.
|
|
||||||
# STLport-4.1b3 was unpacked using unzip -aa and not modified.
|
|
||||||
#
|
|
||||||
# Initial version 2000-10-20: Ralf W. Grosse-Kunstleve, rwgk@cci.lbl.gov
|
|
||||||
#
|
|
||||||
|
|
||||||
PYINC= /usr/local/include/python1.5
|
|
||||||
BOOSTINC= /usr/local/boost_1_18_1
|
|
||||||
STLPORTINC= /usr/local/STLport-4.1b3/stlport
|
|
||||||
STLPORTOPTS= \
|
|
||||||
-D__USE_STD_IOSTREAM \
|
|
||||||
-D__STL_NO_SGI_IOSTREAMS \
|
|
||||||
-D__STL_NO_NEW_C_HEADERS \
|
|
||||||
-D_RWSTD_COMPILE_INSTANTIATE=1
|
|
||||||
|
|
||||||
STDOPTS= -std strict_ansi
|
|
||||||
WARNOPTS= -msg_disable 186,450,1115
|
|
||||||
# use -msg_display_number to obtain integer tags for -msg_disable
|
|
||||||
|
|
||||||
CPP= cxx
|
|
||||||
CPPOPTS= -I$(STLPORTINC) $(STLPORTOPTS) -I$(BOOSTINC) -I$(PYINC) \
|
|
||||||
$(STDOPTS) $(WARNOPTS)
|
|
||||||
|
|
||||||
LD= cxx
|
|
||||||
LDOPTS= -shared -expect_unresolved '*'
|
|
||||||
|
|
||||||
OBJ = extclass.o functions.o init_function.o module.o newtypes.o \
|
|
||||||
objects.o py.o subclass.o
|
|
||||||
|
|
||||||
.SUFFIXES: .o .cpp
|
|
||||||
|
|
||||||
all: demo.so hello.so
|
|
||||||
|
|
||||||
demo.so: $(OBJ) extclass_demo.o
|
|
||||||
$(LD) $(LDOPTS) $(OBJ) extclass_demo.o -o demo.so
|
|
||||||
|
|
||||||
hello.so: $(OBJ) example1.o
|
|
||||||
$(LD) $(LDOPTS) $(OBJ) example1.o -o hello.so
|
|
||||||
|
|
||||||
.cpp.o:
|
|
||||||
-$(CPP) $(CPPOPTS) $(INC) -c $*.cpp
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(OBJ) extclass_demo.o example1.o demo.so hello.so so_locations
|
|
||||||
rm -rf cxx_repository
|
|
||||||
rm -f *.pyc
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
|
||||||
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
|
||||||
<title>
|
|
||||||
Building an Extension Module
|
|
||||||
</title>
|
|
||||||
<div>
|
|
||||||
<h1>
|
|
||||||
<img width="277" height="86" id="_x0000_i1025" align="center"
|
|
||||||
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">Building an Extension Module
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
Right now, the only supported configuration is one in which the BPL
|
|
||||||
source files are statically linked with the source for your extension
|
|
||||||
module. You may first build them into a library and link it with your
|
|
||||||
extension module source, but the effect is the same as compiling all
|
|
||||||
the source files together. Some users have successfully built the
|
|
||||||
sources into a shared library, and support for a shared library
|
|
||||||
build is planned, but not yet implemented. The BPL source files are:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
<a href="../../../libs/python/src/extension_class.cpp">extclass.cpp</a>
|
|
||||||
<a href="../../../libs/python/src/functions.cpp">functions.cpp</a>
|
|
||||||
<a href="../../../libs/python/src/init_function.cpp">init_function.cpp</a>
|
|
||||||
<a href="../../../libs/python/src/module_builder.cpp">module.cpp</a>
|
|
||||||
<a href="../../../libs/python/src/types.cpp">newtypes.cpp</a>
|
|
||||||
<a href="../../../libs/python/src/objects.cpp">objects.cpp</a>
|
|
||||||
<a href="../../../libs/python/src/conversions.cpp">py.cpp</a>
|
|
||||||
<a href="../../../libs/python/src/classes.cpp">subclass.cpp</a>
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<p>
|
|
||||||
Next: <a href="enums.html">Enums</a>
|
|
||||||
Previous: <a href="under-the-hood.html">A Peek Under the Hood</a>
|
|
||||||
Up: <a href="index.html">Top</a>
|
|
||||||
<p>
|
|
||||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
|
||||||
sell and distribute this document is granted provided this copyright
|
|
||||||
notice appears in all copies. This document is provided ``as
|
|
||||||
is'' without express or implied warranty, and with no claim as to
|
|
||||||
its suitability for any purpose.
|
|
||||||
<p>
|
|
||||||
Updated: Nov 26, 2000
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
|
||||||
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
|
||||||
<title>
|
|
||||||
Comparisons with Other Systems
|
|
||||||
</title>
|
|
||||||
<div>
|
|
||||||
<h1>
|
|
||||||
<img width="277" height="86" id="_x0000_i1025" align="center"
|
|
||||||
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">Comparisons with
|
|
||||||
Other Systems
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<h2>CXX</h2>
|
|
||||||
<p>
|
|
||||||
Like BPL, <a href="http://cxx.sourceforge.net/">CXX</a> attempts to
|
|
||||||
provide a C++-oriented interface to Python. In most cases, as with the
|
|
||||||
boost library, it relieves the user from worrying about
|
|
||||||
reference-counts. Both libraries automatically convert thrown C++
|
|
||||||
exceptions into Python exceptions. As far as I can tell, CXX has no
|
|
||||||
support for subclassing C++ extension types in Python. An even
|
|
||||||
more significant difference is that a user's C++ code is still basically
|
|
||||||
``dealing with Python objects'', though they are wrapped in
|
|
||||||
C++ classes. This means such jobs as argument parsing and conversion are
|
|
||||||
still left to be done explicitly by the user.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
CXX claims to interoperate well with the C++ Standard Library
|
|
||||||
(a.k.a. STL) by providing iterators into Python Lists and Dictionaries,
|
|
||||||
but the claim is unfortunately unsupportable. The problem is that in
|
|
||||||
general, access to Python sequence and mapping elements through
|
|
||||||
iterators requires the use of proxy objects as the return value of
|
|
||||||
iterator dereference operations. This usage conflicts with the basic
|
|
||||||
ForwardIterator requirements in <a
|
|
||||||
href="http://anubis.dkuug.dk/jtc1/sc22/open/n2356/lib-iterators.html#lib.forward.iterators">
|
|
||||||
section 24.1.3 of the standard</a> (dereferencing must produce a
|
|
||||||
reference). Although you may be able to use these iterators with some
|
|
||||||
operations in some standard library implementations, it is neither
|
|
||||||
guaranteed to work nor portable.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
As far as I can tell, CXX enables one to write what is essentially
|
|
||||||
idiomatic Python code in C++, manipulating Python objects through the
|
|
||||||
same fully-generic interfaces we use in Python. While you're hardly programming directly to the ``bare
|
|
||||||
metal'' with CXX, it basically presents a ``C++-ized''
|
|
||||||
version of the Python 'C' API.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<a href="mailto:dubois1@llnl.gov">Paul F. Dubois</a>, the original
|
|
||||||
author of CXX, has told me that what I've described is only half of the
|
|
||||||
picture with CXX, but I never understood his explanation well-enough to
|
|
||||||
fill in the other half. Here is his response to the commentary above:
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
``My intention with CXX was not to do what you are doing. It was to enable a
|
|
||||||
person to write an extension directly in C++ rather than C. I figured others had
|
|
||||||
the wrapping business covered. I thought maybe CXX would provide an easier
|
|
||||||
target language for those making wrappers, but I never explored
|
|
||||||
that.''<br><i>-<a href="mailto:dubois1@llnl.gov">Paul Dubois</a></i>
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<h2>SWIG</h2>
|
|
||||||
<p>
|
|
||||||
<a href= "http://www.swig.org/">SWIG</a> is an impressively mature tool
|
|
||||||
for exporting an existing ANSI 'C' interface into various scripting
|
|
||||||
languages. Swig relies on a parser to read your source code and produce
|
|
||||||
additional source code files which can be compiled into a Python (or
|
|
||||||
Perl or Tcl) extension module. It has been successfully used to create
|
|
||||||
many Python extension modules. Like BPL, SWIG is trying to allow an
|
|
||||||
existing interface to be wrapped with little or no change to the
|
|
||||||
existing code. The documentation says ``SWIG parses a form of ANSI C
|
|
||||||
syntax that has been extended with a number of special directives. As a
|
|
||||||
result, interfaces are usually built by grabbing a header file and
|
|
||||||
tweaking it a little bit.'' For C++ interfaces, the tweaking has often
|
|
||||||
proven to amount to more than just a little bit. One user
|
|
||||||
writes:
|
|
||||||
|
|
||||||
<blockquote> ``The problem with swig (when I used it) is that it
|
|
||||||
couldnt handle templates, didnt do func overloading properly etc. For
|
|
||||||
ANSI C libraries this was fine. But for usual C++ code this was a
|
|
||||||
problem. Simple things work. But for anything very complicated (or
|
|
||||||
realistic), one had to write code by hand. I believe BPL doesn't have
|
|
||||||
this problem[<a href="#sic">sic</a>]... IMHO overloaded functions are very important to
|
|
||||||
wrap correctly.''<br><i>-Prabhu Ramachandran</i>
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
By contrast, BPL doesn't attempt to parse C++ - the problem is simply
|
|
||||||
too complex to do correctly. <a name="sic">Technically</a>, one does
|
|
||||||
write code by hand to use BPL. The goal, however, has been to make
|
|
||||||
that code nearly as simple as listing the names of the classes and
|
|
||||||
member functions you want to expose in Python.
|
|
||||||
|
|
||||||
<h2>SIP</h2>
|
|
||||||
<p>
|
|
||||||
<a
|
|
||||||
href="http://www.thekompany.com/projects/pykde/background.php3?dhtml_ok=1">SIP</a>
|
|
||||||
is a system similar to SWIG, though seemingly more
|
|
||||||
C++-oriented. The author says that like BPL, SIP supports overriding
|
|
||||||
extension class member functions in Python subclasses. It appears to
|
|
||||||
have been designed specifically to directly support some features of
|
|
||||||
PyQt/PyKDE, which is its primary client. Documentation is almost
|
|
||||||
entirely missing at the time of this writing, so a detailed comparison
|
|
||||||
is difficult.
|
|
||||||
|
|
||||||
<h2>ILU</h2>
|
|
||||||
<p>
|
|
||||||
<a
|
|
||||||
href="http://www.cl.cam.ac.uk/Research/Rainbow/projects/origami/ilu-1.8-manual">ILU</a>
|
|
||||||
is a very ambitious project which tries to describe a module's interface
|
|
||||||
(types and functions) in terms of an <a
|
|
||||||
href="http://www.cl.cam.ac.uk/Research/Rainbow/projects/origami/ilu-1.8-manual/manual_2.html">Interface
|
|
||||||
Specification Language</a> (ISL) so that it can be uniformly interfaced
|
|
||||||
to a wide range of computer languages, including Common Lisp, C++, C,
|
|
||||||
Modula-3, and Python. ILU can parse the ISL to generate a C++ language
|
|
||||||
header file describing the interface, of which the user is expected to
|
|
||||||
provide an implementation. Unlike BPL, this means that the system
|
|
||||||
imposes implementation details on your C++ code at the deepest level. It
|
|
||||||
is worth noting that some of the C++ names generated by ILU are supposed
|
|
||||||
to be reserved to the C++ implementation. It is unclear from the
|
|
||||||
documentation whether ILU supports overriding C++ virtual functions in Python.
|
|
||||||
|
|
||||||
<h2>GRAD</h2>
|
|
||||||
<p>
|
|
||||||
<a
|
|
||||||
href="http://www.python.org/workshops/1996-11/papers/GRAD/html/GRADcover.html">GRAD</a>
|
|
||||||
is another very ambitious project aimed at generating Python wrappers for
|
|
||||||
interfaces written in ``legacy languages'', among which C++ is the first one
|
|
||||||
implemented. Like SWIG, it aims to parse source code and automatically
|
|
||||||
generate wrappers, though it appears to take a more sophisticated approach
|
|
||||||
to parsing in general and C++ in particular, so it should do a much better
|
|
||||||
job with C++. It appears to support function overloading. The
|
|
||||||
documentation is missing a lot of information I'd like to see, so it is
|
|
||||||
difficult to give an accurate and fair assessment. I am left with the
|
|
||||||
following questions:
|
|
||||||
<ul>
|
|
||||||
<li>Does it support overriding of virtual functions?
|
|
||||||
<li>What about overriding private or protected virtual functions (the documentation indicates
|
|
||||||
that only public interfaces are supported)?
|
|
||||||
<li>Which C++ language constructs are supportd?
|
|
||||||
<li>Does it support implicit conversions between wrapped C++ classes that have
|
|
||||||
an inheritance relationship?
|
|
||||||
<li>Does it support smart pointers?
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
Anyone in the possession of the answers to these questions will earn my
|
|
||||||
gratitude for a write-up <code>;-)</code>
|
|
||||||
|
|
||||||
<h2>Zope ExtensionClasses</h2>
|
|
||||||
<p>
|
|
||||||
<a href="http:http://www.digicool.com/releases/ExtensionClass">
|
|
||||||
ExtensionClasses in Zope</a> use the same underlying mechanism as BPL
|
|
||||||
to support subclassing of extension types in Python, including
|
|
||||||
multiple-inheritance. Both systems support pickling/unpickling of
|
|
||||||
extension class instances in very similar ways. Both systems rely on the
|
|
||||||
same ``<a
|
|
||||||
href="http://www.python.org/workshops/1994-11/BuiltInClasses/Welcome.html">Don
|
|
||||||
Beaudry Hack</a>'' that also inspired Don's MESS System.
|
|
||||||
<p>
|
|
||||||
The major differences are:
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
BPL lifts the burden on the user to parse and convert function
|
|
||||||
argument types. Zope provides no such facility.
|
|
||||||
<li>
|
|
||||||
BPL lifts the burden on the user to maintain Python
|
|
||||||
reference-counts.
|
|
||||||
<li>
|
|
||||||
BPL supports function overloading; Zope does not.
|
|
||||||
<li>
|
|
||||||
BPL supplies a simple mechanism for exposing read-only and
|
|
||||||
read/write access to data members of the wrapped C++ type as Python
|
|
||||||
attributes.
|
|
||||||
<li>
|
|
||||||
Writing a Zope ExtensionClass is significantly more complex than
|
|
||||||
exposing a C++ class to python using BPL (mostly a summary of the
|
|
||||||
previous 4 items). <a href=
|
|
||||||
"http://www.digicool.com/releases/ExtensionClass/MultiMapping.html">A
|
|
||||||
Zope Example</a> illustrates the differences.
|
|
||||||
<li>
|
|
||||||
Zope's ExtensionClasses are specifically motivated by ``the need for a
|
|
||||||
C-based persistence mechanism''. BPL's are motivated by the desire
|
|
||||||
to simply reflect a C++ API into Python with as little modification as
|
|
||||||
possible.
|
|
||||||
<li>
|
|
||||||
The following Zope restriction does not apply to BPL: ``At most one
|
|
||||||
base extension direct or indirect super class may define C data
|
|
||||||
members. If an extension subclass inherits from multiple base
|
|
||||||
extension classes, then all but one must be mix-in classes that
|
|
||||||
provide extension methods but no data.''
|
|
||||||
<li>
|
|
||||||
Zope requires use of the somewhat funky inheritedAttribute (search for
|
|
||||||
``inheritedAttribute'' on <a
|
|
||||||
href="http://www.digicool.com/releases/ExtensionClass">this page</a>)
|
|
||||||
method to access base class methods. In BPL, base class methods can
|
|
||||||
be accessed in the usual way by writing
|
|
||||||
``<code>BaseClass.method</code>''.
|
|
||||||
<li>
|
|
||||||
Zope supplies some creative but esoteric idioms such as <a href=
|
|
||||||
"http://www.digicool.com/releases/ExtensionClass/Acquisition.html">
|
|
||||||
Acquisition</a>. No specific support for this is built into BPL.
|
|
||||||
<li>
|
|
||||||
Zope's ComputedAttribute support is designed to be used from Python.
|
|
||||||
<a href="special.html#getter_setter">The analogous feature of
|
|
||||||
BPL</a> can be used from C++ or Python. The feature is arguably
|
|
||||||
easier to use in BPL.
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
Next: <a href="example1.html">A Simple Example Using BPL</a>
|
|
||||||
Previous: <a href="extending.html">A Brief Introduction to writing Python Extension Modules</a>
|
|
||||||
Up: <a href="index.html">Top</a>
|
|
||||||
<p>
|
|
||||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
|
||||||
sell and distribute this document is granted provided this copyright
|
|
||||||
notice appears in all copies. This document is provided ``as is'' without
|
|
||||||
express or implied warranty, and with no claim as to its suitability
|
|
||||||
for any purpose.
|
|
||||||
<p>
|
|
||||||
Updated: Nov 26, 2000
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
Given a real Python class 'A', a wrapped C++ class 'B', and this definition:
|
|
||||||
|
|
||||||
class C(A, B):
|
|
||||||
def __init__(self):
|
|
||||||
B.__init__(self)
|
|
||||||
self.x = 1
|
|
||||||
...
|
|
||||||
|
|
||||||
c = C()
|
|
||||||
|
|
||||||
this diagram describes the internal structure of an instance of 'C', including
|
|
||||||
its inheritance relationships. Note that ExtensionClass<B> is derived from
|
|
||||||
Class<ExtensionInstance>, and is in fact identical for all intents and purposes.
|
|
||||||
|
|
||||||
MetaClass<ExtensionInstance>
|
|
||||||
+---------+ +---------+
|
|
||||||
types.ClassType: | | | |
|
|
||||||
| | | |
|
|
||||||
| | | |
|
|
||||||
+---------+ +---------+
|
|
||||||
^ ^ ^
|
|
||||||
PyClassObject | ExtensionClass<B> | |
|
|
||||||
A: +------------+ | B: +------------+ | |
|
|
||||||
| ob_type -+-+ | ob_type -+-----+ |
|
|
||||||
| | ()<--+- __bases__ | |
|
|
||||||
| | | __dict__ -+->{...} |
|
|
||||||
| | 'B'<-+- __name__ | |
|
|
||||||
+------------+ +------------+ |
|
|
||||||
^ ^ |
|
|
||||||
| | |
|
|
||||||
+-----+ +-------------+ |
|
|
||||||
| | |
|
|
||||||
| | Class<ExtensionInstance> |
|
|
||||||
| | C: +------------+ |
|
|
||||||
| | | ob_type -+------------+
|
|
||||||
tuple:(*, *)<--+- __bases__ |
|
|
||||||
| __dict__ -+->{__module__, <methods, etc.>}
|
|
||||||
'C' <-+- __name__ |
|
|
||||||
+------------+
|
|
||||||
^ (in case of inheritance from more than one
|
|
||||||
| extension class, this vector would contain
|
|
||||||
+---------------+ a pointer to an instance holder for the data
|
|
||||||
| of each corresponding C++ class)
|
|
||||||
| ExtensionInstance
|
|
||||||
| c: +---------------------+ std::vector<InstanceHolderBase>
|
|
||||||
+----+- __class__ | +---+--
|
|
||||||
| m_wrapped_objects -+->| * | ...
|
|
||||||
{'x': 1}<-+- __dict__ | +-|-+--
|
|
||||||
+---------------------+ | InstanceValueHolder<B>
|
|
||||||
| +--------------------------------+
|
|
||||||
+-->| (contains a C++ instance of B) |
|
|
||||||
+--------------------------------+
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In our inheritance test cases in extclass_demo.cpp/test_extclass.py, we have the
|
|
||||||
following C++ inheritance hierarchy:
|
|
||||||
|
|
||||||
+-----+ +----+
|
|
||||||
| A1 | | A2 |
|
|
||||||
+-----+ +----+
|
|
||||||
^ ^ ^ ^ ^
|
|
||||||
| | | | |
|
|
||||||
+-----+ | +---------+-----+
|
|
||||||
| | | |
|
|
||||||
| +---+----------+
|
|
||||||
.......!...... | |
|
|
||||||
: A_callback : +-+--+ +-+--+
|
|
||||||
:............: | B1 | | B2 |
|
|
||||||
+----+ +----+
|
|
||||||
^
|
|
||||||
|
|
|
||||||
+-------+---------+
|
|
||||||
| |
|
|
||||||
+-+-+ ......!.......
|
|
||||||
| C | : B_callback :
|
|
||||||
+---+ :............:
|
|
||||||
|
|
||||||
|
|
||||||
A_callback and B_callback are used as part of the wrapping mechanism but not
|
|
||||||
represented in Python. C is also not represented in Python but is delivered
|
|
||||||
there polymorphically through a smart pointer.
|
|
||||||
|
|
||||||
This is the data structure in Python.
|
|
||||||
|
|
||||||
ExtensionClass<A1>
|
|
||||||
A1: +------------+
|
|
||||||
()<--+- __bases__ |
|
|
||||||
| __dict__ -+->{...}
|
|
||||||
+------------+
|
|
||||||
^
|
|
||||||
| ExtensionInstance
|
|
||||||
| a1: +---------------------+ vec InstanceValueHolder<A1,A_callback>
|
|
||||||
+---------+- __class__ | +---+ +---------------------+
|
|
||||||
| | m_wrapped_objects -+->| *-+-->| contains A_callback |
|
|
||||||
| +---------------------+ +---+ +---------------------+
|
|
||||||
|
|
|
||||||
| ExtensionInstance
|
|
||||||
| pa1_a1: +---------------------+ vec InstancePtrHolder<auto_ptr<A1>,A1>
|
|
||||||
+---------+- __class__ | +---+ +---+
|
|
||||||
| | m_wrapped_objects -+->| *-+-->| *-+-+ A1
|
|
||||||
| +---------------------+ +---+ +---+ | +---+
|
|
||||||
| +->| |
|
|
||||||
| ExtensionInstance +---+
|
|
||||||
| pb1_a1: +---------------------+ vec InstancePtrHolder<auto_ptr<A1>,A1>
|
|
||||||
+---------+- __class__ | +---+ +---+
|
|
||||||
| | m_wrapped_objects -+->| *-+-->| *-+-+ B1
|
|
||||||
| +---------------------+ +---+ +---+ | +---+
|
|
||||||
| +->| |
|
|
||||||
| ExtensionInstance +---+
|
|
||||||
| pb2_a1: +---------------------+ vec InstancePtrHolder<auto_ptr<A1>,A1>
|
|
||||||
+---------+- __class__ | +---+ +---+
|
|
||||||
| | m_wrapped_objects -+->| *-+-->| *-+-+ B2
|
|
||||||
| +---------------------+ +---+ +---+ | +---+
|
|
||||||
| +->| |
|
|
||||||
| +---+
|
|
||||||
| ExtensionClass<A1>
|
|
||||||
| A2: +------------+
|
|
||||||
| ()<--+- __bases__ |
|
|
||||||
| | __dict__ -+->{...}
|
|
||||||
| +------------+
|
|
||||||
| ^
|
|
||||||
| | ExtensionInstance
|
|
||||||
| a2: | +---------------------+ vec InstanceValueHolder<A2>
|
|
||||||
| +-+- __class__ | +---+ +-------------+
|
|
||||||
| | | m_wrapped_objects -+->| *-+-->| contains A2 |
|
|
||||||
| | +---------------------+ +---+ +-------------+
|
|
||||||
| |
|
|
||||||
| | ExtensionInstance
|
|
||||||
| pa2_a2: | +---------------------+ vec InstancePtrHolder<auto_ptr<A2>,A2>
|
|
||||||
| +-+- __class__ | +---+ +---+
|
|
||||||
| | | m_wrapped_objects -+->| *-+-->| *-+-+ A2
|
|
||||||
| | +---------------------+ +---+ +---+ | +---+
|
|
||||||
| | +->| |
|
|
||||||
| | ExtensionInstance +---+
|
|
||||||
| pb1_a2: | +---------------------+ vec InstancePtrHolder<auto_ptr<A2>,A2>
|
|
||||||
| +-+- __class__ | +---+ +---+
|
|
||||||
| | | m_wrapped_objects -+->| *-+-->| *-+-+ B1
|
|
||||||
| | +---------------------+ +---+ +---+ | +---+
|
|
||||||
| | +->| |
|
|
||||||
| | +---+
|
|
||||||
| |
|
|
||||||
| +---------------+------------------------------+
|
|
||||||
| | |
|
|
||||||
+------+-------------------------+-|----------------------------+ |
|
|
||||||
| | | | |
|
|
||||||
| Class<ExtensionInstance> | | ExtensionClass<B1> | | ExtensionClass<B1>
|
|
||||||
| DA1: +------------+ | | B1: +------------+ | | B2: +------------+
|
|
||||||
(*,)<---+- __bases__ | (*,*)<---+- __bases__ | (*,*)<---+- __bases__ |
|
|
||||||
| __dict__ -+->{...} | __dict__ -+->{...} | __dict__ -+->{...}
|
|
||||||
+------------+ +------------+ +------------+
|
|
||||||
^ ^ ^
|
|
||||||
| ExtensionInstance | |
|
|
||||||
| da1: +---------------------+ | vec InstanceValueHolder<A1,A_callback>
|
|
||||||
+-------+- __class__ | | +---+ +---------------------+ |
|
|
||||||
| m_wrapped_objects -+--|-->| *-+-->| contains A_callback | |
|
|
||||||
+---------------------+ | +---+ +---------------------+ |
|
|
||||||
+--------------------------------------+ |
|
|
||||||
| ExtensionInstance |
|
|
||||||
b1: | +---------------------+ vec InstanceValueHolder<B1,B_callback> |
|
|
||||||
+-+- __class__ | +---+ +---------------------+ |
|
|
||||||
| | m_wrapped_objects -+->| *-+-->| contains B_callback | |
|
|
||||||
| +---------------------+ +---+ +---------------------+ |
|
|
||||||
| |
|
|
||||||
| ExtensionInstance |
|
|
||||||
pb1_b1: | +---------------------+ vec InstancePtrHolder<auto_ptr<B1>,B1> |
|
|
||||||
+-+- __class__ | +---+ +---+ |
|
|
||||||
| | m_wrapped_objects -+->| *-+-->| *-+-+ B1 |
|
|
||||||
| +---------------------+ +---+ +---+ | +---+ |
|
|
||||||
| +->| | |
|
|
||||||
| ExtensionInstance +---+ |
|
|
||||||
pc_b1: | +---------------------+ vec InstancePtrHolder<auto_ptr<B1>,B1> |
|
|
||||||
+-+- __class__ | +---+ +---+ |
|
|
||||||
| | m_wrapped_objects -+->| *-+-->| *-+-+ C |
|
|
||||||
| +---------------------+ +---+ +---+ | +---+ |
|
|
||||||
| +->| | |
|
|
||||||
| +---+ |
|
|
||||||
| |
|
|
||||||
| Class<ExtensionInstance> +---------------------------------------+
|
|
||||||
| DB1: +------------+ | ExtensionInstance
|
|
||||||
(*,)<---+- __bases__ | a2: | +---------------------+ vec InstanceValueHolder<A2>
|
|
||||||
| __dict__ -+->{...} +-+- __class__ | +---+ +-------------+
|
|
||||||
+------------+ | m_wrapped_objects -+->| *-+-->| contains A2 |
|
|
||||||
^ +---------------------+ +---+ +-------------+
|
|
||||||
| ExtensionInstance
|
|
||||||
db1: | +---------------------+ vec InstanceValueHolder<B1,B_callback>
|
|
||||||
+-+- __class__ | +---+ +----------------------+
|
|
||||||
| m_wrapped_objects -+-->| *-+-->| contains B1_callback |
|
|
||||||
+---------------------+ +---+ +----------------------+
|
|
||||||
103
doc/enums.html
103
doc/enums.html
@@ -1,103 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
|
||||||
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
|
||||||
<title>
|
|
||||||
Wrapping enums
|
|
||||||
</title>
|
|
||||||
<div>
|
|
||||||
<h1>
|
|
||||||
<img width="277" height="86" id="_x0000_i1025" align="center"
|
|
||||||
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">Wrapping enums
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<p>Because there is in general no way to deduce that a value of arbitrary type T
|
|
||||||
is an enumeration constant, the Boost Python Library cannot automatically
|
|
||||||
convert enum values to and from Python. To handle this case, you need to decide
|
|
||||||
how you want the enum to show up in Python (since Python doesn't have
|
|
||||||
enums). Once you have done that, you can write some simple
|
|
||||||
<code>from_python()</code> and <code>to_python()</code> functions.
|
|
||||||
|
|
||||||
<p>If you are satisfied with a Python int as a way to represent your enum
|
|
||||||
values, we provide a shorthand for these functions. You just need to
|
|
||||||
instantiate <code>boost::python::enum_as_int_converters<EnumType></code> where
|
|
||||||
<code>EnumType</code> is your enumerated type. There are two convenient ways to do this:
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li><blockquote>
|
|
||||||
<pre>
|
|
||||||
...
|
|
||||||
} // close my_namespace
|
|
||||||
// drop into namespace python and explicitly instantiate
|
|
||||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
|
|
||||||
template class enum_as_int_converters<extclass_demo::EnumOwner::enum_type>;
|
|
||||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
|
||||||
namespace my_namespace { // re-open my_namespace
|
|
||||||
...
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<li><blockquote><pre>
|
|
||||||
// instantiate as base class in any namespace
|
|
||||||
struct EnumTypeConverters
|
|
||||||
: boost::python::enum_as_int_converters<EnumType>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
</blockquote></pre>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>Either of the above is equivalent to the following declarations:
|
|
||||||
<blockquote><pre>
|
|
||||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
|
|
||||||
|
|
||||||
MyEnumType from_python(PyObject* x, boost::python::type<MyEnumType>)
|
|
||||||
{
|
|
||||||
return static_cast<MyEnum>(
|
|
||||||
from_python(x, boost::python::type<long>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
MyEnumType from_python(PyObject* x, boost::python::type<const MyEnumType&>)
|
|
||||||
{
|
|
||||||
return static_cast<MyEnum>(
|
|
||||||
from_python(x, boost::python::type<long>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(MyEnumType x)
|
|
||||||
{
|
|
||||||
return to_python(static_cast<long>(x));
|
|
||||||
}
|
|
||||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>This technique defines the conversions of
|
|
||||||
<code>MyEnumType</code> in terms of the conversions for the built-in
|
|
||||||
<code>long</code> type.
|
|
||||||
|
|
||||||
You may also want to add a bunch of lines like this to your module
|
|
||||||
initialization:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
mymodule.add(boost::python::to_python(enum_value_1), "enum_value_1");
|
|
||||||
mymodule.add(boost::python::to_python(enum_value_2), "enum_value_2");
|
|
||||||
...
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
You can also add these to an extension class definition, if your enum happens to
|
|
||||||
be local to a class and you want the analogous interface in Python:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
my_class.add(boost::python::to_python(enum_value_1), "enum_value_1");
|
|
||||||
my_class.add(boost::python::to_python(enum_value_2), "enum_value_2");
|
|
||||||
...
|
|
||||||
</pre></blockquote>
|
|
||||||
<p>
|
|
||||||
Next: <a href="pointers.html">Pointers</a>
|
|
||||||
Previous: <a href="building.html">Building an Extension Module</a>
|
|
||||||
Up: <a href="index.html">Top</a>
|
|
||||||
<p>
|
|
||||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
|
||||||
sell and distribute this document is granted provided this copyright
|
|
||||||
notice appears in all copies. This document is provided ``as
|
|
||||||
is'' without express or implied warranty, and with no claim as to
|
|
||||||
its suitability for any purpose.
|
|
||||||
<p>
|
|
||||||
Updated: Nov 26, 2000
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
|
||||||
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
|
||||||
<title>
|
|
||||||
A Simple Example
|
|
||||||
</title>
|
|
||||||
<div>
|
|
||||||
<h1>
|
|
||||||
<img width="277" height="86" id="_x0000_i1025" src="../../../c++boost.gif" alt=
|
|
||||||
"c++boost.gif (8819 bytes)">
|
|
||||||
</h1>
|
|
||||||
<h1>
|
|
||||||
A Simple Example
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
Suppose we have the following C++ API which we want to expose in
|
|
||||||
Python:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace hello {
|
|
||||||
class world
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
world(int);
|
|
||||||
~world();
|
|
||||||
std::string greet() const { return "hi, world"; }
|
|
||||||
...
|
|
||||||
};
|
|
||||||
std::size_t length(const world& x) { return std::strlen(x.greet()); }
|
|
||||||
}
|
|
||||||
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<p>
|
|
||||||
Here is the C++ code for a python module called <code>hello</code>
|
|
||||||
which exposes the API using:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
#include <boost/python/class_builder.hpp>
|
|
||||||
// Python requires an exported function called init<module-name> in every
|
|
||||||
// extension module. This is where we build the module contents.
|
|
||||||
extern "C"
|
|
||||||
#ifdef _WIN32
|
|
||||||
__declspec(dllexport)
|
|
||||||
#endif
|
|
||||||
void inithello()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// create an object representing this extension module
|
|
||||||
boost::python::module_builder m("hello");
|
|
||||||
// Create the Python type object for our extension class
|
|
||||||
boost::python::class_builder<hello::world> world_class(m, "world");
|
|
||||||
// Add the __init__ function
|
|
||||||
world_class.def(boost::python::constructor<int>());
|
|
||||||
// Add a regular member function
|
|
||||||
world_class.def(&hello::world::get, "get");
|
|
||||||
// Add a regular function to the module
|
|
||||||
m.def(hello::length, "length");
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
boost::python::handle_exception(); // Deal with the exception for Python
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Win32 DLL boilerplate
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include <windows.h>
|
|
||||||
extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif // _WIN32
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<p>
|
|
||||||
That's it! If we build this shared library and put it on our <code>
|
|
||||||
PYTHONPATH</code> we can now access our C++ class and function from
|
|
||||||
Python.
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
>>> import hello
|
|
||||||
>>> hi_world = hello.world(3)
|
|
||||||
>>> hi_world.greet()
|
|
||||||
'hi, world'
|
|
||||||
>>> hello.length(hi_world)
|
|
||||||
9
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<p>
|
|
||||||
We can even make a subclass of <code>hello.world</code>:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
>>> class my_subclass(hello.world):
|
|
||||||
... def greet(self):
|
|
||||||
... return 'hello, world'
|
|
||||||
...
|
|
||||||
>>> y = my_subclass(4)
|
|
||||||
>>> y.greet()
|
|
||||||
'hello, world'
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<p>
|
|
||||||
Pretty cool! You can't do that with an ordinary Python extension type!
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
>>> hello.length(y)
|
|
||||||
9
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<p>
|
|
||||||
Of course, you may now have a slightly empty feeling in the pit of
|
|
||||||
your little pythonic stomach. Perhaps you feel your subclass deserves
|
|
||||||
to have a <code>length()</code> of <code>12</code>? If so, <a href=
|
|
||||||
"overriding.html">read on</a>...
|
|
||||||
<p>
|
|
||||||
Next: <a href="overriding.html">Overridable virtual functions</a>
|
|
||||||
Previous: <a href="comparisons.html">Comparisons with other systems</a> Up:
|
|
||||||
<a href="index.html">Top</a>
|
|
||||||
<p>
|
|
||||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
|
||||||
sell and distribute this document is granted provided this copyright
|
|
||||||
notice appears in all copies. This document is provided "as is" without
|
|
||||||
express or implied warranty, and with no claim as to its suitability
|
|
||||||
for any purpose.
|
|
||||||
<p>
|
|
||||||
Updated: Nov 26, 2000
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
|
||||||
<title>
|
|
||||||
A Brief Introduction to writing Python extension modules
|
|
||||||
</title>
|
|
||||||
<h1>
|
|
||||||
<img src="../../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
|
|
||||||
width="277" height="86">
|
|
||||||
</h1>
|
|
||||||
<h1>
|
|
||||||
A Brief Introduction to writing Python extension modules
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
Interfacing any language to Python involves building a module which can
|
|
||||||
be loaded by the Python interpreter, but which isn't written in Python.
|
|
||||||
This is known as an <em>extension module</em>. Many of the <a href=
|
|
||||||
"http://www.python.org/doc/current/lib/lib.html">built-in Python
|
|
||||||
libraries</a> are constructed in 'C' this way; Python even supplies its
|
|
||||||
<a href="http://www.python.org/doc/current/lib/types.html">fundamental
|
|
||||||
types</a> using the same mechanism. An extension module can be statically
|
|
||||||
linked with the Python interpreter, but it more commonly resides in a
|
|
||||||
shared library or DLL.
|
|
||||||
<p>
|
|
||||||
As you can see from <a href=
|
|
||||||
"http://www.python.org/doc/current/ext/ext.html"> The Python Extending
|
|
||||||
and Embedding Tutorial</a>, writing an extension module normally means
|
|
||||||
worrying about
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="http://www.python.org/doc/current/ext/refcounts.html">
|
|
||||||
maintaining reference counts</a>
|
|
||||||
<li>
|
|
||||||
<a href="http://www.python.org/doc/current/ext/callingPython.html"> how
|
|
||||||
to call back into Python</a>
|
|
||||||
<li>
|
|
||||||
<a href="http://www.python.org/doc/current/ext/parseTuple.html">
|
|
||||||
function argument parsing and typechecking</a>
|
|
||||||
</ul>
|
|
||||||
This last item typically occupies a great deal of code in an extension
|
|
||||||
module. Remember that Python is a completely dynamic language. A callable
|
|
||||||
object receives its arguments in a tuple; it is up to that object to extract
|
|
||||||
those arguments from the tuple, check their types, and raise appropriate
|
|
||||||
exceptions. There are numerous other tedious details that need to be
|
|
||||||
managed; too many to mention here. The Boost Python Library is designed to
|
|
||||||
lift most of that burden.<br>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Another obstacle that most people run into eventually when extending
|
|
||||||
Python is that there's no way to make a true Python class in an extension
|
|
||||||
module. The typical solution is to create a new Python type in the
|
|
||||||
extension module, and then write an additional module in 100% Python. The
|
|
||||||
Python module defines a Python class which dispatches to an instance of
|
|
||||||
the extension type, which it contains. This allows users to write
|
|
||||||
subclasses of the class in the Python module, almost as though they were
|
|
||||||
sublcassing the extension type. Aside from being tedious, it's not really
|
|
||||||
the same as having a true class, because there's no way for the user to
|
|
||||||
override a method of the extension type which is called from the
|
|
||||||
extension module. BPL solves this problem by taking advantage of <a
|
|
||||||
href="http://www.python.org/doc/essays/metaclasses/">Python's metaclass
|
|
||||||
feature</a> to provide objects which look, walk, and hiss almost exactly
|
|
||||||
like regular Python classes. BPL classes are actually cleaner than
|
|
||||||
Python classes in some subtle ways; a more detailed discussion will
|
|
||||||
follow (someday).</p>
|
|
||||||
<p>Next: <a href="comparisons.html">Comparisons with Other Systems</a> Up: <a
|
|
||||||
href="index.html">Top</a> </p>
|
|
||||||
<p>
|
|
||||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
|
||||||
sell and distribute this document is granted provided this copyright
|
|
||||||
notice appears in all copies. This document is provided "as is" without
|
|
||||||
express or implied warranty, and with no claim as to its suitability for
|
|
||||||
any purpose.</p>
|
|
||||||
|
|
||||||
160
doc/index.html
160
doc/index.html
@@ -1,160 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
|
||||||
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
|
||||||
<title>
|
|
||||||
The Boost Python Library (BPL)
|
|
||||||
</title>
|
|
||||||
<h1>
|
|
||||||
<img src="../../../c++boost.gif" alt="c++boost.gif (8819 bytes)" width="277"
|
|
||||||
align="center" height="86">The Boost Python Library (BPL)
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<h2>Synopsis</h2>
|
|
||||||
<p>
|
|
||||||
Use the Boost Python Library to quickly and easily export a C++ library to <a
|
|
||||||
href="http://www.pythonlabs.com/pub/www.python.org">Python</a> such that the Python interface is
|
|
||||||
very similar to the C++ interface. It is designed to be minimally
|
|
||||||
intrusive on your C++ design. In most cases, you should not have to alter
|
|
||||||
your C++ classes in any way in order to use them with BPL. The system
|
|
||||||
<em>should</em> simply ``reflect'' your C++ classes and functions into
|
|
||||||
Python. The major features of BPL include support for:
|
|
||||||
<ul>
|
|
||||||
<li><a href="inheritance.html">Subclassing extension types in Python</a>
|
|
||||||
<li><a href="overriding.html">Overriding virtual functions in Python</a>
|
|
||||||
<li><a href="overloading.html">[Member] function Overloading</a>
|
|
||||||
<li><a href="special.html#numeric_auto">Automatic wrapping of numeric operators</a>
|
|
||||||
</ul>
|
|
||||||
among others.
|
|
||||||
|
|
||||||
|
|
||||||
<h2>Supported Platforms</h2>
|
|
||||||
<p>BPL has been tested in the following configurations:
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>Against Python 1.5.2 using the following compiler/library:
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><a
|
|
||||||
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a>
|
|
||||||
|
|
||||||
<li><a
|
|
||||||
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a>/<a
|
|
||||||
href="http://www.stlport.org">STLport 4.0</a>
|
|
||||||
|
|
||||||
<li><a href="http://gcc.gnu.org/">GCC 2.95.2</a> [by <a href="mailto:koethe@informatik.uni-hamburg.de">Ullrich
|
|
||||||
Koethe</a>]
|
|
||||||
|
|
||||||
<li><a href="http://gcc.gnu.org/">GCC 2.95.2</a>/<a href="http://www.stlport.org">STLport 4.0</a>
|
|
||||||
|
|
||||||
<li>Compaq C++ V6.2-024 for Digital UNIX V5.0 Rev. 910 (an <a
|
|
||||||
href="http://www.edg.com/">EDG</a>-based compiler) with <a
|
|
||||||
href="http://www.stlport.org/beta.html">STLport-4.1b3</a> [by <a
|
|
||||||
href="mailto:rwgk@cci.lbl.gov">Ralf W. Grosse-Kunstleve</a>]
|
|
||||||
|
|
||||||
<li>An upcoming release of <a href="http://www.metrowerks.com/products/windows/">Metrowerks CodeWarrior
|
|
||||||
Pro6 for Windows</a> (the first release has a bug that's fatal to BPL)
|
|
||||||
</ul>
|
|
||||||
<br>
|
|
||||||
<li>Against Python 2.0 using the following compiler/library combinations:
|
|
||||||
<ul>
|
|
||||||
<li><a
|
|
||||||
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a> [by
|
|
||||||
<a href="mailto:aleaxit@yahoo.com">Alex Martelli</a>]
|
|
||||||
</ul>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2>Credits</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="../../../people/dave_abrahams.htm">David Abrahams</a> originated
|
|
||||||
and wrote the library.
|
|
||||||
|
|
||||||
<li><a href="mailto:koethe@informatik.uni-hamburg.de">Ullrich Koethe</a>
|
|
||||||
had independently developed a similar system. When he discovered BPL,
|
|
||||||
he generously contributed countless hours of coding and much insight into
|
|
||||||
improving it. He is responsible for an early version of the support for <a
|
|
||||||
href="overloading.html">function overloading</a> and wrote the support for
|
|
||||||
<a href="inheritance.html#implicit_conversion">reflecting C++ inheritance
|
|
||||||
relationships</a>. He has helped to improve error-reporting from both
|
|
||||||
Python and C++, and has designed an extremely easy-to-use way of
|
|
||||||
exposing <a href="special.html#numeric">numeric operators</a>, including
|
|
||||||
a way to avoid explicit coercion by means of overloading.
|
|
||||||
|
|
||||||
<li>The members of the boost mailing list and the Python community
|
|
||||||
supplied invaluable early feedback. In particular, Ron Clarke, Mark Evans,
|
|
||||||
Anton Gluck, Ralf W. Grosse-Kunstleve, Chuck Ingold, Prabhu Ramachandran,
|
|
||||||
and Barry Scott took the brave step of trying to use BPL while it was
|
|
||||||
still in early stages of development.
|
|
||||||
|
|
||||||
<li>The development of BPL wouldn't have been
|
|
||||||
possible without the generous support of <a href="http://www.dragonsys.com/">Dragon Systems/Lernout and
|
|
||||||
Hauspie, Inc</a> who supported its development as an open-source project.
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2>Table of Contents</h2>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li><a href="extending.html">A Brief Introduction to writing Python
|
|
||||||
extension modules</a>
|
|
||||||
|
|
||||||
<li><a href="comparisons.html">Comparisons between BPL and other
|
|
||||||
systems for extending Python</a>
|
|
||||||
|
|
||||||
<li><a href="example1.html">A Simple Example</a>
|
|
||||||
|
|
||||||
<li><a href="overriding.html">Overridable Virtual Functions</a>
|
|
||||||
|
|
||||||
<li><a href="overloading.html">Function Overloading</a>
|
|
||||||
|
|
||||||
<li><a href="inheritance.html">Inheritance</a>
|
|
||||||
|
|
||||||
<li><a href="special.html">Special Method and Operator Support</a>
|
|
||||||
|
|
||||||
<li><a href="under-the-hood.html">A Peek Under the Hood</a>
|
|
||||||
|
|
||||||
<li><a href="building.html">Building an Extension Module</a>
|
|
||||||
|
|
||||||
<li>Advanced Topics
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>Pickling
|
|
||||||
|
|
||||||
<li>class_builder<>
|
|
||||||
|
|
||||||
<li><a href="enums.html">enums</a>
|
|
||||||
|
|
||||||
<li>References
|
|
||||||
|
|
||||||
<li><a href="pointers.html">Pointers and Smart Pointers</a>
|
|
||||||
|
|
||||||
<li>Built-in Python Types
|
|
||||||
|
|
||||||
<li>Other Extension Types
|
|
||||||
|
|
||||||
<li>Templates
|
|
||||||
|
|
||||||
<li><a href="data_structures.txt">Internal Data Structures</a>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Documentation is a major ongoing project; assistance is greatly
|
|
||||||
appreciated! In the meantime, useful examples of every BPL feature should
|
|
||||||
be evident in the regression test files <code>test/comprehensive.[<a
|
|
||||||
href="../test/comprehensive.py">py</a>/<a
|
|
||||||
href="../test/comprehensive.hpp">hpp</a>/<a
|
|
||||||
href="../test/comprehensive.cpp">cpp</a>]</code>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Questions should be directed to <a href=
|
|
||||||
"http://www.egroups.com/list/boost">the boost mailing list</a>.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
|
||||||
sell and distribute this document is granted provided this copyright
|
|
||||||
notice appears in all copies. This document is provided ``as is'' without
|
|
||||||
express or implied warranty, and with no claim as to its suitability for
|
|
||||||
any purpose.
|
|
||||||
<p>
|
|
||||||
Updated: Nov 26, 2000
|
|
||||||
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
|
||||||
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
|
||||||
<title>
|
|
||||||
Inheritance
|
|
||||||
</title>
|
|
||||||
<div>
|
|
||||||
<h1>
|
|
||||||
<img width="277" height="86" id="_x0000_i1025" align="center"
|
|
||||||
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">Inheritance
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<h2>Inheritance in Python</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
BPL extension classes support single and multiple-inheritance in
|
|
||||||
Python, just like regular Python classes. You can arbitrarily mix
|
|
||||||
built-in Python classes with extension classes in a derived class'
|
|
||||||
tuple of bases. Whenever a BPL extension class is among the bases for a
|
|
||||||
new class in Python, the result is an extension class:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
>>> class MyPythonClass:
|
|
||||||
... def f(): return 'MyPythonClass.f()'
|
|
||||||
...
|
|
||||||
>>> import my_extension_module
|
|
||||||
>>> class Derived(my_extension_module.MyExtensionClass, MyPythonClass):
|
|
||||||
... '''This is an extension class'''
|
|
||||||
... pass
|
|
||||||
...
|
|
||||||
>>> x = Derived()
|
|
||||||
>>> x.f()
|
|
||||||
'MyPythonClass.f()'
|
|
||||||
>>> x.g()
|
|
||||||
'MyExtensionClass.g()'
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<h2><a name="implicit_conversion">Reflecting C++ Inheritance Relationships</a></h2>
|
|
||||||
<p>
|
|
||||||
BPL also allows us to represent C++ inheritance relationships so that
|
|
||||||
wrapped derived classes may be passed where values, pointers, or
|
|
||||||
references to a base class are expected as arguments. The
|
|
||||||
<code>declare_base</code> member function of
|
|
||||||
<code>class_builder<></code> is used to establish the relationship
|
|
||||||
between base and derived classes:
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
#include <memory> // for std::auto_ptr<>
|
|
||||||
|
|
||||||
struct Base {
|
|
||||||
virtual ~Base() {}
|
|
||||||
virtual const char* name() const { return "Base"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Derived : Base {
|
|
||||||
Derived() : x(-1) {}
|
|
||||||
virtual const char* name() const { return "Derived"; }
|
|
||||||
int x;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::auto_ptr<Base> derived_as_base() {
|
|
||||||
return std::auto_ptr<Base>(new Derived);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* get_name(const Base& b) {
|
|
||||||
return b.name();
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_derived_x(const Derived& d) {
|
|
||||||
return d.x;
|
|
||||||
}
|
|
||||||
<hr>
|
|
||||||
#include <boost/python/class_builder.hpp>
|
|
||||||
|
|
||||||
// namespace alias for code brevity
|
|
||||||
namespace python = boost::python;
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
#ifdef _WIN32
|
|
||||||
__declspec(dllexport)
|
|
||||||
#endif
|
|
||||||
void initmy_module()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
python::module_builder my_module("my_module");
|
|
||||||
|
|
||||||
python::class_builder<Base> base_class(my_module, "Base");
|
|
||||||
base_class.def(python::constructor<void>());
|
|
||||||
|
|
||||||
python::class_builder<Derived> derived_class(my_module, "Derived");
|
|
||||||
derived_class.def(python::constructor<void>());
|
|
||||||
<b>// Establish the inheritance relationship between Base and Derived
|
|
||||||
derived_class.declare_base(base_class);</b>
|
|
||||||
|
|
||||||
my_module.def(derived_as_base, "derived_as_base");
|
|
||||||
my_module.def(get_name, "get_name");
|
|
||||||
my_module.def(get_derived_x, "get_derived_x");
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
python::handle_exception(); // Deal with the exception for Python
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Then, in Python:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
>>> from my_module import *
|
|
||||||
>>> base = Base()
|
|
||||||
>>> derived = Derived()
|
|
||||||
>>> get_name(base)
|
|
||||||
'Base'
|
|
||||||
</pre><i>objects of wrapped class Derived may be passed where Base is expected</i><pre>
|
|
||||||
>>> get_name(derived)
|
|
||||||
'Derived'
|
|
||||||
</pre><i>objects of wrapped class Derived can be passed where Derived is
|
|
||||||
expected but where type information has been lost.</i><pre>
|
|
||||||
>>> get_derived_x(derived_as_base())
|
|
||||||
-1
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<h2>Inheritance Without Virtual Functions</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
If for some reason your base class has no virtual functions but you still want
|
|
||||||
to represent the inheritance relationship between base and derived classes,
|
|
||||||
pass the special symbol <code>boost::python::without_downcast</code> as the 2nd parameter
|
|
||||||
to <code>declare_base</code>:
|
|
||||||
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
struct Base2 {};
|
|
||||||
struct Derived2 { int f(); };
|
|
||||||
<hr>
|
|
||||||
...
|
|
||||||
python::class_builder<Base> base2_class(my_module, "Base2");
|
|
||||||
base2_class.def(python::constructor<void>());
|
|
||||||
|
|
||||||
python::class_builder<Derived2> derived2_class(my_module, "Derived2");
|
|
||||||
derived2_class.def(python::constructor<void>());
|
|
||||||
derived_class.declare_base(base_class, <b>python::without_downcast</b>);
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<p>This approach will allow <code>Derived2</code> objects to be passed where
|
|
||||||
<code>Base2</code> is expected, but does not attempt to implicitly convert (downcast)
|
|
||||||
smart-pointers to <code>Base2</code> into <code>Derived2</code> pointers,
|
|
||||||
references, or values.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Next: <a href="special.html">Special Method and Operator Support</a>
|
|
||||||
Previous: <a href="overloading.html">Function Overloading</a>
|
|
||||||
Up: <a href="index.html">Top</a>
|
|
||||||
<p>
|
|
||||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
|
||||||
sell and distribute this document is granted provided this copyright
|
|
||||||
notice appears in all copies. This document is provided "as is" without
|
|
||||||
express or implied warranty, and with no claim as to its suitability
|
|
||||||
for any purpose.
|
|
||||||
<p>
|
|
||||||
Updated: Nov 26, 2000
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
|
||||||
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
|
||||||
<title>
|
|
||||||
Function Overloading
|
|
||||||
</title>
|
|
||||||
<div>
|
|
||||||
<h1>
|
|
||||||
<img width="277" height="86" id="_x0000_i1025" align="center"
|
|
||||||
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">Function Overloading
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<h2>An Example</h2>
|
|
||||||
<p>
|
|
||||||
To expose overloaded functions in Python, simply <code>def()</code> each
|
|
||||||
one with the same Python name:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
inline int f1() { return 3; }
|
|
||||||
inline int f2(int x) { return x + 1; }
|
|
||||||
|
|
||||||
class X {
|
|
||||||
public:
|
|
||||||
X() : m_value(0) {}
|
|
||||||
X(int n) : m_value(n) {}
|
|
||||||
int value() const { return m_value; }
|
|
||||||
void value(int v) { m_value = v; }
|
|
||||||
private:
|
|
||||||
int m_value;
|
|
||||||
};
|
|
||||||
...
|
|
||||||
|
|
||||||
void initoverload_demo()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
boost::python::module_builder overload_demo("overload_demo");
|
|
||||||
// Overloaded functions at module scope
|
|
||||||
overload_demo.def(f1, "f");
|
|
||||||
overload_demo.def(f2, "f");
|
|
||||||
|
|
||||||
boost::python::class_builder<X> x_class(overload_demo, "X");
|
|
||||||
// Overloaded constructors
|
|
||||||
x_class.def(boost::python::constructor<>());
|
|
||||||
x_class.def(boost::python::constructor<int>());
|
|
||||||
|
|
||||||
// Overloaded member functions
|
|
||||||
x_class.def((int (X::*)() const)&X::value, "value");
|
|
||||||
x_class.def((void (X::*)(int))&X::value, "value");
|
|
||||||
...
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Now in Python:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
>>> from overload_demo import *
|
|
||||||
>>> x0 = X()
|
|
||||||
>>> x1 = X(1)
|
|
||||||
>>> x0.value()
|
|
||||||
0
|
|
||||||
>>> x1.value()
|
|
||||||
1
|
|
||||||
>>> x0.value(3)
|
|
||||||
>>> x0.value()
|
|
||||||
3
|
|
||||||
>>> X('hello')
|
|
||||||
TypeError: No overloaded functions match (X, string). Candidates are:
|
|
||||||
void (*)()
|
|
||||||
void (*)(int)
|
|
||||||
>>> f()
|
|
||||||
3
|
|
||||||
>>> f(4)
|
|
||||||
5
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<h2>Discussion</h2>
|
|
||||||
<p>
|
|
||||||
Notice that overloading in the Python module was produced three ways:<ol>
|
|
||||||
<li>by combining the non-overloaded C++ functions <code>int f1()</code>
|
|
||||||
and <code>int f2(int)</code> and exposing them as <code>f</code> in Python.
|
|
||||||
<li>by exposing the overloaded constructors of <code>class X</code>
|
|
||||||
<li>by exposing the overloaded member functions <code>X::value</code>.
|
|
||||||
</ol>
|
|
||||||
<p>
|
|
||||||
Techniques 1. and 3. above are really alternatives. In case 3, you need
|
|
||||||
to form a pointer to each of the overloaded functions. The casting
|
|
||||||
syntax shown above is one way to do that in C++. Case 1 does not require
|
|
||||||
complicated-looking casts, but may not be viable if you can't change
|
|
||||||
your C++ interface. N.B. There's really nothing unsafe about casting an
|
|
||||||
overloaded (member) function address this way: the compiler won't let
|
|
||||||
you write it at all unless you get it right.
|
|
||||||
|
|
||||||
<h2>An Alternative to Casting</h2>
|
|
||||||
<p>
|
|
||||||
This approach is not neccessarily better, but may be preferable for some
|
|
||||||
people who have trouble writing out the types of (member) function
|
|
||||||
pointers or simply prefer to avoid all casts as a matter of principle:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
// Forwarding functions for X::value
|
|
||||||
inline void set_x_value(X& self, int v) { self.value(v); }
|
|
||||||
inline int get_x_value(X& self) { return self.value(); }
|
|
||||||
...
|
|
||||||
// Overloaded member functions
|
|
||||||
x_class.def(set_x_value, "value");
|
|
||||||
x_class.def(get_x_value, "value");
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<p>Here we are taking advantage of the ability to expose C++ functions at
|
|
||||||
namespace scope as Python member functions.
|
|
||||||
|
|
||||||
<h2>Overload Resolution</h2>
|
|
||||||
<p>
|
|
||||||
The function overload resolution mechanism works as follows:
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li>Attribute lookup for extension classes proceeds in <a
|
|
||||||
href="http://www.pythonlabs.com/pub/www.python.org/doc/current/tut/node11.html#SECTION0011510000000000000000">the
|
|
||||||
usual Python way</a> using a depth-first, left-to-right search. When a
|
|
||||||
class is found which has a matching attribute, only functions overloaded
|
|
||||||
in the context of that class are candidates for overload resolution. In
|
|
||||||
this sense, overload resolution mirrors the C++ mechanism, where a name
|
|
||||||
in a derived class ``hides'' all functions with the same name from a base
|
|
||||||
class.
|
|
||||||
<p>
|
|
||||||
|
|
||||||
<li>Within a name-space context (extension class or module), overloaded
|
|
||||||
functions are tried in the same order they were
|
|
||||||
<code>def()</code>ed. The first function whose signature can be made to
|
|
||||||
match each argument passed is the one which is ultimately called.
|
|
||||||
This means in particular that you cannot overload the same function on
|
|
||||||
both ``<code>int</code>'' and ``<code>float</code>'' because Python
|
|
||||||
automatically converts either of the two types into the other one.
|
|
||||||
If the ``<code>float</code>'' overload is found first, it is used
|
|
||||||
also used for arguments of type ``<code>int</code>'' as well, and the
|
|
||||||
``<code>int</code>'' version of the function is never invoked.
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Next: <a href="inheritance.html">Inheritance</a>
|
|
||||||
Previous: <a href="overriding.html">Overridable Virtual Functions</a>
|
|
||||||
Up: <a href="index.html">Top</a>
|
|
||||||
<p>
|
|
||||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
|
||||||
sell and distribute this document is granted provided this copyright
|
|
||||||
notice appears in all copies. This document is provided ``as
|
|
||||||
is'' without express or implied warranty, and with no claim as to
|
|
||||||
its suitability for any purpose.
|
|
||||||
<p>
|
|
||||||
Updated: Nov 26, 2000
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@@ -1,195 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
|
||||||
|
|
||||||
<title>Overridable Virtual Functions</title>
|
|
||||||
|
|
||||||
<img src="../../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
|
|
||||||
width="277" height="86">
|
|
||||||
|
|
||||||
<h1>Overridable Virtual Functions</h1>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
In the <a href="example1.html">previous example</a> we exposed a simple
|
|
||||||
C++ class in Python and showed that we could write a subclass. We even
|
|
||||||
redefined one of the functions in our derived class. Now we will learn
|
|
||||||
how to make the function behave virtually <em>when called from C++</em>.
|
|
||||||
|
|
||||||
|
|
||||||
<h2><a name="overriding_example">Example</a></h2>
|
|
||||||
|
|
||||||
<p>In this example, it is assumed that <code>world::greet()</code> is a virtual
|
|
||||||
member function:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
class world
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
world(int);
|
|
||||||
virtual ~world();
|
|
||||||
<b>virtual</b> std::string greet() const { return "hi, world"; }
|
|
||||||
};
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
We'll need a derived class<a href="#why_derived">*</a> to help us
|
|
||||||
dispatch the call to Python. In our derived class, we need the following
|
|
||||||
elements:
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
|
|
||||||
<li><a name="derived_1">A</a> <code>PyObject*</code> data member that holds a
|
|
||||||
reference to the corresponding Python object.
|
|
||||||
|
|
||||||
<li><a name="derived_2">A</a> constructor for each exposed constructor of the
|
|
||||||
base class which stores an additional initial <code>PyObject*</code> argument
|
|
||||||
in the data member described above.
|
|
||||||
|
|
||||||
<li><a name="derived_3">An</a> implementation of each virtual function you may
|
|
||||||
wish to override in Python which uses
|
|
||||||
<code>boost::python::callback<<i>return-type</i>>::call_method()</code> to call
|
|
||||||
the Python override.
|
|
||||||
|
|
||||||
<li><a name="derived_4">For</a> each non-pure virtual function meant to be
|
|
||||||
overridable from Python, a static member function (or a free function) taking
|
|
||||||
a reference or pointer to the base type as the first parameter and which
|
|
||||||
forwards any additional parameters neccessary to the <i>default</i>
|
|
||||||
implementation of the virtual function. See also <a href="#private">this
|
|
||||||
note</a> if the base class virtual function is private.
|
|
||||||
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
struct world_callback : world
|
|
||||||
{
|
|
||||||
world_callback(PyObject* self, int x) // <a href="#derived_2">2</a>
|
|
||||||
: world(x),
|
|
||||||
m_self(self) {}
|
|
||||||
|
|
||||||
std::string greet() const // <a href="#derived_3">3</a>
|
|
||||||
{ return boost::python::callback<std::string>::call_method(m_self, "get"); }
|
|
||||||
|
|
||||||
static std::string <a name= "default_implementation">default_get</a>(const hello::world& self) const // <a href="#derived_4">4</a>
|
|
||||||
{ return self.world::greet(); }
|
|
||||||
private:
|
|
||||||
PyObject* m_self; // <a href="#derived_1">1</a>
|
|
||||||
};
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Finally, we add <code>world_callback</code> to the <code>
|
|
||||||
class_builder<></code> declaration in our module initialization
|
|
||||||
function, and when we define the function, we must tell py_cpp about the default
|
|
||||||
implementation:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
// Create the <a name=
|
|
||||||
"world_class">Python type object</a> for our extension class
|
|
||||||
boost::python::class_builder<hello::world<strong>,world_callback></strong> world_class(hello, "world");
|
|
||||||
// Add a virtual member function
|
|
||||||
world_class.def(&world::get, "get", &<b>world_callback::default_get</b>);
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Now our subclass of <code>hello.world</code> behaves as expected:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
>>> class my_subclass(hello.world):
|
|
||||||
... def greet(self):
|
|
||||||
... return 'hello, world'
|
|
||||||
...
|
|
||||||
>>> hello.length(my_subclass())
|
|
||||||
12
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<a name="why_derived">*</a>You may ask, "Why do we need this derived
|
|
||||||
class? This could have been designed so that everything gets done right
|
|
||||||
inside of <code>hello::world</code>." One of the goals of py_cpp is to be
|
|
||||||
minimally intrusive on an existing C++ design. In principle, it should be
|
|
||||||
possible to expose the interface for a 3rd party library without changing
|
|
||||||
it. To unintrusively hook into the virtual functions so that a Python
|
|
||||||
override may be called, we must use a derived class.
|
|
||||||
|
|
||||||
<h2>Pure Virtual Functions</h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
A pure virtual function with no implementation is actually a lot easier to
|
|
||||||
deal with than a virtual function with a default implementation. First of
|
|
||||||
all, you obviously don't need to <a href="#default_implementation"> supply
|
|
||||||
a default implementation</a>. Secondly, you don't need to call
|
|
||||||
<code>def()</code> on the <code>extension_class<></code> instance
|
|
||||||
for the virtual function. In fact, you wouldn't <em>want</em> to: if the
|
|
||||||
corresponding attribute on the Python class stays undefined, you'll get an
|
|
||||||
<code>AttributeError</code> in Python when you try to call the function,
|
|
||||||
indicating that it should have been implemented. For example:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
struct baz {
|
|
||||||
<strong>virtual</strong> int pure(int) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct baz_callback {
|
|
||||||
int pure(int x) { boost::python::callback<int>::call_method(m_self, "pure", x); }
|
|
||||||
};
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
#ifdef _WIN32
|
|
||||||
__declspec(dllexport)
|
|
||||||
#endif
|
|
||||||
initfoobar()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
boost::python::module_builder foobar("foobar");
|
|
||||||
boost::python::class_builder<baz,baz_callback> baz_class("baz");
|
|
||||||
baz_class.def(&baz::pure, "pure");
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
boost::python::handle_exception(); // Deal with the exception for Python
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<p>
|
|
||||||
Now in Python:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
>>> from foobar import baz
|
|
||||||
>>> x = baz()
|
|
||||||
>>> x.pure(1)
|
|
||||||
Traceback (innermost last):
|
|
||||||
File "<stdin>", line 1, in ?
|
|
||||||
AttributeError: pure
|
|
||||||
>>> class mumble(baz):
|
|
||||||
... def pure(self, x): return x + 1
|
|
||||||
...
|
|
||||||
>>> y = mumble()
|
|
||||||
>>> y.pure(99)
|
|
||||||
100
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<a name="private"><h2>Private Non-Pure Virtual Functions</h2></a>
|
|
||||||
|
|
||||||
<p>This is one area where some minor intrusiveness on the wrapped library is
|
|
||||||
required. Once it has been overridden, the only way to call the base class
|
|
||||||
implementation of a private virtual function is to make the derived class a
|
|
||||||
friend of the base class. You didn't hear it from me, but most C++
|
|
||||||
implementations will allow you to change the declaration of the base class in
|
|
||||||
this limited way without breaking binary compatibility (though it will certainly
|
|
||||||
break the <a
|
|
||||||
href="http://cs.calvin.edu/c++/C++Standard-Nov97/basic.html#basic.def.odr">ODR</a>).
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Next: <a href="overloading.html">Function Overloading</a>
|
|
||||||
Previous: <a href="example1.html">A Simple Example Using py_cpp</a>
|
|
||||||
Up: <a href="index.html">Top</a>
|
|
||||||
<p>
|
|
||||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
|
||||||
sell and distribute this document is granted provided this copyright
|
|
||||||
notice appears in all copies. This document is provided "as is" without
|
|
||||||
express or implied warranty, and with no claim as to its suitability for
|
|
||||||
any purpose.
|
|
||||||
<p>
|
|
||||||
Updated: Nov 26, 2000
|
|
||||||
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
|
||||||
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
|
||||||
<title>
|
|
||||||
Pointers
|
|
||||||
</title>
|
|
||||||
<div>
|
|
||||||
<h1>
|
|
||||||
<img width="277" height="86" id="_x0000_i1025" align="center"
|
|
||||||
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">Pointers
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<h2><a name="problem">The Problem With Pointers</a></h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
In general, raw pointers passed to or returned from functions are problematic
|
|
||||||
for BPL because pointers have too many potential meanings. Is it an iterator?
|
|
||||||
A pointer to a single element? An array? When used as a return value, is the
|
|
||||||
caller expected to manage (delete) the pointed-to object or is the pointer
|
|
||||||
really just a reference? If the latter, what happens to Python references to the
|
|
||||||
referent when some C++ code deletes it?
|
|
||||||
<p>
|
|
||||||
There are a few cases in which pointers are converted automatically:
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<li>Both const- and non-const pointers to wrapped class instances can be passed
|
|
||||||
<i>to</i> C++ functions.
|
|
||||||
|
|
||||||
<li>Values of type <code>const char*</code> are interpreted as
|
|
||||||
null-terminated 'C' strings and when passed to or returned from C++ functions are
|
|
||||||
converted from/to Python strings.
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3>Can you avoid the problem?</h3>
|
|
||||||
|
|
||||||
<p>My first piece of advice to anyone with a case not covered above is
|
|
||||||
``find a way to avoid the problem.'' For example, if you have just one
|
|
||||||
or two functions that return a pointer to an individual <code>const
|
|
||||||
T</code>, and <code>T</code> is a wrapped class, you may be able to write a ``thin
|
|
||||||
converting wrapper'' over those two functions as follows:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
const Foo* f(); // original function
|
|
||||||
const Foo& f_wrapper() { return *f(); }
|
|
||||||
...
|
|
||||||
my_module.def(f_wrapper, "f");
|
|
||||||
</pre></blockquote>
|
|
||||||
<p>
|
|
||||||
Foo must have a public copy constructor for this technique to work, since BPL
|
|
||||||
converts <code>const T&</code> values <code>to_python</code> by copying the <code>T</code>
|
|
||||||
value into a new extension instance.
|
|
||||||
|
|
||||||
<h2>Dealing with the problem</h2>
|
|
||||||
|
|
||||||
<p>The first step in handling the remaining cases is to figure out what the pointer
|
|
||||||
means. Several potential solutions are provided in the examples that follow:
|
|
||||||
|
|
||||||
<h3>Returning a pointer to a wrapped type</h3>
|
|
||||||
|
|
||||||
<h4>Returning a const pointer</h4>
|
|
||||||
|
|
||||||
<p>If you have lots of functions returning a <code>const T*</code> for some
|
|
||||||
wrapped <code>T</code>, you may want to provide an automatic
|
|
||||||
<code>to_python</code> conversion function so you don't have to write lots of
|
|
||||||
thin wrappers. You can do this simply as follows:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
|
|
||||||
PyObject* to_python(const Foo* p) {
|
|
||||||
return to_python(*p); // convert const Foo* in terms of const Foo&
|
|
||||||
}
|
|
||||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<h4>If you can't (afford to) copy the referent, or the pointer is non-const</h4>
|
|
||||||
|
|
||||||
<p>If the wrapped type doesn't have a public copy constructor, if copying is
|
|
||||||
<i>extremely</i> costly (remember, we're dealing with Python here), or if the
|
|
||||||
pointer is non-const and you really need to be able to modify the referent from
|
|
||||||
Python, you can use the following dangerous trick. Why dangerous? Because python
|
|
||||||
can not control the lifetime of the referent, so it may be destroyed by your C++
|
|
||||||
code before the last Python reference to it disappears:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
|
|
||||||
PyObject* to_python(Foo* p)
|
|
||||||
{
|
|
||||||
return boost::python::PyExtensionClassConverters<Foo>::ptr_to_python(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(const Foo* p)
|
|
||||||
{
|
|
||||||
return to_python(const_cast<Foo*>(p));
|
|
||||||
}
|
|
||||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
This will cause the Foo* to be treated as though it were an owning smart
|
|
||||||
pointer, even though it's not. Be sure you don't use the reference for anything
|
|
||||||
from Python once the pointer becomes invalid, though. Don't worry too much about
|
|
||||||
the <code>const_cast<></code> above: Const-correctness is completely lost
|
|
||||||
to Python anyway!
|
|
||||||
|
|
||||||
<h3>[In/]Out Parameters and Immutable Types</h3>
|
|
||||||
|
|
||||||
<p>If you have an interface that uses non-const pointers (or references) as
|
|
||||||
in/out parameters to types which in Python are immutable (e.g. int, string),
|
|
||||||
there simply is <i>no way</i> to get the same interface in Python. You must
|
|
||||||
resort to transforming your interface with simple thin wrappers as shown below:
|
|
||||||
<blockquote><pre>
|
|
||||||
const void f(int* in_out_x); // original function
|
|
||||||
const int f_wrapper(int in_x) { f(in_x); return in_x; }
|
|
||||||
...
|
|
||||||
my_module.def(f_wrapper, "f");
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>Of course, [in/]out parameters commonly occur only when there is already a
|
|
||||||
return value. You can handle this case by returning a Python tuple:
|
|
||||||
<blockquote><pre>
|
|
||||||
typedef unsigned ErrorCode;
|
|
||||||
const char* f(int* in_out_x); // original function
|
|
||||||
...
|
|
||||||
#include <boost/python/objects.hpp>
|
|
||||||
const boost::python::tuple f_wrapper(int in_x) {
|
|
||||||
const char* s = f(in_x);
|
|
||||||
return boost::python::tuple(s, in_x);
|
|
||||||
}
|
|
||||||
...
|
|
||||||
my_module.def(f_wrapper, "f");
|
|
||||||
</pre></blockquote>
|
|
||||||
<p>Now, in Python:
|
|
||||||
<blockquote><pre>
|
|
||||||
>>> str,out_x = f(3)
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Previous: <a href="enums.html">Enums</a>
|
|
||||||
Up: <a href="index.html">Top</a>
|
|
||||||
<p>
|
|
||||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
|
||||||
sell and distribute this document is granted provided this copyright
|
|
||||||
notice appears in all copies. This document is provided "as is" without
|
|
||||||
express or implied warranty, and with no claim as to its suitability
|
|
||||||
for any purpose.
|
|
||||||
<p>
|
|
||||||
Updated: Nov 26, 2000
|
|
||||||
</div>
|
|
||||||
|
|
||||||
905
doc/special.html
905
doc/special.html
@@ -1,905 +0,0 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
||||||
<title>
|
|
||||||
Special Method and Operator Support
|
|
||||||
</title>
|
|
||||||
<div>
|
|
||||||
<h1>
|
|
||||||
<img width="277" height="86" id="_x0000_i1025" align="middle" src=
|
|
||||||
"../../../c++boost.gif" alt="c++boost.gif (8819 bytes)">Special Method and
|
|
||||||
Operator Support
|
|
||||||
</h1>
|
|
||||||
<h2>
|
|
||||||
Overview
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
BPL supports all of the standard <a href=
|
|
||||||
"http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/specialnames.html">
|
|
||||||
special method names</a> supported by real Python class instances <em>
|
|
||||||
except</em> <code>__complex__</code> (more on the reasons <a href=
|
|
||||||
"#reasons">below</a>). In addition, it can quickly and easily expose
|
|
||||||
suitable C++ functions and operators as Python operators. The following
|
|
||||||
categories of special method names are supported:
|
|
||||||
<ul>
|
|
||||||
<li><a href="#general">Basic Customization</a>
|
|
||||||
<li><a href="#numeric">Numeric Operators</a>
|
|
||||||
<li><a href="#sequence_and_mapping">Sequence and Mapping protocols</a>
|
|
||||||
<li><a href="#getter_setter">Attribute Getters and Setters</a>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2><a name="general">Basic Customization</a></h2>
|
|
||||||
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Python provides a number of special operators for basic customization of a
|
|
||||||
class. Only a brief description is provided below; more complete
|
|
||||||
documentation can be found <a
|
|
||||||
href="http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/customization.html">here</a>.
|
|
||||||
|
|
||||||
<dl>
|
|
||||||
<dt>
|
|
||||||
<b><tt class='method'>__init__</tt></b>(<i>self</i>)
|
|
||||||
<dd>
|
|
||||||
Initialize the class instance. For extension classes not subclassed in
|
|
||||||
Python, <code> __init__</code> is defined by
|
|
||||||
|
|
||||||
<pre> my_class.def(boost::python::constructor<...>())</pre>
|
|
||||||
|
|
||||||
(see section <a href="example1.html">"A Simple Example Using BPL"</a>).<p>
|
|
||||||
<dt>
|
|
||||||
<b><tt class='method'>__del__</tt></b>(<i>self</i>)
|
|
||||||
<dd>
|
|
||||||
Called when the extension instance is about to be destroyed. For extension classes
|
|
||||||
not subclassed in Python, <code> __del__</code> is always defined automatically by
|
|
||||||
means of the class' destructor.
|
|
||||||
<dt>
|
|
||||||
<b><tt class='method'>__repr__</tt></b>(<i>self</i>)
|
|
||||||
<dd>
|
|
||||||
Create a string representation from which the object can be
|
|
||||||
reconstructed.
|
|
||||||
<dt>
|
|
||||||
<b><tt class='method'>__str__</tt></b>(<i>self</i>)
|
|
||||||
<dd>
|
|
||||||
Create a string representation which is suitable for printing.
|
|
||||||
<dt>
|
|
||||||
<b><tt class='method'>__cmp__</tt></b>(<i>self, other</i>)
|
|
||||||
<dd>
|
|
||||||
Three-way compare function, used to implement comparison operators
|
|
||||||
(< etc.) Should return a negative integer if <code> self < other
|
|
||||||
</code> , zero if <code> self == other </code> , a positive integer if
|
|
||||||
<code> self > other </code>.
|
|
||||||
<dt>
|
|
||||||
<b><tt class='method'>__hash__</tt></b>(<i>self</i>)
|
|
||||||
<dd>
|
|
||||||
Called for the key object for dictionary operations, and by the
|
|
||||||
built-in function hash(). Should return a 32-bit integer usable as a
|
|
||||||
hash value for dictionary operations (only allowed if __cmp__ is also
|
|
||||||
defined)
|
|
||||||
<dt>
|
|
||||||
<b><tt class='method'>__nonzero__</tt></b>(<i>self</i>)
|
|
||||||
<dd>
|
|
||||||
called if the object is used as a truth value (e.g. in an if
|
|
||||||
statement)
|
|
||||||
<dt>
|
|
||||||
<b><tt class='method'>__call__</tt></b> (<var>self</var><big>[</big><var>, args...</var><big>]</big>)
|
|
||||||
<dd>
|
|
||||||
Called when the instance is ``called'' as a function; if this method
|
|
||||||
is defined, <code><var>x</var>(arg1, arg2, ...)</code> is a shorthand for
|
|
||||||
<code><var>x</var>.__call__(arg1, arg2, ...)</code>.
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
If we have a suitable C++ function that supports any of these features,
|
|
||||||
we can export it like any other function, using its Python special name.
|
|
||||||
For example, suppose that class <code>Foo</code> provides a string
|
|
||||||
conversion function:
|
|
||||||
<blockquote><pre>
|
|
||||||
std::string to_string(Foo const& f)
|
|
||||||
{
|
|
||||||
std::ostringstream s;
|
|
||||||
s << f;
|
|
||||||
return s.str();
|
|
||||||
}
|
|
||||||
</pre></blockquote>
|
|
||||||
This function would be wrapped like this:
|
|
||||||
<blockquote><pre>
|
|
||||||
boost::python::class_builder<Foo> foo_class(my_module, "Foo");
|
|
||||||
foo_class.def(&to_string, "__str__");
|
|
||||||
</pre></blockquote>
|
|
||||||
Note that BPL also supports <em>automatic wrapping</em> of
|
|
||||||
<code>__str__</code> and <code>__cmp__</code>. This is explained in the <a
|
|
||||||
href="#numeric">next section</a> and the <a href="#numeric_table">Table of
|
|
||||||
Automatically Wrapped Methods</a>.
|
|
||||||
|
|
||||||
<h2><a name="numeric">Numeric Operators</a></h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Numeric operators can be exposed manually, by <code>def</code>ing C++
|
|
||||||
[member] functions that support the standard Python <a
|
|
||||||
href="http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/numeric-types.html">numeric
|
|
||||||
protocols</a>. This is the same basic technique used to expose
|
|
||||||
<code>to_string()</code> as <code>__str__()</code> above, and is <a
|
|
||||||
href="#numeric_manual">covered in detail below</a>. BPL also supports
|
|
||||||
<i>automatic wrapping</i> of numeric operators whenever they have already
|
|
||||||
been defined in C++.
|
|
||||||
|
|
||||||
<h3><a name="numeric_auto">Exposing C++ Operators Automatically</a></h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Supose we wanted to expose a C++ class
|
|
||||||
<code>BigNum</code> which supports addition. That is, in C++ we can write:
|
|
||||||
<blockquote><pre>
|
|
||||||
BigNum a, b, c;
|
|
||||||
...
|
|
||||||
c = a + b;
|
|
||||||
</pre></blockquote>
|
|
||||||
<p>
|
|
||||||
To enable the same functionality in Python, we first wrap the <code>
|
|
||||||
BigNum</code> class as usual:
|
|
||||||
<blockquote><pre>
|
|
||||||
boost::python::class_builder<BigNum> bignum_class(my_module, "BigNum");
|
|
||||||
bignum_class.def(boost::python::constructor<>());
|
|
||||||
...
|
|
||||||
</pre></blockquote>
|
|
||||||
Then we export the addition operator like this:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
bignum_class.def(boost::python::operators<boost::python::op_add>());
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
Since BigNum also supports subtraction, multiplication, and division, we
|
|
||||||
want to export those also. This can be done in a single command by
|
|
||||||
``or''ing the operator identifiers together (a complete list of these
|
|
||||||
identifiers and the corresponding operators can be found in the <a href=
|
|
||||||
"#numeric_table">Table of Automatically Wrapped Methods</a>):
|
|
||||||
<blockquote><pre>
|
|
||||||
bignum_class.def(boost::python::operators<(boost::python::op_sub | boost::python::op_mul | boost::python::op_div)>());
|
|
||||||
</pre></blockquote>
|
|
||||||
[Note that the or-expression must be enclosed in parentheses.]
|
|
||||||
|
|
||||||
<p>This form of operator definition can be used to wrap unary and
|
|
||||||
homogeneous binary operators (a <i>homogeneous</i> operator has left and
|
|
||||||
right operands of the same type). Now suppose that our C++ library also
|
|
||||||
supports addition of BigNums and plain integers:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
BigNum a, b;
|
|
||||||
int i;
|
|
||||||
...
|
|
||||||
a = b + i;
|
|
||||||
a = i + b;
|
|
||||||
</pre></blockquote>
|
|
||||||
To wrap these heterogeneous operators, we need to specify a different type for
|
|
||||||
one of the operands. This is done using the <code>right_operand</code>
|
|
||||||
and <code>left_operand</code> templates:
|
|
||||||
<blockquote><pre>
|
|
||||||
bignum_class.def(boost::python::operators<boost::python::op_add>(), boost::python::right_operand<int>());
|
|
||||||
bignum_class.def(boost::python::operators<boost::python::op_add>(), boost::python::left_operand<int>());
|
|
||||||
</pre></blockquote>
|
|
||||||
BPL uses overloading to register several variants of the same
|
|
||||||
operation (more on this in the context of <a href="#coercion">
|
|
||||||
coercion</a>). Again, several operators can be exported at once:
|
|
||||||
<blockquote><pre>
|
|
||||||
bignum_class.def(boost::python::operators<(boost::python::op_sub | boost::python::op_mul | boost::python::op_div)>(),
|
|
||||||
boost::python::right_operand<int>());
|
|
||||||
bignum_class.def(boost::python::operators<(boost::python::op_sub | boost::python::op_mul | boost::python::op_div)>(),
|
|
||||||
boost::python::left_operand<int>());
|
|
||||||
</pre></blockquote>
|
|
||||||
The type of the operand not mentioned is taken from the class being wrapped. In
|
|
||||||
our example, the class object is <code>bignum_class</code>, and thus the
|
|
||||||
other operand's type is ``<code>BigNum const&</code>''. You can override
|
|
||||||
this default by explicitly specifying a type in the <code>
|
|
||||||
operators</code> template:
|
|
||||||
<blockquote><pre>
|
|
||||||
bignum_class.def(boost::python::operators<boost::python::op_add, BigNum>(), boost::python::right_operand<int>());
|
|
||||||
</pre></blockquote>
|
|
||||||
<p>
|
|
||||||
Note that automatic wrapping uses the <em>expression</em>
|
|
||||||
``<code>left + right</code>'' and can be used uniformly
|
|
||||||
regardless of whether the C++ operators are supplied as free functions
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
BigNum operator+(BigNum, BigNum)
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
or as member functions
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
BigNum::operator+(BigNum).
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
For the Python built-in functions <code>pow()</code> and
|
|
||||||
<code>abs()</code>, there is no corresponding C++ operator. Instead,
|
|
||||||
automatic wrapping attempts to wrap C++ functions of the same name. This
|
|
||||||
only works if those functions are known in namespace
|
|
||||||
<code>python</code>. On some compilers (e.g. MSVC) it might be
|
|
||||||
necessary to add a using declaration prior to wrapping:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
namespace boost { namespace python {
|
|
||||||
using my_namespace::pow;
|
|
||||||
using my_namespace::abs;
|
|
||||||
}
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<h3><a name="numeric_manual">Wrapping Numeric Operators Manually</a></h3>
|
|
||||||
<p>
|
|
||||||
In some cases, automatic wrapping of operators may be impossible or
|
|
||||||
undesirable. Suppose, for example, that the modulo operation for BigNums
|
|
||||||
is defined by a set of functions called <code>mod()</code>:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
BigNum mod(BigNum const& left, BigNum const& right);
|
|
||||||
BigNum mod(BigNum const& left, int right);
|
|
||||||
BigNum mod(int left, BigNum const& right);
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
For automatic wrapping of the modulo function, <code>operator%()</code> would be needed.
|
|
||||||
Therefore, the <code>mod()</code>-functions must be wrapped manually. That is, we have
|
|
||||||
to export them explicitly with the Python special name "__mod__":
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
bignum_class.def((BigNum (*)(BigNum const&, BigNum const&))&mod, "__mod__");
|
|
||||||
bignum_class.def((BigNum (*)(BigNum const&, int))&mod, "__mod__");
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The third form of <code>mod()</code> (with <code>int</code> as left operand) cannot
|
|
||||||
be wrapped directly. We must first create a function <code>rmod()</code> with the
|
|
||||||
operands reversed:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
BigNum rmod(BigNum const& right, int left)
|
|
||||||
{
|
|
||||||
return mod(left, right);
|
|
||||||
}
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
This function must be wrapped under the name "__rmod__" (standing for "reverse mod"):
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
bignum_class.def(&rmod, "__rmod__");
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
Many of the possible operator names can be found in the <a href=
|
|
||||||
"#numeric_table">Table of Automatically Wrapped Methods</a>. Special treatment is
|
|
||||||
necessary to export the <a href="#ternary_pow">ternary pow</a> operator.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Automatic and manual wrapping can be mixed arbitrarily. Note that you
|
|
||||||
cannot overload the same operator for a given extension class on both
|
|
||||||
``<code>int</code>'' and ``<code>float</code>'', because Python implicitly
|
|
||||||
converts these types into each other. Thus, the overloaded variant
|
|
||||||
found first (be it ``<code>int</code>`` or ``<code>float</code>'') will be
|
|
||||||
used for either of the two types.
|
|
||||||
|
|
||||||
<h3><a name="coercion">Coercion</a></h3>
|
|
||||||
|
|
||||||
|
|
||||||
Plain Python can only execute operators with identical types on the left
|
|
||||||
and right hand side. If it encounters an expression where the types of
|
|
||||||
the left and right operand differ, it tries to coerce these types to a
|
|
||||||
common type before invoking the actual operator. Implementing good
|
|
||||||
coercion functions can be difficult if many type combinations must be
|
|
||||||
supported.
|
|
||||||
<p>
|
|
||||||
BPL solves this problem the same way that C++ does: with <em><a
|
|
||||||
href="overloading.html">overloading</a></em>. This technique drastically
|
|
||||||
simplifies the code neccessary to support operators: you just register
|
|
||||||
operators for all desired type combinations, and BPL automatically
|
|
||||||
ensures that the correct function is called in each case; there is no
|
|
||||||
need for user-defined coercion functions. To enable operator
|
|
||||||
overloading, BPL provides a standard coercion which is <em>implicitly
|
|
||||||
registered</em> whenever automatic operator wrapping is used.
|
|
||||||
<p>
|
|
||||||
If you wrap all operator functions manually, but still want to use
|
|
||||||
operator overloading, you have to register the standard coercion
|
|
||||||
function explicitly:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
// this is not necessary if automatic operator wrapping is used
|
|
||||||
bignum_class.def_standard_coerce();
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
If you encounter a situation where you absolutely need a customized
|
|
||||||
coercion, you can still define the "__coerce__" operator manually. The signature
|
|
||||||
of a coercion function should look like one of the following (the first is
|
|
||||||
the safest):
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
boost::python::tuple custom_coerce(boost::python::reference left, boost::python::reference right);
|
|
||||||
boost::python::tuple custom_coerce(PyObject* left, PyObject* right);
|
|
||||||
PyObject* custom_coerce(PyObject* left, PyObject* right);
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
The resulting <code>tuple</code> must contain two elements which
|
|
||||||
represent the values of <code>left</code> and <code>right</code>
|
|
||||||
converted to the same type. Such a function is wrapped as usual:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
// this must be called before any use of automatic operator
|
|
||||||
// wrapping or a call to some_class.def_standard_coerce()
|
|
||||||
some_class.def(&custom_coerce, "__coerce__");
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
Note that the standard coercion (defined by use of automatic
|
|
||||||
operator wrapping on a <code>class_builder</code> or a call to
|
|
||||||
<code>class_builder::def_standard_coerce()</code>) will never be applied if
|
|
||||||
a custom coercion function has been registered. Therefore, in
|
|
||||||
your coercion function you should call
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
boost::python::standard_coerce(left, right);
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
for all cases that you don't want to handle yourself.
|
|
||||||
|
|
||||||
<h3><a name="ternary_pow">The Ternary <code>pow()</code> Operator</a></h3>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
In addition to the usual binary <code>pow(x, y)</code> operator (meaning
|
|
||||||
<i>x<sup>y</sup></i>), Python also provides a ternary variant that implements
|
|
||||||
<i>x<sup>y</sup> <b>mod</b> z</i>, presumably using a more efficient algorithm than
|
|
||||||
concatenation of power and modulo operators. Automatic operator wrapping
|
|
||||||
can only be used with the binary variant. Ternary <code>pow()</code> must
|
|
||||||
always be wrapped manually. For a homgeneous ternary <code>pow()</code>,
|
|
||||||
this is done as usual:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
BigNum power(BigNum const& first, BigNum const& second, BigNum const& modulus);
|
|
||||||
typedef BigNum (ternary_function1)(const BigNum&, const BigNum&, const BigNum&);
|
|
||||||
...
|
|
||||||
bignum_class.def((ternary_function1)&power, "__pow__");
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
If you want to support this function with non-uniform argument
|
|
||||||
types, wrapping is a little more involved. Suppose you have to wrap:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
BigNum power(BigNum const& first, int second, int modulus);
|
|
||||||
BigNum power(int first, BigNum const& second, int modulus);
|
|
||||||
BigNum power(int first, int second, BigNum const& modulus);
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
The first variant can be wrapped as usual:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
typedef BigNum (ternary_function2)(const BigNum&, int, int);
|
|
||||||
bignum_class.def((ternary_function2)&power, "__pow__");
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
In the second variant, however, <code>BigNum</code> appears only as second
|
|
||||||
argument, and in the last one it's the third argument. These functions
|
|
||||||
must be presented to BPL such that that the <code>BigNum</code>
|
|
||||||
argument appears in first position:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
BigNum rpower(BigNum const& second, int first, int modulus)
|
|
||||||
{
|
|
||||||
return power(first, second, modulus);
|
|
||||||
}
|
|
||||||
|
|
||||||
BigNum rrpower(BigNum const& modulus, int first, int second)
|
|
||||||
{
|
|
||||||
return power(first, second, modulus);
|
|
||||||
}
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>These functions must be wrapped under the names "__rpow__" and "__rrpow__"
|
|
||||||
respectively:
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
bignum_class.def((ternary_function2)&rpower, "__rpow__");
|
|
||||||
bignum_class.def((ternary_function2)&rrpower, "__rrpow__");
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
Note that "__rrpow__" is an extension not present in plain Python.
|
|
||||||
|
|
||||||
<h2><a name="numeric_table">Table of Automatically Wrapped Methods</a></h2>
|
|
||||||
<p>
|
|
||||||
BPL can automatically wrap the following <a href=
|
|
||||||
"http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/specialnames.html">
|
|
||||||
special methods</a>:
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<table summary="special numeric methods" cellpadding="5" border="1"
|
|
||||||
width="100%">
|
|
||||||
<tr>
|
|
||||||
<td align="center">
|
|
||||||
<b>Python Operator Name</b>
|
|
||||||
<td align="center">
|
|
||||||
<b>Python Expression</b>
|
|
||||||
<td align="center">
|
|
||||||
<b>C++ Operator Id</b>
|
|
||||||
<td align="center">
|
|
||||||
<b>C++ Expression Used For Automatic Wrapping</b><br>
|
|
||||||
with <code>cpp_left = from_python(left,
|
|
||||||
type<Left>())</code>,<br>
|
|
||||||
<code>cpp_right = from_python(right,
|
|
||||||
type<Right>())</code>,<br>
|
|
||||||
and <code>cpp_oper = from_python(oper, type<Oper>())</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__add__, __radd__</code>
|
|
||||||
<td>
|
|
||||||
<code>left + right</code>
|
|
||||||
<td>
|
|
||||||
<code>op_add</code>
|
|
||||||
<td>
|
|
||||||
<code>cpp_left + cpp_right</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__sub__, __rsub__</code>
|
|
||||||
<td>
|
|
||||||
<code>left - right</code>
|
|
||||||
<td>
|
|
||||||
<code>op_sub</code>
|
|
||||||
<td>
|
|
||||||
<code>cpp_left - cpp_right</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__mul__, __rmul__</code>
|
|
||||||
<td>
|
|
||||||
<code>left * right</code>
|
|
||||||
<td>
|
|
||||||
<code>op_mul</code>
|
|
||||||
<td>
|
|
||||||
<code>cpp_left * cpp_right</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__div__, __rdiv__</code>
|
|
||||||
<td>
|
|
||||||
<code>left / right</code>
|
|
||||||
<td>
|
|
||||||
<code>op_div</code>
|
|
||||||
<td>
|
|
||||||
<code>cpp_left / cpp_right</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__mod__, __rmod__</code>
|
|
||||||
<td>
|
|
||||||
<code>left % right</code>
|
|
||||||
<td>
|
|
||||||
<code>op_mod</code>
|
|
||||||
<td>
|
|
||||||
<code>cpp_left % cpp_right</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__divmod__, __rdivmod__</code>
|
|
||||||
<td>
|
|
||||||
<code>(quotient, remainder)<br>
|
|
||||||
= divmod(left, right)</code>
|
|
||||||
<td>
|
|
||||||
<code>op_divmod</code>
|
|
||||||
<td>
|
|
||||||
<code>cpp_left / cpp_right</code>
|
|
||||||
<br><code>cpp_left % cpp_right</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__pow__, __rpow__</code>
|
|
||||||
<td>
|
|
||||||
<code>pow(left, right)</code><br>
|
|
||||||
(binary power)
|
|
||||||
<td>
|
|
||||||
<code>op_pow</code>
|
|
||||||
<td>
|
|
||||||
<code>pow(cpp_left, cpp_right)</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__rrpow__</code>
|
|
||||||
<td>
|
|
||||||
<code>pow(left, right, modulo)</code><br>
|
|
||||||
(ternary power modulo)
|
|
||||||
<td colspan="2">
|
|
||||||
no automatic wrapping, <a href="#ternary_pow">special treatment</a>
|
|
||||||
required
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__lshift__, __rlshift__</code>
|
|
||||||
<td>
|
|
||||||
<code>left << right</code>
|
|
||||||
<td>
|
|
||||||
<code>op_lshift</code>
|
|
||||||
<td>
|
|
||||||
<code>cpp_left << cpp_right</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__rshift__, __rrshift__</code>
|
|
||||||
<td>
|
|
||||||
<code>left >> right</code>
|
|
||||||
<td>
|
|
||||||
<code>op_rshift</code>
|
|
||||||
<td>
|
|
||||||
<code>cpp_left >> cpp_right</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__and__, __rand__</code>
|
|
||||||
<td>
|
|
||||||
<code>left & right</code>
|
|
||||||
<td>
|
|
||||||
<code>op_and</code>
|
|
||||||
<td>
|
|
||||||
<code>cpp_left & cpp_right</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__xor__, __rxor__</code>
|
|
||||||
<td>
|
|
||||||
<code>left ^ right</code>
|
|
||||||
<td>
|
|
||||||
<code>op_xor</code>
|
|
||||||
<td>
|
|
||||||
<code>cpp_left ^ cpp_right</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__or__, __ror__</code>
|
|
||||||
<td>
|
|
||||||
<code>left | right</code>
|
|
||||||
<td>
|
|
||||||
<code>op_or</code>
|
|
||||||
<td>
|
|
||||||
<code>cpp_left | cpp_right</code>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__cmp__, __rcmp__</code>
|
|
||||||
<td>
|
|
||||||
<code>cmp(left, right)</code><br>
|
|
||||||
<code>left < right</code><br>
|
|
||||||
<code>left <= right</code><br>
|
|
||||||
<code>left > right</code><br>
|
|
||||||
<code>left >= right</code><br>
|
|
||||||
<code>left == right</code><br>
|
|
||||||
<code>left != right</code>
|
|
||||||
<td>
|
|
||||||
<code>op_cmp</code>
|
|
||||||
<td>
|
|
||||||
<code>cpp_left < cpp_right </code>
|
|
||||||
<br><code>cpp_right < cpp_left</code>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__neg__</code>
|
|
||||||
<td>
|
|
||||||
<code>-oper </code> (unary negation)
|
|
||||||
<td>
|
|
||||||
<code>op_neg</code>
|
|
||||||
<td>
|
|
||||||
<code>-cpp_oper</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__pos__</code>
|
|
||||||
<td>
|
|
||||||
<code>+oper </code> (identity)
|
|
||||||
<td>
|
|
||||||
<code>op_pos</code>
|
|
||||||
<td>
|
|
||||||
<code>+cpp_oper</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__abs__</code>
|
|
||||||
<td>
|
|
||||||
<code>abs(oper) </code> (absolute value)
|
|
||||||
<td>
|
|
||||||
<code>op_abs</code>
|
|
||||||
<td>
|
|
||||||
<code>abs(cpp_oper)</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__invert__</code>
|
|
||||||
<td>
|
|
||||||
<code>~oper </code> (bitwise inversion)
|
|
||||||
<td>
|
|
||||||
<code>op_invert</code>
|
|
||||||
<td>
|
|
||||||
<code>~cpp_oper</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__int__</code>
|
|
||||||
<td>
|
|
||||||
<code>int(oper) </code> (integer conversion)
|
|
||||||
<td>
|
|
||||||
<code>op_int</code>
|
|
||||||
<td>
|
|
||||||
<code>long(cpp_oper)</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__long__</code>
|
|
||||||
<td>
|
|
||||||
<code>long(oper) </code><br>
|
|
||||||
(infinite precision integer conversion)
|
|
||||||
<td>
|
|
||||||
<code>op_long</code>
|
|
||||||
<td>
|
|
||||||
<code>PyLong_FromLong(cpp_oper)</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__float__</code>
|
|
||||||
<td>
|
|
||||||
<code>float(oper) </code> (float conversion)
|
|
||||||
<td>
|
|
||||||
<code>op_float</code>
|
|
||||||
<td>
|
|
||||||
<code>double(cpp_oper)</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__str__</code>
|
|
||||||
<td>
|
|
||||||
<code>str(oper) </code> (string conversion)
|
|
||||||
<td>
|
|
||||||
<code>op_str</code>
|
|
||||||
<td>
|
|
||||||
<code>std::ostringstream s; s << oper;</code>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>__coerce__</code>
|
|
||||||
<td>
|
|
||||||
<code>coerce(left, right)</code>
|
|
||||||
<td colspan="2">
|
|
||||||
usually defined automatically, otherwise <a href="#coercion">
|
|
||||||
special treatment</a> required
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h2><a name="sequence_and_mapping">Sequence and Mapping Operators</a></h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Sequence and mapping operators let wrapped objects behave in accordance
|
|
||||||
to Python's iteration and access protocols. These protocols differ
|
|
||||||
considerably from the ones found in C++. For example, Python's typical
|
|
||||||
iteration idiom looks like
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
for i in S:
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
while in C++ one writes
|
|
||||||
|
|
||||||
<blockquote><pre>
|
|
||||||
for (iterator i = S.begin(), end = S.end(); i != end; ++i)
|
|
||||||
</pre></blockquote>
|
|
||||||
|
|
||||||
<p>One could try to wrap C++ iterators in order to carry the C++ idiom into
|
|
||||||
Python. However, this does not work very well because
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>It leads to
|
|
||||||
non-uniform Python code (wrapped sequences support a usage different from
|
|
||||||
Python built-in sequences) and
|
|
||||||
|
|
||||||
<li>Iterators (e.g. <code>std::vector::iterator</code>) are often implemented as plain C++
|
|
||||||
pointers which are <a href="pointers.html#problem">problematic</a> for any automatic
|
|
||||||
wrapping system.
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
It is a better idea to support the standard <a
|
|
||||||
href="http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/sequence-types.html">Python
|
|
||||||
sequence and mapping protocols</a> for your wrapped containers. These
|
|
||||||
operators have to be wrapped manually because there are no corresponding
|
|
||||||
C++ operators that could be used for automatic wrapping. The Python
|
|
||||||
documentation lists the relevant <a href=
|
|
||||||
"http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/sequence-types.html">
|
|
||||||
container operators</a>. In particular, expose __getitem__, __setitem__
|
|
||||||
and remember to raise the appropriate Python exceptions
|
|
||||||
(<code>PyExc_IndexError</code> for sequences,
|
|
||||||
<code>PyExc_KeyError</code> for mappings) when the requested item is not
|
|
||||||
present.
|
|
||||||
|
|
||||||
<p>
|
|
||||||
In the following example, we expose <code>std::map<std::size_t,std::string></code>:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
typedef std::map<std::size_t, std::string> StringMap;
|
|
||||||
|
|
||||||
// A helper function for dealing with errors. Throw a Python exception
|
|
||||||
// if p == m.end().
|
|
||||||
void throw_key_error_if_end(
|
|
||||||
const StringMap& m,
|
|
||||||
StringMap::const_iterator p,
|
|
||||||
std::size_t key)
|
|
||||||
{
|
|
||||||
if (p == m.end())
|
|
||||||
{
|
|
||||||
PyErr_SetObject(PyExc_KeyError, boost::python::converters::to_python(key));
|
|
||||||
throw boost::python::error_already_set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define some simple wrapper functions which match the Python protocol
|
|
||||||
// for __getitem__, __setitem__, and __delitem__. Just as in Python, a
|
|
||||||
// free function with a ``self'' first parameter makes a fine class method.
|
|
||||||
|
|
||||||
const std::string& get_item(const StringMap& self, std::size_t key)
|
|
||||||
{
|
|
||||||
const StringMap::const_iterator p = self.find(key);
|
|
||||||
throw_key_error_if_end(self, p, key);
|
|
||||||
return p->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the item corresponding to key in the map.
|
|
||||||
void StringMapPythonClass::set_item(StringMap& self, std::size_t key, const std::string& value)
|
|
||||||
{
|
|
||||||
self[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deletes the item corresponding to key from the map.
|
|
||||||
void StringMapPythonClass::del_item(StringMap& self, std::size_t key)
|
|
||||||
{
|
|
||||||
const StringMap::iterator p = self.find(key);
|
|
||||||
throw_key_error_if_end(self, p, key);
|
|
||||||
self.erase(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
class_builder<StringMap> string_map(my_module, "StringMap");
|
|
||||||
string_map.def(boost::python::constructor<>());
|
|
||||||
string_map.def(&StringMap::size, "__len__");
|
|
||||||
string_map.def(get_item, "__getitem__");
|
|
||||||
string_map.def(set_item, "__setitem__");
|
|
||||||
string_map.def(del_item, "__delitem__");
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<p>
|
|
||||||
Then in Python:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
>>> m = StringMap()
|
|
||||||
>>> m[1]
|
|
||||||
Traceback (innermost last):
|
|
||||||
File "<stdin>", line 1, in ?
|
|
||||||
KeyError: 1
|
|
||||||
>>> m[1] = 'hello'
|
|
||||||
>>> m[1]
|
|
||||||
'hello'
|
|
||||||
>>> del m[1]
|
|
||||||
>>> m[1] # prove that it's gone
|
|
||||||
Traceback (innermost last):
|
|
||||||
File "<stdin>", line 1, in ?
|
|
||||||
KeyError: 1
|
|
||||||
>>> del m[2]
|
|
||||||
Traceback (innermost last):
|
|
||||||
File "<stdin>", line 1, in ?
|
|
||||||
KeyError: 2
|
|
||||||
>>> len(m)
|
|
||||||
0
|
|
||||||
>>> m[0] = 'zero'
|
|
||||||
>>> m[1] = 'one'
|
|
||||||
>>> m[2] = 'two'
|
|
||||||
>>> m[3] = 'three'
|
|
||||||
>>> len(m)
|
|
||||||
4
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<h2><a name="getter_setter">Customized Attribute Access</a></h2>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Just like built-in Python classes, BPL extension classes support <a
|
|
||||||
href="http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/attribute-access.html">special
|
|
||||||
the usual attribute access methods</a> <code>__getattr__</code>,
|
|
||||||
<code>__setattr__</code>, and <code>__delattr__</code>.
|
|
||||||
Because writing these functions can
|
|
||||||
be tedious in the common case where the attributes being accessed are
|
|
||||||
known statically, BPL checks the special names
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<code>__getattr__<em><name></em>__</code>
|
|
||||||
<li>
|
|
||||||
<code>__setattr__<em><name></em>__</code>
|
|
||||||
<li>
|
|
||||||
<code>__delattr__<em><name></em>__</code>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
to provide functional access to the attribute <em><name></em>. This
|
|
||||||
facility can be used from C++ or entirely from Python. For example, the
|
|
||||||
following shows how we can implement a ``computed attribute'' in Python:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
>>> class Range(AnyBPLExtensionClass):
|
|
||||||
... def __init__(self, start, end):
|
|
||||||
... self.start = start
|
|
||||||
... self.end = end
|
|
||||||
... def __getattr__length__(self):
|
|
||||||
... return self.end - self.start
|
|
||||||
...
|
|
||||||
>>> x = Range(3, 9)
|
|
||||||
>>> x.length
|
|
||||||
6
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<h4>
|
|
||||||
Direct Access to Data Members
|
|
||||||
</h4>
|
|
||||||
<p>
|
|
||||||
BPL uses the special <code>
|
|
||||||
__xxxattr__<em><name></em>__</code> functionality described above
|
|
||||||
to allow direct access to data members through the following special
|
|
||||||
functions on <code>class_builder<></code> and <code>
|
|
||||||
extension_class<></code>:
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<code>def_getter(<em>pointer-to-member</em>, <em>name</em>)</code> //
|
|
||||||
read access to the member via attribute <em>name</em>
|
|
||||||
<li>
|
|
||||||
<code>def_setter(<em>pointer-to-member</em>, <em>name</em>)</code> //
|
|
||||||
write access to the member via attribute <em>name</em>
|
|
||||||
<li>
|
|
||||||
<code>def_readonly(<em>pointer-to-member</em>, <em>name</em>)</code>
|
|
||||||
// read-only access to the member via attribute <em>name</em>
|
|
||||||
<li>
|
|
||||||
<code>def_read_write(<em>pointer-to-member</em>, <em>
|
|
||||||
name</em>)</code> // read/write access to the member via attribute
|
|
||||||
<em>name</em>
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
Note that the first two functions, used alone, may produce surprising
|
|
||||||
behavior. For example, when <code>def_getter()</code> is used, the
|
|
||||||
default functionality for <code>setattr()</code> and <code>
|
|
||||||
delattr()</code> remains in effect, operating on items in the extension
|
|
||||||
instance's name-space (i.e., its <code>__dict__</code>). For that
|
|
||||||
reason, you'll usually want to stick with <code>def_readonly</code> and
|
|
||||||
<code>def_read_write</code>.
|
|
||||||
<p>
|
|
||||||
For example, to expose a <code>std::pair<int,long></code> we
|
|
||||||
might write:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
typedef std::pair<int,long> Pil;
|
|
||||||
int first(const Pil& x) { return x.first; }
|
|
||||||
long second(const Pil& x) { return x.second; }
|
|
||||||
...
|
|
||||||
my_module.def(first, "first");
|
|
||||||
my_module.def(second, "second");
|
|
||||||
|
|
||||||
class_builder<Pil> pair_int_long(my_module, "Pair");
|
|
||||||
pair_int_long.def(boost::python::constructor<>());
|
|
||||||
pair_int_long.def(boost::python::constructor<int,long>());
|
|
||||||
pair_int_long.def_read_write(&Pil::first, "first");
|
|
||||||
pair_int_long.def_read_write(&Pil::second, "second");
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<p>
|
|
||||||
Now your Python class has attributes <code>first</code> and <code>
|
|
||||||
second</code> which, when accessed, actually modify or reflect the
|
|
||||||
values of corresponding data members of the underlying C++ object. Now
|
|
||||||
in Python:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
>>> x = Pair(3,5)
|
|
||||||
>>> x.first
|
|
||||||
3
|
|
||||||
>>> x.second
|
|
||||||
5
|
|
||||||
>>> x.second = 8
|
|
||||||
>>> x.second
|
|
||||||
8
|
|
||||||
>>> second(x) # Prove that we're not just changing the instance __dict__
|
|
||||||
8
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<h2>
|
|
||||||
<a name="reasons">And what about <code>__complex__</code>?</a>
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
That, dear reader, is one problem we don't know how to solve. The
|
|
||||||
Python source contains the following fragment, indicating the
|
|
||||||
special-case code really is hardwired:
|
|
||||||
<blockquote>
|
|
||||||
<pre>
|
|
||||||
/* XXX Hack to support classes with __complex__ method */
|
|
||||||
if (PyInstance_Check(r)) { ...
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
<p>
|
|
||||||
Next: <a href="under-the-hood.html">A Peek Under the Hood</a>
|
|
||||||
Previous: <a href="inheritance.html">Inheritance</a>
|
|
||||||
Up: <a href= "index.html">Top</a>
|
|
||||||
<p>
|
|
||||||
© Copyright David Abrahams and Ullrich Köthe 2000.
|
|
||||||
Permission to copy, use, modify, sell and distribute this document is
|
|
||||||
granted provided this copyright notice appears in all copies. This
|
|
||||||
document is provided ``as is'' without express or implied
|
|
||||||
warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
<p>
|
|
||||||
Updated: Nov 26, 2000
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
|
|
||||||
"http://www.w3.org/TR/REC-html40/strict.dtd">
|
|
||||||
<title>
|
|
||||||
The Title Of This Page
|
|
||||||
</title>
|
|
||||||
<div>
|
|
||||||
<h1>
|
|
||||||
<img width="277" height="86" id="_x0000_i1025" align="center"
|
|
||||||
src="../../../c++boost.gif" alt= "c++boost.gif (8819 bytes)">The Title Of This
|
|
||||||
Page
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
<p>
|
|
||||||
Prev: <a href="prev.html">Previous</a>
|
|
||||||
Next: <a href="next.html">Next</a>
|
|
||||||
Up: <a href="index.html">Top</a>
|
|
||||||
<p>
|
|
||||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
|
||||||
sell and distribute this document is granted provided this copyright
|
|
||||||
notice appears in all copies. This document is provided "as is" without
|
|
||||||
express or implied warranty, and with no claim as to its suitability
|
|
||||||
for any purpose.
|
|
||||||
<p>
|
|
||||||
Updated: Nov 26, 2000
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
|
||||||
<title>
|
|
||||||
A Peek Under the Hood
|
|
||||||
</title>
|
|
||||||
<h1>
|
|
||||||
<img src="../../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
|
|
||||||
width="277" height="86">
|
|
||||||
</h1>
|
|
||||||
<h1>
|
|
||||||
A Peek Under the Hood
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
Declaring a <code>class_builder<T></code> causes the instantiation
|
|
||||||
of an <code>extension_class<T></code> to which it forwards all
|
|
||||||
member function calls and which is doing most of the real work.
|
|
||||||
<code>extension_class<T></code> is a subclass of <code>
|
|
||||||
PyTypeObject</code>, the <code> struct</code> which Python's 'C' API uses
|
|
||||||
to describe a type. <a href="example1.html#world_class">An instance of the
|
|
||||||
<code>extension_class<></code></a> becomes the Python type object
|
|
||||||
corresponding to <code>hello::world</code>. When we <a href=
|
|
||||||
"example1.html#add_world_class">add it to the module</a> it goes into the
|
|
||||||
module's dictionary to be looked up under the name "world".
|
|
||||||
<p>
|
|
||||||
BPL uses C++'s template argument deduction mechanism to determine the
|
|
||||||
types of arguments to functions (except constructors, for which we must
|
|
||||||
<a href="example1.html#Constructor_example">provide an argument list</a>
|
|
||||||
because they can't be named in C++). Then, it calls the appropriate
|
|
||||||
overloaded functions <code>PyObject*
|
|
||||||
to_python(</code><em>S</em><code>)</code> and <em>
|
|
||||||
S'</em><code>from_python(PyObject*,
|
|
||||||
type<</code><em>S</em><code>>)</code> which convert between any C++
|
|
||||||
type <em>S</em> and a <code>PyObject*</code>, the type which represents a
|
|
||||||
reference to any Python object in its 'C' API. The <a href=
|
|
||||||
"example1.html#world_class"><code>extension_class<T></code></a>
|
|
||||||
template defines a whole raft of these conversions (for <code>T, T*,
|
|
||||||
T&, std::auto_ptr<T></code>, etc.), using the same inline
|
|
||||||
friend function technique employed by <a href=
|
|
||||||
"http://www.boost.org/libs/utility/operators.htm">the boost operators
|
|
||||||
library</a>.
|
|
||||||
<p>
|
|
||||||
Because the <code>to_python</code> and <code>from_python</code> functions
|
|
||||||
for a user-defined class are defined by <code>
|
|
||||||
extension_class<T></code>, it is important that an instantiation of
|
|
||||||
<code> extension_class<T></code> is visible to any code which wraps
|
|
||||||
a C++ function with a <code>T, T*, const T&</code>, etc. parameter or
|
|
||||||
return value. In particular, you may want to create all of the classes at
|
|
||||||
the top of your module's init function, then <code>def</code> the member
|
|
||||||
functions later to avoid problems with inter-class dependencies.
|
|
||||||
<p>
|
|
||||||
Next: <a href="building.html">Building a Module with BPL</a>
|
|
||||||
Previous: <a href="special.html">Special Method and Operator Support</a>
|
|
||||||
Up: <a href="index.html">Top</a>
|
|
||||||
<p>
|
|
||||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
|
||||||
sell and distribute this document is granted provided this copyright
|
|
||||||
notice appears in all copies. This document is provided "as is" without
|
|
||||||
express or implied warranty, and with no claim as to its suitability for
|
|
||||||
any purpose.
|
|
||||||
<p>
|
|
||||||
Updated: Nov 26, 2000
|
|
||||||
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace hello {
|
|
||||||
class world
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
world(int) {}
|
|
||||||
~world() {}
|
|
||||||
const char* get() const { return "hi, world"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t length(const world& x) { return strlen(x.get()); }
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <boost/python/class_builder.hpp>
|
|
||||||
|
|
||||||
// Python requires an exported function called init<module-name> in every
|
|
||||||
// extension module. This is where we build the module contents.
|
|
||||||
extern "C"
|
|
||||||
#ifdef _WIN32
|
|
||||||
__declspec(dllexport)
|
|
||||||
#endif
|
|
||||||
void inithello()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// create an object representing this extension module
|
|
||||||
boost::python::module_builder hello("hello");
|
|
||||||
|
|
||||||
// Create the Python type object for our extension class
|
|
||||||
boost::python::class_builder<hello::world> world_class(hello, "world");
|
|
||||||
|
|
||||||
// Add the __init__ function
|
|
||||||
world_class.def(boost::python::constructor<int>());
|
|
||||||
// Add a regular member function
|
|
||||||
world_class.def(&hello::world::get, "get");
|
|
||||||
|
|
||||||
// Add a regular function to the module
|
|
||||||
hello.def(hello::length, "length");
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
boost::python::handle_exception(); // Deal with the exception for Python
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Win32 DLL boilerplate
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include <windows.h>
|
|
||||||
extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif // _WIN32
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#include <string>
|
|
||||||
|
|
||||||
namespace { // Avoid cluttering the global namespace.
|
|
||||||
|
|
||||||
// A couple of simple C++ functions that we want to expose to Python.
|
|
||||||
std::string greet() { return "hello, world"; }
|
|
||||||
int square(int number) { return number * number; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <boost/python/class_builder.hpp>
|
|
||||||
|
|
||||||
namespace python = boost::python;
|
|
||||||
|
|
||||||
// Python requires an exported function called init<module-name> in every
|
|
||||||
// extension module. This is where we build the module contents.
|
|
||||||
extern "C"
|
|
||||||
#ifdef _WIN32
|
|
||||||
__declspec(dllexport)
|
|
||||||
#endif
|
|
||||||
void initrwgk1()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Create an object representing this extension module.
|
|
||||||
python::module_builder this_module("rwgk1");
|
|
||||||
|
|
||||||
// Add regular functions to the module.
|
|
||||||
this_module.def(greet, "greet");
|
|
||||||
this_module.def(square, "square");
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
python::handle_exception(); // Deal with the exception for Python
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Win32 DLL boilerplate
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include <windows.h>
|
|
||||||
extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) { return 1; }
|
|
||||||
#endif // _WIN32
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
r'''
|
|
||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
That's it! If we build this shared library and put it on our PYTHONPATH we can
|
|
||||||
now access our C++ class and function from Python.
|
|
||||||
|
|
||||||
>>> import hello
|
|
||||||
>>> hi_world = hello.world(3)
|
|
||||||
>>> hi_world.get()
|
|
||||||
'hi, world'
|
|
||||||
>>> hello.length(hi_world)
|
|
||||||
9
|
|
||||||
|
|
||||||
We can even make a subclass of hello.world:
|
|
||||||
|
|
||||||
|
|
||||||
>>> class my_subclass(hello.world):
|
|
||||||
... def get(self):
|
|
||||||
... return 'hello, world'
|
|
||||||
...
|
|
||||||
>>> y = my_subclass(2)
|
|
||||||
>>> y.get()
|
|
||||||
'hello, world'
|
|
||||||
|
|
||||||
Pretty cool! You can't do that with an ordinary Python extension type!
|
|
||||||
|
|
||||||
>>> hello.length(y)
|
|
||||||
9
|
|
||||||
|
|
||||||
Of course, you may now have a slightly empty feeling in the pit of your little
|
|
||||||
pythonic stomach. Perhaps you feel your subclass deserves to have a length() of
|
|
||||||
12? If so, read on...
|
|
||||||
'''
|
|
||||||
from hello import *
|
|
||||||
|
|
||||||
def run(args = None):
|
|
||||||
if args is not None:
|
|
||||||
import sys
|
|
||||||
sys.argv = args
|
|
||||||
import doctest, test_example1
|
|
||||||
doctest.testmod(test_example1)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
run()
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
r'''>>> import rwgk1
|
|
||||||
>>> print rwgk1.greet()
|
|
||||||
hello, world
|
|
||||||
>>> number = 11
|
|
||||||
>>> print number, '*', number, '=', rwgk1.square(number)
|
|
||||||
11 * 11 = 121
|
|
||||||
'''
|
|
||||||
|
|
||||||
def run(args = None):
|
|
||||||
if args is not None:
|
|
||||||
import sys
|
|
||||||
sys.argv = args
|
|
||||||
import doctest, test_rwgk1
|
|
||||||
doctest.testmod(test_rwgk1)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
run()
|
|
||||||
@@ -1,829 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
//
|
|
||||||
// This file was generated for 10-argument python callbacks by gen_callback.python
|
|
||||||
|
|
||||||
#ifndef CALLBACK_DWA_052100_H_
|
|
||||||
# define CALLBACK_DWA_052100_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/python/conversions.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template <class T>
|
|
||||||
inline void callback_adjust_refcount(PyObject*, type<T>) {}
|
|
||||||
|
|
||||||
inline void callback_adjust_refcount(PyObject* p, type<PyObject*>)
|
|
||||||
{ Py_INCREF(p); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calling Python from C++
|
|
||||||
template <class R>
|
|
||||||
struct callback
|
|
||||||
{
|
|
||||||
static R call_method(PyObject* self, const char* name)
|
|
||||||
{
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("()")));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
static R call(PyObject* self)
|
|
||||||
{
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("()")));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1>
|
|
||||||
static R call_method(PyObject* self, const char* name, const A1& a1)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(O)"),
|
|
||||||
p1.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1>
|
|
||||||
static R call(PyObject* self, const A1& a1)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(O)"),
|
|
||||||
p1.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2>
|
|
||||||
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2>
|
|
||||||
static R call(PyObject* self, const A1& a1, const A2& a2)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3>
|
|
||||||
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3>
|
|
||||||
static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4>
|
|
||||||
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4>
|
|
||||||
static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5>
|
|
||||||
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5>
|
|
||||||
static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6>
|
|
||||||
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6>
|
|
||||||
static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
|
||||||
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
|
||||||
static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
|
||||||
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref p8(to_python(a8));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get(),
|
|
||||||
p8.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
|
||||||
static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref p8(to_python(a8));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get(),
|
|
||||||
p8.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
|
|
||||||
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref p8(to_python(a8));
|
|
||||||
ref p9(to_python(a9));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get(),
|
|
||||||
p8.get(),
|
|
||||||
p9.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
|
|
||||||
static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref p8(to_python(a8));
|
|
||||||
ref p9(to_python(a9));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get(),
|
|
||||||
p8.get(),
|
|
||||||
p9.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
|
|
||||||
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref p8(to_python(a8));
|
|
||||||
ref p9(to_python(a9));
|
|
||||||
ref p10(to_python(a10));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOOOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get(),
|
|
||||||
p8.get(),
|
|
||||||
p9.get(),
|
|
||||||
p10.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
|
|
||||||
static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref p8(to_python(a8));
|
|
||||||
ref p9(to_python(a9));
|
|
||||||
ref p10(to_python(a10));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOOOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get(),
|
|
||||||
p8.get(),
|
|
||||||
p9.get(),
|
|
||||||
p10.get()));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// This specialization wouldn't be needed, but MSVC6 doesn't correctly allow the following:
|
|
||||||
// void g();
|
|
||||||
// void f() { return g(); }
|
|
||||||
template <>
|
|
||||||
struct callback<void>
|
|
||||||
{
|
|
||||||
|
|
||||||
static void call_method(PyObject* self, const char* name)
|
|
||||||
{
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("()")));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void call(PyObject* self)
|
|
||||||
{
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("()")));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1>
|
|
||||||
static void call_method(PyObject* self, const char* name, const A1& a1)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(O)"),
|
|
||||||
p1.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1>
|
|
||||||
static void call(PyObject* self, const A1& a1)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(O)"),
|
|
||||||
p1.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2>
|
|
||||||
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2>
|
|
||||||
static void call(PyObject* self, const A1& a1, const A2& a2)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3>
|
|
||||||
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3>
|
|
||||||
static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4>
|
|
||||||
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4>
|
|
||||||
static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5>
|
|
||||||
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5>
|
|
||||||
static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6>
|
|
||||||
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6>
|
|
||||||
static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
|
||||||
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
|
||||||
static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
|
||||||
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref p8(to_python(a8));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get(),
|
|
||||||
p8.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
|
||||||
static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref p8(to_python(a8));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get(),
|
|
||||||
p8.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
|
|
||||||
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref p8(to_python(a8));
|
|
||||||
ref p9(to_python(a9));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get(),
|
|
||||||
p8.get(),
|
|
||||||
p9.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
|
|
||||||
static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref p8(to_python(a8));
|
|
||||||
ref p9(to_python(a9));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get(),
|
|
||||||
p8.get(),
|
|
||||||
p9.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
|
|
||||||
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref p8(to_python(a8));
|
|
||||||
ref p9(to_python(a9));
|
|
||||||
ref p10(to_python(a10));
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(OOOOOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get(),
|
|
||||||
p8.get(),
|
|
||||||
p9.get(),
|
|
||||||
p10.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
|
|
||||||
static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10)
|
|
||||||
{
|
|
||||||
ref p1(to_python(a1));
|
|
||||||
ref p2(to_python(a2));
|
|
||||||
ref p3(to_python(a3));
|
|
||||||
ref p4(to_python(a4));
|
|
||||||
ref p5(to_python(a5));
|
|
||||||
ref p6(to_python(a6));
|
|
||||||
ref p7(to_python(a7));
|
|
||||||
ref p8(to_python(a8));
|
|
||||||
ref p9(to_python(a9));
|
|
||||||
ref p10(to_python(a10));
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(OOOOOOOOOO)"),
|
|
||||||
p1.get(),
|
|
||||||
p2.get(),
|
|
||||||
p3.get(),
|
|
||||||
p4.get(),
|
|
||||||
p5.get(),
|
|
||||||
p6.get(),
|
|
||||||
p7.get(),
|
|
||||||
p8.get(),
|
|
||||||
p9.get(),
|
|
||||||
p10.get()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Make it a compile-time error to try to return a const char* from a virtual
|
|
||||||
// function. The standard conversion
|
|
||||||
//
|
|
||||||
// from_python(PyObject* string, boost::python::type<const char*>)
|
|
||||||
//
|
|
||||||
// returns a pointer to the character array which is internal to string. The
|
|
||||||
// problem with trying to do this in a standard callback function is that the
|
|
||||||
// Python string would likely be destroyed upon return from the calling function
|
|
||||||
// (boost::python::callback<const char*>::call[_method]) when its reference count is
|
|
||||||
// decremented. If you absolutely need to do this and you're sure it's safe (it
|
|
||||||
// usually isn't), you can use
|
|
||||||
//
|
|
||||||
// boost::python::string result(boost::python::callback<boost::python::string>::call[_method](...args...));
|
|
||||||
// ...result.c_str()... // access the char* array
|
|
||||||
template <>
|
|
||||||
struct callback<const char*>
|
|
||||||
{
|
|
||||||
// Try hard to generate a readable error message
|
|
||||||
typedef struct unsafe_since_python_string_may_be_destroyed {} call, call_method;
|
|
||||||
};
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
|
|
||||||
#endif // CALLBACK_DWA_052100_H_
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,156 +0,0 @@
|
|||||||
#ifndef CLASS_WRAPPER_DWA101000_H_
|
|
||||||
# define CLASS_WRAPPER_DWA101000_H_
|
|
||||||
|
|
||||||
#include <boost/python/detail/extension_class.hpp>
|
|
||||||
#include <boost/python/operators.hpp>
|
|
||||||
#include <boost/python/module_builder.hpp>
|
|
||||||
#include <boost/python/conversions.hpp>
|
|
||||||
#include <boost/python/detail/cast.hpp>
|
|
||||||
#include <boost/python/reference.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
// Syntactic sugar to make wrapping classes more convenient
|
|
||||||
template <class T, class U = detail::held_instance<T> >
|
|
||||||
class class_builder
|
|
||||||
: python_extension_class_converters<T, U> // Works around MSVC6.x/GCC2.95.2 bug described below
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
class_builder(module_builder& module, const char* name)
|
|
||||||
: m_class(new detail::extension_class<T, U>(name))
|
|
||||||
{
|
|
||||||
module.add(ref(as_object(m_class.get()), ref::increment_count), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
~class_builder()
|
|
||||||
{}
|
|
||||||
|
|
||||||
// define constructors
|
|
||||||
template <class signature>
|
|
||||||
void def(const signature& s)
|
|
||||||
{ m_class->def(s); }
|
|
||||||
|
|
||||||
// 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 &>());
|
|
||||||
template <long which, class left, class right>
|
|
||||||
void def(operators<which, right> o1, left_operand<left> o2)
|
|
||||||
{ m_class->def(o1, o2); }
|
|
||||||
|
|
||||||
// export heterogeneous operators (type of lhs: 'left', of rhs: 'right')
|
|
||||||
// usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub), Foo>(),
|
|
||||||
// boost::python::right_operand<int const &>());
|
|
||||||
template <long which, class left, class right>
|
|
||||||
void def(operators<which, left> o1, right_operand<right> o2)
|
|
||||||
{ m_class->def(o1, o2); }
|
|
||||||
|
|
||||||
// define a function that passes Python arguments and keywords
|
|
||||||
// to C++ verbatim (as a 'tuple const &' and 'dictionary const &'
|
|
||||||
// respectively). This is useful for manual argument passing.
|
|
||||||
// It's also the only possibility to pass keyword arguments to C++.
|
|
||||||
// Fn must have a signatur that is compatible to
|
|
||||||
// PyObject * (*)(PyObject * aTuple, PyObject * aDictionary)
|
|
||||||
template <class Fn>
|
|
||||||
void def_raw(Fn fn, const char* name)
|
|
||||||
{ m_class->def_raw(fn, name); }
|
|
||||||
|
|
||||||
// define member functions. In fact this works for free functions, too -
|
|
||||||
// they act like static member functions, or if they start with the
|
|
||||||
// appropriate self argument (as a pointer or reference), they can be used
|
|
||||||
// just like ordinary member functions -- just like Python!
|
|
||||||
template <class Fn>
|
|
||||||
void def(Fn fn, const char* name)
|
|
||||||
{ m_class->def(fn, name); }
|
|
||||||
|
|
||||||
// Define a virtual member function with a default implementation.
|
|
||||||
// default_fn should be a function which provides the default implementation.
|
|
||||||
// Be careful that default_fn does not in fact call fn virtually!
|
|
||||||
template <class Fn, class DefaultFn>
|
|
||||||
void def(Fn fn, const char* name, DefaultFn default_fn)
|
|
||||||
{ m_class->def(fn, name, default_fn); }
|
|
||||||
|
|
||||||
// Provide a function which implements x.<name>, reading from the given
|
|
||||||
// member (pm) of the T obj
|
|
||||||
template <class MemberType>
|
|
||||||
void def_getter(MemberType T::*pm, const char* name)
|
|
||||||
{ m_class->def_getter(pm, name); }
|
|
||||||
|
|
||||||
// Provide a function which implements assignment to x.<name>, writing to
|
|
||||||
// the given member (pm) of the T obj
|
|
||||||
template <class MemberType>
|
|
||||||
void def_setter(MemberType T::*pm, const char* name)
|
|
||||||
{ m_class->def_getter(pm, name); }
|
|
||||||
|
|
||||||
// Expose the given member (pm) of the T obj as a read-only attribute
|
|
||||||
template <class MemberType>
|
|
||||||
void def_readonly(MemberType T::*pm, const char* name)
|
|
||||||
{ m_class->def_readonly(pm, name); }
|
|
||||||
|
|
||||||
// Expose the given member (pm) of the T obj as a read/write attribute
|
|
||||||
template <class MemberType>
|
|
||||||
void def_read_write(MemberType T::*pm, const char* name)
|
|
||||||
{ m_class->def_read_write(pm, name); }
|
|
||||||
|
|
||||||
// define the standard coercion needed for operator overloading
|
|
||||||
void def_standard_coerce()
|
|
||||||
{ m_class->def_standard_coerce(); }
|
|
||||||
|
|
||||||
// declare the given class a base class of this one and register
|
|
||||||
// conversion functions
|
|
||||||
template <class S, class V>
|
|
||||||
void declare_base(class_builder<S, V> const & base)
|
|
||||||
{
|
|
||||||
m_class->declare_base(base.get_extension_class());
|
|
||||||
}
|
|
||||||
|
|
||||||
// declare the given class a base class of this one and register
|
|
||||||
// upcast conversion function
|
|
||||||
template <class S, class V>
|
|
||||||
void declare_base(class_builder<S, V> const & base, without_downcast_t)
|
|
||||||
{
|
|
||||||
m_class->declare_base(base.get_extension_class(), without_downcast);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the embedded ExtensioClass object
|
|
||||||
detail::extension_class<T, U> * get_extension_class() const
|
|
||||||
{
|
|
||||||
return m_class.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
// set an arbitrary attribute. Useful for non-function class data members,
|
|
||||||
// e.g. enums
|
|
||||||
void add(PyObject* x, const char* name)
|
|
||||||
{ m_class->set_attribute(name, x); }
|
|
||||||
void add(ref x, const char* name)
|
|
||||||
{ m_class->set_attribute(name, x); }
|
|
||||||
private:
|
|
||||||
// declare the given class a base class of this one and register
|
|
||||||
// conversion functions
|
|
||||||
template <class S, class V>
|
|
||||||
void declare_base(detail::extension_class<S, V> * base)
|
|
||||||
{
|
|
||||||
m_class->declare_base(base);
|
|
||||||
}
|
|
||||||
|
|
||||||
// declare the given class a base class of this one and register
|
|
||||||
// upcast conversion function
|
|
||||||
template <class S, class V>
|
|
||||||
void declare_base(detail::extension_class<S, V> * base, without_downcast_t)
|
|
||||||
{
|
|
||||||
m_class->declare_base(base, without_downcast);
|
|
||||||
}
|
|
||||||
|
|
||||||
reference<detail::extension_class<T, U> > m_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
// The bug mentioned at the top of this file is that on certain compilers static
|
|
||||||
// global functions declared within the body of a class template will only be
|
|
||||||
// generated when the class template is constructed, and when (for some reason)
|
|
||||||
// the construction does not occur via a new-expression. Otherwise, we could
|
|
||||||
// rely on the initialization of the m_class data member to cause all of the
|
|
||||||
// to_/from_python functions to come into being.
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
|
|
||||||
#endif // CLASS_WRAPPER_DWA101000_H_
|
|
||||||
@@ -1,527 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef SUBCLASS_DWA051500_H_
|
|
||||||
# define SUBCLASS_DWA051500_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/python/detail/types.hpp>
|
|
||||||
# include <boost/python/objects.hpp>
|
|
||||||
# include <boost/python/detail/singleton.hpp>
|
|
||||||
# include <boost/utility.hpp>
|
|
||||||
# include <boost/python/conversions.hpp>
|
|
||||||
# include <boost/python/callback.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
// A simple type which acts something like a built-in Python class obj.
|
|
||||||
class instance
|
|
||||||
: public boost::python::detail::python_object
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
instance(PyTypeObject* class_);
|
|
||||||
~instance();
|
|
||||||
|
|
||||||
// Standard Python functions.
|
|
||||||
PyObject* repr();
|
|
||||||
int compare(PyObject*);
|
|
||||||
PyObject* str();
|
|
||||||
long hash();
|
|
||||||
PyObject* call(PyObject* args, PyObject* keywords);
|
|
||||||
PyObject* getattr(const char* name, bool use_special_function = true);
|
|
||||||
int setattr(const char* name, PyObject* value);
|
|
||||||
|
|
||||||
// Mapping methods
|
|
||||||
int length();
|
|
||||||
PyObject* get_subscript(PyObject* key);
|
|
||||||
void set_subscript(PyObject* key, PyObject* value);
|
|
||||||
|
|
||||||
// Sequence methods
|
|
||||||
PyObject* get_slice(int start, int finish);
|
|
||||||
void set_slice(int start, int finish, PyObject* value);
|
|
||||||
|
|
||||||
// Number methods
|
|
||||||
PyObject* add(PyObject* other);
|
|
||||||
PyObject* subtract(PyObject* other);
|
|
||||||
PyObject* multiply(PyObject* other);
|
|
||||||
PyObject* divide(PyObject* other);
|
|
||||||
PyObject* remainder(PyObject* other);
|
|
||||||
PyObject* divmod(PyObject* other);
|
|
||||||
PyObject* power(PyObject*, PyObject*);
|
|
||||||
PyObject* negative();
|
|
||||||
PyObject* positive();
|
|
||||||
PyObject* absolute();
|
|
||||||
int nonzero();
|
|
||||||
PyObject* invert();
|
|
||||||
PyObject* lshift(PyObject* other);
|
|
||||||
PyObject* rshift(PyObject* other);
|
|
||||||
PyObject* do_and(PyObject* other);
|
|
||||||
PyObject* do_xor(PyObject* other);
|
|
||||||
PyObject* do_or(PyObject* other);
|
|
||||||
int coerce(PyObject**, PyObject**);
|
|
||||||
PyObject* as_int();
|
|
||||||
PyObject* as_long();
|
|
||||||
PyObject* as_float();
|
|
||||||
PyObject* oct();
|
|
||||||
PyObject* hex();
|
|
||||||
|
|
||||||
private: // noncopyable, without the size bloat
|
|
||||||
instance(const instance&);
|
|
||||||
void operator=(const instance&);
|
|
||||||
|
|
||||||
private: // helper functions
|
|
||||||
int setattr_dict(PyObject* value);
|
|
||||||
|
|
||||||
private:
|
|
||||||
dictionary m_name_space;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T> class meta_class;
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
class class_base : public type_object_base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
class_base(PyTypeObject* meta_class_obj, string name, tuple bases, const dictionary& name_space);
|
|
||||||
tuple bases() const;
|
|
||||||
string name() const;
|
|
||||||
dictionary& dict();
|
|
||||||
|
|
||||||
// Standard Python functions.
|
|
||||||
PyObject* getattr(const char* name);
|
|
||||||
int setattr(const char* name, PyObject* value);
|
|
||||||
PyObject* repr() const;
|
|
||||||
void add_base(ref base);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool initialize_instance(instance* obj, PyObject* args, PyObject* keywords);
|
|
||||||
|
|
||||||
private: // virtual functions
|
|
||||||
// Subclasses should override this to delete the particular obj type
|
|
||||||
virtual void delete_instance(PyObject*) const = 0;
|
|
||||||
|
|
||||||
private: // boost::python::type_object_base required interface implementation
|
|
||||||
void instance_dealloc(PyObject*) const; // subclasses should not override this
|
|
||||||
|
|
||||||
private:
|
|
||||||
string m_name;
|
|
||||||
tuple m_bases;
|
|
||||||
dictionary m_name_space;
|
|
||||||
};
|
|
||||||
|
|
||||||
void enable_named_method(class_base* type_obj, const char* name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A type which acts a lot like a built-in Python class. T is the obj type,
|
|
||||||
// so class_t<instance> is a very simple "class-alike".
|
|
||||||
template <class T>
|
|
||||||
class class_t
|
|
||||||
: public boost::python::detail::class_base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
class_t(meta_class<T>* meta_class_obj, string name, tuple bases, const dictionary& name_space);
|
|
||||||
|
|
||||||
// Standard Python functions.
|
|
||||||
PyObject* call(PyObject* args, PyObject* keywords);
|
|
||||||
|
|
||||||
private: // Implement mapping methods on instances
|
|
||||||
PyObject* instance_repr(PyObject*) const;
|
|
||||||
int instance_compare(PyObject*, PyObject* other) const;
|
|
||||||
PyObject* instance_str(PyObject*) const;
|
|
||||||
long instance_hash(PyObject*) const;
|
|
||||||
int instance_mapping_length(PyObject*) const;
|
|
||||||
PyObject* instance_mapping_subscript(PyObject*, PyObject*) const;
|
|
||||||
int instance_mapping_ass_subscript(PyObject*, PyObject*, PyObject*) const;
|
|
||||||
|
|
||||||
private: // Implement sequence methods on instances
|
|
||||||
int instance_sequence_length(PyObject*) const;
|
|
||||||
PyObject* instance_sequence_item(PyObject* obj, int n) const;
|
|
||||||
int instance_sequence_ass_item(PyObject* obj, int n, PyObject* value) const;
|
|
||||||
PyObject* instance_sequence_slice(PyObject*, int start, int finish) const;
|
|
||||||
int instance_sequence_ass_slice(PyObject*, int start, int finish, PyObject* value) const;
|
|
||||||
|
|
||||||
private: // Implement number methods on instances
|
|
||||||
PyObject* instance_number_add(PyObject*, PyObject*) const;
|
|
||||||
PyObject* instance_number_subtract(PyObject*, PyObject*) const;
|
|
||||||
PyObject* instance_number_multiply(PyObject*, PyObject*) const;
|
|
||||||
PyObject* instance_number_divide(PyObject*, PyObject*) const;
|
|
||||||
PyObject* instance_number_remainder(PyObject*, PyObject*) const;
|
|
||||||
PyObject* instance_number_divmod(PyObject*, PyObject*) const;
|
|
||||||
PyObject* instance_number_power(PyObject*, PyObject*, PyObject*) const;
|
|
||||||
PyObject* instance_number_negative(PyObject*) const;
|
|
||||||
PyObject* instance_number_positive(PyObject*) const;
|
|
||||||
PyObject* instance_number_absolute(PyObject*) const;
|
|
||||||
int instance_number_nonzero(PyObject*) const;
|
|
||||||
PyObject* instance_number_invert(PyObject*) const;
|
|
||||||
PyObject* instance_number_lshift(PyObject*, PyObject*) const;
|
|
||||||
PyObject* instance_number_rshift(PyObject*, PyObject*) const;
|
|
||||||
PyObject* instance_number_and(PyObject*, PyObject*) const;
|
|
||||||
PyObject* instance_number_xor(PyObject*, PyObject*) const;
|
|
||||||
PyObject* instance_number_or(PyObject*, PyObject*) const;
|
|
||||||
int instance_number_coerce(PyObject*, PyObject**, PyObject**) const;
|
|
||||||
PyObject* instance_number_int(PyObject*) const;
|
|
||||||
PyObject* instance_number_long(PyObject*) const;
|
|
||||||
PyObject* instance_number_float(PyObject*) const;
|
|
||||||
PyObject* instance_number_oct(PyObject*) const;
|
|
||||||
PyObject* instance_number_hex(PyObject*) const;
|
|
||||||
|
|
||||||
private: // Miscellaneous "special" methods
|
|
||||||
PyObject* instance_call(PyObject* obj, PyObject* args, PyObject* keywords) const;
|
|
||||||
PyObject* instance_getattr(PyObject* obj, const char* name) const;
|
|
||||||
int instance_setattr(PyObject* obj, const char* name, PyObject* value) const;
|
|
||||||
|
|
||||||
private: // Implementation of boost::python::detail::class_base required interface
|
|
||||||
void delete_instance(PyObject*) const;
|
|
||||||
|
|
||||||
private: // noncopyable, without the size bloat
|
|
||||||
class_t(const class_t<T>&);
|
|
||||||
void operator=(const class_t&);
|
|
||||||
};
|
|
||||||
|
|
||||||
// The type of a class_t<T> object.
|
|
||||||
template <class T>
|
|
||||||
class meta_class
|
|
||||||
: public boost::python::detail::reprable<
|
|
||||||
boost::python::detail::callable<
|
|
||||||
boost::python::detail::getattrable<
|
|
||||||
boost::python::detail::setattrable<
|
|
||||||
boost::python::detail::type_object<class_t<T> > > > > >,
|
|
||||||
boost::noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
meta_class();
|
|
||||||
|
|
||||||
// Standard Python functions.
|
|
||||||
PyObject* call(PyObject* args, PyObject* keywords);
|
|
||||||
|
|
||||||
struct type_object
|
|
||||||
: boost::python::detail::singleton<type_object,
|
|
||||||
boost::python::detail::callable<
|
|
||||||
boost::python::detail::type_object<meta_class> > >
|
|
||||||
{
|
|
||||||
type_object() : singleton_base(&PyType_Type) {}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Member function implementations.
|
|
||||||
//
|
|
||||||
template <class T>
|
|
||||||
meta_class<T>::meta_class()
|
|
||||||
: properties(type_object::instance())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class_t<T>::class_t(meta_class<T>* meta_class_obj, string name, tuple bases, const dictionary& name_space)
|
|
||||||
: boost::python::detail::class_base(meta_class_obj, name, bases, name_space)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void class_t<T>::delete_instance(PyObject* obj) const
|
|
||||||
{
|
|
||||||
delete downcast<T>(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::call(PyObject* args, PyObject* keywords)
|
|
||||||
{
|
|
||||||
reference<T> result(new T(this));
|
|
||||||
if (!this->initialize_instance(result.get(), args, keywords))
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return result.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_repr(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->repr();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
int class_t<T>::instance_compare(PyObject* obj, PyObject* other) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->compare(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_str(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->str();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
long class_t<T>::instance_hash(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->hash();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
int class_t<T>::instance_mapping_length(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->length();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
int class_t<T>::instance_sequence_length(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->length();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_mapping_subscript(PyObject* obj, PyObject* key) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->get_subscript(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_sequence_item(PyObject* obj, int n) const
|
|
||||||
{
|
|
||||||
ref key(to_python(n));
|
|
||||||
return downcast<T>(obj)->get_subscript(key.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
int class_t<T>::instance_sequence_ass_item(PyObject* obj, int n, PyObject* value) const
|
|
||||||
{
|
|
||||||
ref key(to_python(n));
|
|
||||||
downcast<T>(obj)->set_subscript(key.get(), value);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
int class_t<T>::instance_mapping_ass_subscript(PyObject* obj, PyObject* key, PyObject* value) const
|
|
||||||
{
|
|
||||||
downcast<T>(obj)->set_subscript(key, value);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void adjust_slice_indices(PyObject* obj, int& start, int& finish);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_sequence_slice(PyObject* obj, int start, int finish) const
|
|
||||||
{
|
|
||||||
adjust_slice_indices(obj, start, finish);
|
|
||||||
return downcast<T>(obj)->get_slice(start, finish);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
int class_t<T>::instance_sequence_ass_slice(PyObject* obj, int start, int finish, PyObject* value) const
|
|
||||||
{
|
|
||||||
adjust_slice_indices(obj, start, finish);
|
|
||||||
downcast<T>(obj)->set_slice(start, finish, value);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_call(PyObject* obj, PyObject* args, PyObject* keywords) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->call(args, keywords);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_getattr(PyObject* obj, const char* name) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->getattr(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
int class_t<T>::instance_setattr(PyObject* obj, const char* name, PyObject* value) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->setattr(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_add(PyObject* obj, PyObject* other) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->add(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_subtract(PyObject* obj, PyObject* other) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->subtract(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_multiply(PyObject* obj, PyObject* other) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->multiply(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_divide(PyObject* obj, PyObject* other) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->divide(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_remainder(PyObject* obj, PyObject* other) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->remainder(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_divmod(PyObject* obj, PyObject* other) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->divmod(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_power(PyObject* obj, PyObject* exponent, PyObject* modulus) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->power(exponent, modulus);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_negative(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->negative();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_positive(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->positive();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_absolute(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->absolute();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
int class_t<T>::instance_number_nonzero(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->nonzero();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_invert(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->invert();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_lshift(PyObject* obj, PyObject* other) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->lshift(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_rshift(PyObject* obj, PyObject* other) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->rshift(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_and(PyObject* obj, PyObject* other) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->do_and(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_xor(PyObject* obj, PyObject* other) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->do_xor(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_or(PyObject* obj, PyObject* other) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->do_or(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
int class_t<T>::instance_number_coerce(PyObject* obj, PyObject** x, PyObject** y) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->coerce(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_int(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->as_int();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_long(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->as_long();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_float(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->as_float();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_oct(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->oct();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* class_t<T>::instance_number_hex(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<T>(obj)->hex();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
inline dictionary& class_base::dict()
|
|
||||||
{
|
|
||||||
return m_name_space;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline tuple class_base::bases() const
|
|
||||||
{
|
|
||||||
return m_bases;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* meta_class<T>::call(PyObject* args, PyObject* /*keywords*/)
|
|
||||||
{
|
|
||||||
PyObject* name;
|
|
||||||
PyObject* bases;
|
|
||||||
PyObject* name_space;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("O!O!O!"),
|
|
||||||
&PyString_Type, &name,
|
|
||||||
&PyTuple_Type, &bases,
|
|
||||||
&PyDict_Type, &name_space))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return as_object(
|
|
||||||
new class_t<T>(this, string(ref(name, ref::increment_count)),
|
|
||||||
tuple(ref(bases, ref::increment_count)),
|
|
||||||
dictionary(ref(name_space, ref::increment_count)))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
const string& setattr_string();
|
|
||||||
const string& getattr_string();
|
|
||||||
const string& delattr_string();
|
|
||||||
|
|
||||||
inline string class_base::name() const
|
|
||||||
{
|
|
||||||
return m_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
#endif
|
|
||||||
@@ -1,325 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef METHOD_DWA122899_H_
|
|
||||||
# define METHOD_DWA122899_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/python/detail/wrap_python.hpp>
|
|
||||||
# include <boost/python/detail/none.hpp>
|
|
||||||
# include <boost/python/detail/signatures.hpp>
|
|
||||||
# include <boost/smart_ptr.hpp>
|
|
||||||
# include <boost/python/errors.hpp>
|
|
||||||
# include <string>
|
|
||||||
|
|
||||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
|
|
||||||
|
|
||||||
// This can be instantiated on an enum to provide the to_python/from_python
|
|
||||||
// conversions, provided the values can fit in a long.
|
|
||||||
template <class EnumType>
|
|
||||||
class py_enum_as_int_converters
|
|
||||||
{
|
|
||||||
friend EnumType from_python(PyObject* x, boost::python::type<EnumType>)
|
|
||||||
{
|
|
||||||
return static_cast<EnumType>(
|
|
||||||
from_python(x, boost::python::type<long>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
friend EnumType from_python(PyObject* x, boost::python::type<const EnumType&>)
|
|
||||||
{
|
|
||||||
return static_cast<EnumType>(
|
|
||||||
from_python(x, boost::python::type<long>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
friend PyObject* to_python(EnumType x)
|
|
||||||
{
|
|
||||||
return to_python(static_cast<long>(x));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
template <class EnumType> class enum_as_int_converters
|
|
||||||
: public BOOST_PYTHON_CONVERSION::py_enum_as_int_converters<EnumType> {};
|
|
||||||
|
|
||||||
template <class P, class T> class wrapped_pointer;
|
|
||||||
|
|
||||||
//#pragma warn_possunwant off
|
|
||||||
inline void decref_impl(PyObject* p) { Py_DECREF(p); }
|
|
||||||
inline void xdecref_impl(PyObject* p) { Py_XDECREF(p); }
|
|
||||||
//#pragma warn_possunwant reset
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline void decref(T* p)
|
|
||||||
{
|
|
||||||
char* const raw_p = reinterpret_cast<char*>(p);
|
|
||||||
char* const p_base = raw_p - offsetof(PyObject, ob_refcnt);
|
|
||||||
decref_impl(reinterpret_cast<PyObject*>(p_base));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline void xdecref(T* p)
|
|
||||||
{
|
|
||||||
char* const raw_p = reinterpret_cast<char*>(p);
|
|
||||||
char* const p_base = raw_p - offsetof(PyObject, ob_refcnt);
|
|
||||||
xdecref_impl(reinterpret_cast<PyObject*>(p_base));
|
|
||||||
}
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
|
|
||||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
|
||||||
//
|
|
||||||
// Converters
|
|
||||||
//
|
|
||||||
PyObject* to_python(long);
|
|
||||||
long from_python(PyObject* p, boost::python::type<long>);
|
|
||||||
long from_python(PyObject* p, boost::python::type<const long&>);
|
|
||||||
|
|
||||||
PyObject* to_python(unsigned long);
|
|
||||||
unsigned long from_python(PyObject* p, boost::python::type<unsigned long>);
|
|
||||||
unsigned long from_python(PyObject* p, boost::python::type<const unsigned long&>);
|
|
||||||
|
|
||||||
PyObject* to_python(int);
|
|
||||||
int from_python(PyObject*, boost::python::type<int>);
|
|
||||||
int from_python(PyObject*, boost::python::type<const int&>);
|
|
||||||
|
|
||||||
PyObject* to_python(unsigned int);
|
|
||||||
unsigned int from_python(PyObject*, boost::python::type<unsigned int>);
|
|
||||||
unsigned int from_python(PyObject*, boost::python::type<const unsigned int&>);
|
|
||||||
|
|
||||||
PyObject* to_python(short);
|
|
||||||
short from_python(PyObject*, boost::python::type<short>);
|
|
||||||
short from_python(PyObject*, boost::python::type<const short&>);
|
|
||||||
|
|
||||||
PyObject* to_python(unsigned short);
|
|
||||||
unsigned short from_python(PyObject*, boost::python::type<unsigned short>);
|
|
||||||
unsigned short from_python(PyObject*, boost::python::type<const unsigned short&>);
|
|
||||||
|
|
||||||
PyObject* to_python(signed char);
|
|
||||||
signed char from_python(PyObject*, boost::python::type<signed char>);
|
|
||||||
signed char from_python(PyObject*, boost::python::type<const signed char&>);
|
|
||||||
|
|
||||||
PyObject* to_python(unsigned char);
|
|
||||||
unsigned char from_python(PyObject*, boost::python::type<unsigned char>);
|
|
||||||
unsigned char from_python(PyObject*, boost::python::type<const unsigned char&>);
|
|
||||||
|
|
||||||
PyObject* to_python(float);
|
|
||||||
float from_python(PyObject*, boost::python::type<float>);
|
|
||||||
float from_python(PyObject*, boost::python::type<const float&>);
|
|
||||||
|
|
||||||
PyObject* to_python(double);
|
|
||||||
double from_python(PyObject*, boost::python::type<double>);
|
|
||||||
double from_python(PyObject*, boost::python::type<const double&>);
|
|
||||||
|
|
||||||
PyObject* to_python(bool);
|
|
||||||
bool from_python(PyObject*, boost::python::type<bool>);
|
|
||||||
bool from_python(PyObject*, boost::python::type<const bool&>);
|
|
||||||
|
|
||||||
PyObject* to_python(void);
|
|
||||||
void from_python(PyObject*, boost::python::type<void>);
|
|
||||||
|
|
||||||
PyObject* to_python(const char* s);
|
|
||||||
const char* from_python(PyObject*, boost::python::type<const char*>);
|
|
||||||
|
|
||||||
PyObject* to_python(const std::string& s);
|
|
||||||
std::string from_python(PyObject*, boost::python::type<std::string>);
|
|
||||||
std::string from_python(PyObject*, boost::python::type<const std::string&>);
|
|
||||||
|
|
||||||
// For when your C++ function really wants to pass/return a PyObject*
|
|
||||||
PyObject* to_python(PyObject*);
|
|
||||||
PyObject* from_python(PyObject*, boost::python::type<PyObject*>);
|
|
||||||
|
|
||||||
// Some standard conversions to/from smart pointer types. You can add your own
|
|
||||||
// from these examples. These are not generated using the friend technique from
|
|
||||||
// wrapped_pointer because:
|
|
||||||
//
|
|
||||||
// 1. We want to be able to extend conversion to/from WrappedPointers using
|
|
||||||
// arbitrary smart pointer types.
|
|
||||||
//
|
|
||||||
// 2. It helps with compilation independence. This way, code which creates
|
|
||||||
// wrappers for functions accepting and returning smart_ptr<T> does not
|
|
||||||
// have to have already seen the invocation of wrapped_type<T>.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Unfortunately, MSVC6 is so incredibly lame that we have to rely on the friend
|
|
||||||
// technique to auto_generate standard pointer conversions for wrapped
|
|
||||||
// types. This means that you need to write a non-templated function for each
|
|
||||||
// specific smart_ptr<T> which you want to convert from_python. For example,
|
|
||||||
//
|
|
||||||
// namespace boost { namespace python {
|
|
||||||
// #ifdef MUST_SUPPORT_MSVC
|
|
||||||
//
|
|
||||||
// MyPtr<Foo> from_python(PyObject*p, type<MyPtr<Foo> >)
|
|
||||||
// { return smart_ptr_from_python(p, type<MyPtr<Foo> >(), type<Foo>());}
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// MyPtr<Bar> from_python(PyObject*p, type<MyPtr<Bar> >)
|
|
||||||
// { return smart_ptr_from_python(p, type<MyPtr<Bar> >(), type<Bar>());}
|
|
||||||
//
|
|
||||||
// ... // definitions for MyPtr<Baz>, MyPtr<Mumble>, etc.
|
|
||||||
//
|
|
||||||
// #else
|
|
||||||
//
|
|
||||||
// // Just once for all MyPtr<T>
|
|
||||||
// template <class T>
|
|
||||||
// MyPtr<T> from_python(PyObject*p, type<MyPtr<T> >)
|
|
||||||
// {
|
|
||||||
// return smart_ptr_from_python(p, type<MyPtr<T> >(), type<T>());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #endif
|
|
||||||
// }} // namespace boost::python
|
|
||||||
|
|
||||||
#if !defined(BOOST_MSVC6_OR_EARLIER)
|
|
||||||
template <class T>
|
|
||||||
boost::shared_ptr<T> from_python(PyObject*p, boost::python::type<boost::shared_ptr<T> >)
|
|
||||||
{
|
|
||||||
return smart_ptr_from_python(p, boost::python::type<boost::shared_ptr<T> >(), boost::python::type<T>());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
template <class T>
|
|
||||||
PyObject* to_python(std::auto_ptr<T> p)
|
|
||||||
{
|
|
||||||
return new boost::python::wrapped_pointer<std::auto_ptr<T>, T>(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* to_python(boost::shared_ptr<T> p)
|
|
||||||
{
|
|
||||||
return new boost::python::wrapped_pointer<boost::shared_ptr<T>, T>(p);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
|
||||||
// inline implementations
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef BOOST_MSVC6_OR_EARLIER
|
|
||||||
inline PyObject* to_python(double d)
|
|
||||||
{
|
|
||||||
return PyFloat_FromDouble(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PyObject* to_python(float f)
|
|
||||||
{
|
|
||||||
return PyFloat_FromDouble(f);
|
|
||||||
}
|
|
||||||
#endif // BOOST_MSVC6_OR_EARLIER
|
|
||||||
|
|
||||||
inline PyObject* to_python(long l)
|
|
||||||
{
|
|
||||||
return PyInt_FromLong(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PyObject* to_python(int x)
|
|
||||||
{
|
|
||||||
return PyInt_FromLong(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PyObject* to_python(short x)
|
|
||||||
{
|
|
||||||
return PyInt_FromLong(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PyObject* to_python(bool b)
|
|
||||||
{
|
|
||||||
return PyInt_FromLong(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PyObject* to_python(void)
|
|
||||||
{
|
|
||||||
return boost::python::detail::none();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PyObject* to_python(const char* s)
|
|
||||||
{
|
|
||||||
return PyString_FromString(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string from_python(PyObject* p, boost::python::type<const std::string&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<std::string>());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PyObject* to_python(PyObject* p)
|
|
||||||
{
|
|
||||||
Py_INCREF(p);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PyObject* from_python(PyObject* p, boost::python::type<PyObject*>)
|
|
||||||
{
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char* from_python(PyObject* p, boost::python::type<const char* const&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<const char*>());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double from_python(PyObject* p, boost::python::type<const double&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<double>());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float from_python(PyObject* p, boost::python::type<const float&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<float>());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int from_python(PyObject* p, boost::python::type<const int&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<int>());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline short from_python(PyObject* p, boost::python::type<const short&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<short>());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline long from_python(PyObject* p, boost::python::type<const long&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<long>());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool from_python(PyObject* p, boost::python::type<const bool&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<bool>());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned int from_python(PyObject* p, boost::python::type<const unsigned int&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<unsigned int>());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned short from_python(PyObject* p, boost::python::type<const unsigned short&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<unsigned short>());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline signed char from_python(PyObject* p, boost::python::type<const signed char&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<signed char>());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned char from_python(PyObject* p, boost::python::type<const unsigned char&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<unsigned char>());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned long from_python(PyObject* p, boost::python::type<const unsigned long&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<unsigned long>());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
|
||||||
|
|
||||||
#endif // METHOD_DWA122899_H_
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef BASE_OBJECT_DWA051600_H_
|
|
||||||
# define BASE_OBJECT_DWA051600_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/python/detail/signatures.hpp> // really just for type<>
|
|
||||||
# include <boost/python/detail/wrap_python.hpp>
|
|
||||||
# include <cstring>
|
|
||||||
|
|
||||||
namespace boost { namespace python { namespace detail {
|
|
||||||
|
|
||||||
// base_object - adds a constructor and non-virtual destructor to a
|
|
||||||
// base Python type (e.g. PyObject, PyTypeObject).
|
|
||||||
template <class python_type>
|
|
||||||
struct base_object : python_type
|
|
||||||
{
|
|
||||||
typedef python_type base_python_type;
|
|
||||||
|
|
||||||
// Initializes type and reference count. All other fields of base_python_type are 0
|
|
||||||
base_object(PyTypeObject* type_obj);
|
|
||||||
|
|
||||||
// Decrements reference count on the type
|
|
||||||
~base_object();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Easy typedefs for common usage
|
|
||||||
typedef base_object<PyObject> python_object;
|
|
||||||
typedef base_object<PyTypeObject> python_type;
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// class_t template member function implementations
|
|
||||||
//
|
|
||||||
template <class python_type>
|
|
||||||
base_object<python_type>::base_object(PyTypeObject* type_obj)
|
|
||||||
{
|
|
||||||
base_python_type* bp = this;
|
|
||||||
#if !defined(_MSC_VER) || defined(__STLPORT)
|
|
||||||
std::
|
|
||||||
#endif
|
|
||||||
memset(bp, 0, sizeof(base_python_type));
|
|
||||||
ob_refcnt = 1;
|
|
||||||
ob_type = type_obj;
|
|
||||||
Py_INCREF(type_obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class python_type>
|
|
||||||
inline base_object<python_type>::~base_object()
|
|
||||||
{
|
|
||||||
Py_DECREF(ob_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
}}} // namespace boost::python::detail
|
|
||||||
|
|
||||||
#endif // BASE_OBJECT_DWA051600_H_
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef CAST_DWA052500_H_
|
|
||||||
# define CAST_DWA052500_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/wrap_python.hpp>
|
|
||||||
# include <boost/operators.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
// The default way of converting a PyObject* or PyTypeObject* to a T*
|
|
||||||
template <class T>
|
|
||||||
struct downcast_traits
|
|
||||||
{
|
|
||||||
template <class U>
|
|
||||||
static T* cast(U* p) { return static_cast<T*>(p); }
|
|
||||||
};
|
|
||||||
|
|
||||||
inline PyTypeObject* as_base_object(const PyTypeObject*, PyObject* p)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<PyTypeObject*>(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PyObject* as_base_object(const PyObject*, PyObject* p)
|
|
||||||
{
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const PyTypeObject* as_base_object(const PyTypeObject*, const PyObject* p)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<const PyTypeObject*>(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const PyObject* as_base_object(const PyObject*, const PyObject* p)
|
|
||||||
{
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
// Convert a pointer to any type derived from PyObject or PyTypeObject to a PyObject*
|
|
||||||
inline PyObject* as_object(PyObject* p) { return p; }
|
|
||||||
inline PyObject* as_object(PyTypeObject* p) { return reinterpret_cast<PyObject*>(p); }
|
|
||||||
|
|
||||||
// If I didn't have to support stupid MSVC6 we could just use a simple template function:
|
|
||||||
// template <class T> T* downcast(PyObject*).
|
|
||||||
template <class T>
|
|
||||||
struct downcast : boost::dereferenceable<downcast<T>, T*>
|
|
||||||
{
|
|
||||||
downcast(PyObject* p)
|
|
||||||
: m_p(detail::downcast_traits<T>::cast(detail::as_base_object((T*)0, p)))
|
|
||||||
{}
|
|
||||||
|
|
||||||
downcast(const PyObject* p)
|
|
||||||
: m_p(detail::downcast_traits<T>::cast(detail::as_base_object((const T*)0, p)))
|
|
||||||
{}
|
|
||||||
|
|
||||||
downcast(PyTypeObject* p)
|
|
||||||
: m_p(detail::downcast_traits<T>::cast(p))
|
|
||||||
{}
|
|
||||||
|
|
||||||
downcast(const PyTypeObject* p)
|
|
||||||
: m_p(detail::downcast_traits<T>::cast(p))
|
|
||||||
{}
|
|
||||||
|
|
||||||
operator T*() const { return m_p; }
|
|
||||||
T* get() const { return m_p; }
|
|
||||||
T& operator*() const { return *m_p; }
|
|
||||||
private:
|
|
||||||
T* m_p;
|
|
||||||
};
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
|
|
||||||
#endif // CAST_DWA052500_H_
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef CONFIG_DWA052200_H_
|
|
||||||
# define CONFIG_DWA052200_H_
|
|
||||||
|
|
||||||
# include <boost/config.hpp>
|
|
||||||
# include <cstddef>
|
|
||||||
|
|
||||||
# ifdef BOOST_NO_OPERATORS_IN_NAMESPACE
|
|
||||||
// A gcc bug forces some symbols into the global namespace
|
|
||||||
# define BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
|
||||||
# define BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
|
||||||
# define BOOST_PYTHON_CONVERSION
|
|
||||||
# define BOOST_PYTHON_IMPORT_CONVERSION(x) using ::x
|
|
||||||
# else
|
|
||||||
# define BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE namespace boost { namespace python {
|
|
||||||
# define BOOST_PYTHON_END_CONVERSION_NAMESPACE }} // namespace boost::python
|
|
||||||
# define BOOST_PYTHON_CONVERSION boost::python
|
|
||||||
# define BOOST_PYTHON_IMPORT_CONVERSION(x) void never_defined() // so we can follow the macro with a ';'
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# if defined(BOOST_MSVC)
|
|
||||||
# if _MSC_VER <= 1200
|
|
||||||
# define BOOST_MSVC6_OR_EARLIER 1
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# pragma warning (disable : 4786)
|
|
||||||
|
|
||||||
# endif
|
|
||||||
|
|
||||||
// Work around the broken library implementation/strict ansi checking on some
|
|
||||||
// EDG-based compilers (e.g. alpha), which incorrectly warn that the result of
|
|
||||||
// offsetof() is not an integer constant expression.
|
|
||||||
# if defined(__DECCXX_VER) && __DECCXX_VER <= 60290024
|
|
||||||
# define BOOST_OFFSETOF(s_name, s_member) \
|
|
||||||
((size_t)__INTADDR__(&(((s_name *)0)->s_member)))
|
|
||||||
# else
|
|
||||||
# define BOOST_OFFSETOF(s_name, s_member) \
|
|
||||||
offsetof(s_name, s_member)
|
|
||||||
# endif
|
|
||||||
|
|
||||||
// The STLport puts all of the standard 'C' library names in std (as far as the
|
|
||||||
// user is concerned), but without it you need a fix if you're using MSVC.
|
|
||||||
# if defined(BOOST_MSVC6_OR_EARLIER) && !defined(__STLPORT)
|
|
||||||
# define BOOST_CSTD_
|
|
||||||
# else
|
|
||||||
# define BOOST_CSTD_ std
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif // CONFIG_DWA052200_H_
|
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
# include <boost/python/detail/init_function.hpp>
|
# include <boost/python/detail/init_function.hpp>
|
||||||
# include <typeinfo>
|
# include <typeinfo>
|
||||||
# include <boost/smart_ptr.hpp>
|
# include <boost/smart_ptr.hpp>
|
||||||
|
# include <boost/type_traits.hpp>
|
||||||
|
|
||||||
namespace boost { namespace python {
|
namespace boost { namespace python {
|
||||||
|
|
||||||
@@ -133,6 +134,26 @@ class class_registry
|
|||||||
static std::vector<derived_class_info> static_derived_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(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
|
}}} // namespace boost::python::detail
|
||||||
|
|
||||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
||||||
@@ -178,9 +199,9 @@ class python_extension_class_converters
|
|||||||
new boost::python::detail::instance_value_holder<T,U>(result.get(), x)));
|
new boost::python::detail::instance_value_holder<T,U>(result.get(), x)));
|
||||||
return result.release();
|
return result.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to T*
|
friend
|
||||||
friend T* from_python(PyObject* obj, boost::python::type<T*>)
|
T* non_null_from_python(PyObject* obj, boost::python::type<T*>)
|
||||||
{
|
{
|
||||||
// downcast to an extension_instance, then find the actual T
|
// downcast to an extension_instance, then find the actual T
|
||||||
boost::python::detail::extension_instance* self = boost::python::detail::get_extension_instance(obj);
|
boost::python::detail::extension_instance* self = boost::python::detail::get_extension_instance(obj);
|
||||||
@@ -201,6 +222,15 @@ class python_extension_class_converters
|
|||||||
throw boost::python::argument_error();
|
throw boost::python::argument_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert to T*
|
||||||
|
friend T* from_python(PyObject* obj, boost::python::type<T*>)
|
||||||
|
{
|
||||||
|
if (obj == Py_None)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return non_null_from_python(obj, boost::python::type<T*>());
|
||||||
|
}
|
||||||
|
|
||||||
// Convert to PtrType, where PtrType can be dereferenced to obtain a T.
|
// Convert to PtrType, where PtrType can be dereferenced to obtain a T.
|
||||||
template <class PtrType>
|
template <class PtrType>
|
||||||
static PtrType& ptr_from_python(PyObject* obj, boost::python::type<PtrType>)
|
static PtrType& ptr_from_python(PyObject* obj, boost::python::type<PtrType>)
|
||||||
@@ -220,9 +250,25 @@ class python_extension_class_converters
|
|||||||
throw boost::python::argument_error();
|
throw boost::python::argument_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class PtrType>
|
||||||
|
static const PtrType& ptr_const_ref_from_python(PyObject* obj, boost::python::type<PtrType>)
|
||||||
|
{
|
||||||
|
if (obj == Py_None)
|
||||||
|
{
|
||||||
|
static PtrType null_ptr;
|
||||||
|
return null_ptr;
|
||||||
|
}
|
||||||
|
return ptr_from_python(obj, boost::python::type<PtrType>());
|
||||||
|
}
|
||||||
|
|
||||||
template <class PtrType>
|
template <class PtrType>
|
||||||
static PyObject* ptr_to_python(PtrType x)
|
static PyObject* 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());
|
boost::python::reference<boost::python::detail::extension_instance> result(create_instance());
|
||||||
result->add_implementation(
|
result->add_implementation(
|
||||||
std::auto_ptr<boost::python::detail::instance_holder_base>(
|
std::auto_ptr<boost::python::detail::instance_holder_base>(
|
||||||
@@ -254,7 +300,7 @@ class python_extension_class_converters
|
|||||||
|
|
||||||
// Convert to T&
|
// Convert to T&
|
||||||
friend T& from_python(PyObject* p, boost::python::type<T&>)
|
friend T& from_python(PyObject* p, boost::python::type<T&>)
|
||||||
{ return *boost::python::detail::check_non_null(from_python(p, boost::python::type<T*>())); }
|
{ return *boost::python::detail::check_non_null(non_null_from_python(p, boost::python::type<T*>())); }
|
||||||
|
|
||||||
// Convert to const T&
|
// Convert to const T&
|
||||||
friend const T& from_python(PyObject* p, boost::python::type<const T&>)
|
friend const T& from_python(PyObject* p, boost::python::type<const T&>)
|
||||||
@@ -267,11 +313,11 @@ class python_extension_class_converters
|
|||||||
friend std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<std::auto_ptr<T>&>)
|
friend std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<std::auto_ptr<T>&>)
|
||||||
{ return ptr_from_python(p, boost::python::type<std::auto_ptr<T> >()); }
|
{ return ptr_from_python(p, boost::python::type<std::auto_ptr<T> >()); }
|
||||||
|
|
||||||
friend std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<std::auto_ptr<T> >)
|
friend const std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<std::auto_ptr<T> >)
|
||||||
{ return ptr_from_python(p, boost::python::type<std::auto_ptr<T> >()); }
|
{ return ptr_const_ref_from_python(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>&>)
|
friend const std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<const std::auto_ptr<T>&>)
|
||||||
{ return ptr_from_python(p, boost::python::type<std::auto_ptr<T> >()); }
|
{ return ptr_const_ref_from_python(p, boost::python::type<std::auto_ptr<T> >()); }
|
||||||
|
|
||||||
friend PyObject* to_python(std::auto_ptr<T> x)
|
friend PyObject* to_python(std::auto_ptr<T> x)
|
||||||
{ return ptr_to_python(x); }
|
{ return ptr_to_python(x); }
|
||||||
@@ -279,11 +325,11 @@ class python_extension_class_converters
|
|||||||
friend boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<boost::shared_ptr<T>&>)
|
friend boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<boost::shared_ptr<T>&>)
|
||||||
{ return ptr_from_python(p, boost::python::type<boost::shared_ptr<T> >()); }
|
{ return ptr_from_python(p, boost::python::type<boost::shared_ptr<T> >()); }
|
||||||
|
|
||||||
friend boost::shared_ptr<T>& from_python(PyObject* 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> >)
|
||||||
{ return ptr_from_python(p, boost::python::type<boost::shared_ptr<T> >()); }
|
{ return ptr_const_ref_from_python(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>&>)
|
friend const boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<const boost::shared_ptr<T>&>)
|
||||||
{ return ptr_from_python(p, boost::python::type<boost::shared_ptr<T> >()); }
|
{ return ptr_const_ref_from_python(p, boost::python::type<boost::shared_ptr<T> >()); }
|
||||||
|
|
||||||
friend PyObject* to_python(boost::shared_ptr<T> x)
|
friend PyObject* to_python(boost::shared_ptr<T> x)
|
||||||
{ return ptr_to_python(x); }
|
{ return ptr_to_python(x); }
|
||||||
|
|||||||
@@ -1,306 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef FUNCTIONS_DWA051400_H_
|
|
||||||
# define FUNCTIONS_DWA051400_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/python/detail/wrap_python.hpp>
|
|
||||||
# include <boost/python/reference.hpp>
|
|
||||||
# include <boost/python/detail/signatures.hpp>
|
|
||||||
# include <boost/python/caller.hpp>
|
|
||||||
# include <boost/call_traits.hpp>
|
|
||||||
# include <boost/python/objects.hpp>
|
|
||||||
# include <boost/python/detail/base_object.hpp>
|
|
||||||
# include <typeinfo>
|
|
||||||
# include <vector>
|
|
||||||
|
|
||||||
namespace boost { namespace python { namespace detail {
|
|
||||||
|
|
||||||
// forward declaration
|
|
||||||
class extension_instance;
|
|
||||||
|
|
||||||
|
|
||||||
// function --
|
|
||||||
// the common base class for all overloadable function and method objects
|
|
||||||
// supplied by the library.
|
|
||||||
class function : public python_object
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
function();
|
|
||||||
// function objects are reasonably rare, so we guess we can afford a virtual table.
|
|
||||||
// This cuts down on the number of distinct type objects which need to be defined.
|
|
||||||
virtual ~function() {}
|
|
||||||
|
|
||||||
PyObject* call(PyObject* args, PyObject* keywords) const;
|
|
||||||
static void add_to_namespace(reference<function> f, const char* name, PyObject* dict);
|
|
||||||
|
|
||||||
private:
|
|
||||||
virtual PyObject* do_call(PyObject* args, PyObject* keywords) const = 0;
|
|
||||||
virtual const char* description() const = 0;
|
|
||||||
private:
|
|
||||||
struct type_object;
|
|
||||||
private:
|
|
||||||
reference<function> m_overloads;
|
|
||||||
};
|
|
||||||
|
|
||||||
// wrapped_function_pointer<> --
|
|
||||||
// A single function or member function pointer wrapped and presented to
|
|
||||||
// Python as a callable object.
|
|
||||||
//
|
|
||||||
// Template parameters:
|
|
||||||
// R - the return type of the function pointer
|
|
||||||
// F - the complete type of the wrapped function pointer
|
|
||||||
template <class R, class F>
|
|
||||||
struct wrapped_function_pointer : function
|
|
||||||
{
|
|
||||||
typedef F ptr_fun; // pointer-to--function or pointer-to-member-function
|
|
||||||
|
|
||||||
wrapped_function_pointer(ptr_fun pf)
|
|
||||||
: m_pf(pf) {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
PyObject* do_call(PyObject* args, PyObject* keywords) const
|
|
||||||
{ return caller<R>::call(m_pf, args, keywords); }
|
|
||||||
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(F).name(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const ptr_fun m_pf;
|
|
||||||
};
|
|
||||||
|
|
||||||
// raw_arguments_function
|
|
||||||
// A function that passes the Python argument tuple and keyword dictionary
|
|
||||||
// verbatim to C++ (useful for customized argument parsing and variable
|
|
||||||
// argument lists)
|
|
||||||
template <class Ret, class Args, class Keywords>
|
|
||||||
struct raw_arguments_function : function
|
|
||||||
{
|
|
||||||
typedef Ret (*ptr_fun)(Args, Keywords);
|
|
||||||
|
|
||||||
raw_arguments_function(ptr_fun pf)
|
|
||||||
: m_pf(pf) {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
PyObject* do_call(PyObject* args, PyObject* keywords) const
|
|
||||||
{
|
|
||||||
ref dict(keywords ?
|
|
||||||
ref(keywords, ref::increment_count) :
|
|
||||||
ref(PyDict_New()));
|
|
||||||
|
|
||||||
return to_python(
|
|
||||||
(*m_pf)(from_python(args, boost::python::type<Args>()),
|
|
||||||
from_python(dict.get(), boost::python::type<Keywords>())));
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(ptr_fun).name(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const ptr_fun m_pf;
|
|
||||||
};
|
|
||||||
|
|
||||||
// virtual_function<> --
|
|
||||||
// A virtual function with a default implementation wrapped and presented
|
|
||||||
// to Python as a callable object.
|
|
||||||
//
|
|
||||||
// Template parameters:
|
|
||||||
// T - the type of the target class
|
|
||||||
// R - the return type of the function pointer
|
|
||||||
// V - the virtual function pointer being wrapped
|
|
||||||
// (should be of the form R(T::*)(<args>), or R (*)(T, <args>))
|
|
||||||
// D - a function which takes a T&, const T&, T*, or const T* first
|
|
||||||
// parameter and calls T::f on it /non-virtually/, where V
|
|
||||||
// approximates &T::f.
|
|
||||||
template <class T, class R, class V, class D>
|
|
||||||
class virtual_function : public function
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual_function(V virtual_function_ptr, D default_implementation)
|
|
||||||
: m_virtual_function_ptr(virtual_function_ptr),
|
|
||||||
m_default_implementation(default_implementation)
|
|
||||||
{}
|
|
||||||
|
|
||||||
private:
|
|
||||||
PyObject* do_call(PyObject* args, PyObject* keywords) const;
|
|
||||||
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(V).name(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const V m_virtual_function_ptr;
|
|
||||||
const D m_default_implementation;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A helper function for new_member_function(), below. Implements the core
|
|
||||||
// functionality once the return type has already been deduced. R is expected to
|
|
||||||
// be type<X>, where X is the actual return type of pmf.
|
|
||||||
template <class F, class R>
|
|
||||||
function* new_wrapped_function_aux(R, F pmf)
|
|
||||||
{
|
|
||||||
// We can't just use "typename R::Type" below because MSVC (incorrectly) pukes.
|
|
||||||
typedef typename R::type return_type;
|
|
||||||
return new wrapped_function_pointer<return_type, F>(pmf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and return a new member function object wrapping the given
|
|
||||||
// pointer-to-member function
|
|
||||||
template <class F>
|
|
||||||
inline function* new_wrapped_function(F pmf)
|
|
||||||
{
|
|
||||||
// Deduce the return type and pass it off to the helper function above
|
|
||||||
return new_wrapped_function_aux(return_value(pmf), pmf);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class R, class Args, class keywords>
|
|
||||||
function* new_raw_arguments_function(R (*pmf)(Args, keywords))
|
|
||||||
{
|
|
||||||
return new raw_arguments_function<R, Args, keywords>(pmf);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// A helper function for new_virtual_function(), below. Implements the core
|
|
||||||
// functionality once the return type has already been deduced. R is expected to
|
|
||||||
// be type<X>, where X is the actual return type of V.
|
|
||||||
template <class T, class R, class V, class D>
|
|
||||||
inline function* new_virtual_function_aux(
|
|
||||||
type<T>, R, V virtual_function_ptr, D default_implementation
|
|
||||||
)
|
|
||||||
{
|
|
||||||
// We can't just use "typename R::Type" below because MSVC (incorrectly) pukes.
|
|
||||||
typedef typename R::type return_type;
|
|
||||||
return new virtual_function<T, return_type, V, D>(
|
|
||||||
virtual_function_ptr, default_implementation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and return a new virtual_function object wrapping the given
|
|
||||||
// virtual_function_ptr and default_implementation
|
|
||||||
template <class T, class V, class D>
|
|
||||||
inline function* new_virtual_function(
|
|
||||||
type<T>, V virtual_function_ptr, D default_implementation
|
|
||||||
)
|
|
||||||
{
|
|
||||||
// Deduce the return type and pass it off to the helper function above
|
|
||||||
return new_virtual_function_aux(
|
|
||||||
type<T>(), return_value(virtual_function_ptr),
|
|
||||||
virtual_function_ptr, default_implementation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A function with a bundled "bound target" object. This is what is produced by
|
|
||||||
// the expression a.b where a is an instance or extension_instance object and b
|
|
||||||
// is a callable object not found in the obj namespace but on its class or
|
|
||||||
// a base class.
|
|
||||||
class bound_function : public python_object
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static bound_function* create(const ref& target, const ref& fn);
|
|
||||||
|
|
||||||
bound_function(const ref& target, const ref& fn);
|
|
||||||
PyObject* call(PyObject*args, PyObject* keywords) const;
|
|
||||||
PyObject* getattr(const char* name) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct type_object;
|
|
||||||
friend struct type_object;
|
|
||||||
|
|
||||||
ref m_target;
|
|
||||||
ref m_unbound_function;
|
|
||||||
|
|
||||||
private: // data members for allocation/deallocation optimization
|
|
||||||
bound_function* m_free_list_link;
|
|
||||||
|
|
||||||
static bound_function* free_list;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Special functions designed to access data members of a wrapped C++ object.
|
|
||||||
template <class ClassType, class MemberType>
|
|
||||||
class getter_function : public function
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef MemberType ClassType::* pointer_to_member;
|
|
||||||
|
|
||||||
getter_function(pointer_to_member pm)
|
|
||||||
: m_pm(pm) {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
PyObject* do_call(PyObject* args, PyObject* keywords) const;
|
|
||||||
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(MemberType (*)(const ClassType&)).name(); }
|
|
||||||
private:
|
|
||||||
pointer_to_member m_pm;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class ClassType, class MemberType>
|
|
||||||
class setter_function : public function
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef MemberType ClassType::* pointer_to_member;
|
|
||||||
|
|
||||||
setter_function(pointer_to_member pm)
|
|
||||||
: m_pm(pm) {}
|
|
||||||
|
|
||||||
private:
|
|
||||||
PyObject* do_call(PyObject* args, PyObject* keywords) const;
|
|
||||||
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(void (*)(const ClassType&, const MemberType&)).name(); }
|
|
||||||
private:
|
|
||||||
pointer_to_member m_pm;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class ClassType, class MemberType>
|
|
||||||
PyObject* getter_function<ClassType, MemberType>::do_call(
|
|
||||||
PyObject* args, PyObject* /* keywords */) const
|
|
||||||
{
|
|
||||||
PyObject* self;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("O"), &self))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return to_python(
|
|
||||||
from_python(self, type<const ClassType*>())->*m_pm);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ClassType, class MemberType>
|
|
||||||
PyObject* setter_function<ClassType, MemberType>::do_call(
|
|
||||||
PyObject* args, PyObject* /* keywords */) const
|
|
||||||
{
|
|
||||||
PyObject* self;
|
|
||||||
PyObject* value;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &self, &value))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
typedef typename boost::call_traits<MemberType>::const_reference extract_type;
|
|
||||||
from_python(self, type<ClassType*>())->*m_pm
|
|
||||||
= from_python(value, type<extract_type>());
|
|
||||||
|
|
||||||
return none();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T, class R, class V, class D>
|
|
||||||
PyObject* virtual_function<T,R,V,D>::do_call(PyObject* args, PyObject* keywords) const
|
|
||||||
{
|
|
||||||
// If the target object is held by pointer, we must call through the virtual
|
|
||||||
// function pointer to the most-derived override.
|
|
||||||
PyObject* target = PyTuple_GetItem(args, 0);
|
|
||||||
if (target != 0)
|
|
||||||
{
|
|
||||||
extension_instance* self = get_extension_instance(target);
|
|
||||||
if (self->wrapped_objects().size() == 1
|
|
||||||
&& !self->wrapped_objects()[0]->held_by_value())
|
|
||||||
{
|
|
||||||
return caller<R>::call(m_virtual_function_ptr, args, keywords);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return caller<R>::call(m_default_implementation, args, keywords);
|
|
||||||
}
|
|
||||||
|
|
||||||
}}} // namespace boost::python::detail
|
|
||||||
|
|
||||||
#endif // FUNCTIONS_DWA051400_H_
|
|
||||||
@@ -1,507 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
//
|
|
||||||
// This file was generated for %d-argument constructors by gen_init_function.python
|
|
||||||
|
|
||||||
#ifndef INIT_FUNCTION_DWA052000_H_
|
|
||||||
# define INIT_FUNCTION_DWA052000_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/python/detail/functions.hpp>
|
|
||||||
# include <boost/python/detail/signatures.hpp>
|
|
||||||
# include <typeinfo>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
// parameter_traits - so far, this is a way to pass a const T& when we can be
|
|
||||||
// sure T is not a reference type, and a raw T otherwise. This should be
|
|
||||||
// rolled into boost::call_traits. Ordinarily, parameter_traits would be
|
|
||||||
// written:
|
|
||||||
//
|
|
||||||
// template <class T> struct parameter_traits
|
|
||||||
// {
|
|
||||||
// typedef const T& const_reference;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// template <class T> struct parameter_traits<T&>
|
|
||||||
// {
|
|
||||||
// typedef T& const_reference;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// template <> struct parameter_traits<void>
|
|
||||||
// {
|
|
||||||
// typedef void const_reference;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// ...but since we can't partially specialize on reference types, we need this
|
|
||||||
// long-winded but equivalent incantation.
|
|
||||||
|
|
||||||
// const_ref_selector -- an implementation detail of parameter_traits (below). This uses
|
|
||||||
// the usual "poor man's partial specialization" hack for MSVC.
|
|
||||||
template <bool is_ref>
|
|
||||||
struct const_ref_selector
|
|
||||||
{
|
|
||||||
template <class T>
|
|
||||||
struct const_ref
|
|
||||||
{
|
|
||||||
typedef const T& type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct const_ref_selector<true>
|
|
||||||
{
|
|
||||||
template <class T>
|
|
||||||
struct const_ref
|
|
||||||
{
|
|
||||||
typedef T type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# ifdef BOOST_MSVC
|
|
||||||
# pragma warning(push)
|
|
||||||
# pragma warning(disable: 4181)
|
|
||||||
# endif // BOOST_MSVC
|
|
||||||
template <class T>
|
|
||||||
struct parameter_traits
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
typedef const_ref_selector<boost::is_reference<T>::value> selector;
|
|
||||||
public:
|
|
||||||
typedef typename selector::template const_ref<T>::type const_reference;
|
|
||||||
};
|
|
||||||
# ifdef BOOST_MSVC
|
|
||||||
# pragma warning(pop)
|
|
||||||
# endif // BOOST_MSVC
|
|
||||||
|
|
||||||
// Full spcialization for void
|
|
||||||
template <>
|
|
||||||
struct parameter_traits<void>
|
|
||||||
{
|
|
||||||
typedef void const_reference;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class reference_parameter
|
|
||||||
{
|
|
||||||
typedef typename parameter_traits<T>::const_reference const_reference;
|
|
||||||
public:
|
|
||||||
reference_parameter(const_reference value)
|
|
||||||
: value(value) {}
|
|
||||||
operator const_reference() { return value; }
|
|
||||||
private:
|
|
||||||
const_reference value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class extension_instance;
|
|
||||||
class instance_holder_base;
|
|
||||||
|
|
||||||
class init;
|
|
||||||
template <class T> struct init0;
|
|
||||||
template <class T, class A1> struct init1;
|
|
||||||
template <class T, class A1, class A2> struct init2;
|
|
||||||
template <class T, class A1, class A2, class A3> struct init3;
|
|
||||||
template <class T, class A1, class A2, class A3, class A4> struct init4;
|
|
||||||
template <class T, class A1, class A2, class A3, class A4, class A5> struct init5;
|
|
||||||
template <class T, class A1, class A2, class A3, class A4, class A5, class A6> struct init6;
|
|
||||||
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7> struct init7;
|
|
||||||
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> struct init8;
|
|
||||||
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9> struct init9;
|
|
||||||
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10> struct init10;
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct init_function
|
|
||||||
{
|
|
||||||
static init* create(signature0) {
|
|
||||||
return new init0<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1>
|
|
||||||
static init* create(signature1<A1>) {
|
|
||||||
return new init1<T,
|
|
||||||
detail::parameter_traits<A1>::const_reference>;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2>
|
|
||||||
static init* create(signature2<A1, A2>) {
|
|
||||||
return new init2<T,
|
|
||||||
detail::parameter_traits<A1>::const_reference,
|
|
||||||
detail::parameter_traits<A2>::const_reference>;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3>
|
|
||||||
static init* create(signature3<A1, A2, A3>) {
|
|
||||||
return new init3<T,
|
|
||||||
detail::parameter_traits<A1>::const_reference,
|
|
||||||
detail::parameter_traits<A2>::const_reference,
|
|
||||||
detail::parameter_traits<A3>::const_reference>;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4>
|
|
||||||
static init* create(signature4<A1, A2, A3, A4>) {
|
|
||||||
return new init4<T,
|
|
||||||
detail::parameter_traits<A1>::const_reference,
|
|
||||||
detail::parameter_traits<A2>::const_reference,
|
|
||||||
detail::parameter_traits<A3>::const_reference,
|
|
||||||
detail::parameter_traits<A4>::const_reference>;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5>
|
|
||||||
static init* create(signature5<A1, A2, A3, A4, A5>) {
|
|
||||||
return new init5<T,
|
|
||||||
detail::parameter_traits<A1>::const_reference,
|
|
||||||
detail::parameter_traits<A2>::const_reference,
|
|
||||||
detail::parameter_traits<A3>::const_reference,
|
|
||||||
detail::parameter_traits<A4>::const_reference,
|
|
||||||
detail::parameter_traits<A5>::const_reference>;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6>
|
|
||||||
static init* create(signature6<A1, A2, A3, A4, A5, A6>) {
|
|
||||||
return new init6<T,
|
|
||||||
detail::parameter_traits<A1>::const_reference,
|
|
||||||
detail::parameter_traits<A2>::const_reference,
|
|
||||||
detail::parameter_traits<A3>::const_reference,
|
|
||||||
detail::parameter_traits<A4>::const_reference,
|
|
||||||
detail::parameter_traits<A5>::const_reference,
|
|
||||||
detail::parameter_traits<A6>::const_reference>;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
|
||||||
static init* create(signature7<A1, A2, A3, A4, A5, A6, A7>) {
|
|
||||||
return new init7<T,
|
|
||||||
detail::parameter_traits<A1>::const_reference,
|
|
||||||
detail::parameter_traits<A2>::const_reference,
|
|
||||||
detail::parameter_traits<A3>::const_reference,
|
|
||||||
detail::parameter_traits<A4>::const_reference,
|
|
||||||
detail::parameter_traits<A5>::const_reference,
|
|
||||||
detail::parameter_traits<A6>::const_reference,
|
|
||||||
detail::parameter_traits<A7>::const_reference>;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
|
||||||
static init* create(signature8<A1, A2, A3, A4, A5, A6, A7, A8>) {
|
|
||||||
return new init8<T,
|
|
||||||
detail::parameter_traits<A1>::const_reference,
|
|
||||||
detail::parameter_traits<A2>::const_reference,
|
|
||||||
detail::parameter_traits<A3>::const_reference,
|
|
||||||
detail::parameter_traits<A4>::const_reference,
|
|
||||||
detail::parameter_traits<A5>::const_reference,
|
|
||||||
detail::parameter_traits<A6>::const_reference,
|
|
||||||
detail::parameter_traits<A7>::const_reference,
|
|
||||||
detail::parameter_traits<A8>::const_reference>;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
|
|
||||||
static init* create(signature9<A1, A2, A3, A4, A5, A6, A7, A8, A9>) {
|
|
||||||
return new init9<T,
|
|
||||||
detail::parameter_traits<A1>::const_reference,
|
|
||||||
detail::parameter_traits<A2>::const_reference,
|
|
||||||
detail::parameter_traits<A3>::const_reference,
|
|
||||||
detail::parameter_traits<A4>::const_reference,
|
|
||||||
detail::parameter_traits<A5>::const_reference,
|
|
||||||
detail::parameter_traits<A6>::const_reference,
|
|
||||||
detail::parameter_traits<A7>::const_reference,
|
|
||||||
detail::parameter_traits<A8>::const_reference,
|
|
||||||
detail::parameter_traits<A9>::const_reference>;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
|
|
||||||
static init* create(signature10<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>) {
|
|
||||||
return new init10<T,
|
|
||||||
detail::parameter_traits<A1>::const_reference,
|
|
||||||
detail::parameter_traits<A2>::const_reference,
|
|
||||||
detail::parameter_traits<A3>::const_reference,
|
|
||||||
detail::parameter_traits<A4>::const_reference,
|
|
||||||
detail::parameter_traits<A5>::const_reference,
|
|
||||||
detail::parameter_traits<A6>::const_reference,
|
|
||||||
detail::parameter_traits<A7>::const_reference,
|
|
||||||
detail::parameter_traits<A8>::const_reference,
|
|
||||||
detail::parameter_traits<A9>::const_reference,
|
|
||||||
detail::parameter_traits<A10>::const_reference>;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class init : public function
|
|
||||||
{
|
|
||||||
private: // override function hook
|
|
||||||
PyObject* do_call(PyObject* args, PyObject* keywords) const;
|
|
||||||
private:
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* tail_args, PyObject* keywords) const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct init0 : init
|
|
||||||
{
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
|
|
||||||
{
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("")))
|
|
||||||
throw argument_error();
|
|
||||||
return new T(self
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(void (*)(T&)).name(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T, class A1>
|
|
||||||
struct init1 : init
|
|
||||||
{
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
|
|
||||||
{
|
|
||||||
PyObject* a1;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("O"), &a1))
|
|
||||||
throw argument_error();
|
|
||||||
return new T(self,
|
|
||||||
boost::python::detail::reference_parameter<A1>(from_python(a1, type<A1>()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(void (*)(T&, A1)).name(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T, class A1, class A2>
|
|
||||||
struct init2 : init
|
|
||||||
{
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
|
|
||||||
{
|
|
||||||
PyObject* a1;
|
|
||||||
PyObject* a2;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &a1, &a2))
|
|
||||||
throw argument_error();
|
|
||||||
return new T(self,
|
|
||||||
boost::python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
|
|
||||||
boost::python::detail::reference_parameter<A2>(from_python(a2, type<A2>()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(void (*)(T&, A1, A2)).name(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T, class A1, class A2, class A3>
|
|
||||||
struct init3 : init
|
|
||||||
{
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
|
|
||||||
{
|
|
||||||
PyObject* a1;
|
|
||||||
PyObject* a2;
|
|
||||||
PyObject* a3;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOO"), &a1, &a2, &a3))
|
|
||||||
throw argument_error();
|
|
||||||
return new T(self,
|
|
||||||
boost::python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
|
|
||||||
boost::python::detail::reference_parameter<A2>(from_python(a2, type<A2>())),
|
|
||||||
boost::python::detail::reference_parameter<A3>(from_python(a3, type<A3>()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(void (*)(T&, A1, A2, A3)).name(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T, class A1, class A2, class A3, class A4>
|
|
||||||
struct init4 : init
|
|
||||||
{
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
|
|
||||||
{
|
|
||||||
PyObject* a1;
|
|
||||||
PyObject* a2;
|
|
||||||
PyObject* a3;
|
|
||||||
PyObject* a4;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOO"), &a1, &a2, &a3, &a4))
|
|
||||||
throw argument_error();
|
|
||||||
return new T(self,
|
|
||||||
boost::python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
|
|
||||||
boost::python::detail::reference_parameter<A2>(from_python(a2, type<A2>())),
|
|
||||||
boost::python::detail::reference_parameter<A3>(from_python(a3, type<A3>())),
|
|
||||||
boost::python::detail::reference_parameter<A4>(from_python(a4, type<A4>()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(void (*)(T&, A1, A2, A3, A4)).name(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T, class A1, class A2, class A3, class A4, class A5>
|
|
||||||
struct init5 : init
|
|
||||||
{
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
|
|
||||||
{
|
|
||||||
PyObject* a1;
|
|
||||||
PyObject* a2;
|
|
||||||
PyObject* a3;
|
|
||||||
PyObject* a4;
|
|
||||||
PyObject* a5;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOO"), &a1, &a2, &a3, &a4, &a5))
|
|
||||||
throw argument_error();
|
|
||||||
return new T(self,
|
|
||||||
boost::python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
|
|
||||||
boost::python::detail::reference_parameter<A2>(from_python(a2, type<A2>())),
|
|
||||||
boost::python::detail::reference_parameter<A3>(from_python(a3, type<A3>())),
|
|
||||||
boost::python::detail::reference_parameter<A4>(from_python(a4, type<A4>())),
|
|
||||||
boost::python::detail::reference_parameter<A5>(from_python(a5, type<A5>()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(void (*)(T&, A1, A2, A3, A4, A5)).name(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T, class A1, class A2, class A3, class A4, class A5, class A6>
|
|
||||||
struct init6 : init
|
|
||||||
{
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
|
|
||||||
{
|
|
||||||
PyObject* a1;
|
|
||||||
PyObject* a2;
|
|
||||||
PyObject* a3;
|
|
||||||
PyObject* a4;
|
|
||||||
PyObject* a5;
|
|
||||||
PyObject* a6;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6))
|
|
||||||
throw argument_error();
|
|
||||||
return new T(self,
|
|
||||||
boost::python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
|
|
||||||
boost::python::detail::reference_parameter<A2>(from_python(a2, type<A2>())),
|
|
||||||
boost::python::detail::reference_parameter<A3>(from_python(a3, type<A3>())),
|
|
||||||
boost::python::detail::reference_parameter<A4>(from_python(a4, type<A4>())),
|
|
||||||
boost::python::detail::reference_parameter<A5>(from_python(a5, type<A5>())),
|
|
||||||
boost::python::detail::reference_parameter<A6>(from_python(a6, type<A6>()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6)).name(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
|
||||||
struct init7 : init
|
|
||||||
{
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
|
|
||||||
{
|
|
||||||
PyObject* a1;
|
|
||||||
PyObject* a2;
|
|
||||||
PyObject* a3;
|
|
||||||
PyObject* a4;
|
|
||||||
PyObject* a5;
|
|
||||||
PyObject* a6;
|
|
||||||
PyObject* a7;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7))
|
|
||||||
throw argument_error();
|
|
||||||
return new T(self,
|
|
||||||
boost::python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
|
|
||||||
boost::python::detail::reference_parameter<A2>(from_python(a2, type<A2>())),
|
|
||||||
boost::python::detail::reference_parameter<A3>(from_python(a3, type<A3>())),
|
|
||||||
boost::python::detail::reference_parameter<A4>(from_python(a4, type<A4>())),
|
|
||||||
boost::python::detail::reference_parameter<A5>(from_python(a5, type<A5>())),
|
|
||||||
boost::python::detail::reference_parameter<A6>(from_python(a6, type<A6>())),
|
|
||||||
boost::python::detail::reference_parameter<A7>(from_python(a7, type<A7>()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7)).name(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
|
||||||
struct init8 : init
|
|
||||||
{
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
|
|
||||||
{
|
|
||||||
PyObject* a1;
|
|
||||||
PyObject* a2;
|
|
||||||
PyObject* a3;
|
|
||||||
PyObject* a4;
|
|
||||||
PyObject* a5;
|
|
||||||
PyObject* a6;
|
|
||||||
PyObject* a7;
|
|
||||||
PyObject* a8;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8))
|
|
||||||
throw argument_error();
|
|
||||||
return new T(self,
|
|
||||||
boost::python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
|
|
||||||
boost::python::detail::reference_parameter<A2>(from_python(a2, type<A2>())),
|
|
||||||
boost::python::detail::reference_parameter<A3>(from_python(a3, type<A3>())),
|
|
||||||
boost::python::detail::reference_parameter<A4>(from_python(a4, type<A4>())),
|
|
||||||
boost::python::detail::reference_parameter<A5>(from_python(a5, type<A5>())),
|
|
||||||
boost::python::detail::reference_parameter<A6>(from_python(a6, type<A6>())),
|
|
||||||
boost::python::detail::reference_parameter<A7>(from_python(a7, type<A7>())),
|
|
||||||
boost::python::detail::reference_parameter<A8>(from_python(a8, type<A8>()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7, A8)).name(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
|
|
||||||
struct init9 : init
|
|
||||||
{
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
|
|
||||||
{
|
|
||||||
PyObject* a1;
|
|
||||||
PyObject* a2;
|
|
||||||
PyObject* a3;
|
|
||||||
PyObject* a4;
|
|
||||||
PyObject* a5;
|
|
||||||
PyObject* a6;
|
|
||||||
PyObject* a7;
|
|
||||||
PyObject* a8;
|
|
||||||
PyObject* a9;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9))
|
|
||||||
throw argument_error();
|
|
||||||
return new T(self,
|
|
||||||
boost::python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
|
|
||||||
boost::python::detail::reference_parameter<A2>(from_python(a2, type<A2>())),
|
|
||||||
boost::python::detail::reference_parameter<A3>(from_python(a3, type<A3>())),
|
|
||||||
boost::python::detail::reference_parameter<A4>(from_python(a4, type<A4>())),
|
|
||||||
boost::python::detail::reference_parameter<A5>(from_python(a5, type<A5>())),
|
|
||||||
boost::python::detail::reference_parameter<A6>(from_python(a6, type<A6>())),
|
|
||||||
boost::python::detail::reference_parameter<A7>(from_python(a7, type<A7>())),
|
|
||||||
boost::python::detail::reference_parameter<A8>(from_python(a8, type<A8>())),
|
|
||||||
boost::python::detail::reference_parameter<A9>(from_python(a9, type<A9>()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7, A8, A9)).name(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
|
|
||||||
struct init10 : init
|
|
||||||
{
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
|
|
||||||
{
|
|
||||||
PyObject* a1;
|
|
||||||
PyObject* a2;
|
|
||||||
PyObject* a3;
|
|
||||||
PyObject* a4;
|
|
||||||
PyObject* a5;
|
|
||||||
PyObject* a6;
|
|
||||||
PyObject* a7;
|
|
||||||
PyObject* a8;
|
|
||||||
PyObject* a9;
|
|
||||||
PyObject* a10;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOOOOOO"), &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10))
|
|
||||||
throw argument_error();
|
|
||||||
return new T(self,
|
|
||||||
boost::python::detail::reference_parameter<A1>(from_python(a1, type<A1>())),
|
|
||||||
boost::python::detail::reference_parameter<A2>(from_python(a2, type<A2>())),
|
|
||||||
boost::python::detail::reference_parameter<A3>(from_python(a3, type<A3>())),
|
|
||||||
boost::python::detail::reference_parameter<A4>(from_python(a4, type<A4>())),
|
|
||||||
boost::python::detail::reference_parameter<A5>(from_python(a5, type<A5>())),
|
|
||||||
boost::python::detail::reference_parameter<A6>(from_python(a6, type<A6>())),
|
|
||||||
boost::python::detail::reference_parameter<A7>(from_python(a7, type<A7>())),
|
|
||||||
boost::python::detail::reference_parameter<A8>(from_python(a8, type<A8>())),
|
|
||||||
boost::python::detail::reference_parameter<A9>(from_python(a9, type<A9>())),
|
|
||||||
boost::python::detail::reference_parameter<A10>(from_python(a10, type<A10>()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(void (*)(T&, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)).name(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
}}} // namespace boost::python::detail
|
|
||||||
|
|
||||||
#endif // INIT_FUNCTION_DWA052000_H_
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef NONE_DWA_052000_H_
|
|
||||||
# define NONE_DWA_052000_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/python/detail/wrap_python.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python { namespace detail {
|
|
||||||
|
|
||||||
inline PyObject* none() { Py_INCREF(Py_None); return Py_None; }
|
|
||||||
|
|
||||||
}}} // namespace boost::python::detail
|
|
||||||
|
|
||||||
#endif // NONE_DWA_052000_H_
|
|
||||||
@@ -1,251 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
//
|
|
||||||
// This file automatically generated by gen_signatures.python for 10 arguments.
|
|
||||||
#ifndef SIGNATURES_DWA050900_H_
|
|
||||||
# define SIGNATURES_DWA050900_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
// A stand-in for the built-in void. This one can be passed to functions and
|
|
||||||
// (under MSVC, which has a bug, be used as a default template type parameter).
|
|
||||||
struct void_t {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// An envelope in which type information can be delivered for the purposes
|
|
||||||
// of selecting an overloaded from_python() function. This is needed to work
|
|
||||||
// around MSVC's lack of partial specialiation/ordering. Where normally we'd
|
|
||||||
// want to form a function call like void f<const T&>(), We instead pass
|
|
||||||
// type<const T&> as one of the function parameters to select a particular
|
|
||||||
// overload.
|
|
||||||
//
|
|
||||||
// The id typedef helps us deal with the lack of partial ordering by generating
|
|
||||||
// unique types for constructor signatures. In general, type<T>::id is type<T>,
|
|
||||||
// but type<void_t>::id is just void_t.
|
|
||||||
template <class T>
|
|
||||||
struct type
|
|
||||||
{
|
|
||||||
typedef type id;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct type<boost::python::detail::void_t>
|
|
||||||
{
|
|
||||||
typedef boost::python::detail::void_t id;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
// These basically encapsulate a chain of types, , used to make the syntax of
|
|
||||||
// add(constructor<T1, ...>()) work. We need to produce a unique type for each number
|
|
||||||
// of non-default parameters to constructor<>. Q: why not use a recursive
|
|
||||||
// formulation for infinite extensibility? A: MSVC6 seems to choke on constructs
|
|
||||||
// that involve recursive template nesting.
|
|
||||||
//
|
|
||||||
// signature chaining
|
|
||||||
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10>
|
|
||||||
struct signature10 {};
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9>
|
|
||||||
struct signature9 {};
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class X>
|
|
||||||
inline signature10<X, T1, T2, T3, T4, T5, T6, T7, T8, T9> prepend(type<X>, signature9<T1, T2, T3, T4, T5, T6, T7, T8, T9>)
|
|
||||||
{ return signature10<X, T1, T2, T3, T4, T5, T6, T7, T8, T9>(); }
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
|
|
||||||
struct signature8 {};
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class X>
|
|
||||||
inline signature9<X, T1, T2, T3, T4, T5, T6, T7, T8> prepend(type<X>, signature8<T1, T2, T3, T4, T5, T6, T7, T8>)
|
|
||||||
{ return signature9<X, T1, T2, T3, T4, T5, T6, T7, T8>(); }
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7>
|
|
||||||
struct signature7 {};
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class X>
|
|
||||||
inline signature8<X, T1, T2, T3, T4, T5, T6, T7> prepend(type<X>, signature7<T1, T2, T3, T4, T5, T6, T7>)
|
|
||||||
{ return signature8<X, T1, T2, T3, T4, T5, T6, T7>(); }
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class T4, class T5, class T6>
|
|
||||||
struct signature6 {};
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class T4, class T5, class T6, class X>
|
|
||||||
inline signature7<X, T1, T2, T3, T4, T5, T6> prepend(type<X>, signature6<T1, T2, T3, T4, T5, T6>)
|
|
||||||
{ return signature7<X, T1, T2, T3, T4, T5, T6>(); }
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class T4, class T5>
|
|
||||||
struct signature5 {};
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class T4, class T5, class X>
|
|
||||||
inline signature6<X, T1, T2, T3, T4, T5> prepend(type<X>, signature5<T1, T2, T3, T4, T5>)
|
|
||||||
{ return signature6<X, T1, T2, T3, T4, T5>(); }
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class T4>
|
|
||||||
struct signature4 {};
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class T4, class X>
|
|
||||||
inline signature5<X, T1, T2, T3, T4> prepend(type<X>, signature4<T1, T2, T3, T4>)
|
|
||||||
{ return signature5<X, T1, T2, T3, T4>(); }
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3>
|
|
||||||
struct signature3 {};
|
|
||||||
|
|
||||||
template <class T1, class T2, class T3, class X>
|
|
||||||
inline signature4<X, T1, T2, T3> prepend(type<X>, signature3<T1, T2, T3>)
|
|
||||||
{ return signature4<X, T1, T2, T3>(); }
|
|
||||||
|
|
||||||
template <class T1, class T2>
|
|
||||||
struct signature2 {};
|
|
||||||
|
|
||||||
template <class T1, class T2, class X>
|
|
||||||
inline signature3<X, T1, T2> prepend(type<X>, signature2<T1, T2>)
|
|
||||||
{ return signature3<X, T1, T2>(); }
|
|
||||||
|
|
||||||
template <class T1>
|
|
||||||
struct signature1 {};
|
|
||||||
|
|
||||||
template <class T1, class X>
|
|
||||||
inline signature2<X, T1> prepend(type<X>, signature1<T1>)
|
|
||||||
{ return signature2<X, T1>(); }
|
|
||||||
|
|
||||||
struct signature0 {};
|
|
||||||
|
|
||||||
template <class X>
|
|
||||||
inline signature1<X> prepend(type<X>, signature0)
|
|
||||||
{ return signature1<X>(); }
|
|
||||||
|
|
||||||
|
|
||||||
// This one terminates the chain. Prepending void_t to the head of a void_t
|
|
||||||
// signature results in a void_t signature again.
|
|
||||||
inline signature0 prepend(void_t, signature0) { return signature0(); }
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template <class A1 = detail::void_t, class A2 = detail::void_t, class A3 = detail::void_t, class A4 = detail::void_t, class A5 = detail::void_t, class A6 = detail::void_t, class A7 = detail::void_t, class A8 = detail::void_t, class A9 = detail::void_t, class A10 = detail::void_t>
|
|
||||||
struct constructor
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
// Return value extraction:
|
|
||||||
|
|
||||||
// This is just another little envelope for carrying a typedef (see type,
|
|
||||||
// above). I could have re-used type, but that has a very specific purpose. I
|
|
||||||
// thought this would be clearer.
|
|
||||||
template <class T>
|
|
||||||
struct return_value_select { typedef T type; };
|
|
||||||
|
|
||||||
// free functions
|
|
||||||
template <class R>
|
|
||||||
return_value_select<R> return_value(R (*)()) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class A1>
|
|
||||||
return_value_select<R> return_value(R (*)(A1)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class A1, class A2>
|
|
||||||
return_value_select<R> return_value(R (*)(A1, A2)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class A1, class A2, class A3>
|
|
||||||
return_value_select<R> return_value(R (*)(A1, A2, A3)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class A1, class A2, class A3, class A4>
|
|
||||||
return_value_select<R> return_value(R (*)(A1, A2, A3, A4)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class A1, class A2, class A3, class A4, class A5>
|
|
||||||
return_value_select<R> return_value(R (*)(A1, A2, A3, A4, A5)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class A1, class A2, class A3, class A4, class A5, class A6>
|
|
||||||
return_value_select<R> return_value(R (*)(A1, A2, A3, A4, A5, A6)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
|
||||||
return_value_select<R> return_value(R (*)(A1, A2, A3, A4, A5, A6, A7)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
|
||||||
return_value_select<R> return_value(R (*)(A1, A2, A3, A4, A5, A6, A7, A8)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
|
|
||||||
return_value_select<R> return_value(R (*)(A1, A2, A3, A4, A5, A6, A7, A8, A9)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
|
|
||||||
return_value_select<R> return_value(R (*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
// TODO(?): handle 'const void'
|
|
||||||
|
|
||||||
// member functions
|
|
||||||
template <class R, class T>
|
|
||||||
return_value_select<R> return_value(R (T::*)()) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4, A5)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5, class A6>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4, A5, A6)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7, A8)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T>
|
|
||||||
return_value_select<R> return_value(R (T::*)() const) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1) const) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2) const) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3) const) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4) const) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4, A5) const) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5, class A6>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4, A5, A6) const) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7) const) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7, A8) const) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9) const) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
|
|
||||||
return_value_select<R> return_value(R (T::*)(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) const) { return return_value_select<R>(); }
|
|
||||||
|
|
||||||
}}} // namespace boost::python::detail
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef SINGLETON_DWA051900_H_
|
|
||||||
# define SINGLETON_DWA051900_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python { namespace detail {
|
|
||||||
|
|
||||||
struct empty {};
|
|
||||||
template <class Derived, class Base = empty>
|
|
||||||
struct singleton : Base
|
|
||||||
{
|
|
||||||
typedef singleton singleton_base; // Convenience type for derived class constructors
|
|
||||||
|
|
||||||
static Derived* instance();
|
|
||||||
|
|
||||||
// Pass-through constructors
|
|
||||||
singleton() : Base() {}
|
|
||||||
|
|
||||||
template <class A1>
|
|
||||||
singleton(const A1& a1) : Base(a1) {}
|
|
||||||
|
|
||||||
template <class A1, class A2>
|
|
||||||
singleton(const A1& a1, const A2& a2) : Base(a1, a2) {}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3>
|
|
||||||
singleton(const A1& a1, const A2& a2, const A3& a3) : Base(a1, a2, a3) {}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4>
|
|
||||||
singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4) : Base(a1, a2, a3, a4) {}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5>
|
|
||||||
singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) : Base(a1, a2, a3, a4, a5) {}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6>
|
|
||||||
singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) : Base(a1, a2, a3, a4, a5, a6) {}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
|
|
||||||
singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7) : Base(a1, a2, a3, a4, a5, a6, a7) {}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
|
|
||||||
singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8) : Base(a1, a2, a3, a4, a5, a6, a7, a8) {}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
|
|
||||||
singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9) : Base(a1, a2, a3, a4, a5, a6, a7, a8, a9) {}
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
|
|
||||||
singleton(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10) : Base(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) {}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Derived, class Base>
|
|
||||||
Derived* singleton<Derived,Base>::instance()
|
|
||||||
{
|
|
||||||
static Derived x;
|
|
||||||
return &x;
|
|
||||||
}
|
|
||||||
|
|
||||||
}}} // namespace boost::python::detail
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,389 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef TYPES_DWA051800_H_
|
|
||||||
# define TYPES_DWA051800_H_
|
|
||||||
|
|
||||||
// Usage:
|
|
||||||
// class X : public
|
|
||||||
// boost::python::callable<
|
|
||||||
// boost::python::getattrable <
|
|
||||||
// boost::python::setattrable<python_object, X> > >
|
|
||||||
// {
|
|
||||||
// public:
|
|
||||||
// ref call(args, kw);
|
|
||||||
// ref getattr(args, kw);
|
|
||||||
// ref setattr(args, kw);
|
|
||||||
// };
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/python/detail/signatures.hpp> // really just for type<>
|
|
||||||
# include <boost/python/detail/cast.hpp>
|
|
||||||
# include <boost/python/detail/base_object.hpp>
|
|
||||||
# include <typeinfo>
|
|
||||||
# include <vector>
|
|
||||||
# include <cassert>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
class string;
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
class instance_holder_base;
|
|
||||||
|
|
||||||
class type_object_base : public python_type
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit type_object_base(PyTypeObject* type_type);
|
|
||||||
virtual ~type_object_base();
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum capability {
|
|
||||||
hash, call, str, getattr, setattr, compare, repr,
|
|
||||||
|
|
||||||
mapping_length, mapping_subscript, mapping_ass_subscript,
|
|
||||||
|
|
||||||
sequence_length, sequence_item, sequence_ass_item,
|
|
||||||
sequence_concat, sequence_repeat, sequence_slice, sequence_ass_slice,
|
|
||||||
|
|
||||||
number_add, number_subtract, number_multiply, number_divide,
|
|
||||||
number_remainder, number_divmod, number_power, number_negative,
|
|
||||||
number_positive, number_absolute, number_nonzero, number_invert,
|
|
||||||
number_lshift, number_rshift, number_and, number_xor, number_or,
|
|
||||||
number_coerce, number_int, number_long, number_float, number_oct,
|
|
||||||
number_hex
|
|
||||||
};
|
|
||||||
|
|
||||||
void enable(capability);
|
|
||||||
|
|
||||||
//
|
|
||||||
// type behaviors
|
|
||||||
//
|
|
||||||
public: // Callbacks for basic type functionality.
|
|
||||||
virtual PyObject* instance_repr(PyObject*) const;
|
|
||||||
virtual int instance_compare(PyObject*, PyObject* other) const;
|
|
||||||
virtual PyObject* instance_str(PyObject*) const;
|
|
||||||
virtual long instance_hash(PyObject*) const;
|
|
||||||
virtual PyObject* instance_call(PyObject* obj, PyObject* args, PyObject* kw) const;
|
|
||||||
virtual PyObject* instance_getattr(PyObject* obj, const char* name) const;
|
|
||||||
virtual int instance_setattr(PyObject* obj, const char* name, PyObject* value) const;
|
|
||||||
|
|
||||||
// Dealloc is a special case, since every type needs a nonzero tp_dealloc slot.
|
|
||||||
virtual void instance_dealloc(PyObject*) const = 0;
|
|
||||||
|
|
||||||
public: // Callbacks for mapping methods
|
|
||||||
virtual int instance_mapping_length(PyObject*) const;
|
|
||||||
virtual PyObject* instance_mapping_subscript(PyObject*, PyObject*) const ;
|
|
||||||
virtual int instance_mapping_ass_subscript(PyObject*, PyObject*, PyObject*) const;
|
|
||||||
|
|
||||||
public: // Callbacks for sequence methods
|
|
||||||
virtual int instance_sequence_length(PyObject* obj) const;
|
|
||||||
virtual PyObject* instance_sequence_concat(PyObject* obj, PyObject* other) const;
|
|
||||||
virtual PyObject* instance_sequence_repeat(PyObject* obj, int n) const;
|
|
||||||
virtual PyObject* instance_sequence_item(PyObject* obj, int n) const;
|
|
||||||
virtual PyObject* instance_sequence_slice(PyObject* obj, int start, int finish) const;
|
|
||||||
virtual int instance_sequence_ass_item(PyObject* obj, int n, PyObject* value) const;
|
|
||||||
virtual int instance_sequence_ass_slice(PyObject* obj, int start, int finish, PyObject* value) const;
|
|
||||||
|
|
||||||
public: // Callbacks for number methods
|
|
||||||
virtual PyObject* instance_number_add(PyObject*, PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_subtract(PyObject*, PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_multiply(PyObject*, PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_divide(PyObject*, PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_remainder(PyObject*, PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_divmod(PyObject*, PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_power(PyObject*, PyObject*, PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_negative(PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_positive(PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_absolute(PyObject*) const;
|
|
||||||
virtual int instance_number_nonzero(PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_invert(PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_lshift(PyObject*, PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_rshift(PyObject*, PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_and(PyObject*, PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_xor(PyObject*, PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_or(PyObject*, PyObject*) const;
|
|
||||||
virtual int instance_number_coerce(PyObject*, PyObject**, PyObject**) const;
|
|
||||||
virtual PyObject* instance_number_int(PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_long(PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_float(PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_oct(PyObject*) const;
|
|
||||||
virtual PyObject* instance_number_hex(PyObject*) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class type_object : public type_object_base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef T instance;
|
|
||||||
|
|
||||||
type_object(PyTypeObject* type_type, const char* name)
|
|
||||||
: type_object_base(type_type)
|
|
||||||
{
|
|
||||||
assert(name != 0);
|
|
||||||
this->tp_name = const_cast<char*>(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
type_object(PyTypeObject* type_type)
|
|
||||||
: type_object_base(type_type)
|
|
||||||
{
|
|
||||||
this->tp_name = const_cast<char*>(typeid(instance).name());
|
|
||||||
}
|
|
||||||
|
|
||||||
private: // Overridable behaviors.
|
|
||||||
// Called when the reference count goes to zero. The default implementation
|
|
||||||
// is "delete p". If you have not allocated your object with operator new or
|
|
||||||
// you have other constraints, you'll need to override this
|
|
||||||
virtual void dealloc(T* p) const;
|
|
||||||
|
|
||||||
private: // Implementation of type_object_base hooks. Do not reimplement in derived classes.
|
|
||||||
void instance_dealloc(PyObject*) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// type objects
|
|
||||||
//
|
|
||||||
template <class Base>
|
|
||||||
class callable : public Base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef callable properties; // Convenience for derived class construction
|
|
||||||
typedef typename Base::instance instance;
|
|
||||||
callable(PyTypeObject* type_type, const char* name);
|
|
||||||
callable(PyTypeObject* type_type);
|
|
||||||
private:
|
|
||||||
PyObject* instance_call(PyObject* obj, PyObject* args, PyObject* kw) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Base>
|
|
||||||
class getattrable : public Base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef getattrable properties; // Convenience for derived class construction
|
|
||||||
typedef typename Base::instance instance;
|
|
||||||
getattrable(PyTypeObject* type_type, const char* name);
|
|
||||||
getattrable(PyTypeObject* type_type);
|
|
||||||
private:
|
|
||||||
PyObject* instance_getattr(PyObject* obj, const char* name) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Base>
|
|
||||||
class setattrable : public Base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef setattrable properties; // Convenience for derived class construction
|
|
||||||
typedef typename Base::instance instance;
|
|
||||||
setattrable(PyTypeObject* type_type, const char* name);
|
|
||||||
setattrable(PyTypeObject* type_type);
|
|
||||||
private:
|
|
||||||
int instance_setattr(PyObject* obj, const char* name, PyObject* value) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Base>
|
|
||||||
class reprable : public Base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef reprable properties; // Convenience for derived class construction
|
|
||||||
typedef typename Base::instance instance;
|
|
||||||
reprable(PyTypeObject* type_type, const char* name);
|
|
||||||
reprable(PyTypeObject* type_type);
|
|
||||||
private:
|
|
||||||
PyObject* instance_repr(PyObject* obj) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Member function definitions
|
|
||||||
//
|
|
||||||
|
|
||||||
// type_object<>
|
|
||||||
template <class T>
|
|
||||||
void type_object<T>::instance_dealloc(PyObject* obj) const
|
|
||||||
{
|
|
||||||
this->dealloc(downcast<instance>(obj).get());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void type_object<T>::dealloc(T* obj) const
|
|
||||||
{
|
|
||||||
delete obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
// callable
|
|
||||||
template <class Base>
|
|
||||||
callable<Base>::callable(PyTypeObject* type_type, const char* name)
|
|
||||||
: Base(type_type, name)
|
|
||||||
{
|
|
||||||
this->enable(call);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Base>
|
|
||||||
callable<Base>::callable(PyTypeObject* type_type)
|
|
||||||
: Base(type_type)
|
|
||||||
{
|
|
||||||
this->enable(call);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Base>
|
|
||||||
PyObject* callable<Base>::instance_call(PyObject* obj, PyObject* args, PyObject* kw) const
|
|
||||||
{
|
|
||||||
return downcast<instance>(obj)->call(args, kw);
|
|
||||||
}
|
|
||||||
|
|
||||||
// getattrable
|
|
||||||
template <class Base>
|
|
||||||
getattrable<Base>::getattrable(PyTypeObject* type_type, const char* name)
|
|
||||||
: Base(type_type, name)
|
|
||||||
{
|
|
||||||
this->enable(getattr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Base>
|
|
||||||
getattrable<Base>::getattrable(PyTypeObject* type_type)
|
|
||||||
: Base(type_type)
|
|
||||||
{
|
|
||||||
this->enable(getattr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Base>
|
|
||||||
PyObject* getattrable<Base>::instance_getattr(PyObject* obj, const char* name) const
|
|
||||||
{
|
|
||||||
return downcast<instance>(obj)->getattr(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// setattrable
|
|
||||||
template <class Base>
|
|
||||||
setattrable<Base>::setattrable(PyTypeObject* type_type, const char* name)
|
|
||||||
: Base(type_type, name)
|
|
||||||
{
|
|
||||||
this->enable(setattr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Base>
|
|
||||||
setattrable<Base>::setattrable(PyTypeObject* type_type)
|
|
||||||
: Base(type_type)
|
|
||||||
{
|
|
||||||
this->enable(setattr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Base>
|
|
||||||
int setattrable<Base>::instance_setattr(PyObject* obj, const char* name, PyObject* value) const
|
|
||||||
{
|
|
||||||
return downcast<instance>(obj)->setattr(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// reprable
|
|
||||||
template <class Base>
|
|
||||||
reprable<Base>::reprable(PyTypeObject* type_type, const char* name)
|
|
||||||
: Base(type_type, name)
|
|
||||||
{
|
|
||||||
this->enable(repr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Base>
|
|
||||||
reprable<Base>::reprable(PyTypeObject* type_type)
|
|
||||||
: Base(type_type)
|
|
||||||
{
|
|
||||||
this->enable(repr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Base>
|
|
||||||
PyObject* reprable<Base>::instance_repr(PyObject* obj) const
|
|
||||||
{
|
|
||||||
return downcast<instance>(obj)->repr();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper class for optimized allocation of PODs: If two PODs
|
|
||||||
// happen to contain identical byte patterns, they may share their
|
|
||||||
// memory. Reference counting is used to free unused memory.
|
|
||||||
// This is useful because method tables of related extension classes tend
|
|
||||||
// to be identical, so less memory is needed for them.
|
|
||||||
class shared_pod_manager
|
|
||||||
{
|
|
||||||
typedef std::pair<char*, std::size_t> holder;
|
|
||||||
typedef std::vector<holder> storage;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static shared_pod_manager& obj();
|
|
||||||
~shared_pod_manager();
|
|
||||||
|
|
||||||
// Allocate memory for POD T and fill it with zeros.
|
|
||||||
// This memory is initially not shared.
|
|
||||||
template <class T>
|
|
||||||
static void create(T*& t)
|
|
||||||
{
|
|
||||||
t = reinterpret_cast<T*>(obj().create(sizeof(T)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrement the refcount for the memory t points to. If the count
|
|
||||||
// goes to zero, the memory is freed.
|
|
||||||
template <class T>
|
|
||||||
static void dispose(T* t)
|
|
||||||
{
|
|
||||||
obj().dec_ref(t, sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to share the memory t points to. If memory with the same
|
|
||||||
// contents already exists, t is replaced by a pointer to this memory,
|
|
||||||
// and t's old memory is disposed. Otherwise, t will be registered for
|
|
||||||
// potential future sharing.
|
|
||||||
template <class T>
|
|
||||||
static void replace_if_equal(T*& t)
|
|
||||||
{
|
|
||||||
t = reinterpret_cast<T*>(obj().replace_if_equal(t, sizeof(T)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a copy of t's memory that is guaranteed to be private to t.
|
|
||||||
// Afterwards t points to the new memory, unless it was already private, in
|
|
||||||
// which case there is no change (except that t's memory will no longer
|
|
||||||
// be considered for future sharing - see raplade_if_equal())
|
|
||||||
// This function *must* be called before the contents of (*t) can
|
|
||||||
// be overwritten. Otherwise, inconsistencies and crashes may result.
|
|
||||||
template <class T>
|
|
||||||
static void make_unique_copy(T*& t)
|
|
||||||
{
|
|
||||||
t = reinterpret_cast<T*>(obj().make_unique_copy(t, sizeof(T)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void* replace_if_equal(void* pod, std::size_t size);
|
|
||||||
void* make_unique_copy(void* pod, std::size_t size);
|
|
||||||
void* create(std::size_t size);
|
|
||||||
void dec_ref(void* pod, std::size_t size);
|
|
||||||
void erase_from_list(void* pod);
|
|
||||||
|
|
||||||
struct compare;
|
|
||||||
struct identical;
|
|
||||||
|
|
||||||
private:
|
|
||||||
shared_pod_manager() {} // instance
|
|
||||||
|
|
||||||
#ifdef TYPE_OBJECT_BASE_STANDALONE_TEST
|
|
||||||
public:
|
|
||||||
#endif
|
|
||||||
storage m_storage;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void add_capability(type_object_base::capability capability,
|
|
||||||
PyTypeObject* dest);
|
|
||||||
|
|
||||||
// This macro gets the length of an array as a compile-time constant, and will
|
|
||||||
// fail to compile if the parameter is a pointer.
|
|
||||||
# define PY_ARRAY_LENGTH(a) \
|
|
||||||
(sizeof(::boost::python::detail::countof_validate(a, &(a))) ? sizeof(a) / sizeof((a)[0]) : 0)
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline void countof_validate(T* const, T* const*);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline int countof_validate(const void*, T);
|
|
||||||
|
|
||||||
}}} // namespace boost::python::detail
|
|
||||||
|
|
||||||
#endif // TYPES_DWA051800_H_
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
// This file serves as a wrapper around <Python.h> which allows it to be
|
|
||||||
// compiled with GCC 2.95.2 under Win32 and which disables the default MSVC
|
|
||||||
// behavior so that a program may be compiled in debug mode without requiring a
|
|
||||||
// special debugging build of the Python library.
|
|
||||||
|
|
||||||
|
|
||||||
// To use the Python debugging library, #define BOOST_DEBUG_PYTHON on the
|
|
||||||
// compiler command-line.
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
# ifndef BOOST_DEBUG_PYTHON
|
|
||||||
# undef _DEBUG // Don't let Python force the debug library just because we're debugging.
|
|
||||||
# define DEBUG_UNDEFINED_FROM_WRAP_PYTHON_H
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
|
||||||
// Some things we need in order to get Python.h to work with compilers other
|
|
||||||
// than MSVC on Win32
|
|
||||||
//
|
|
||||||
#if defined(_WIN32)
|
|
||||||
# ifdef __GNUC__
|
|
||||||
|
|
||||||
typedef int pid_t;
|
|
||||||
# define WORD_BIT 32
|
|
||||||
# define hypot _hypot
|
|
||||||
# include <stdio.h>
|
|
||||||
# define HAVE_CLOCK
|
|
||||||
# define HAVE_STRFTIME
|
|
||||||
# define HAVE_STRERROR
|
|
||||||
# define NT_THREADS
|
|
||||||
# define WITH_THREAD
|
|
||||||
# ifndef NETSCAPE_PI
|
|
||||||
# define USE_SOCKET
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# ifdef USE_DL_IMPORT
|
|
||||||
# define DL_IMPORT(RTYPE) __declspec(dllimport) RTYPE
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# ifdef USE_DL_EXPORT
|
|
||||||
# define DL_IMPORT(RTYPE) __declspec(dllexport) RTYPE
|
|
||||||
# define DL_EXPORT(RTYPE) __declspec(dllexport) RTYPE
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# define HAVE_LONG_LONG 1
|
|
||||||
# define LONG_LONG long long
|
|
||||||
|
|
||||||
# elif defined(__MWERKS__)
|
|
||||||
|
|
||||||
# ifndef _MSC_VER
|
|
||||||
# define PY_MSC_VER_DEFINED_FROM_WRAP_PYTHON_H 1
|
|
||||||
# define _MSC_VER 900
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif // _WIN32
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
|
|
||||||
#ifdef PY_MSC_VER_DEFINED_FROM_WRAP_PYTHON_H
|
|
||||||
# undef _MSC_VER
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG_UNDEFINED_FROM_WRAP_PYTHON_H
|
|
||||||
# undef DEBUG_UNDEFINED_FROM_WRAP_PYTHON_H
|
|
||||||
# define _DEBUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef ERRORS_DWA052500_H_
|
|
||||||
# define ERRORS_DWA052500_H_
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
struct error_already_set {};
|
|
||||||
struct argument_error : error_already_set {};
|
|
||||||
|
|
||||||
// Handles exceptions caught just before returning to Python code.
|
|
||||||
void handle_exception();
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
T* expect_non_null(T* x)
|
|
||||||
{
|
|
||||||
if (x == 0)
|
|
||||||
throw error_already_set();
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
|
|
||||||
#endif // ERRORS_DWA052500_H_
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef MODULE_DWA051000_H_
|
|
||||||
# define MODULE_DWA051000_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/python/reference.hpp>
|
|
||||||
# include <boost/python/objects.hpp>
|
|
||||||
# include <boost/python/detail/functions.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
class module_builder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Create a module. REQUIRES: only one module_builder is created per module.
|
|
||||||
module_builder(const char* name);
|
|
||||||
~module_builder();
|
|
||||||
|
|
||||||
// Add elements to the module
|
|
||||||
void add(detail::function* x, const char* name);
|
|
||||||
void add(PyTypeObject* x, const char* name = 0);
|
|
||||||
void add(ref x, const char*name);
|
|
||||||
|
|
||||||
template <class Fn>
|
|
||||||
void def_raw(Fn fn, const char* name)
|
|
||||||
{
|
|
||||||
add(detail::new_raw_arguments_function(fn), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Fn>
|
|
||||||
void def(Fn fn, const char* name)
|
|
||||||
{
|
|
||||||
add(detail::new_wrapped_function(fn), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true iff a module is currently being built.
|
|
||||||
static bool initializing();
|
|
||||||
|
|
||||||
// Return the name of the module currently being built.
|
|
||||||
// REQUIRES: initializing() == true
|
|
||||||
static string name();
|
|
||||||
|
|
||||||
// Return a pointer to the Python module object being built
|
|
||||||
PyObject* module() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
PyObject* m_module;
|
|
||||||
static PyMethodDef initial_methods[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// inline implementations
|
|
||||||
//
|
|
||||||
inline PyObject* module_builder::module() const
|
|
||||||
{
|
|
||||||
return m_module;
|
|
||||||
}
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,334 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef OBJECTS_DWA051100_H_
|
|
||||||
# define OBJECTS_DWA051100_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/wrap_python.hpp>
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/python/reference.hpp>
|
|
||||||
# include "boost/operators.hpp"
|
|
||||||
# include <utility>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
class object
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit object(ref p);
|
|
||||||
|
|
||||||
// Return a reference to the held object
|
|
||||||
ref reference() const;
|
|
||||||
|
|
||||||
// Return a raw pointer to the held object
|
|
||||||
PyObject* get() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
ref m_p;
|
|
||||||
};
|
|
||||||
|
|
||||||
class tuple : public object
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit tuple(std::size_t n = 0);
|
|
||||||
explicit tuple(ref p);
|
|
||||||
|
|
||||||
template <class First, class Second>
|
|
||||||
tuple(const std::pair<First,Second>& x)
|
|
||||||
: object(ref(PyTuple_New(2)))
|
|
||||||
{
|
|
||||||
set_item(0, x.first);
|
|
||||||
set_item(1, x.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class First, class Second>
|
|
||||||
tuple(const First& first, const Second& second)
|
|
||||||
: object(ref(PyTuple_New(2)))
|
|
||||||
{
|
|
||||||
set_item(0, first);
|
|
||||||
set_item(1, second);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class First, class Second, class Third>
|
|
||||||
tuple(const First& first, const Second& second, const Third& third)
|
|
||||||
: object(ref(PyTuple_New(3)))
|
|
||||||
{
|
|
||||||
set_item(0, first);
|
|
||||||
set_item(1, second);
|
|
||||||
set_item(2, third);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class First, class Second, class Third, class Fourth>
|
|
||||||
tuple(const First& first, const Second& second, const Third& third, const Fourth& fourth)
|
|
||||||
: object(ref(PyTuple_New(4)))
|
|
||||||
{
|
|
||||||
set_item(0, first);
|
|
||||||
set_item(1, second);
|
|
||||||
set_item(2, third);
|
|
||||||
set_item(3, fourth);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyTypeObject* type_obj();
|
|
||||||
static bool accepts(ref p);
|
|
||||||
std::size_t size() const;
|
|
||||||
ref operator[](std::size_t pos) const;
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void set_item(std::size_t pos, const T& rhs)
|
|
||||||
{
|
|
||||||
this->set_item(pos, make_ref(rhs));
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_item(std::size_t pos, const ref& rhs);
|
|
||||||
|
|
||||||
tuple slice(int low, int high) const;
|
|
||||||
|
|
||||||
friend tuple operator+(const tuple&, const tuple&);
|
|
||||||
tuple& operator+=(const tuple& rhs);
|
|
||||||
};
|
|
||||||
|
|
||||||
class list : public object
|
|
||||||
{
|
|
||||||
struct proxy;
|
|
||||||
struct slice_proxy;
|
|
||||||
public:
|
|
||||||
explicit list(ref p);
|
|
||||||
explicit list(std::size_t sz = 0);
|
|
||||||
static PyTypeObject* type_obj();
|
|
||||||
static bool accepts(ref p);
|
|
||||||
std::size_t size();
|
|
||||||
ref operator[](std::size_t pos) const;
|
|
||||||
proxy operator[](std::size_t pos);
|
|
||||||
ref get_item(std::size_t pos) const;
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void set_item(std::size_t pos, const T& x)
|
|
||||||
{ this->set_item(pos, make_ref(x)); }
|
|
||||||
void set_item(std::size_t pos, const ref& );
|
|
||||||
|
|
||||||
// void set_item(std::size_t pos, const object& );
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void insert(std::size_t index, const T& x)
|
|
||||||
{ this->insert(index, make_ref(x)); }
|
|
||||||
void insert(std::size_t index, const ref& item);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void push_back(const T& item)
|
|
||||||
{ this->push_back(make_ref(item)); }
|
|
||||||
void push_back(const ref& item);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void append(const T& item)
|
|
||||||
{ this->append(make_ref(item)); }
|
|
||||||
void append(const ref& item);
|
|
||||||
|
|
||||||
list slice(int low, int high) const;
|
|
||||||
slice_proxy slice(int low, int high);
|
|
||||||
void sort();
|
|
||||||
void reverse();
|
|
||||||
tuple as_tuple() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class string
|
|
||||||
: public object, public boost::multipliable2<string, unsigned int>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Construct from an owned PyObject*.
|
|
||||||
// Precondition: p must point to a python string.
|
|
||||||
explicit string(ref p);
|
|
||||||
explicit string(const char* s);
|
|
||||||
string(const char* s, std::size_t length);
|
|
||||||
string(const string& rhs);
|
|
||||||
|
|
||||||
enum interned_t { interned };
|
|
||||||
string(const char* s, interned_t);
|
|
||||||
|
|
||||||
// Get the type object for Strings
|
|
||||||
static PyTypeObject* type_obj();
|
|
||||||
|
|
||||||
// Return true if the given object is a python string
|
|
||||||
static bool accepts(ref o);
|
|
||||||
|
|
||||||
// Return the length of the string.
|
|
||||||
std::size_t size() const;
|
|
||||||
|
|
||||||
// Returns a null-terminated representation of the contents of string.
|
|
||||||
// The pointer refers to the internal buffer of string, not a copy.
|
|
||||||
// The data must not be modified in any way. It must not be de-allocated.
|
|
||||||
const char* c_str() const;
|
|
||||||
|
|
||||||
string& operator*=(unsigned int repeat_count);
|
|
||||||
string& operator+=(const string& rhs);
|
|
||||||
friend string operator+(string x, string y);
|
|
||||||
string& operator+=(const char* rhs);
|
|
||||||
friend string operator+(string x, const char* y);
|
|
||||||
friend string operator+(const char* x, string y);
|
|
||||||
|
|
||||||
void intern();
|
|
||||||
|
|
||||||
friend string operator%(const string& format, const tuple& args);
|
|
||||||
};
|
|
||||||
|
|
||||||
class dictionary : public object
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
struct proxy;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit dictionary(ref p);
|
|
||||||
dictionary();
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
static PyTypeObject* type_obj();
|
|
||||||
static bool accepts(ref p);
|
|
||||||
|
|
||||||
public:
|
|
||||||
template <class Key>
|
|
||||||
proxy operator[](const Key& key)
|
|
||||||
{ return this->operator[](make_ref(key)); }
|
|
||||||
proxy operator[](ref key);
|
|
||||||
|
|
||||||
template <class Key>
|
|
||||||
ref operator[](const Key& key) const
|
|
||||||
{ return this->operator[](make_ref(key)); }
|
|
||||||
ref operator[](ref key) const;
|
|
||||||
|
|
||||||
template <class Key>
|
|
||||||
ref get_item(const Key& key) const
|
|
||||||
{ return this->get_item(make_ref(key)); }
|
|
||||||
ref get_item(const ref& key) const;
|
|
||||||
|
|
||||||
template <class Key, class Default>
|
|
||||||
ref get_item(const Key& key, const Default& default_) const
|
|
||||||
{ return this->get_item(make_ref(key), make_ref(default_)); }
|
|
||||||
ref get_item(const ref& key, const ref& default_) const;
|
|
||||||
|
|
||||||
template <class Key, class Value>
|
|
||||||
void set_item(const Key& key, const Value& value)
|
|
||||||
{ this->set_item(make_ref(key), make_ref(value)); }
|
|
||||||
void set_item(const ref& key, const ref& value);
|
|
||||||
|
|
||||||
template <class Key>
|
|
||||||
void erase(const Key& key)
|
|
||||||
{ this->erase(make_ref(key)); }
|
|
||||||
void erase(ref key);
|
|
||||||
|
|
||||||
// proxy operator[](const object& key);
|
|
||||||
// ref operator[](const object& key) const;
|
|
||||||
|
|
||||||
// ref get_item(const object& key, ref default_ = ref()) const;
|
|
||||||
// void set_item(const object& key, const ref& value);
|
|
||||||
|
|
||||||
// void erase(const object& key);
|
|
||||||
|
|
||||||
list items() const;
|
|
||||||
list keys() const;
|
|
||||||
list values() const;
|
|
||||||
|
|
||||||
std::size_t size() const;
|
|
||||||
// TODO: iterator support
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dictionary::proxy
|
|
||||||
{
|
|
||||||
template <class T>
|
|
||||||
const ref& operator=(const T& rhs)
|
|
||||||
{ return (*this) = make_ref(rhs); }
|
|
||||||
const ref& operator=(const ref& rhs);
|
|
||||||
|
|
||||||
operator ref() const;
|
|
||||||
private:
|
|
||||||
friend class dictionary;
|
|
||||||
proxy(const ref& dict, const ref& key);
|
|
||||||
|
|
||||||
// This is needed to work around the very strange MSVC error report that the
|
|
||||||
// return type of the built-in operator= differs from that of the ones
|
|
||||||
// defined above. Couldn't hurt to make these un-assignable anyway, though.
|
|
||||||
const ref& operator=(const proxy&); // Not actually implemented
|
|
||||||
private:
|
|
||||||
ref m_dict;
|
|
||||||
ref m_key;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct list::proxy
|
|
||||||
{
|
|
||||||
template <class T>
|
|
||||||
const ref& operator=(const T& rhs)
|
|
||||||
{ return (*this) = make_ref(rhs); }
|
|
||||||
const ref& operator=(const ref& rhs);
|
|
||||||
|
|
||||||
operator ref() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class list;
|
|
||||||
proxy(const ref& list, std::size_t index);
|
|
||||||
|
|
||||||
// This is needed to work around the very strange MSVC error report that the
|
|
||||||
// return type of the built-in operator= differs from that of the ones
|
|
||||||
// defined above. Couldn't hurt to make these un-assignable anyway, though.
|
|
||||||
const ref& operator=(const proxy&); // Not actually implemented
|
|
||||||
private:
|
|
||||||
list m_list;
|
|
||||||
std::size_t m_index;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct list::slice_proxy
|
|
||||||
{
|
|
||||||
const list& operator=(const list& rhs);
|
|
||||||
operator ref() const;
|
|
||||||
operator list() const;
|
|
||||||
std::size_t size();
|
|
||||||
ref operator[](std::size_t pos) const;
|
|
||||||
private:
|
|
||||||
friend class list;
|
|
||||||
slice_proxy(const ref& list, int low, int high);
|
|
||||||
private:
|
|
||||||
ref m_list;
|
|
||||||
int m_low, m_high;
|
|
||||||
};
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
|
|
||||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
|
||||||
|
|
||||||
PyObject* to_python(const boost::python::tuple&);
|
|
||||||
boost::python::tuple from_python(PyObject* p, boost::python::type<boost::python::tuple>);
|
|
||||||
|
|
||||||
inline boost::python::tuple from_python(PyObject* p, boost::python::type<const boost::python::tuple&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<boost::python::tuple>());
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(const boost::python::list&);
|
|
||||||
boost::python::list from_python(PyObject* p, boost::python::type<boost::python::list>);
|
|
||||||
|
|
||||||
inline boost::python::list from_python(PyObject* p, boost::python::type<const boost::python::list&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<boost::python::list>());
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(const boost::python::string&);
|
|
||||||
boost::python::string from_python(PyObject* p, boost::python::type<boost::python::string>);
|
|
||||||
|
|
||||||
inline boost::python::string from_python(PyObject* p, boost::python::type<const boost::python::string&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<boost::python::string>());
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(const boost::python::dictionary&);
|
|
||||||
boost::python::dictionary from_python(PyObject* p, boost::python::type<boost::python::dictionary>);
|
|
||||||
|
|
||||||
inline boost::python::dictionary from_python(PyObject* p, boost::python::type<const boost::python::dictionary&>)
|
|
||||||
{
|
|
||||||
return from_python(p, boost::python::type<boost::python::dictionary>());
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
|
||||||
|
|
||||||
#endif // OBJECTS_DWA051100_H_
|
|
||||||
@@ -1,509 +0,0 @@
|
|||||||
#ifndef OPERATORS_UK112000_H_
|
|
||||||
#define OPERATORS_UK112000_H_
|
|
||||||
|
|
||||||
# include <boost/python/reference.hpp>
|
|
||||||
# include <boost/python/detail/functions.hpp>
|
|
||||||
|
|
||||||
// When STLport is used with native streams, _STL::ostringstream().str() is not
|
|
||||||
// _STL::string, but std::string. This confuses to_python(), so we'll use
|
|
||||||
// strstream instead. Also, GCC 2.95.2 doesn't have sstream.
|
|
||||||
# if defined(__SGI_STL_PORT) ? defined(__SGI_STL_OWN_IOSTREAMS) : (!defined(__GNUC__) || __GNUC__ > 2)
|
|
||||||
# include <sstream>
|
|
||||||
# else
|
|
||||||
# include <strstream>
|
|
||||||
# endif
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
tuple standard_coerce(ref l, ref r);
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
// helper class for automatic operand type detection
|
|
||||||
// during operator wrapping.
|
|
||||||
struct auto_operand {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define operator ids that can be or'ed together
|
|
||||||
// (boost::python::op_add | boost::python::op_sub | boost::python::op_mul).
|
|
||||||
// This allows to wrap several operators in one line.
|
|
||||||
enum operator_id
|
|
||||||
{
|
|
||||||
op_add = 0x1,
|
|
||||||
op_sub = 0x2,
|
|
||||||
op_mul = 0x4,
|
|
||||||
op_div = 0x8,
|
|
||||||
op_mod = 0x10,
|
|
||||||
op_divmod =0x20,
|
|
||||||
op_pow = 0x40,
|
|
||||||
op_lshift = 0x80,
|
|
||||||
op_rshift = 0x100,
|
|
||||||
op_and = 0x200,
|
|
||||||
op_xor = 0x400,
|
|
||||||
op_or = 0x800,
|
|
||||||
op_neg = 0x1000,
|
|
||||||
op_pos = 0x2000,
|
|
||||||
op_abs = 0x4000,
|
|
||||||
op_invert = 0x8000,
|
|
||||||
op_int = 0x10000,
|
|
||||||
op_long = 0x20000,
|
|
||||||
op_float = 0x40000,
|
|
||||||
op_str = 0x80000,
|
|
||||||
op_cmp = 0x100000
|
|
||||||
};
|
|
||||||
|
|
||||||
// Wrap the operators given by "which". Usage:
|
|
||||||
// foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>());
|
|
||||||
template <long which, class operand = boost::python::detail::auto_operand>
|
|
||||||
struct operators {};
|
|
||||||
|
|
||||||
// Wrap heterogeneous operators with given left operand type. Usage:
|
|
||||||
// foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>(),
|
|
||||||
// boost::python::left_operand<int>());
|
|
||||||
template <class T>
|
|
||||||
struct left_operand {};
|
|
||||||
|
|
||||||
// Wrap heterogeneous operators with given right operand type. Usage:
|
|
||||||
// foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>(),
|
|
||||||
// boost::python::right_operand<int>());
|
|
||||||
template <class T>
|
|
||||||
struct right_operand {};
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
template <class Specified>
|
|
||||||
struct operand_select
|
|
||||||
{
|
|
||||||
template <class wrapped_type>
|
|
||||||
struct wrapped
|
|
||||||
{
|
|
||||||
typedef Specified type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct operand_select<auto_operand>
|
|
||||||
{
|
|
||||||
template <class wrapped_type>
|
|
||||||
struct wrapped
|
|
||||||
{
|
|
||||||
typedef const wrapped_type& type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <long> struct define_operator;
|
|
||||||
|
|
||||||
// Base class which grants access to extension_class_base::add_method() to its derived classes
|
|
||||||
struct add_operator_base
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
static inline void add_method(extension_class_base* target, function* method, const char* name)
|
|
||||||
{ target->add_method(method, name); }
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// choose_op, choose_unary_op, and choose_rop
|
|
||||||
//
|
|
||||||
// These templates use "poor man's partial specialization" to generate the
|
|
||||||
// appropriate add_method() call (if any) for a given operator and argument set.
|
|
||||||
//
|
|
||||||
// Usage:
|
|
||||||
// choose_op<(which & op_add)>::template args<left_t,right_t>::add(ext_class);
|
|
||||||
//
|
|
||||||
// (see extension_class<>::def_operators() for more examples).
|
|
||||||
//
|
|
||||||
template <long op_selector>
|
|
||||||
struct choose_op
|
|
||||||
{
|
|
||||||
template <class Left, class Right = Left>
|
|
||||||
struct args : add_operator_base
|
|
||||||
{
|
|
||||||
static inline void add(extension_class_base* target)
|
|
||||||
{
|
|
||||||
typedef define_operator<op_selector> def_op;
|
|
||||||
add_method(target,
|
|
||||||
new typename def_op::template operator_function<Left, Right>(),
|
|
||||||
def_op::name());
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// specialization for 0 has no effect
|
|
||||||
template <>
|
|
||||||
struct choose_op<0>
|
|
||||||
{
|
|
||||||
template <class Left, class Right = Left>
|
|
||||||
struct args
|
|
||||||
{
|
|
||||||
static inline void add(extension_class_base*)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <long op_selector>
|
|
||||||
struct choose_unary_op
|
|
||||||
{
|
|
||||||
template <class Operand>
|
|
||||||
struct args : add_operator_base
|
|
||||||
{
|
|
||||||
static inline void add(extension_class_base* target)
|
|
||||||
{
|
|
||||||
typedef define_operator<op_selector> def_op;
|
|
||||||
add_method(target,
|
|
||||||
new typename def_op::template operator_function<Operand>(),
|
|
||||||
def_op::name());
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// specialization for 0 has no effect
|
|
||||||
template <>
|
|
||||||
struct choose_unary_op<0>
|
|
||||||
{
|
|
||||||
template <class Operand>
|
|
||||||
struct args
|
|
||||||
{
|
|
||||||
static inline void add(extension_class_base*)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <long op_selector>
|
|
||||||
struct choose_rop
|
|
||||||
{
|
|
||||||
template <class Left, class Right = Left>
|
|
||||||
struct args : add_operator_base
|
|
||||||
{
|
|
||||||
static inline void add(extension_class_base* target)
|
|
||||||
{
|
|
||||||
typedef define_operator<op_selector> def_op;
|
|
||||||
add_method(target,
|
|
||||||
new typename def_op::template roperator_function<Right, Left>(),
|
|
||||||
def_op::rname());
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// specialization for 0 has no effect
|
|
||||||
template <>
|
|
||||||
struct choose_rop<0>
|
|
||||||
{
|
|
||||||
template <class Left, class Right = Left>
|
|
||||||
struct args
|
|
||||||
{
|
|
||||||
static inline void add(extension_class_base*)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Fully specialize define_operator for all operators defined in operator_id above.
|
|
||||||
// Every specialization defines one function object for normal operator calls and one
|
|
||||||
// for operator calls with operands reversed ("__r*__" function variants).
|
|
||||||
// Specializations for most operators follow a standard pattern: execute the expression
|
|
||||||
// that uses the operator in question. This standard pattern is realized by the following
|
|
||||||
// macros so that the actual specialization can be done by just calling a macro.
|
|
||||||
#define PY_DEFINE_BINARY_OPERATORS(id, oper) \
|
|
||||||
template <> \
|
|
||||||
struct define_operator<op_##id> \
|
|
||||||
{ \
|
|
||||||
template <class Left, class Right = Left> \
|
|
||||||
struct operator_function : function \
|
|
||||||
{ \
|
|
||||||
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \
|
|
||||||
{ \
|
|
||||||
tuple args(ref(arguments, ref::increment_count)); \
|
|
||||||
\
|
|
||||||
return BOOST_PYTHON_CONVERSION::to_python( \
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<Left>()) oper \
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type<Right>())); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
const char* description() const \
|
|
||||||
{ return "__" #id "__"; } \
|
|
||||||
}; \
|
|
||||||
\
|
|
||||||
template <class Right, class Left> \
|
|
||||||
struct roperator_function : function \
|
|
||||||
{ \
|
|
||||||
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \
|
|
||||||
{ \
|
|
||||||
tuple args(ref(arguments, ref::increment_count)); \
|
|
||||||
\
|
|
||||||
return BOOST_PYTHON_CONVERSION::to_python( \
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type<Left>()) oper \
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<Right>())); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
const char* description() const \
|
|
||||||
{ return "__r" #id "__"; } \
|
|
||||||
\
|
|
||||||
}; \
|
|
||||||
\
|
|
||||||
static const char * name() { return "__" #id "__"; } \
|
|
||||||
static const char * rname() { return "__r" #id "__"; } \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PY_DEFINE_UNARY_OPERATORS(id, oper) \
|
|
||||||
template <> \
|
|
||||||
struct define_operator<op_##id> \
|
|
||||||
{ \
|
|
||||||
template <class operand> \
|
|
||||||
struct operator_function : function \
|
|
||||||
{ \
|
|
||||||
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \
|
|
||||||
{ \
|
|
||||||
tuple args(ref(arguments, ref::increment_count)); \
|
|
||||||
\
|
|
||||||
return BOOST_PYTHON_CONVERSION::to_python( \
|
|
||||||
oper(BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<operand>()))); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
const char* description() const \
|
|
||||||
{ return "__" #id "__"; } \
|
|
||||||
}; \
|
|
||||||
\
|
|
||||||
static const char * name() { return "__" #id "__"; } \
|
|
||||||
}
|
|
||||||
|
|
||||||
PY_DEFINE_BINARY_OPERATORS(add, +);
|
|
||||||
PY_DEFINE_BINARY_OPERATORS(sub, -);
|
|
||||||
PY_DEFINE_BINARY_OPERATORS(mul, *);
|
|
||||||
PY_DEFINE_BINARY_OPERATORS(div, /);
|
|
||||||
PY_DEFINE_BINARY_OPERATORS(mod, %);
|
|
||||||
PY_DEFINE_BINARY_OPERATORS(lshift, <<);
|
|
||||||
PY_DEFINE_BINARY_OPERATORS(rshift, >>);
|
|
||||||
PY_DEFINE_BINARY_OPERATORS(and, &);
|
|
||||||
PY_DEFINE_BINARY_OPERATORS(xor, ^);
|
|
||||||
PY_DEFINE_BINARY_OPERATORS(or, |);
|
|
||||||
|
|
||||||
PY_DEFINE_UNARY_OPERATORS(neg, -);
|
|
||||||
PY_DEFINE_UNARY_OPERATORS(pos, +);
|
|
||||||
PY_DEFINE_UNARY_OPERATORS(abs, abs);
|
|
||||||
PY_DEFINE_UNARY_OPERATORS(invert, ~);
|
|
||||||
PY_DEFINE_UNARY_OPERATORS(int, long);
|
|
||||||
PY_DEFINE_UNARY_OPERATORS(long, PyLong_FromLong);
|
|
||||||
PY_DEFINE_UNARY_OPERATORS(float, double);
|
|
||||||
|
|
||||||
#undef PY_DEFINE_BINARY_OPERATORS
|
|
||||||
#undef PY_DEFINE_UNARY_OPERATORS
|
|
||||||
|
|
||||||
// Some operators need special treatment, e.g. because there is no corresponding
|
|
||||||
// expression in C++. These are specialized manually.
|
|
||||||
|
|
||||||
// pow(): Manual specialization needed because an error message is required if this
|
|
||||||
// function is called with three arguments. The "power modulo" operator is not
|
|
||||||
// supported by define_operator, but can be wrapped manually (see special.html).
|
|
||||||
template <>
|
|
||||||
struct define_operator<op_pow>
|
|
||||||
{
|
|
||||||
template <class Left, class Right = Left>
|
|
||||||
struct operator_function : function
|
|
||||||
{
|
|
||||||
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const
|
|
||||||
{
|
|
||||||
tuple args(ref(arguments, ref::increment_count));
|
|
||||||
|
|
||||||
if (args.size() == 3 && args[2]->ob_type != Py_None->ob_type)
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, "expected 2 arguments, got 3");
|
|
||||||
throw argument_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
return BOOST_PYTHON_CONVERSION::to_python(
|
|
||||||
pow(BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<Left>()),
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type<Right>())));
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* description() const
|
|
||||||
{ return "__pow__"; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Right, class Left>
|
|
||||||
struct roperator_function : function
|
|
||||||
{
|
|
||||||
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const
|
|
||||||
{
|
|
||||||
tuple args(ref(arguments, ref::increment_count));
|
|
||||||
|
|
||||||
if (args.size() == 3 && args[2]->ob_type != Py_None->ob_type)
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for pow()");
|
|
||||||
throw argument_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
return BOOST_PYTHON_CONVERSION::to_python(
|
|
||||||
pow(BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type<Left>()),
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<Right>())));
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* description() const
|
|
||||||
{ return "__rpow__"; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char * name() { return "__pow__"; }
|
|
||||||
static const char * rname() { return "__rpow__"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// divmod(): Manual specialization needed because we must actually call two operators and
|
|
||||||
// return a tuple containing both results
|
|
||||||
template <>
|
|
||||||
struct define_operator<op_divmod>
|
|
||||||
{
|
|
||||||
template <class Left, class Right = Left>
|
|
||||||
struct operator_function : function
|
|
||||||
{
|
|
||||||
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const
|
|
||||||
{
|
|
||||||
tuple args(ref(arguments, ref::increment_count));
|
|
||||||
PyObject * res = PyTuple_New(2);
|
|
||||||
|
|
||||||
PyTuple_SET_ITEM(res, 0,
|
|
||||||
BOOST_PYTHON_CONVERSION::to_python(
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<Left>()) /
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type<Right>())));
|
|
||||||
PyTuple_SET_ITEM(res, 1,
|
|
||||||
BOOST_PYTHON_CONVERSION::to_python(
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<Left>()) %
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type<Right>())));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* description() const
|
|
||||||
{ return "__divmod__"; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Right, class Left>
|
|
||||||
struct roperator_function : function
|
|
||||||
{
|
|
||||||
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const
|
|
||||||
{
|
|
||||||
tuple args(ref(arguments, ref::increment_count));
|
|
||||||
PyObject * res = PyTuple_New(2);
|
|
||||||
|
|
||||||
PyTuple_SET_ITEM(res, 0,
|
|
||||||
BOOST_PYTHON_CONVERSION::to_python(
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type<Left>()) /
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<Right>())));
|
|
||||||
PyTuple_SET_ITEM(res, 1,
|
|
||||||
BOOST_PYTHON_CONVERSION::to_python(
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type<Left>()) %
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<Right>())));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* description() const
|
|
||||||
{ return "__rdivmod__"; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char * name() { return "__divmod__"; }
|
|
||||||
static const char * rname() { return "__rdivmod__"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// cmp(): Manual specialization needed because there is no three-way compare in C++.
|
|
||||||
// It is implemented by two one-way comparisons with operators reversed in the second.
|
|
||||||
template <>
|
|
||||||
struct define_operator<op_cmp>
|
|
||||||
{
|
|
||||||
template <class Left, class Right = Left>
|
|
||||||
struct operator_function : function
|
|
||||||
{
|
|
||||||
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const
|
|
||||||
{
|
|
||||||
tuple args(ref(arguments, ref::increment_count));
|
|
||||||
|
|
||||||
return BOOST_PYTHON_CONVERSION::to_python(
|
|
||||||
(BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<Left>()) <
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type<Right>())) ?
|
|
||||||
- 1 :
|
|
||||||
(BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type<Right>()) <
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<Left>())) ?
|
|
||||||
1 :
|
|
||||||
0) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* description() const
|
|
||||||
{ return "__cmp__"; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Right, class Left>
|
|
||||||
struct roperator_function : function
|
|
||||||
{
|
|
||||||
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const
|
|
||||||
{
|
|
||||||
tuple args(ref(arguments, ref::increment_count));
|
|
||||||
|
|
||||||
return BOOST_PYTHON_CONVERSION::to_python(
|
|
||||||
(BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type<Left>()) <
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<Right>())) ?
|
|
||||||
- 1 :
|
|
||||||
(BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<Right>()) <
|
|
||||||
BOOST_PYTHON_CONVERSION::from_python(args[1].get(), boost::python::type<Left>())) ?
|
|
||||||
1 :
|
|
||||||
0) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* description() const
|
|
||||||
{ return "__rcmp__"; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char * name() { return "__cmp__"; }
|
|
||||||
static const char * rname() { return "__rcmp__"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// str(): Manual specialization needed because the string conversion does not follow
|
|
||||||
// the standard pattern relized by the macros.
|
|
||||||
template <>
|
|
||||||
struct define_operator<op_str>
|
|
||||||
{
|
|
||||||
template <class operand>
|
|
||||||
struct operator_function : function
|
|
||||||
{
|
|
||||||
PyObject* do_call(PyObject* arguments, PyObject*) const
|
|
||||||
{
|
|
||||||
tuple args(ref(arguments, ref::increment_count));
|
|
||||||
|
|
||||||
// When STLport is used with native streams, _STL::ostringstream().str() is not
|
|
||||||
// _STL::string, but std::string.
|
|
||||||
#if defined(__SGI_STL_PORT) ? defined(__SGI_STL_OWN_IOSTREAMS) : (!defined(__GNUC__) || __GNUC__ > 2)
|
|
||||||
std::ostringstream s;
|
|
||||||
s << BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<operand>());
|
|
||||||
return BOOST_PYTHON_CONVERSION::to_python(s.str());
|
|
||||||
#else
|
|
||||||
std::ostrstream s;
|
|
||||||
s << BOOST_PYTHON_CONVERSION::from_python(args[0].get(), boost::python::type<operand>()) << char();
|
|
||||||
return BOOST_PYTHON_CONVERSION::to_python(const_cast<char const *>(s.str()));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* description() const
|
|
||||||
{ return "__str__"; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char * name() { return "__str__"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
|
|
||||||
#endif /* OPERATORS_UK112000_H_ */
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef PYPTR_DWA050400_H_
|
|
||||||
# define PYPTR_DWA050400_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/operators.hpp>
|
|
||||||
# include <boost/python/detail/wrap_python.hpp>
|
|
||||||
# include <boost/python/detail/cast.hpp>
|
|
||||||
# include <cassert>
|
|
||||||
# include <boost/python/detail/signatures.hpp>
|
|
||||||
# include <boost/python/errors.hpp>
|
|
||||||
# include <boost/python/conversions.hpp>
|
|
||||||
|
|
||||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
|
||||||
|
|
||||||
template <class T, class Value, class Base>
|
|
||||||
struct py_ptr_conversions : Base
|
|
||||||
{
|
|
||||||
inline friend T from_python(PyObject* x, boost::python::type<const T&>)
|
|
||||||
{ return T(boost::python::downcast<Value>(x).get(), T::increment_count); }
|
|
||||||
|
|
||||||
inline friend T from_python(PyObject* x, boost::python::type<T>)
|
|
||||||
{ return T(boost::python::downcast<Value>(x).get(), T::increment_count); }
|
|
||||||
|
|
||||||
inline friend PyObject* to_python(T x)
|
|
||||||
{ return boost::python::as_object(x.release()); }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
BOOST_PYTHON_IMPORT_CONVERSION(py_ptr_conversions);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class reference
|
|
||||||
: public py_ptr_conversions<reference<T>, T,
|
|
||||||
boost::dereferenceable<reference<T>, T*> > // supplies op->
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef T value_type;
|
|
||||||
|
|
||||||
reference(const reference& rhs)
|
|
||||||
: m_p(rhs.m_p)
|
|
||||||
{
|
|
||||||
Py_XINCREF(object());
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(BOOST_MSVC6_OR_EARLIER)
|
|
||||||
template <class T2>
|
|
||||||
reference(const reference<T2>& rhs)
|
|
||||||
: m_p(rhs.object())
|
|
||||||
{
|
|
||||||
Py_XINCREF(object());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
reference() : m_p(0) {}
|
|
||||||
|
|
||||||
// These are two ways of spelling the same thing, that we need to increment
|
|
||||||
// the reference count on the pointer when we're initialized.
|
|
||||||
enum increment_count_t { increment_count };
|
|
||||||
|
|
||||||
enum allow_null { null_ok };
|
|
||||||
|
|
||||||
template <class T2>
|
|
||||||
explicit reference(T2* x)
|
|
||||||
: m_p(expect_non_null(x)) {}
|
|
||||||
|
|
||||||
template <class T2>
|
|
||||||
reference(T2* x, increment_count_t)
|
|
||||||
: m_p(expect_non_null(x)) { Py_INCREF(object()); }
|
|
||||||
|
|
||||||
template <class T2>
|
|
||||||
reference(T2* x, allow_null)
|
|
||||||
: m_p(x) {}
|
|
||||||
|
|
||||||
template <class T2>
|
|
||||||
reference(T2* x, allow_null, increment_count_t)
|
|
||||||
: m_p(x) { Py_XINCREF(object()); }
|
|
||||||
|
|
||||||
template <class T2>
|
|
||||||
reference(T2* x, increment_count_t, allow_null)
|
|
||||||
: m_p(x) { Py_XINCREF(object()); }
|
|
||||||
|
|
||||||
#if !defined(BOOST_MSVC6_OR_EARLIER)
|
|
||||||
template <class T2>
|
|
||||||
reference& operator=(const reference<T2>& rhs)
|
|
||||||
{
|
|
||||||
Py_XDECREF(object());
|
|
||||||
m_p = rhs.m_p;
|
|
||||||
Py_XINCREF(object());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
reference& operator=(const reference& rhs)
|
|
||||||
{
|
|
||||||
Py_XINCREF(static_cast<PyObject*>(rhs.m_p));
|
|
||||||
Py_XDECREF(object());
|
|
||||||
m_p = rhs.m_p;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~reference()
|
|
||||||
{
|
|
||||||
Py_XDECREF(m_p);
|
|
||||||
}
|
|
||||||
|
|
||||||
T& operator*() const { return *m_p; }
|
|
||||||
|
|
||||||
T* get() const { return m_p; }
|
|
||||||
|
|
||||||
T* release()
|
|
||||||
{
|
|
||||||
T* p = m_p;
|
|
||||||
m_p = 0;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
|
||||||
{ Py_XDECREF(m_p); m_p = 0; }
|
|
||||||
|
|
||||||
template <class T2>
|
|
||||||
void reset(T2* x)
|
|
||||||
{ Py_XDECREF(m_p); m_p = expect_non_null(x);}
|
|
||||||
|
|
||||||
template <class T2>
|
|
||||||
void reset(T2* x, increment_count_t)
|
|
||||||
{ Py_XDECREF(m_p); m_p = expect_non_null(x); Py_INCREF(object()); }
|
|
||||||
|
|
||||||
template <class T2>
|
|
||||||
void reset(T2* x, allow_null)
|
|
||||||
{ Py_XDECREF(m_p); m_p = x;}
|
|
||||||
|
|
||||||
template <class T2>
|
|
||||||
void reset(T2* x, allow_null, increment_count_t)
|
|
||||||
{ Py_XDECREF(m_p); m_p = x; Py_XINCREF(object()); }
|
|
||||||
|
|
||||||
template <class T2>
|
|
||||||
void reset(T2* x, increment_count_t, allow_null)
|
|
||||||
{ Py_XDECREF(m_p); m_p = x; Py_XINCREF(object()); }
|
|
||||||
|
|
||||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
|
||||||
private:
|
|
||||||
template<typename Y> friend class shared_ptr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inline PyObject* object() const
|
|
||||||
{ return as_object(m_p); }
|
|
||||||
|
|
||||||
T* m_p;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef reference<PyObject> ref;
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
ref make_ref(const T& x)
|
|
||||||
{
|
|
||||||
return ref(to_python(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
|
|
||||||
#endif // PYPTR_DWA050400_H_
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
2000-11-22 10:00
|
|
||||||
Ullrich fixed bug in operator_dispatcher<op_long>.
|
|
||||||
|
|
||||||
2000-11-21 10:00
|
|
||||||
Changed all class and function names into lower_case.
|
|
||||||
|
|
||||||
Ullrich updated documentation for operator wrapping.
|
|
||||||
|
|
||||||
2000-11-20 10:00
|
|
||||||
Ullrich renamed ExtensionClass:register_coerce() into
|
|
||||||
ExtensionClass:def_standard_coerce() and made it public
|
|
||||||
|
|
||||||
Ullrich improved shared_pod_manager.
|
|
||||||
|
|
||||||
2000-11-17 15:04
|
|
||||||
Changed allocation strategy of shared_pod_manager to make it portable.
|
|
||||||
|
|
||||||
Added pickling support + tests thanks to "Ralf W. Grosse-Kunstleve"
|
|
||||||
<rwgk@cci.lbl.gov>
|
|
||||||
|
|
||||||
Added a specialization of Callback<const char*> to prevent unsafe usage.
|
|
||||||
|
|
||||||
Fixed Ullrich's operator_dispatcher refcount bug
|
|
||||||
|
|
||||||
Removed const char* return values from virtual functions in tests; that
|
|
||||||
usage was unsafe.
|
|
||||||
|
|
||||||
Ullrich changed Module::add() so that it steals a reference (fix of refcount bug)
|
|
||||||
|
|
||||||
Ullrich added operator_dispatcher::create() optimization
|
|
||||||
|
|
||||||
Ullrich changed design and implementation of TypeObjectBase::enable() (to eliminate low-level
|
|
||||||
code) and added shared_pod_manager optimization.
|
|
||||||
|
|
||||||
|
|
||||||
2000-11-15 12:01
|
|
||||||
Fixed refcount bugs in operator calls.
|
|
||||||
|
|
||||||
Added callback_adjust_refcount(PyObject*, Type<T>) to account for different ownership
|
|
||||||
semantics of Callback's return types and Caller's arguments (which both use from_python())
|
|
||||||
This bug caused refcount errors during operator calls.
|
|
||||||
|
|
||||||
Moved operator_dispatcher into extclass.cpp
|
|
||||||
Gave it shared ownership of the objects it wraps
|
|
||||||
|
|
||||||
Introduced sequence points in extension_class_coerce for exception-safety
|
|
||||||
|
|
||||||
UPPER_CASE_MACRO_NAMES
|
|
||||||
|
|
||||||
MixedCase template type argument names
|
|
||||||
|
|
||||||
Changed internal error reporting to use Python exceptions so we don't force the
|
|
||||||
user to link in iostreams code
|
|
||||||
|
|
||||||
Changed error return value of call_cmp to -1
|
|
||||||
|
|
||||||
Moved unwrap_* functions out of operator_dispatcher. This was transitional: when
|
|
||||||
I realized they didn't need to be declared in extclass.h I moved them out, but
|
|
||||||
now that operator_dispatcher itself is in extclass.cpp they could go back in.
|
|
||||||
|
|
||||||
Numerous formatting tweaks
|
|
||||||
|
|
||||||
Updated the BoundFunction::create() optimization and enabled it so it could actually be used!
|
|
||||||
|
|
||||||
2000-11-15 00:26
|
|
||||||
|
|
||||||
Made Ullrich's operators support work with MSVC
|
|
||||||
|
|
||||||
Cleaned up operators.h such that invalid define_operator<0> is no longer needed.
|
|
||||||
|
|
||||||
Ullrich created operators.h to support wrapping of C++ operators (including the "__r*__" forms).
|
|
||||||
He added several auxiliary classes to extclass.h and extclass.cpp (most importantly,
|
|
||||||
py::detail::operator_dispatcher and py::operators)
|
|
||||||
|
|
||||||
2000-11-13 22:29
|
|
||||||
|
|
||||||
removed obsolete ExtensionClassFromPython for good.
|
|
||||||
|
|
||||||
removed unused class ExtensionType forward declaration
|
|
||||||
|
|
||||||
2000-11-12 13:08
|
|
||||||
|
|
||||||
Added enum_as_int_converters for easier enum wrapping
|
|
||||||
|
|
||||||
Introduced new conversion namespace macros:
|
|
||||||
PY_BEGIN_CONVERSION_NAMESPACE,
|
|
||||||
PY_END_CONVERSION_NAMESPACE,
|
|
||||||
PY_CONVERSION
|
|
||||||
|
|
||||||
callback.h, gen_callback.py:
|
|
||||||
Added call() function so that a regular python function (as opposed to
|
|
||||||
method or other function-as-attribute) can be called.
|
|
||||||
|
|
||||||
Added newlines for readability.
|
|
||||||
|
|
||||||
class_wrapper.h:
|
|
||||||
Fixed a bug in add(), which allows non-method class attributes
|
|
||||||
|
|
||||||
Ullrich has added def_raw for simple varargs and keyword support.
|
|
||||||
|
|
||||||
Fixed version number check for __MWERKS__
|
|
||||||
|
|
||||||
Added tests for enums and non-method class attributes
|
|
||||||
|
|
||||||
objects.h/objects.cpp:
|
|
||||||
Added py::String operator*= and operator* for repetition
|
|
||||||
|
|
||||||
Change Dict::items(), keys(), and values() to return a List
|
|
||||||
|
|
||||||
Added template versions of set_item, etc., methods so that users can optionally
|
|
||||||
use C++ types that have to_python() functions as parameters.
|
|
||||||
|
|
||||||
Changed various Ptr by-value parameters to const Ptr&
|
|
||||||
|
|
||||||
|
|
||||||
======= Release =======
|
|
||||||
2000-11-06 0:22
|
|
||||||
Lots of documentation updates
|
|
||||||
|
|
||||||
added 4-argument template constructor to py::Tuple
|
|
||||||
|
|
||||||
added "add" member function to ClassWrapper<> to allow arbitrary Python
|
|
||||||
objects to be added to an extension class.
|
|
||||||
|
|
||||||
gen_all.py now generates support for n argument member functions and n+1
|
|
||||||
argument member functions at the suggestion of "Ralf W. Grosse-Kunstleve"
|
|
||||||
<rwgk@cci.lbl.gov>
|
|
||||||
|
|
||||||
Added regression tests and re-ordered declare_base calls to verify that the
|
|
||||||
phantom base class issue is resolved.
|
|
||||||
|
|
||||||
2000-11-04 17:35
|
|
||||||
|
|
||||||
Integrated Ullrich Koethe's brilliant from_python_experiment for better
|
|
||||||
error-reporting in many cases.
|
|
||||||
|
|
||||||
extclass.h, gen_extclass.py:
|
|
||||||
removed special-case MSVC code
|
|
||||||
added much commentary
|
|
||||||
removed unused py_copy_to_new_value_holder
|
|
||||||
|
|
||||||
init_function.h, gen_init_function.py:
|
|
||||||
added missing 'template' keyword on type-dependent template member usage
|
|
||||||
removed special-case MSVC code
|
|
||||||
added much commentary
|
|
||||||
|
|
||||||
2000-11-04 0:36
|
|
||||||
|
|
||||||
Removed the need for the phantom base class that screwed up inheritance
|
|
||||||
hierarchies, introduced error-prone ordering dependencies, and complexified
|
|
||||||
logic in many places!
|
|
||||||
|
|
||||||
extclass.h: Added some explanatory comments, removed wasteful m_self member
|
|
||||||
of HeldInstance
|
|
||||||
|
|
||||||
extclass_demo.cpp: Added #pragmas which allow compilation in ansi strict
|
|
||||||
mode under Metrowerks
|
|
||||||
|
|
||||||
functions.h: Added virtual_function as part of phantom base class removal;
|
|
||||||
expanded commentary
|
|
||||||
|
|
||||||
pyptr.h: Added some missing 'typename's and a GCC workaround fix
|
|
||||||
|
|
||||||
subclass.cpp: Added missing string literal const_cast<>s.
|
|
||||||
|
|
||||||
2000-11-03 10:58
|
|
||||||
|
|
||||||
Fix friend function instantiation bug caught by Metrowerks (thanks
|
|
||||||
Metrowerks!)
|
|
||||||
|
|
||||||
Add proof-of-concept for one technique of wrapping function that return a
|
|
||||||
pointer
|
|
||||||
|
|
||||||
Worked around MSVC optimizer bug by writing to_python(double) and
|
|
||||||
to_python(float) out-of-line
|
|
||||||
|
|
||||||
2000-11-02 23:25
|
|
||||||
|
|
||||||
Add /Zm200 option to vc6_prj to deal with MSVC resource limitations
|
|
||||||
|
|
||||||
Remove conflicting /Ot option from vc6_prj release build
|
|
||||||
|
|
||||||
======= Release =======
|
|
||||||
2000-11-02 17:42
|
|
||||||
|
|
||||||
Added a fix for interactions between default virtual function
|
|
||||||
implementations and declare_base(). You still need to write your
|
|
||||||
declare_base() /after/ all member functions have been def()d for the two
|
|
||||||
classes concerned. Many, many thanks to Ullrich Koethe
|
|
||||||
<koethe@informatik.uni-hamburg.de> for all his work on this.
|
|
||||||
|
|
||||||
Added missing conversions:
|
|
||||||
to_python(float)
|
|
||||||
from_python(const char* const&)
|
|
||||||
from_python(const double&)
|
|
||||||
from_python(const float&)
|
|
||||||
|
|
||||||
Added a Regression test for a reference-counting bug thanks to Mark Evans
|
|
||||||
(<mark.evans@clarisay.com>)
|
|
||||||
|
|
||||||
const-ify ClassBase::getattr()
|
|
||||||
|
|
||||||
Add repr() function to Class<T>
|
|
||||||
|
|
||||||
Add to_python/from_python conversions for PyPtr<T>
|
|
||||||
|
|
||||||
Standardize set_item/get_item interfaces (instead of proxies) for Dict and List
|
|
||||||
|
|
||||||
Add Reprable<> template to newtypes.h
|
|
||||||
|
|
||||||
Fix a bug wherein the __module__ attribute would be lost for classes that have a
|
|
||||||
default virtual function implementation.
|
|
||||||
|
|
||||||
Remove extra ';' in module.cpp thanks to "Ralf W. Grosse-Kunstleve"
|
|
||||||
<rwgk@cci.lbl.gov>
|
|
||||||
|
|
||||||
Fix a bug in the code of example1.html
|
|
||||||
904
src/classes.cpp
904
src/classes.cpp
@@ -1,904 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#include <boost/python/classes.hpp>
|
|
||||||
#include <boost/python/detail/functions.hpp>
|
|
||||||
#include <boost/python/detail/singleton.hpp>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <boost/python/callback.hpp>
|
|
||||||
#include <cstring>
|
|
||||||
#include <boost/python/module_builder.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
void enable_named_method(boost::python::detail::class_base* type_obj, const char* name);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
// Add the name of the module currently being loaded to the name_space with the
|
|
||||||
// key "__module__". If no module is being loaded, or if name_space already has
|
|
||||||
// a key "__module", has no effect. This is not really a useful public
|
|
||||||
// interface; it's just used for class_t<>::class_t() below.
|
|
||||||
void add_current_module_name(dictionary&);
|
|
||||||
|
|
||||||
bool is_prefix(const char* s1, const char* s2);
|
|
||||||
bool is_special_name(const char* name);
|
|
||||||
void enable_special_methods(boost::python::detail::class_base* derived, const tuple& bases, const dictionary& name_space);
|
|
||||||
|
|
||||||
void report_ignored_exception(PyObject* source)
|
|
||||||
{
|
|
||||||
// This bit of code copied wholesale from classobject.c in the Python source.
|
|
||||||
PyObject *f, *t, *v, *tb;
|
|
||||||
PyErr_Fetch(&t, &v, &tb);
|
|
||||||
f = PySys_GetObject(const_cast<char*>("stderr"));
|
|
||||||
if (f != NULL)
|
|
||||||
{
|
|
||||||
PyFile_WriteString(const_cast<char*>("Exception "), f);
|
|
||||||
if (t) {
|
|
||||||
PyFile_WriteObject(t, f, Py_PRINT_RAW);
|
|
||||||
if (v && v != Py_None) {
|
|
||||||
PyFile_WriteString(const_cast<char*>(": "), f);
|
|
||||||
PyFile_WriteObject(v, f, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PyFile_WriteString(const_cast<char*>(" in "), f);
|
|
||||||
PyFile_WriteObject(source, f, 0);
|
|
||||||
PyFile_WriteString(const_cast<char*>(" ignored\n"), f);
|
|
||||||
PyErr_Clear(); /* Just in case */
|
|
||||||
}
|
|
||||||
Py_XDECREF(t);
|
|
||||||
Py_XDECREF(v);
|
|
||||||
Py_XDECREF(tb);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// pickle support courtesy of "Ralf W. Grosse-Kunstleve" <rwgk@cci.lbl.gov>
|
|
||||||
//
|
|
||||||
PyObject* class_reduce(PyObject* klass)
|
|
||||||
{
|
|
||||||
return PyObject_GetAttrString(klass, const_cast<char*>("__name__"));
|
|
||||||
}
|
|
||||||
|
|
||||||
ref global_class_reduce()
|
|
||||||
{
|
|
||||||
static ref result(detail::new_wrapped_function(class_reduce));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
tuple instance_reduce(PyObject* obj)
|
|
||||||
{
|
|
||||||
ref instance_class(PyObject_GetAttrString(obj, const_cast<char*>("__class__")));
|
|
||||||
|
|
||||||
ref getinitargs(PyObject_GetAttrString(obj, const_cast<char*>("__getinitargs__")),
|
|
||||||
ref::null_ok);
|
|
||||||
PyErr_Clear();
|
|
||||||
ref initargs;
|
|
||||||
if (getinitargs.get() != 0)
|
|
||||||
{
|
|
||||||
initargs = ref(PyEval_CallObject(getinitargs.get(), NULL));
|
|
||||||
initargs = ref(PySequence_Tuple(initargs.get()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
initargs = ref(PyTuple_New(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
ref getstate(PyObject_GetAttrString(obj, const_cast<char*>("__getstate__")),
|
|
||||||
ref::null_ok);
|
|
||||||
PyErr_Clear();
|
|
||||||
if (getstate.get() != 0)
|
|
||||||
{
|
|
||||||
ref state = ref(PyEval_CallObject(getstate.get(), NULL));
|
|
||||||
return tuple(instance_class, initargs, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
ref state(PyObject_GetAttrString(obj, const_cast<char*>("__dict__")), ref::null_ok);
|
|
||||||
PyErr_Clear();
|
|
||||||
if (state.get() != 0 && dictionary(state).size() > 0)
|
|
||||||
{
|
|
||||||
return tuple(instance_class, initargs, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tuple(instance_class, initargs);
|
|
||||||
}
|
|
||||||
|
|
||||||
ref global_instance_reduce()
|
|
||||||
{
|
|
||||||
static ref result(detail::new_wrapped_function(instance_reduce));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
class_base::class_base(PyTypeObject* meta_class_obj, string name, tuple bases, const dictionary& name_space)
|
|
||||||
: type_object_base(meta_class_obj),
|
|
||||||
m_name(name),
|
|
||||||
m_bases(bases),
|
|
||||||
m_name_space(name_space)
|
|
||||||
{
|
|
||||||
this->tp_name = const_cast<char*>(name.c_str());
|
|
||||||
enable(type_object_base::getattr);
|
|
||||||
enable(type_object_base::setattr);
|
|
||||||
add_current_module_name(m_name_space);
|
|
||||||
static const boost::python::string docstr("__doc__", boost::python::string::interned);
|
|
||||||
if (PyDict_GetItem(m_name_space.get(), docstr.get())== 0)
|
|
||||||
{
|
|
||||||
PyDict_SetItem(m_name_space.get(), docstr.get(), Py_None);
|
|
||||||
}
|
|
||||||
enable_special_methods(this, bases, name_space);
|
|
||||||
}
|
|
||||||
|
|
||||||
void class_base::add_base(ref base)
|
|
||||||
{
|
|
||||||
tuple new_bases(m_bases.size() + 1);
|
|
||||||
for (std::size_t i = 0; i < m_bases.size(); ++i)
|
|
||||||
new_bases.set_item(i, m_bases[i]);
|
|
||||||
new_bases.set_item(m_bases.size(), base);
|
|
||||||
m_bases = new_bases;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* class_base::getattr(const char* name)
|
|
||||||
{
|
|
||||||
if (!BOOST_CSTD_::strcmp(name, "__dict__"))
|
|
||||||
{
|
|
||||||
PyObject* result = m_name_space.get();
|
|
||||||
Py_INCREF(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!BOOST_CSTD_::strcmp(name, "__bases__"))
|
|
||||||
{
|
|
||||||
PyObject* result = m_bases.get();
|
|
||||||
Py_INCREF(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!BOOST_CSTD_::strcmp(name, "__name__"))
|
|
||||||
{
|
|
||||||
PyObject* result = m_name.get();
|
|
||||||
Py_INCREF(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pickle support courtesy of "Ralf W. Grosse-Kunstleve" <rwgk@cci.lbl.gov>
|
|
||||||
if (!BOOST_CSTD_::strcmp(name, "__safe_for_unpickling__"))
|
|
||||||
{
|
|
||||||
return PyInt_FromLong(1);
|
|
||||||
}
|
|
||||||
if (!BOOST_CSTD_::strcmp(name, "__reduce__"))
|
|
||||||
{
|
|
||||||
ref target(as_object(this), ref::increment_count);
|
|
||||||
return new bound_function(target, global_class_reduce());
|
|
||||||
}
|
|
||||||
|
|
||||||
ref local_attribute = m_name_space.get_item(string(name).reference());
|
|
||||||
|
|
||||||
if (local_attribute.get())
|
|
||||||
return local_attribute.release();
|
|
||||||
|
|
||||||
// In case there are no bases...
|
|
||||||
PyErr_SetString(PyExc_AttributeError, name);
|
|
||||||
|
|
||||||
// Check bases
|
|
||||||
for (std::size_t i = 0; i < m_bases.size(); ++i)
|
|
||||||
{
|
|
||||||
if (PyErr_ExceptionMatches(PyExc_AttributeError))
|
|
||||||
PyErr_Clear(); // we're going to try a base class
|
|
||||||
else if (PyErr_Occurred())
|
|
||||||
break; // Other errors count, though!
|
|
||||||
|
|
||||||
PyObject* base_attribute = PyObject_GetAttrString(m_bases[i].get(), const_cast<char*>(name));
|
|
||||||
|
|
||||||
if (base_attribute != 0)
|
|
||||||
{
|
|
||||||
// Unwind the actual underlying function from unbound Python class
|
|
||||||
// methods in case of multiple inheritance from real Python
|
|
||||||
// classes. Python stubbornly insists that the first argument to a
|
|
||||||
// method must be a true Python instance object otherwise. Do not
|
|
||||||
// unwrap bound methods; that would interfere with intended semantics.
|
|
||||||
if (PyMethod_Check(base_attribute)
|
|
||||||
&& reinterpret_cast<PyMethodObject*>(base_attribute)->im_self == 0)
|
|
||||||
{
|
|
||||||
PyObject* function
|
|
||||||
= reinterpret_cast<PyMethodObject*>(base_attribute)->im_func;
|
|
||||||
Py_INCREF(function);
|
|
||||||
Py_DECREF(base_attribute);
|
|
||||||
return function;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return base_attribute;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mostly copied wholesale from Python's classobject.c
|
|
||||||
PyObject* class_base::repr() const
|
|
||||||
{
|
|
||||||
PyObject *mod = PyDict_GetItemString(
|
|
||||||
m_name_space.get(), const_cast<char*>("__module__"));
|
|
||||||
unsigned long address = reinterpret_cast<unsigned long>(this);
|
|
||||||
string result = (mod == NULL || !PyString_Check(mod))
|
|
||||||
? string("<extension class %s at %lx>") % tuple(m_name, address)
|
|
||||||
: string("<extension class %s.%s at %lx>") % tuple(ref(mod, ref::increment_count), m_name, address);
|
|
||||||
return result.reference().release();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int class_base::setattr(const char* name, PyObject* value)
|
|
||||||
{
|
|
||||||
if (is_special_name(name)
|
|
||||||
&& BOOST_CSTD_::strcmp(name, "__doc__") != 0
|
|
||||||
&& BOOST_CSTD_::strcmp(name, "__name__") != 0)
|
|
||||||
{
|
|
||||||
boost::python::string message("Special attribute names other than '__doc__' and '__name__' are read-only, in particular: ");
|
|
||||||
PyErr_SetObject(PyExc_TypeError, (message + name).get());
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PyCallable_Check(value))
|
|
||||||
detail::enable_named_method(this, name);
|
|
||||||
|
|
||||||
return PyDict_SetItemString(
|
|
||||||
m_name_space.reference().get(), const_cast<char*>(name), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool class_base::initialize_instance(instance* obj, PyObject* args, PyObject* keywords)
|
|
||||||
{
|
|
||||||
// Getting the init function off the obj should result in a
|
|
||||||
// bound method.
|
|
||||||
PyObject* const init_function = obj->getattr("__init__", false);
|
|
||||||
|
|
||||||
if (init_function == 0)
|
|
||||||
{
|
|
||||||
if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
|
||||||
PyErr_Clear(); // no __init__? That's legal.
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false; // Something else? Keep the error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Manage the reference to the bound function
|
|
||||||
ref init_function_holder(init_function);
|
|
||||||
|
|
||||||
// Declare a ref to manage the result of calling __init__ (which should be None).
|
|
||||||
ref init_result(
|
|
||||||
PyEval_CallObjectWithKeywords(init_function, args, keywords));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void class_base::instance_dealloc(PyObject* obj) const
|
|
||||||
{
|
|
||||||
Py_INCREF(obj); // This allows a __del__ function to revive the obj
|
|
||||||
|
|
||||||
PyObject* exc_type;
|
|
||||||
PyObject* exc_value;
|
|
||||||
PyObject* exc_traceback;
|
|
||||||
PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
|
|
||||||
|
|
||||||
// This scope ensures that the reference held by del_function doesn't release
|
|
||||||
// the last reference and delete the object recursively (infinitely).
|
|
||||||
{
|
|
||||||
ref del_function;
|
|
||||||
try {
|
|
||||||
instance* const target = boost::python::downcast<boost::python::instance>(obj);
|
|
||||||
del_function = ref(target->getattr("__del__", false), ref::null_ok);
|
|
||||||
}
|
|
||||||
catch(...) {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (del_function.get() != 0)
|
|
||||||
{
|
|
||||||
ref result(PyEval_CallObject(del_function.get(), (PyObject *)NULL), ref::null_ok);
|
|
||||||
|
|
||||||
if (result.get() == NULL)
|
|
||||||
report_ignored_exception(del_function.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PyErr_Restore(exc_type, exc_value, exc_traceback);
|
|
||||||
|
|
||||||
if (--obj->ob_refcnt <= 0)
|
|
||||||
delete_instance(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
instance::instance(PyTypeObject* class_)
|
|
||||||
: boost::python::detail::base_object<PyObject>(class_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
instance::~instance()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::getattr(const char* name, bool use_special_function)
|
|
||||||
{
|
|
||||||
if (!BOOST_CSTD_::strcmp(name, "__dict__"))
|
|
||||||
{
|
|
||||||
if (PyEval_GetRestricted()) {
|
|
||||||
PyErr_SetString(PyExc_RuntimeError,
|
|
||||||
"instance.__dict__ not accessible in restricted mode");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
Py_INCREF(m_name_space.get());
|
|
||||||
return m_name_space.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!BOOST_CSTD_::strcmp(name, "__class__"))
|
|
||||||
{
|
|
||||||
Py_INCREF(this->ob_type);
|
|
||||||
return as_object(this->ob_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!BOOST_CSTD_::strcmp(name, "__reduce__"))
|
|
||||||
{
|
|
||||||
return new detail::bound_function(ref(this, ref::increment_count), global_instance_reduce());
|
|
||||||
}
|
|
||||||
|
|
||||||
ref local_attribute = m_name_space.get_item(string(name).reference());
|
|
||||||
|
|
||||||
if (local_attribute.get())
|
|
||||||
return local_attribute.release();
|
|
||||||
|
|
||||||
// Check its class.
|
|
||||||
PyObject* function =
|
|
||||||
PyObject_GetAttrString(as_object(this->ob_type), const_cast<char*>(name));
|
|
||||||
|
|
||||||
if (function == 0 && !use_special_function)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ref class_attribute;
|
|
||||||
if (function != 0)
|
|
||||||
{
|
|
||||||
// This will throw if the attribute wasn't found
|
|
||||||
class_attribute = ref(function);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Clear the error while we try special methods method (if any).
|
|
||||||
PyErr_Clear();
|
|
||||||
|
|
||||||
// First we try the special method that comes from concatenating
|
|
||||||
// "__getattr__" and <name> and 2 trailing underscores. This is an
|
|
||||||
// extension to regular Python class functionality.
|
|
||||||
const string specific_getattr_name(detail::getattr_string() + name + "__");
|
|
||||||
PyObject* getattr_method = PyObject_GetAttr(
|
|
||||||
as_object(this->ob_type), specific_getattr_name.get());
|
|
||||||
|
|
||||||
// Use just the first arg to PyEval_CallFunction if found
|
|
||||||
char* arg_format = const_cast<char*>("(O)");
|
|
||||||
|
|
||||||
// Try for the regular __getattr__ method if not found
|
|
||||||
if (getattr_method == 0)
|
|
||||||
{
|
|
||||||
PyErr_Clear();
|
|
||||||
getattr_method = PyObject_GetAttrString(
|
|
||||||
as_object(this->ob_type), const_cast<char*>("__getattr__"));
|
|
||||||
|
|
||||||
// Use both args to PyEval_CallFunction
|
|
||||||
arg_format = const_cast<char*>("(Os)");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is no such method, throw now.
|
|
||||||
if (PyErr_Occurred())
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_AttributeError, name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take ownership of the method
|
|
||||||
ref owner(getattr_method);
|
|
||||||
|
|
||||||
// Call it to get the attribute.
|
|
||||||
return PyEval_CallFunction(getattr_method, arg_format, this, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PyCallable_Check(class_attribute.get()))
|
|
||||||
{
|
|
||||||
PyErr_Clear();
|
|
||||||
return class_attribute.release();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return detail::bound_function::create(ref(this, ref::increment_count), class_attribute);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// instance::setattr_dict
|
|
||||||
//
|
|
||||||
// Implements setattr() functionality for the "__dict__" attribute
|
|
||||||
//
|
|
||||||
int instance::setattr_dict(PyObject* value)
|
|
||||||
{
|
|
||||||
if (PyEval_GetRestricted())
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_RuntimeError,
|
|
||||||
"__dict__ not accessible in restricted mode");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value == 0 || !PyDict_Check(value))
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"__dict__ must be set to a dictionary");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
m_name_space = dictionary(ref(value, ref::increment_count));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// instance::setattr -
|
|
||||||
//
|
|
||||||
// Implements the setattr() and delattr() functionality for our own instance
|
|
||||||
// objects, using the standard Python interface: if value == 0, we are deleting
|
|
||||||
// the attribute, and returns 0 unless an error occurred.
|
|
||||||
int instance::setattr(const char* name, PyObject* value)
|
|
||||||
{
|
|
||||||
if (BOOST_CSTD_::strcmp(name, "__class__") == 0)
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, "__class__ attribute is read-only");
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BOOST_CSTD_::strcmp(name, "__dict__") == 0)
|
|
||||||
return setattr_dict(value);
|
|
||||||
|
|
||||||
// Try to find an appropriate "specific" setter or getter method, either
|
|
||||||
// __setattr__<name>__(value) or __delattr__<name>__(). This is an extension
|
|
||||||
// to regular Python class functionality.
|
|
||||||
const string& base_name = value ? detail::setattr_string() : detail::delattr_string();
|
|
||||||
const string specific_method_name(base_name + name + "__");
|
|
||||||
|
|
||||||
ref special_method(
|
|
||||||
PyObject_GetAttr(as_object(this->ob_type), specific_method_name.get()),
|
|
||||||
ref::null_ok);
|
|
||||||
|
|
||||||
PyObject* result_object = 0;
|
|
||||||
if (special_method.get() != 0)
|
|
||||||
{
|
|
||||||
// The specific function was found; call it now. Note that if value is
|
|
||||||
// not included in the format string, it is ignored.
|
|
||||||
char* format_string = const_cast<char*>(value ? "(OO)" : "(O)");
|
|
||||||
result_object = PyEval_CallFunction(special_method.get(), format_string, this, value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If not found, try the usual __setattr__(name, value) or
|
|
||||||
// __delattr__(name) functions.
|
|
||||||
PyErr_Clear();
|
|
||||||
special_method.reset(
|
|
||||||
PyObject_GetAttr(as_object(this->ob_type), base_name.get()),
|
|
||||||
ref::null_ok);
|
|
||||||
|
|
||||||
if (special_method.get() != 0)
|
|
||||||
{
|
|
||||||
// The special function was found; call it now. Note that if value
|
|
||||||
// is not included in the format string, it is ignored.
|
|
||||||
char* format_string = const_cast<char*>(value ? "(OsO)" : "(Os)");
|
|
||||||
result_object = PyEval_CallFunction(
|
|
||||||
special_method.get(), format_string, this, name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we found an appropriate special method, handle the return value.
|
|
||||||
if (special_method.get() != 0)
|
|
||||||
{
|
|
||||||
ref manage_result(result_object);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyErr_Clear(); // Nothing was found; clear the python error state
|
|
||||||
|
|
||||||
if (value == 0) // Try to remove the attribute from our name space
|
|
||||||
{
|
|
||||||
const int result = PyDict_DelItemString(m_name_space.reference().get(),
|
|
||||||
const_cast<char*>(name));
|
|
||||||
if (result < 0)
|
|
||||||
{
|
|
||||||
PyErr_Clear();
|
|
||||||
PyErr_SetString(PyExc_AttributeError, "delete non-existing instance attribute");
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else // Change the specified item in our name space
|
|
||||||
{
|
|
||||||
return PyDict_SetItemString(m_name_space.reference().get(),
|
|
||||||
const_cast<char*>(name), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::call(PyObject* args, PyObject* keywords)
|
|
||||||
{
|
|
||||||
return PyEval_CallObjectWithKeywords(
|
|
||||||
ref(getattr("__call__")).get(), // take possession of the result from getattr()
|
|
||||||
args, keywords);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::repr()
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__repr__");
|
|
||||||
}
|
|
||||||
|
|
||||||
int instance::compare(PyObject* other)
|
|
||||||
{
|
|
||||||
return callback<int>::call_method(this, "__cmp__", other);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::str()
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__str__");
|
|
||||||
}
|
|
||||||
|
|
||||||
long instance::hash()
|
|
||||||
{
|
|
||||||
return callback<long>::call_method(this, "__hash__");
|
|
||||||
}
|
|
||||||
|
|
||||||
int instance::length()
|
|
||||||
{
|
|
||||||
return callback<int>::call_method(this, "__len__");
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::get_subscript(PyObject* key)
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__getitem__", key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void instance::set_subscript(PyObject* key, PyObject* value)
|
|
||||||
{
|
|
||||||
if (value == 0)
|
|
||||||
callback<void>::call_method(this, "__delitem__", key);
|
|
||||||
else
|
|
||||||
callback<void>::call_method(this, "__setitem__", key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::get_slice(int start, int finish)
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__getslice__", start, finish);
|
|
||||||
}
|
|
||||||
|
|
||||||
void instance::set_slice(int start, int finish, PyObject* value)
|
|
||||||
{
|
|
||||||
if (value == 0)
|
|
||||||
callback<void>::call_method(this, "__delslice__", start, finish);
|
|
||||||
else
|
|
||||||
callback<void>::call_method(this, "__setslice__", start, finish, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::add(PyObject* other)
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__add__", other);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::subtract(PyObject* other)
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__sub__", other);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::multiply(PyObject* other)
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__mul__", other);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::divide(PyObject* other)
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__div__", other);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::remainder(PyObject* other)
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__mod__", other);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::divmod(PyObject* other)
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__divmod__", other);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::power(PyObject* exponent, PyObject* modulus)
|
|
||||||
{
|
|
||||||
if (as_object(modulus->ob_type) == Py_None)
|
|
||||||
return callback<PyObject*>::call_method(this, "__pow__", exponent);
|
|
||||||
else
|
|
||||||
return callback<PyObject*>::call_method(this, "__pow__", exponent, modulus);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::negative()
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__neg__");
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::positive()
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__pos__");
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::absolute()
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__abs__");
|
|
||||||
}
|
|
||||||
|
|
||||||
int instance::nonzero()
|
|
||||||
{
|
|
||||||
return callback<bool>::call_method(this, "__nonzero__");
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::invert()
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__invert__");
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::lshift(PyObject* other)
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__lshift__", other);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::rshift(PyObject* other)
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__rshift__", other);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::do_and(PyObject* other)
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__and__", other);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::do_xor(PyObject* other)
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__xor__", other);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::do_or(PyObject* other)
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__or__", other);
|
|
||||||
}
|
|
||||||
|
|
||||||
int instance::coerce(PyObject** x, PyObject** y)
|
|
||||||
{
|
|
||||||
assert(this == *x);
|
|
||||||
|
|
||||||
// Coerce must return a tuple
|
|
||||||
tuple result(callback<tuple>::call_method(this, "__coerce__", *y));
|
|
||||||
|
|
||||||
*x = result[0].release();
|
|
||||||
*y = result[1].release();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::as_int()
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__int__");
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::as_long()
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__long__");
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::as_float()
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__float__");
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::oct()
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__oct__");
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* instance::hex()
|
|
||||||
{
|
|
||||||
return callback<PyObject*>::call_method(this, "__hex__");
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
struct named_capability
|
|
||||||
{
|
|
||||||
const char* name;
|
|
||||||
detail::type_object_base::capability capability;
|
|
||||||
};
|
|
||||||
|
|
||||||
const named_capability enablers[] =
|
|
||||||
{
|
|
||||||
{ "__hash__", detail::type_object_base::hash },
|
|
||||||
{ "__cmp__", detail::type_object_base::compare },
|
|
||||||
{ "__repr__", detail::type_object_base::repr },
|
|
||||||
{ "__str__", detail::type_object_base::str },
|
|
||||||
{ "__call__", detail::type_object_base::call },
|
|
||||||
{ "__getattr__", detail::type_object_base::getattr },
|
|
||||||
{ "__setattr__", detail::type_object_base::setattr },
|
|
||||||
{ "__len__", detail::type_object_base::mapping_length },
|
|
||||||
{ "__len__", detail::type_object_base::sequence_length },
|
|
||||||
{ "__getitem__", detail::type_object_base::mapping_subscript },
|
|
||||||
{ "__getitem__", detail::type_object_base::sequence_item },
|
|
||||||
{ "__setitem__", detail::type_object_base::mapping_ass_subscript },
|
|
||||||
{ "__setitem__", detail::type_object_base::sequence_ass_item },
|
|
||||||
{ "__delitem__", detail::type_object_base::mapping_ass_subscript },
|
|
||||||
{ "__delitem__", detail::type_object_base::sequence_ass_item },
|
|
||||||
{ "__getslice__", detail::type_object_base::sequence_slice },
|
|
||||||
{ "__setslice__", detail::type_object_base::sequence_ass_slice },
|
|
||||||
{ "__delslice__", detail::type_object_base::sequence_ass_slice },
|
|
||||||
{ "__add__", detail::type_object_base::number_add },
|
|
||||||
{ "__sub__", detail::type_object_base::number_subtract },
|
|
||||||
{ "__mul__", detail::type_object_base::number_multiply },
|
|
||||||
{ "__div__", detail::type_object_base::number_divide },
|
|
||||||
{ "__mod__", detail::type_object_base::number_remainder },
|
|
||||||
{ "__divmod__", detail::type_object_base::number_divmod },
|
|
||||||
{ "__pow__", detail::type_object_base::number_power },
|
|
||||||
{ "__neg__", detail::type_object_base::number_negative },
|
|
||||||
{ "__pos__", detail::type_object_base::number_positive },
|
|
||||||
{ "__abs__", detail::type_object_base::number_absolute },
|
|
||||||
{ "__nonzero__", detail::type_object_base::number_nonzero },
|
|
||||||
{ "__invert__", detail::type_object_base::number_invert },
|
|
||||||
{ "__lshift__", detail::type_object_base::number_lshift },
|
|
||||||
{ "__rshift__", detail::type_object_base::number_rshift },
|
|
||||||
{ "__and__", detail::type_object_base::number_and },
|
|
||||||
{ "__xor__", detail::type_object_base::number_xor },
|
|
||||||
{ "__or__", detail::type_object_base::number_or },
|
|
||||||
{ "__coerce__", detail::type_object_base::number_coerce },
|
|
||||||
{ "__int__", detail::type_object_base::number_int },
|
|
||||||
{ "__long__", detail::type_object_base::number_long },
|
|
||||||
{ "__float__", detail::type_object_base::number_float },
|
|
||||||
{ "__oct__", detail::type_object_base::number_oct },
|
|
||||||
{ "__hex__", detail::type_object_base::number_hex }
|
|
||||||
};
|
|
||||||
|
|
||||||
bool is_prefix(const char* s1, const char* s2)
|
|
||||||
{
|
|
||||||
while (*s1 != 0 && *s2 != 0 && *s1 == *s2)
|
|
||||||
++s1, ++s2;
|
|
||||||
return *s1 == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_special_name(const char* name)
|
|
||||||
{
|
|
||||||
if (name[0] != '_' || name[1] != '_' || name[2] == 0 || name[3] == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::size_t name_length = BOOST_CSTD_::strlen(name);
|
|
||||||
return name[name_length - 1] == '_' && name[name_length - 2] == '_';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
// Enable the special handler for methods of the given name, if any.
|
|
||||||
void enable_named_method(boost::python::detail::class_base* type_obj, const char* name)
|
|
||||||
{
|
|
||||||
const std::size_t num_enablers = sizeof(enablers) / sizeof(enablers[0]);
|
|
||||||
|
|
||||||
// Make sure this ends with "__" since we'll only compare the head of the
|
|
||||||
// string. This is done to make the __getattr__<name>__/__setattr__<name>__
|
|
||||||
// extension work.
|
|
||||||
if (!is_special_name(name))
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < num_enablers; ++i)
|
|
||||||
{
|
|
||||||
if (is_prefix(enablers[i].name + 2, name + 2))
|
|
||||||
{
|
|
||||||
type_obj->enable(enablers[i].capability);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
// Enable any special methods which are enabled in the base class.
|
|
||||||
void enable_special_methods(boost::python::detail::class_base* derived, const tuple& bases, const dictionary& name_space)
|
|
||||||
{
|
|
||||||
for (std::size_t i = 0; i < bases.size(); ++i)
|
|
||||||
{
|
|
||||||
PyObject* base = bases[i].get();
|
|
||||||
|
|
||||||
for (std::size_t n = 0; n < PY_ARRAY_LENGTH(enablers); ++n)
|
|
||||||
{
|
|
||||||
ref attribute(
|
|
||||||
PyObject_GetAttrString(base, const_cast<char*>(enablers[n].name)),
|
|
||||||
ref::null_ok);
|
|
||||||
PyErr_Clear();
|
|
||||||
if (attribute.get() != 0 && PyCallable_Check(attribute.get()))
|
|
||||||
detail::add_capability(enablers[n].capability, derived);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list keys(name_space.keys());
|
|
||||||
for (std::size_t j = 0, len = keys.size(); j < len; ++j)
|
|
||||||
{
|
|
||||||
string name_obj(keys.get_item(j));
|
|
||||||
const char* name = name_obj.c_str();
|
|
||||||
|
|
||||||
if (!is_special_name(name))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < PY_ARRAY_LENGTH(enablers); ++i)
|
|
||||||
{
|
|
||||||
if (is_prefix(enablers[i].name + 2, name + 2))
|
|
||||||
{
|
|
||||||
detail::add_capability(enablers[i].capability, derived);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_current_module_name(dictionary& name_space)
|
|
||||||
{
|
|
||||||
static string module_key("__module__", string::interned);
|
|
||||||
|
|
||||||
// If the user didn't specify a __module__ attribute already
|
|
||||||
if (name_space.get_item(module_key).get() == 0)
|
|
||||||
{
|
|
||||||
if (module_builder::initializing())
|
|
||||||
{
|
|
||||||
// The global __name__ is not properly set in this case
|
|
||||||
name_space.set_item(module_key, module_builder::name());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Get the module name from the global __name__
|
|
||||||
PyObject *globals = PyEval_GetGlobals();
|
|
||||||
if (globals != NULL)
|
|
||||||
{
|
|
||||||
PyObject *module_name = PyDict_GetItemString(globals, "__name__");
|
|
||||||
if (module_name != NULL)
|
|
||||||
name_space.set_item(module_key, module_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void adjust_slice_indices(PyObject* obj, int& start, int& finish)
|
|
||||||
{
|
|
||||||
int length = callback<int>::call_method(obj, "__len__");
|
|
||||||
|
|
||||||
// This is standard Python class behavior.
|
|
||||||
if (start < 0)
|
|
||||||
start += length;
|
|
||||||
if (finish < 0)
|
|
||||||
finish += length;
|
|
||||||
|
|
||||||
// This is not
|
|
||||||
if (start < 0)
|
|
||||||
start = 0;
|
|
||||||
if (finish < 0)
|
|
||||||
finish = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
const string& setattr_string()
|
|
||||||
{
|
|
||||||
static string x("__setattr__", string::interned);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
const string& getattr_string()
|
|
||||||
{
|
|
||||||
static string x("__getattr__", string::interned);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
const string& delattr_string()
|
|
||||||
{
|
|
||||||
static string x("__delattr__", string::interned);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
@@ -1,241 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#include <boost/python/conversions.hpp>
|
|
||||||
#include <typeinfo>
|
|
||||||
#include <exception>
|
|
||||||
#ifndef BOOST_NO_LIMITS
|
|
||||||
# include <boost/cast.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
// IMPORTANT: this function may only be called from within a catch block!
|
|
||||||
void handle_exception()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
// re-toss the current exception so we can find out what type it is.
|
|
||||||
// NOTE: a heinous bug in MSVC6 causes exception objects re-thrown in
|
|
||||||
// this way to be double-destroyed. Thus, you must only use objects that
|
|
||||||
// can tolerate double-destruction with that compiler. Metrowerks
|
|
||||||
// Codewarrior doesn't suffer from this problem.
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch(const boost::python::error_already_set&)
|
|
||||||
{
|
|
||||||
// The python error reporting has already been handled.
|
|
||||||
}
|
|
||||||
catch(const std::bad_alloc&)
|
|
||||||
{
|
|
||||||
PyErr_NoMemory();
|
|
||||||
}
|
|
||||||
catch(const std::exception& x)
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, x.what());
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, "unidentifiable C++ exception");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
|
|
||||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
|
||||||
|
|
||||||
long from_python(PyObject* p, boost::python::type<long>)
|
|
||||||
{
|
|
||||||
// Why am I clearing the error here before trying to convert? I know there's a reason...
|
|
||||||
long result;
|
|
||||||
{
|
|
||||||
result = PyInt_AsLong(p);
|
|
||||||
if (PyErr_Occurred())
|
|
||||||
throw boost::python::argument_error();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
double from_python(PyObject* p, boost::python::type<double>)
|
|
||||||
{
|
|
||||||
double result;
|
|
||||||
{
|
|
||||||
result = PyFloat_AsDouble(p);
|
|
||||||
if (PyErr_Occurred())
|
|
||||||
throw boost::python::argument_error();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
T integer_from_python(PyObject* p, boost::python::type<T>)
|
|
||||||
{
|
|
||||||
const long long_result = from_python(p, boost::python::type<long>());
|
|
||||||
|
|
||||||
#ifndef BOOST_NO_LIMITS
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return boost::numeric_cast<T>(long_result);
|
|
||||||
}
|
|
||||||
catch(const boost::bad_numeric_cast&)
|
|
||||||
#else
|
|
||||||
if (static_cast<T>(long_result) == long_result)
|
|
||||||
{
|
|
||||||
return static_cast<T>(long_result);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
char buffer[256];
|
|
||||||
const char message[] = "%ld out of range for %s";
|
|
||||||
sprintf(buffer, message, long_result, typeid(T).name());
|
|
||||||
PyErr_SetString(PyExc_ValueError, buffer);
|
|
||||||
throw boost::python::argument_error();
|
|
||||||
}
|
|
||||||
#if defined(__MWERKS__) && __MWERKS__ <= 0x2400
|
|
||||||
return 0; // Not smart enough to know that the catch clause always rethrows
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* integer_to_python(T value)
|
|
||||||
{
|
|
||||||
long value_as_long;
|
|
||||||
|
|
||||||
#ifndef BOOST_NO_LIMITS
|
|
||||||
try
|
|
||||||
{
|
|
||||||
value_as_long = boost::numeric_cast<long>(value);
|
|
||||||
}
|
|
||||||
catch(const boost::bad_numeric_cast&)
|
|
||||||
#else
|
|
||||||
value_as_long = static_cast<long>(value);
|
|
||||||
if (value_as_long != value)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
const char message[] = "value out of range for Python int";
|
|
||||||
PyErr_SetString(PyExc_ValueError, message);
|
|
||||||
throw boost::python::error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
return to_python(value_as_long);
|
|
||||||
}
|
|
||||||
|
|
||||||
int from_python(PyObject* p, boost::python::type<int> type)
|
|
||||||
{
|
|
||||||
return integer_from_python(p, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(unsigned int i)
|
|
||||||
{
|
|
||||||
return integer_to_python(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int from_python(PyObject* p, boost::python::type<unsigned int> type)
|
|
||||||
{
|
|
||||||
return integer_from_python(p, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
short from_python(PyObject* p, boost::python::type<short> type)
|
|
||||||
{
|
|
||||||
return integer_from_python(p, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
float from_python(PyObject* p, boost::python::type<float>)
|
|
||||||
{
|
|
||||||
return static_cast<float>(from_python(p, boost::python::type<double>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(unsigned short i)
|
|
||||||
{
|
|
||||||
return integer_to_python(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned short from_python(PyObject* p, boost::python::type<unsigned short> type)
|
|
||||||
{
|
|
||||||
return integer_from_python(p, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(unsigned char i)
|
|
||||||
{
|
|
||||||
return integer_to_python(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char from_python(PyObject* p, boost::python::type<unsigned char> type)
|
|
||||||
{
|
|
||||||
return integer_from_python(p, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(signed char i)
|
|
||||||
{
|
|
||||||
return integer_to_python(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
signed char from_python(PyObject* p, boost::python::type<signed char> type)
|
|
||||||
{
|
|
||||||
return integer_from_python(p, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(unsigned long x)
|
|
||||||
{
|
|
||||||
return integer_to_python(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long from_python(PyObject* p, boost::python::type<unsigned long> type)
|
|
||||||
{
|
|
||||||
return integer_from_python(p, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
void from_python(PyObject* p, boost::python::type<void>)
|
|
||||||
{
|
|
||||||
if (p != Py_None) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "expected argument of type None");
|
|
||||||
throw boost::python::argument_error();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* from_python(PyObject* p, boost::python::type<const char*>)
|
|
||||||
{
|
|
||||||
const char* s = PyString_AsString(p);
|
|
||||||
if (!s)
|
|
||||||
throw boost::python::argument_error();
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(const std::string& s)
|
|
||||||
{
|
|
||||||
return PyString_FromString(s.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string from_python(PyObject* p, boost::python::type<std::string>)
|
|
||||||
{
|
|
||||||
return std::string(from_python(p, boost::python::type<const char*>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool from_python(PyObject* p, boost::python::type<bool>)
|
|
||||||
{
|
|
||||||
int value = from_python(p, boost::python::type<int>());
|
|
||||||
if (value == 0)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BOOST_MSVC6_OR_EARLIER
|
|
||||||
// An optimizer bug prevents these from being inlined.
|
|
||||||
PyObject* to_python(double d)
|
|
||||||
{
|
|
||||||
return PyFloat_FromDouble(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(float f)
|
|
||||||
{
|
|
||||||
return PyFloat_FromDouble(f);
|
|
||||||
}
|
|
||||||
#endif // BOOST_MSVC6_OR_EARLIER
|
|
||||||
|
|
||||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
|
||||||
|
|
||||||
@@ -1,678 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#include <boost/python/detail/extension_class.hpp>
|
|
||||||
#include <cstring>
|
|
||||||
#include <boost/utility.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
struct operator_dispatcher
|
|
||||||
: public PyObject
|
|
||||||
{
|
|
||||||
static PyTypeObject type_obj;
|
|
||||||
static PyNumberMethods number_methods;
|
|
||||||
|
|
||||||
static operator_dispatcher* create(const ref& o, const ref& s);
|
|
||||||
|
|
||||||
ref m_object;
|
|
||||||
ref m_self;
|
|
||||||
|
|
||||||
// data members for allocation/deallocation optimization
|
|
||||||
operator_dispatcher* m_free_list_link;
|
|
||||||
static operator_dispatcher* free_list;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// only accessible through create()
|
|
||||||
operator_dispatcher(const ref& o, const ref& s);
|
|
||||||
};
|
|
||||||
|
|
||||||
operator_dispatcher* operator_dispatcher::free_list = 0;
|
|
||||||
|
|
||||||
}}} // namespace boost::python::detail
|
|
||||||
|
|
||||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
|
||||||
|
|
||||||
inline PyObject* to_python(boost::python::detail::operator_dispatcher* n) { return n; }
|
|
||||||
|
|
||||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
|
||||||
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
tuple standard_coerce(ref l, ref r)
|
|
||||||
{
|
|
||||||
// Introduced sequence points for exception-safety.
|
|
||||||
ref first(detail::operator_dispatcher::create(l, l));
|
|
||||||
|
|
||||||
ref second(r->ob_type == &detail::operator_dispatcher::type_obj
|
|
||||||
? r
|
|
||||||
: ref(detail::operator_dispatcher::create(r, ref())));
|
|
||||||
|
|
||||||
return tuple(first, second);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
enum { unwrap_exception_code = -1000 };
|
|
||||||
|
|
||||||
int unwrap_args(PyObject* left, PyObject* right, PyObject*& self, PyObject*& other)
|
|
||||||
{
|
|
||||||
if (left->ob_type != &operator_dispatcher::type_obj ||
|
|
||||||
right->ob_type != &operator_dispatcher::type_obj)
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, "operator_dispatcher::unwrap_args(): expecting operator_dispatcher arguments only!");
|
|
||||||
return unwrap_exception_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef reference<operator_dispatcher> DPtr;
|
|
||||||
DPtr lwrapper(static_cast<operator_dispatcher*>(left), DPtr::increment_count);
|
|
||||||
DPtr rwrapper(static_cast<operator_dispatcher*>(right), DPtr::increment_count);
|
|
||||||
|
|
||||||
if (lwrapper->m_self.get() != 0)
|
|
||||||
{
|
|
||||||
self = lwrapper->m_self.get();
|
|
||||||
other = rwrapper->m_object.get();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self = rwrapper->m_self.get();
|
|
||||||
other = lwrapper->m_object.get();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int unwrap_pow_args(PyObject* left, PyObject* right, PyObject* m,
|
|
||||||
PyObject*& self, PyObject*& first, PyObject*& second)
|
|
||||||
{
|
|
||||||
if (left->ob_type != &operator_dispatcher::type_obj ||
|
|
||||||
right->ob_type != &operator_dispatcher::type_obj ||
|
|
||||||
m->ob_type != &operator_dispatcher::type_obj)
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, "operator_dispatcher::unwrap_pow_args(): expecting operator_dispatcher arguments only!");
|
|
||||||
return unwrap_exception_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef reference<operator_dispatcher> DPtr;
|
|
||||||
DPtr lwrapper(static_cast<operator_dispatcher*>(left), DPtr::increment_count);
|
|
||||||
DPtr rwrapper(static_cast<operator_dispatcher*>(right), DPtr::increment_count);
|
|
||||||
DPtr mwrapper(static_cast<operator_dispatcher*>(m), DPtr::increment_count);
|
|
||||||
|
|
||||||
if (lwrapper->m_self.get() != 0)
|
|
||||||
{
|
|
||||||
self = lwrapper->m_self.get();
|
|
||||||
first = rwrapper->m_object.get();
|
|
||||||
second = mwrapper->m_object.get();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (rwrapper->m_self.get() != 0)
|
|
||||||
{
|
|
||||||
self = rwrapper->m_self.get();
|
|
||||||
first = lwrapper->m_object.get();
|
|
||||||
second = mwrapper->m_object.get();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self = mwrapper->m_self.get();
|
|
||||||
first = lwrapper->m_object.get();
|
|
||||||
second = rwrapper->m_object.get();
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension_instance* get_extension_instance(PyObject* p)
|
|
||||||
{
|
|
||||||
// The object's type will just be some class_t<extension_instance> object,
|
|
||||||
// but if its meta-type is right, then it is an extension_instance.
|
|
||||||
if (p->ob_type->ob_type != extension_meta_class())
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
|
||||||
throw boost::python::argument_error();
|
|
||||||
}
|
|
||||||
return static_cast<extension_instance*>(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
extension_instance::add_implementation(std::auto_ptr<instance_holder_base> holder)
|
|
||||||
{
|
|
||||||
for (held_objects::const_iterator p = m_wrapped_objects.begin();
|
|
||||||
p != m_wrapped_objects.end(); ++p)
|
|
||||||
{
|
|
||||||
if (typeid(*holder) == typeid(**p))
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Base class already initialized");
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_wrapped_objects.push_back(holder.release());
|
|
||||||
}
|
|
||||||
|
|
||||||
extension_instance::extension_instance(PyTypeObject* class_)
|
|
||||||
: instance(class_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
extension_instance::~extension_instance()
|
|
||||||
{
|
|
||||||
for (held_objects::const_iterator p = m_wrapped_objects.begin(),
|
|
||||||
finish = m_wrapped_objects.end();
|
|
||||||
p != finish; ++p)
|
|
||||||
{
|
|
||||||
delete *p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
meta_class<extension_instance>* extension_meta_class()
|
|
||||||
{
|
|
||||||
static meta_class<extension_instance> result;
|
|
||||||
return &result;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef class_t<extension_instance> extension_class_t;
|
|
||||||
|
|
||||||
bool is_subclass(const extension_class_t* derived,
|
|
||||||
const PyObject* possible_base)
|
|
||||||
{
|
|
||||||
|
|
||||||
tuple bases = derived->bases();
|
|
||||||
|
|
||||||
for (std::size_t i = 0, size = bases.size(); i < size; ++i)
|
|
||||||
{
|
|
||||||
const PyObject* base = bases[i].get();
|
|
||||||
|
|
||||||
if (base == possible_base)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (base->ob_type == extension_meta_class())
|
|
||||||
{
|
|
||||||
const extension_class_t* base_class = downcast<const extension_class_t>(base);
|
|
||||||
if (is_subclass(base_class, possible_base))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true iff obj is an obj of target_class
|
|
||||||
bool is_instance(extension_instance* obj,
|
|
||||||
class_t<extension_instance>* target_class)
|
|
||||||
{
|
|
||||||
if (obj->ob_type == target_class)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return is_subclass(
|
|
||||||
downcast<class_t<extension_instance> >(obj->ob_type).get(),
|
|
||||||
as_object(target_class));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void two_string_error(PyObject* exception_object, const char* format, const char* s1, const char* s2)
|
|
||||||
{
|
|
||||||
char buffer[256];
|
|
||||||
std::size_t format_length = BOOST_CSTD_::strlen(format);
|
|
||||||
std::size_t length1 = BOOST_CSTD_::strlen(s1);
|
|
||||||
std::size_t length2 = BOOST_CSTD_::strlen(s2);
|
|
||||||
|
|
||||||
std::size_t additional_length = length1 + length2;
|
|
||||||
if (additional_length + format_length > format_length - 1)
|
|
||||||
{
|
|
||||||
std::size_t difference = sizeof(buffer) - 1 - additional_length;
|
|
||||||
length1 -= difference / 2;
|
|
||||||
additional_length -= difference / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(buffer, format, length1, s1, length2, s2);
|
|
||||||
|
|
||||||
PyErr_SetString(exception_object, buffer);
|
|
||||||
if (exception_object == PyExc_TypeError)
|
|
||||||
throw argument_error();
|
|
||||||
else
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is called when an attempt has been made to convert the given obj to
|
|
||||||
// a C++ type for which it doesn't have any obj data. In that case, either
|
|
||||||
// the obj was not derived from the target_class, or the appropriate
|
|
||||||
// __init__ function wasn't called to initialize the obj data of the target class.
|
|
||||||
void report_missing_instance_data(
|
|
||||||
extension_instance* obj, // The object being converted
|
|
||||||
class_t<extension_instance>* target_class, // the extension class of the C++ type
|
|
||||||
const std::type_info& target_typeid, // The typeid of the C++ type
|
|
||||||
bool target_is_ptr)
|
|
||||||
{
|
|
||||||
char buffer[256];
|
|
||||||
if (is_instance(obj, target_class))
|
|
||||||
{
|
|
||||||
if (target_is_ptr)
|
|
||||||
{
|
|
||||||
two_string_error(PyExc_RuntimeError,
|
|
||||||
"Object of extension class '%.*s' does not wrap <%.*s>.",
|
|
||||||
obj->ob_type->tp_name, target_typeid.name());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const char message[] = "__init__ function for extension class '%.*s' was never called.";
|
|
||||||
sprintf(buffer, message, sizeof(buffer) - sizeof(message) - 1,
|
|
||||||
target_class->tp_name);
|
|
||||||
}
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, buffer);
|
|
||||||
}
|
|
||||||
else if (target_class == 0)
|
|
||||||
{
|
|
||||||
const char message[] = "Cannot convert to <%.*s>; its Python class was never created or has been deleted.";
|
|
||||||
sprintf(buffer, message, sizeof(buffer) - sizeof(message) - 1, target_typeid.name());
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, buffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
two_string_error(PyExc_TypeError, "extension class '%.*s' is not convertible into '%.*s'.",
|
|
||||||
obj->ob_type->tp_name, target_class->tp_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void report_missing_instance_data(
|
|
||||||
extension_instance* obj, // The object being converted
|
|
||||||
class_t<extension_instance>* target_class, // the extension class of the C++ type
|
|
||||||
const std::type_info& target_typeid) // The typeid of the C++ type
|
|
||||||
{
|
|
||||||
report_missing_instance_data(obj, target_class, target_typeid, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void report_missing_ptr_data(
|
|
||||||
extension_instance* obj, // The object being converted
|
|
||||||
class_t<extension_instance>* target_class, // the extension class of the C++ type
|
|
||||||
const std::type_info& target_typeid) // The typeid of the C++ type
|
|
||||||
{
|
|
||||||
report_missing_instance_data(obj, target_class, target_typeid, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void report_missing_class_object(const std::type_info& info)
|
|
||||||
{
|
|
||||||
char buffer[256];
|
|
||||||
const char message[] = "Cannot convert <%.*s> to python; its Python class was never created or has been deleted.";
|
|
||||||
sprintf(buffer, message, sizeof(buffer) - sizeof(message) - 1, info.name());
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, buffer);
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
void report_released_smart_pointer(const std::type_info& info)
|
|
||||||
{
|
|
||||||
char buffer[256];
|
|
||||||
const char message[] = "Converting from python, pointer or smart pointer to <%.*s> is NULL.";
|
|
||||||
sprintf(buffer, message, sizeof(buffer) - sizeof(message) - 1, info.name());
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, buffer);
|
|
||||||
throw argument_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
read_only_setattr_function::read_only_setattr_function(const char* name)
|
|
||||||
: m_name(name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* read_only_setattr_function::do_call(PyObject* /*args*/, PyObject* /*keywords*/) const
|
|
||||||
{
|
|
||||||
PyErr_SetObject(PyExc_AttributeError, ("'" + m_name + "' attribute is read-only").get());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* read_only_setattr_function::description() const
|
|
||||||
{
|
|
||||||
return "uncallable";
|
|
||||||
}
|
|
||||||
|
|
||||||
extension_class_base::extension_class_base(const char* name)
|
|
||||||
: class_t<extension_instance>(
|
|
||||||
extension_meta_class(), string(name), tuple(), dictionary())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function is used in from_python() to convert wrapped classes that are
|
|
||||||
// related by inheritance. The problem is this: although C++ provides all necessary
|
|
||||||
// conversion operators, source and target of a conversion must be known at compile
|
|
||||||
// time. However, in Python we want to convert classes at runtime. The solution is to
|
|
||||||
// generate conversion functions at compile time, register them within the appropriate
|
|
||||||
// class objects and call them when a particular runtime conversion is required.
|
|
||||||
|
|
||||||
// If functions for any possible conversion have to be stored, their number will grow
|
|
||||||
// qudratically. To reduce this number, we actually store only conversion functions
|
|
||||||
// between adjacent levels in the inheritance tree. By traversing the tree recursively,
|
|
||||||
// we can build any allowed conversion as a concatenation of simple conversions. This
|
|
||||||
// traversal is done in the functions try_base_class_conversions() and
|
|
||||||
// try_derived_class_conversions(). If a particular conversion is impossible, all
|
|
||||||
// conversion functions will return a NULL pointer.
|
|
||||||
|
|
||||||
// The function extract_object_from_holder() attempts to actually extract the pointer
|
|
||||||
// to the contained object from an instance_holder_base (a wrapper class). A conversion
|
|
||||||
// of the held object to 'T *' is allowed when the conversion
|
|
||||||
// 'dynamic_cast<instance_holder<T> *>(an_instance_holder_base)' succeeds.
|
|
||||||
void* extension_class_base::try_class_conversions(instance_holder_base* object) const
|
|
||||||
{
|
|
||||||
void* result = try_derived_class_conversions(object);
|
|
||||||
if (result)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
if (!object->held_by_value())
|
|
||||||
return try_base_class_conversions(object);
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* extension_class_base::try_base_class_conversions(instance_holder_base* object) const
|
|
||||||
{
|
|
||||||
for (std::size_t i = 0; i < base_classes().size(); ++i)
|
|
||||||
{
|
|
||||||
if (base_classes()[i].convert == 0)
|
|
||||||
continue;
|
|
||||||
void* result1 = base_classes()[i].class_object->extract_object_from_holder(object);
|
|
||||||
if (result1)
|
|
||||||
return (*base_classes()[i].convert)(result1);
|
|
||||||
|
|
||||||
void* result2 = base_classes()[i].class_object->try_base_class_conversions(object);
|
|
||||||
if (result2)
|
|
||||||
return (*base_classes()[i].convert)(result2);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* extension_class_base::try_derived_class_conversions(instance_holder_base* object) const
|
|
||||||
{
|
|
||||||
for (std::size_t i = 0; i < derived_classes().size(); ++i)
|
|
||||||
{
|
|
||||||
void* result1 = derived_classes()[i].class_object->extract_object_from_holder(object);
|
|
||||||
if (result1)
|
|
||||||
return (*derived_classes()[i].convert)(result1);
|
|
||||||
|
|
||||||
void* result2 = derived_classes()[i].class_object->try_derived_class_conversions(object);
|
|
||||||
if (result2)
|
|
||||||
return (*derived_classes()[i].convert)(result2);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void extension_class_base::add_method(function* method, const char* name)
|
|
||||||
{
|
|
||||||
add_method(reference<function>(method), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void extension_class_base::add_method(reference<function> method, const char* name)
|
|
||||||
{
|
|
||||||
// Add the attribute to the computed target
|
|
||||||
function::add_to_namespace(method, name, this->dict().get());
|
|
||||||
|
|
||||||
// If it is a special member function it should be enabled both here and there.
|
|
||||||
detail::enable_named_method(this, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void extension_class_base::add_constructor_object(function* init_fn)
|
|
||||||
{
|
|
||||||
add_method(init_fn, "__init__");
|
|
||||||
}
|
|
||||||
|
|
||||||
void extension_class_base::add_setter_method(function* setter_, const char* name)
|
|
||||||
{
|
|
||||||
reference<function> setter(setter_);
|
|
||||||
add_method(setter, (detail::setattr_string() + name + "__").c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void extension_class_base::add_getter_method(function* getter_, const char* name)
|
|
||||||
{
|
|
||||||
reference<function> getter(getter_);
|
|
||||||
add_method(getter, (detail::getattr_string() + name + "__").c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void extension_class_base::set_attribute(const char* name, PyObject* x_)
|
|
||||||
{
|
|
||||||
ref x(x_);
|
|
||||||
set_attribute(name, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
void extension_class_base::set_attribute(const char* name, ref x)
|
|
||||||
{
|
|
||||||
dict().set_item(string(name), x);
|
|
||||||
if (PyCallable_Check(x.get()))
|
|
||||||
detail::enable_named_method(this, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
operator_dispatcher::operator_dispatcher(const ref& o, const ref& s)
|
|
||||||
: m_object(o), m_self(s), m_free_list_link(0)
|
|
||||||
|
|
||||||
{
|
|
||||||
ob_refcnt = 1;
|
|
||||||
ob_type = &type_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator_dispatcher*
|
|
||||||
operator_dispatcher::create(const ref& object, const ref& self)
|
|
||||||
{
|
|
||||||
operator_dispatcher* const result = free_list;
|
|
||||||
if (result == 0)
|
|
||||||
return new operator_dispatcher(object, self);
|
|
||||||
|
|
||||||
free_list = result->m_free_list_link;
|
|
||||||
result->m_object = object;
|
|
||||||
result->m_self = self;
|
|
||||||
Py_INCREF(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
|
|
||||||
void operator_dispatcher_dealloc(PyObject* self)
|
|
||||||
{
|
|
||||||
operator_dispatcher* obj = static_cast<operator_dispatcher*>(self);
|
|
||||||
obj->m_free_list_link = operator_dispatcher::free_list;
|
|
||||||
operator_dispatcher::free_list = obj;
|
|
||||||
obj->m_object.reset();
|
|
||||||
obj->m_self.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
int operator_dispatcher_coerce(PyObject** l, PyObject** r)
|
|
||||||
{
|
|
||||||
Py_INCREF(*l);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
*r = operator_dispatcher::create(ref(*r, ref::increment_count), ref());
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
handle_exception();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define PY_DEFINE_OPERATOR(id, symbol) \
|
|
||||||
PyObject* operator_dispatcher_call_##id(PyObject* left, PyObject* right) \
|
|
||||||
{ \
|
|
||||||
/* unwrap the arguments from their OperatorDispatcher */ \
|
|
||||||
PyObject* self; \
|
|
||||||
PyObject* other; \
|
|
||||||
int reverse = unwrap_args(left, right, self, other); \
|
|
||||||
if (reverse == unwrap_exception_code) \
|
|
||||||
return 0; \
|
|
||||||
\
|
|
||||||
/* call the function */ \
|
|
||||||
PyObject* result = \
|
|
||||||
PyEval_CallMethod(self, \
|
|
||||||
const_cast<char*>(reverse ? "__r" #id "__" : "__" #id "__"), \
|
|
||||||
const_cast<char*>("(O)"), \
|
|
||||||
other); \
|
|
||||||
if (result == 0 && PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)) \
|
|
||||||
{ \
|
|
||||||
PyErr_Clear(); \
|
|
||||||
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for " #symbol); \
|
|
||||||
} \
|
|
||||||
return result; \
|
|
||||||
}
|
|
||||||
|
|
||||||
PY_DEFINE_OPERATOR(add, +)
|
|
||||||
PY_DEFINE_OPERATOR(sub, -)
|
|
||||||
PY_DEFINE_OPERATOR(mul, *)
|
|
||||||
PY_DEFINE_OPERATOR(div, /)
|
|
||||||
PY_DEFINE_OPERATOR(mod, %)
|
|
||||||
PY_DEFINE_OPERATOR(divmod, divmod)
|
|
||||||
PY_DEFINE_OPERATOR(lshift, <<)
|
|
||||||
PY_DEFINE_OPERATOR(rshift, >>)
|
|
||||||
PY_DEFINE_OPERATOR(and, &)
|
|
||||||
PY_DEFINE_OPERATOR(xor, ^)
|
|
||||||
PY_DEFINE_OPERATOR(or, |)
|
|
||||||
|
|
||||||
/* coercion rules for heterogeneous pow():
|
|
||||||
pow(Foo, int): left, right coerced; m: None => reverse = 0
|
|
||||||
pow(int, Foo): left, right coerced; m: None => reverse = 1
|
|
||||||
pow(Foo, int, int): left, right, m coerced => reverse = 0
|
|
||||||
pow(int, Foo, int): left, right, m coerced => reverse = 1
|
|
||||||
pow(int, int, Foo): left, right, m coerced => reverse = 2
|
|
||||||
pow(Foo, Foo, int): left, right coerced; m coerced twice => reverse = 0
|
|
||||||
pow(Foo, int, Foo): left, right, m coerced => reverse = 0
|
|
||||||
pow(int, Foo, Foo): left, right, m coerced => reverse = 1
|
|
||||||
*/
|
|
||||||
PyObject* operator_dispatcher_call_pow(PyObject* left, PyObject* right, PyObject* m)
|
|
||||||
{
|
|
||||||
int reverse;
|
|
||||||
PyObject* self;
|
|
||||||
PyObject* first;
|
|
||||||
PyObject* second;
|
|
||||||
|
|
||||||
if (m->ob_type == Py_None->ob_type)
|
|
||||||
{
|
|
||||||
reverse = unwrap_args(left, right, self, first);
|
|
||||||
second = m;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reverse = unwrap_pow_args(left, right, m, self, first, second);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reverse == unwrap_exception_code)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// call the function
|
|
||||||
PyObject* result =
|
|
||||||
PyEval_CallMethod(self,
|
|
||||||
const_cast<char*>((reverse == 0)
|
|
||||||
? "__pow__"
|
|
||||||
: (reverse == 1)
|
|
||||||
? "__rpow__"
|
|
||||||
: "__rrpow__"),
|
|
||||||
const_cast<char*>("(OO)"),
|
|
||||||
first, second);
|
|
||||||
if (result == 0 &&
|
|
||||||
(PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_TypeError) ||
|
|
||||||
PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)))
|
|
||||||
{
|
|
||||||
PyErr_Clear();
|
|
||||||
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for pow()");
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int operator_dispatcher_call_cmp(PyObject* left, PyObject* right)
|
|
||||||
{
|
|
||||||
// unwrap the arguments from their OperatorDispatcher
|
|
||||||
PyObject* self;
|
|
||||||
PyObject* other;
|
|
||||||
int reverse = unwrap_args(left, right, self, other);
|
|
||||||
if (reverse == unwrap_exception_code)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
// call the function
|
|
||||||
PyObject* result =
|
|
||||||
PyEval_CallMethod(self,
|
|
||||||
const_cast<char*>(reverse ? "__rcmp__" : "__cmp__"),
|
|
||||||
const_cast<char*>("(O)"),
|
|
||||||
other);
|
|
||||||
if (result == 0)
|
|
||||||
{
|
|
||||||
PyErr_Clear();
|
|
||||||
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for cmp() or <");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return BOOST_PYTHON_CONVERSION::from_python(result, type<int>());
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
PyErr_Clear();
|
|
||||||
PyErr_SetString(PyExc_TypeError, "cmp() didn't return int");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // extern "C"
|
|
||||||
|
|
||||||
PyTypeObject operator_dispatcher::type_obj =
|
|
||||||
{
|
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
|
||||||
0,
|
|
||||||
const_cast<char*>("operator_dispatcher"),
|
|
||||||
sizeof(operator_dispatcher),
|
|
||||||
0,
|
|
||||||
&operator_dispatcher_dealloc,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
&operator_dispatcher_call_cmp,
|
|
||||||
0,
|
|
||||||
&operator_dispatcher::number_methods,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
PyNumberMethods operator_dispatcher::number_methods =
|
|
||||||
{
|
|
||||||
&operator_dispatcher_call_add,
|
|
||||||
&operator_dispatcher_call_sub,
|
|
||||||
&operator_dispatcher_call_mul,
|
|
||||||
&operator_dispatcher_call_div,
|
|
||||||
&operator_dispatcher_call_mod,
|
|
||||||
&operator_dispatcher_call_divmod,
|
|
||||||
&operator_dispatcher_call_pow,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
&operator_dispatcher_call_lshift,
|
|
||||||
&operator_dispatcher_call_rshift,
|
|
||||||
&operator_dispatcher_call_and,
|
|
||||||
&operator_dispatcher_call_xor,
|
|
||||||
&operator_dispatcher_call_or,
|
|
||||||
&operator_dispatcher_coerce,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#include <boost/python/detail/functions.hpp>
|
|
||||||
#include <boost/python/detail/types.hpp>
|
|
||||||
#include <boost/python/detail/singleton.hpp>
|
|
||||||
#include <boost/python/objects.hpp>
|
|
||||||
#include <boost/python/errors.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python { namespace detail {
|
|
||||||
|
|
||||||
struct function::type_object :
|
|
||||||
singleton<function::type_object, callable<boost::python::detail::type_object<function> > >
|
|
||||||
{
|
|
||||||
type_object() : singleton_base(&PyType_Type) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void function::add_to_namespace(reference<function> new_function, const char* name, PyObject* dict)
|
|
||||||
{
|
|
||||||
dictionary d(ref(dict, ref::increment_count));
|
|
||||||
string key(name);
|
|
||||||
|
|
||||||
ref existing_object = d.get_item(key.reference());
|
|
||||||
if (existing_object.get() == 0)
|
|
||||||
{
|
|
||||||
d[key] = ref(new_function.get(), ref::increment_count);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (existing_object->ob_type == type_object::instance())
|
|
||||||
{
|
|
||||||
function* f = static_cast<function*>(existing_object.get());
|
|
||||||
while (f->m_overloads.get() != 0)
|
|
||||||
f = f->m_overloads.get();
|
|
||||||
f->m_overloads = new_function;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PyErr_SetObject(PyExc_RuntimeError,
|
|
||||||
(string("Attempt to overload ") + name
|
|
||||||
+ " failed. The existing attribute has type "
|
|
||||||
+ existing_object->ob_type->tp_name).get());
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function::function()
|
|
||||||
: python_object(type_object::instance())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* function::call(PyObject* args, PyObject* keywords) const
|
|
||||||
{
|
|
||||||
for (const function* f = this; f != 0; f = f->m_overloads.get())
|
|
||||||
{
|
|
||||||
PyErr_Clear();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PyObject* const result = f->do_call(args, keywords);
|
|
||||||
if (result != 0)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch(const argument_error&)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_overloads.get() == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
PyErr_Clear();
|
|
||||||
string message("No overloaded functions match (");
|
|
||||||
tuple arguments(ref(args, ref::increment_count));
|
|
||||||
for (std::size_t i = 0; i < arguments.size(); ++i)
|
|
||||||
{
|
|
||||||
if (i != 0)
|
|
||||||
message += ", ";
|
|
||||||
message += arguments[i]->ob_type->tp_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
message += "). Candidates are:\n";
|
|
||||||
for (const function* f1 = this; f1 != 0; f1 = f1->m_overloads.get())
|
|
||||||
{
|
|
||||||
if (f1 != this)
|
|
||||||
message += "\n";
|
|
||||||
message += f1->description();
|
|
||||||
}
|
|
||||||
|
|
||||||
PyErr_SetObject(PyExc_TypeError, message.get());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bound_function* bound_function::create(const ref& target, const ref& fn)
|
|
||||||
{
|
|
||||||
bound_function* const result = free_list;
|
|
||||||
if (result == 0)
|
|
||||||
return new bound_function(target, fn);
|
|
||||||
|
|
||||||
free_list = result->m_free_list_link;
|
|
||||||
result->m_target = target;
|
|
||||||
result->m_unbound_function = fn;
|
|
||||||
Py_INCREF(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The instance class whose obj represents the type of bound_function
|
|
||||||
// objects in Python. bound_functions must be GetAttrable so the __doc__
|
|
||||||
// attribute of built-in Python functions can be accessed when bound.
|
|
||||||
struct bound_function::type_object :
|
|
||||||
singleton<bound_function::type_object,
|
|
||||||
getattrable<callable<boost::python::detail::type_object<bound_function> > > >
|
|
||||||
{
|
|
||||||
type_object() : singleton_base(&PyType_Type) {}
|
|
||||||
|
|
||||||
private: // type_object<bound_function> hook override
|
|
||||||
void dealloc(bound_function*) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
bound_function::bound_function(const ref& target, const ref& fn)
|
|
||||||
: python_object(type_object::instance()),
|
|
||||||
m_target(target),
|
|
||||||
m_unbound_function(fn),
|
|
||||||
m_free_list_link(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject*
|
|
||||||
bound_function::call(PyObject* args, PyObject* keywords) const
|
|
||||||
{
|
|
||||||
// Build a new tuple which prepends the target to the arguments
|
|
||||||
tuple tail_arguments(ref(args, ref::increment_count));
|
|
||||||
ref all_arguments(PyTuple_New(tail_arguments.size() + 1));
|
|
||||||
|
|
||||||
PyTuple_SET_ITEM(all_arguments.get(), 0, m_target.get());
|
|
||||||
Py_INCREF(m_target.get());
|
|
||||||
for (std::size_t i = 0; i < tail_arguments.size(); ++i)
|
|
||||||
{
|
|
||||||
PyTuple_SET_ITEM(all_arguments.get(), i + 1, tail_arguments[i].get());
|
|
||||||
Py_INCREF(tail_arguments[i].get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return PyEval_CallObjectWithKeywords(m_unbound_function.get(), all_arguments.get(), keywords);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* bound_function::getattr(const char* name) const
|
|
||||||
{
|
|
||||||
return PyObject_GetAttrString(m_unbound_function.get(), const_cast<char*>(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
void bound_function::type_object::dealloc(bound_function* obj) const
|
|
||||||
{
|
|
||||||
obj->m_free_list_link = free_list;
|
|
||||||
free_list = obj;
|
|
||||||
obj->m_target.reset();
|
|
||||||
obj->m_unbound_function.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
bound_function* bound_function::free_list;
|
|
||||||
|
|
||||||
}}} // namespace boost::python::detail
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
from gen_callback import *
|
|
||||||
from gen_caller import *
|
|
||||||
from gen_init_function import *
|
|
||||||
from gen_signatures import *
|
|
||||||
from gen_singleton import *
|
|
||||||
from gen_extclass import *
|
|
||||||
|
|
||||||
def gen_all(args):
|
|
||||||
open('callback.h', 'w').write(gen_callback(args))
|
|
||||||
open('caller.h', 'w').write(gen_caller(args))
|
|
||||||
open('init_function.h', 'w').write(gen_init_function(args))
|
|
||||||
open('signatures.h', 'w').write(gen_signatures(args))
|
|
||||||
open('instance.h', 'w').write(gen_singleton(args))
|
|
||||||
open('extclass.h', 'w').write(gen_extclass(args))
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
|
||||||
args = 10
|
|
||||||
else:
|
|
||||||
args = int(sys.argv[1])
|
|
||||||
|
|
||||||
print gen_all(args)
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
from gen_function import *
|
|
||||||
import string
|
|
||||||
|
|
||||||
def gen_callback(args):
|
|
||||||
return (
|
|
||||||
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
//
|
|
||||||
// This file was generated for %d-argument python callbacks by gen_callback.python
|
|
||||||
|
|
||||||
#ifndef CALLBACK_DWA_052100_H_
|
|
||||||
# define CALLBACK_DWA_052100_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/python/conversions.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template <class T>
|
|
||||||
inline void callback_adjust_refcount(PyObject*, type<T>) {}
|
|
||||||
|
|
||||||
inline void callback_adjust_refcount(PyObject* p, type<PyObject*>)
|
|
||||||
{ Py_INCREF(p); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calling Python from C++
|
|
||||||
template <class R>
|
|
||||||
struct callback
|
|
||||||
{""" % args
|
|
||||||
|
|
||||||
+ gen_functions('''
|
|
||||||
%{ template <%(class A%n%:, %)>
|
|
||||||
%} static R call_method(PyObject* self, const char* name%(, const A%n& a%n%))
|
|
||||||
{%(
|
|
||||||
ref p%n(to_python(a%n));%)
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(%(O%))")%(,
|
|
||||||
p%n.get()%)));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
|
|
||||||
%{ template <%(class A%n%:, %)>
|
|
||||||
%} static R call(PyObject* self%(, const A%n& a%n%))
|
|
||||||
{%(
|
|
||||||
ref p%n(to_python(a%n));%)
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(%(O%))")%(,
|
|
||||||
p%n.get()%)));
|
|
||||||
detail::callback_adjust_refcount(result.get(), type<R>());
|
|
||||||
return from_python(result.get(), type<R>());
|
|
||||||
}
|
|
||||||
''', args)
|
|
||||||
+
|
|
||||||
"""};
|
|
||||||
|
|
||||||
// This specialization wouldn't be needed, but MSVC6 doesn't correctly allow the following:
|
|
||||||
// void g();
|
|
||||||
// void f() { return g(); }
|
|
||||||
template <>
|
|
||||||
struct callback<void>
|
|
||||||
{
|
|
||||||
"""
|
|
||||||
+ gen_functions('''
|
|
||||||
%{ template <%(class A%n%:, %)>
|
|
||||||
%} static void call_method(PyObject* self, const char* name%(, const A%n& a%n%))
|
|
||||||
{%(
|
|
||||||
ref p%n(to_python(a%n));%)
|
|
||||||
ref result(PyEval_CallMethod(self, const_cast<char*>(name),
|
|
||||||
const_cast<char*>("(%(O%))")%(,
|
|
||||||
p%n.get()%)));
|
|
||||||
}
|
|
||||||
|
|
||||||
%{ template <%(class A%n%:, %)>
|
|
||||||
%} static void call(PyObject* self%(, const A%n& a%n%))
|
|
||||||
{%(
|
|
||||||
ref p%n(to_python(a%n));%)
|
|
||||||
ref result(PyEval_CallFunction(self, const_cast<char*>("(%(O%))")%(,
|
|
||||||
p%n.get()%)));
|
|
||||||
}
|
|
||||||
''', args)
|
|
||||||
+
|
|
||||||
"""};
|
|
||||||
|
|
||||||
// Make it a compile-time error to try to return a const char* from a virtual
|
|
||||||
// function. The standard conversion
|
|
||||||
//
|
|
||||||
// from_python(PyObject* string, boost::python::type<const char*>)
|
|
||||||
//
|
|
||||||
// returns a pointer to the character array which is internal to string. The
|
|
||||||
// problem with trying to do this in a standard callback function is that the
|
|
||||||
// Python string would likely be destroyed upon return from the calling function
|
|
||||||
// (boost::python::callback<const char*>::call[_method]) when its reference count is
|
|
||||||
// decremented. If you absolutely need to do this and you're sure it's safe (it
|
|
||||||
// usually isn't), you can use
|
|
||||||
//
|
|
||||||
// boost::python::string result(boost::python::callback<boost::python::string>::call[_method](...args...));
|
|
||||||
// ...result.c_str()... // access the char* array
|
|
||||||
template <>
|
|
||||||
struct callback<const char*>
|
|
||||||
{
|
|
||||||
// Try hard to generate a readable error message
|
|
||||||
typedef struct unsafe_since_python_string_may_be_destroyed {} call, call_method;
|
|
||||||
};
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
|
|
||||||
#endif // CALLBACK_DWA_052100_H_
|
|
||||||
""")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
|
||||||
args = 5
|
|
||||||
else:
|
|
||||||
args = int(sys.argv[1])
|
|
||||||
|
|
||||||
print gen_callback(args)
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
# (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
# distribute this software is granted provided this copyright notice appears
|
|
||||||
# in all copies. This software is provided "as is" without express or implied
|
|
||||||
# warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
#
|
|
||||||
# The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
# producing this work.
|
|
||||||
|
|
||||||
from gen_function import *
|
|
||||||
import string
|
|
||||||
|
|
||||||
header = '''// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
//
|
|
||||||
// This file generated for %d-argument member functions and %d-argument free
|
|
||||||
// functions by gen_caller.python
|
|
||||||
'''
|
|
||||||
|
|
||||||
body_sections = (
|
|
||||||
'''
|
|
||||||
#ifndef CALLER_DWA05090_H_
|
|
||||||
# define CALLER_DWA05090_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/python/detail/wrap_python.hpp>
|
|
||||||
# include <boost/config.hpp>
|
|
||||||
# include <boost/python/detail/signatures.hpp>
|
|
||||||
# include <boost/python/detail/none.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
// Calling C++ from Python
|
|
||||||
template <class R>
|
|
||||||
struct caller
|
|
||||||
{
|
|
||||||
''',
|
|
||||||
'''
|
|
||||||
''',
|
|
||||||
''' // Free functions
|
|
||||||
''',
|
|
||||||
'''};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct caller<void>
|
|
||||||
{
|
|
||||||
''',
|
|
||||||
'''
|
|
||||||
''',
|
|
||||||
'''
|
|
||||||
// Free functions
|
|
||||||
''',
|
|
||||||
'''};
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
|
|
||||||
#endif
|
|
||||||
''')
|
|
||||||
|
|
||||||
#'
|
|
||||||
|
|
||||||
member_function = ''' template <class T%(, class A%n%)>
|
|
||||||
static PyObject* call(%1 (T::*pmf)(%(A%n%:, %))%2, PyObject* args, PyObject* /* keywords */ ) {
|
|
||||||
PyObject* self;
|
|
||||||
%( PyObject* a%n;
|
|
||||||
%) if (!PyArg_ParseTuple(args, const_cast<char*>("O%(O%)"), &self%(, &a%n%)))
|
|
||||||
return 0;
|
|
||||||
T& target = from_python(self, type<T&>());
|
|
||||||
%3(target.*pmf)(%(from_python(a%n, type<A%n>())%:,
|
|
||||||
%))%4
|
|
||||||
}
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
free_function = '''%{ template <%(class A%n%:, %)>
|
|
||||||
%} static PyObject* call(%1 (*f)(%(A%n%:, %)), PyObject* args, PyObject* /* keywords */ ) {
|
|
||||||
%( PyObject* a%n;
|
|
||||||
%) if (!PyArg_ParseTuple(args, const_cast<char*>("%(O%)")%(, &a%n%)))
|
|
||||||
return 0;
|
|
||||||
%2f(%(from_python(a%n, type<A%n>())%:,
|
|
||||||
%))%3
|
|
||||||
}
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
def gen_caller(member_function_args, free_function_args = None):
|
|
||||||
if free_function_args is None:
|
|
||||||
free_function_args = member_function_args + 1
|
|
||||||
|
|
||||||
return_none = ''';
|
|
||||||
return detail::none();'''
|
|
||||||
|
|
||||||
return (header % (member_function_args, free_function_args)
|
|
||||||
+ body_sections[0]
|
|
||||||
+ gen_functions(member_function, member_function_args,
|
|
||||||
'R', '', 'return to_python(', ');')
|
|
||||||
+ body_sections[1]
|
|
||||||
+ gen_functions(member_function, member_function_args,
|
|
||||||
'R', ' const', 'return to_python(', ');')
|
|
||||||
+ body_sections[2]
|
|
||||||
|
|
||||||
+ gen_functions(free_function, free_function_args,
|
|
||||||
'R', 'return to_python(', ');')
|
|
||||||
+ body_sections[3]
|
|
||||||
|
|
||||||
# specialized part for void return values begins here
|
|
||||||
+ gen_functions(member_function, member_function_args,
|
|
||||||
'void', '', '', return_none)
|
|
||||||
+ body_sections[4]
|
|
||||||
+ gen_functions(member_function, member_function_args,
|
|
||||||
'void', ' const', '', return_none)
|
|
||||||
+ body_sections[5]
|
|
||||||
|
|
||||||
+ gen_functions(free_function, free_function_args,
|
|
||||||
'void', '', return_none)
|
|
||||||
+ body_sections[6]
|
|
||||||
)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
|
||||||
member_function_args = 5
|
|
||||||
free_function_args = 6
|
|
||||||
else:
|
|
||||||
member_function_args = int(sys.argv[1])
|
|
||||||
if len(sys.argv) > 2:
|
|
||||||
free_function_args = int(sys.argv[2])
|
|
||||||
else:
|
|
||||||
free_function_args = member_function_args
|
|
||||||
|
|
||||||
print gen_caller(member_function_args, free_function_args)
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,828 +0,0 @@
|
|||||||
from gen_function import *
|
|
||||||
import string
|
|
||||||
|
|
||||||
def gen_extclass(args):
|
|
||||||
return (
|
|
||||||
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
//
|
|
||||||
// This file automatically generated for %d-argument constructors by
|
|
||||||
// gen_extclass.python
|
|
||||||
|
|
||||||
#ifndef EXTENSION_CLASS_DWA052000_H_
|
|
||||||
# define EXTENSION_CLASS_DWA052000_H_
|
|
||||||
|
|
||||||
# include <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>
|
|
||||||
|
|
||||||
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 T> 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}}} // 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>)
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to T*
|
|
||||||
friend T* 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 PtrType, where PtrType can be dereferenced to obtain a T.
|
|
||||||
template <class PtrType>
|
|
||||||
static PtrType& ptr_from_python(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();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class PtrType>
|
|
||||||
static PyObject* ptr_to_python(PtrType x)
|
|
||||||
{
|
|
||||||
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*>)
|
|
||||||
{ 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&>)
|
|
||||||
{ return from_python(p, boost::python::type<const T*>()); }
|
|
||||||
|
|
||||||
// Convert to T* const&
|
|
||||||
friend T* from_python(PyObject* p, boost::python::type<T* const&>)
|
|
||||||
{ return from_python(p, boost::python::type<T*>()); }
|
|
||||||
|
|
||||||
// Convert to T&
|
|
||||||
friend T& from_python(PyObject* p, boost::python::type<T&>)
|
|
||||||
{ return *boost::python::detail::check_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&>)
|
|
||||||
{ return from_python(p, boost::python::type<T&>()); }
|
|
||||||
|
|
||||||
// Convert to T
|
|
||||||
friend const T& from_python(PyObject* p, boost::python::type<T>)
|
|
||||||
{ return from_python(p, boost::python::type<T&>()); }
|
|
||||||
|
|
||||||
friend std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<std::auto_ptr<T>&>)
|
|
||||||
{ return ptr_from_python(p, boost::python::type<std::auto_ptr<T> >()); }
|
|
||||||
|
|
||||||
friend std::auto_ptr<T>& from_python(PyObject* p, boost::python::type<std::auto_ptr<T> >)
|
|
||||||
{ return ptr_from_python(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>&>)
|
|
||||||
{ return ptr_from_python(p, boost::python::type<std::auto_ptr<T> >()); }
|
|
||||||
|
|
||||||
friend PyObject* to_python(std::auto_ptr<T> x)
|
|
||||||
{ return ptr_to_python(x); }
|
|
||||||
|
|
||||||
friend boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<boost::shared_ptr<T>&>)
|
|
||||||
{ return ptr_from_python(p, boost::python::type<boost::shared_ptr<T> >()); }
|
|
||||||
|
|
||||||
friend boost::shared_ptr<T>& from_python(PyObject* p, boost::python::type<boost::shared_ptr<T> >)
|
|
||||||
{ return ptr_from_python(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>&>)
|
|
||||||
{ return ptr_from_python(p, boost::python::type<boost::shared_ptr<T> >()); }
|
|
||||||
|
|
||||||
friend PyObject* to_python(boost::shared_ptr<T> x)
|
|
||||||
{ return ptr_to_python(x); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Convert T to_python, instantiated on demand and only if there isn't a
|
|
||||||
// non-template overload for this function. This version is the one invoked when
|
|
||||||
// T is a wrapped class. See the first 2 functions declared in
|
|
||||||
// python_extension_class_converters above for more info.
|
|
||||||
template <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
|
|
||||||
""" % args
|
|
||||||
+ gen_function(
|
|
||||||
""" template <%(class A%n%:, %)>
|
|
||||||
inline void def(constructor<%(A%n%:, %)>)
|
|
||||||
// The following incantation builds a signature1, signature2,... object. It
|
|
||||||
// should _all_ get optimized away.
|
|
||||||
{ add_constructor(
|
|
||||||
%(prepend(type<A%n>::id(),
|
|
||||||
%) signature0()%()%));
|
|
||||||
}
|
|
||||||
""", args)
|
|
||||||
+
|
|
||||||
"""
|
|
||||||
|
|
||||||
// export homogeneous operators (type of both lhs and rhs is 'operator')
|
|
||||||
// usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub), Foo>());
|
|
||||||
|
|
||||||
// export homogeneous operators (type of both lhs and rhs is 'T const&')
|
|
||||||
// usage: foo_class.def(boost::python::operators<(boost::python::op_add | boost::python::op_sub)>());
|
|
||||||
template <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 T>
|
|
||||||
class held_instance : public T
|
|
||||||
{
|
|
||||||
// There are no member functions: we want to avoid inadvertently overriding
|
|
||||||
// any virtual functions in T.
|
|
||||||
public:"""
|
|
||||||
+ gen_functions("""%{
|
|
||||||
template <%(class A%n%:, %)>%}
|
|
||||||
held_instance(PyObject*%(, A%n% a%n%)) : T(%(a%n%:, %)) {}""", args)
|
|
||||||
+ """
|
|
||||||
};
|
|
||||||
|
|
||||||
// Abstract base class for all obj holders. Base for template class
|
|
||||||
// instance_holder<>, below.
|
|
||||||
class instance_holder_base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~instance_holder_base() {}
|
|
||||||
virtual bool held_by_value() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Abstract base class which holds a Held, somehow. Provides a uniform way to
|
|
||||||
// get a pointer to the held object
|
|
||||||
template <class 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; }
|
|
||||||
"""
|
|
||||||
+ gen_functions("""%{
|
|
||||||
template <%(class A%n%:, %)>%}
|
|
||||||
instance_value_holder(extension_instance* p%(, A%n a%n%)) :
|
|
||||||
m_held(p%(, a%n%)) {}""", args)
|
|
||||||
+ """
|
|
||||||
|
|
||||||
public: // implementation of instance_holder_base required interface
|
|
||||||
bool held_by_value() { return true; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Wrapper m_held;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Concrete class which holds a HeldType by way of a (possibly smart) pointer
|
|
||||||
// PtrType. By default, these are only generated for PtrType ==
|
|
||||||
// std::auto_ptr<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_
|
|
||||||
""")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
|
||||||
args = 5
|
|
||||||
else:
|
|
||||||
args = int(sys.argv[1])
|
|
||||||
|
|
||||||
print gen_extclass(args)
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
import string
|
|
||||||
|
|
||||||
def _find(s, sub, start=0, end=None):
|
|
||||||
"""Just like string.find, except it returns end or len(s) when not found.
|
|
||||||
"""
|
|
||||||
if end == None:
|
|
||||||
end = len(s)
|
|
||||||
|
|
||||||
pos = string.find(s, sub, start, end)
|
|
||||||
if pos < 0:
|
|
||||||
return end
|
|
||||||
else:
|
|
||||||
return pos
|
|
||||||
|
|
||||||
def _gen_common_key(key, n, args):
|
|
||||||
if len(key) > 0 and key in '123456789':
|
|
||||||
return str(args[int(key) - 1])
|
|
||||||
elif key == 'x':
|
|
||||||
return str(n)
|
|
||||||
else:
|
|
||||||
return key
|
|
||||||
|
|
||||||
def _gen_arg(template, n, args, delimiter = '%'):
|
|
||||||
result = ''
|
|
||||||
i = 0
|
|
||||||
while i < len(template): # until the template is consumed
|
|
||||||
# consume everything up to the first delimiter
|
|
||||||
delimiter_pos = _find(template, delimiter, i)
|
|
||||||
result = result + template[i:delimiter_pos]
|
|
||||||
|
|
||||||
# The start position of whatever comes after the delimiter+key
|
|
||||||
start = delimiter_pos + 2
|
|
||||||
key = template[start - 1 : start] # the key character. If there were no
|
|
||||||
# delimiters left, key will be empty
|
|
||||||
|
|
||||||
if key == 'n':
|
|
||||||
result = result + `n`
|
|
||||||
else:
|
|
||||||
result = result + _gen_common_key(key, n, args)
|
|
||||||
|
|
||||||
i = start
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def gen_function(template, n, *args, **keywords):
|
|
||||||
r"""gen_function(template, n, [args...] ) -> string
|
|
||||||
|
|
||||||
Generate a function declaration based on the given template.
|
|
||||||
|
|
||||||
Sections of the template between '%(', '%)' pairs are repeated n times. If '%:'
|
|
||||||
appears in the middle, it denotes the beginning of a delimiter.
|
|
||||||
|
|
||||||
Sections of the template between '%{', '%}' pairs are ommitted if n == 0.
|
|
||||||
|
|
||||||
%n is transformed into the string representation of 1..n for each repetition
|
|
||||||
of n.
|
|
||||||
|
|
||||||
%x, where x is a digit, is transformed into the corresponding additional
|
|
||||||
argument.
|
|
||||||
|
|
||||||
for example,
|
|
||||||
|
|
||||||
>>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 2, 'void')
|
|
||||||
'void abc(int a1, int a2); // all args are ints'
|
|
||||||
>>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 0, 'x')
|
|
||||||
'x abc();'
|
|
||||||
|
|
||||||
|
|
||||||
>>> template = ''' template <class T%(, class A%n%)>
|
|
||||||
... static PyObject* call( %1(T::*pmf)(%(A%n%:, %))%2, PyObject* args, PyObject* /* keywords */ ) {
|
|
||||||
... PyObject* self;
|
|
||||||
... %( PyObject* a%n;
|
|
||||||
... %) if (!PyArg_ParseTuple(args, const_cast<char*>("O%(O%)"), &self%(, &a%n%)))
|
|
||||||
... return 0;
|
|
||||||
... T& target = from_python(self, type<T&>());
|
|
||||||
... %3to_python((target.*pmf)(%(
|
|
||||||
... from_python(a%n, type<A%n>())%:,%)
|
|
||||||
... ));%4
|
|
||||||
... }'''
|
|
||||||
|
|
||||||
>>> print gen_function(template, 0, 'R ', '', 'return ', '')
|
|
||||||
template <class T>
|
|
||||||
static PyObject* call( R (T::*pmf)(), PyObject* args, PyObject* /* keywords */ ) {
|
|
||||||
PyObject* self;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("O"), &self))
|
|
||||||
return 0;
|
|
||||||
T& target = from_python(self, type<T&>());
|
|
||||||
return to_python((target.*pmf)(
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
>>> print gen_function(template, 2, 'R ', '', 'return ', '')
|
|
||||||
template <class T, class A1, class A2>
|
|
||||||
static PyObject* call( R (T::*pmf)(A1, A2), PyObject* args, PyObject* /* keywords */ ) {
|
|
||||||
PyObject* self;
|
|
||||||
PyObject* a1;
|
|
||||||
PyObject* a2;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOO"), &self, &a1, &a2))
|
|
||||||
return 0;
|
|
||||||
T& target = from_python(self, type<T&>());
|
|
||||||
return to_python((target.*pmf)(
|
|
||||||
from_python(a1, type<A1>()),
|
|
||||||
from_python(a2, type<A2>())
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
>>> print gen_function(template, 3, 'void ', ' const', '', '\n'+8*' ' + 'return none();')
|
|
||||||
template <class T, class A1, class A2, class A3>
|
|
||||||
static PyObject* call( void (T::*pmf)(A1, A2, A3) const, PyObject* args, PyObject* /* keywords */ ) {
|
|
||||||
PyObject* self;
|
|
||||||
PyObject* a1;
|
|
||||||
PyObject* a2;
|
|
||||||
PyObject* a3;
|
|
||||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOO"), &self, &a1, &a2, &a3))
|
|
||||||
return 0;
|
|
||||||
T& target = from_python(self, type<T&>());
|
|
||||||
to_python((target.*pmf)(
|
|
||||||
from_python(a1, type<A1>()),
|
|
||||||
from_python(a2, type<A2>()),
|
|
||||||
from_python(a3, type<A3>())
|
|
||||||
));
|
|
||||||
return none();
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
delimiter = keywords.get('delimiter', '%')
|
|
||||||
result = ''
|
|
||||||
i = 0
|
|
||||||
while i < len(template): # until the template is consumed
|
|
||||||
# consume everything up to the first delimiter
|
|
||||||
delimiter_pos = _find(template, delimiter, i)
|
|
||||||
result = result + template[i:delimiter_pos]
|
|
||||||
|
|
||||||
# The start position of whatever comes after the delimiter+key
|
|
||||||
start = delimiter_pos + 2
|
|
||||||
key = template[start - 1 : start] # the key character. If there were no
|
|
||||||
# delimiters left, key will be empty
|
|
||||||
|
|
||||||
pairs = { '(':')', '{':'}' }
|
|
||||||
|
|
||||||
if key in pairs.keys():
|
|
||||||
end = string.find(template, delimiter + pairs[key], start)
|
|
||||||
assert end >= 0, "Matching '" + delimiter + pairs[key] +"' not found!"
|
|
||||||
delimiter_pos = end
|
|
||||||
|
|
||||||
if key == '{':
|
|
||||||
if n > 0:
|
|
||||||
result = result + gen_function(template[start:end], n, args, delimiter)
|
|
||||||
else:
|
|
||||||
separator_pos = _find(template, delimiter + ':', start, end)
|
|
||||||
separator = template[separator_pos+2 : end]
|
|
||||||
|
|
||||||
for x in range(1, n + 1):
|
|
||||||
result = result + _gen_arg(template[start:separator_pos], x, args,
|
|
||||||
delimiter)
|
|
||||||
if x != n:
|
|
||||||
result = result + separator
|
|
||||||
|
|
||||||
else:
|
|
||||||
result = result + _gen_common_key(key, n, args)
|
|
||||||
|
|
||||||
i = delimiter_pos + 2
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def gen_functions(template, n, *args):
|
|
||||||
r"""gen_functions(template, n, [args...]) -> string
|
|
||||||
|
|
||||||
Call gen_function repeatedly with from 0..n and the given optional
|
|
||||||
arguments.
|
|
||||||
|
|
||||||
>>> print gen_functions('%1 abc(%(int a%n%:, %));%{ // all args are ints%}\n', 2, 'void'),
|
|
||||||
void abc();
|
|
||||||
void abc(int a1); // all args are ints
|
|
||||||
void abc(int a1, int a2); // all args are ints
|
|
||||||
|
|
||||||
"""
|
|
||||||
result = ''
|
|
||||||
for x in range(n + 1):
|
|
||||||
result = result + apply(gen_function, (template, x) + args)
|
|
||||||
return result
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import doctest
|
|
||||||
doctest.testmod()
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
from gen_function import *
|
|
||||||
import string
|
|
||||||
|
|
||||||
def gen_init_function(args):
|
|
||||||
|
|
||||||
return (
|
|
||||||
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
//
|
|
||||||
// This file was generated for %d-argument constructors by gen_init_function.python
|
|
||||||
|
|
||||||
#ifndef INIT_FUNCTION_DWA052000_H_
|
|
||||||
# define INIT_FUNCTION_DWA052000_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
# include <boost/python/detail/functions.hpp>
|
|
||||||
# include <boost/python/detail/signatures.hpp>
|
|
||||||
# include <typeinfo>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
// parameter_traits - so far, this is a way to pass a const T& when we can be
|
|
||||||
// sure T is not a reference type, and a raw T otherwise. This should be
|
|
||||||
// rolled into boost::call_traits. Ordinarily, parameter_traits would be
|
|
||||||
// written:
|
|
||||||
//
|
|
||||||
// template <class T> struct parameter_traits
|
|
||||||
// {
|
|
||||||
// typedef const T& const_reference;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// template <class T> struct parameter_traits<T&>
|
|
||||||
// {
|
|
||||||
// typedef T& const_reference;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// template <> struct parameter_traits<void>
|
|
||||||
// {
|
|
||||||
// typedef void const_reference;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// ...but since we can't partially specialize on reference types, we need this
|
|
||||||
// long-winded but equivalent incantation.
|
|
||||||
|
|
||||||
// const_ref_selector -- an implementation detail of parameter_traits (below). This uses
|
|
||||||
// the usual "poor man's partial specialization" hack for MSVC.
|
|
||||||
template <bool is_ref>
|
|
||||||
struct const_ref_selector
|
|
||||||
{
|
|
||||||
template <class T>
|
|
||||||
struct const_ref
|
|
||||||
{
|
|
||||||
typedef const T& type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct const_ref_selector<true>
|
|
||||||
{
|
|
||||||
template <class T>
|
|
||||||
struct const_ref
|
|
||||||
{
|
|
||||||
typedef T type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# ifdef BOOST_MSVC
|
|
||||||
# pragma warning(push)
|
|
||||||
# pragma warning(disable: 4181)
|
|
||||||
# endif // BOOST_MSVC
|
|
||||||
template <class T>
|
|
||||||
struct parameter_traits
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
typedef const_ref_selector<boost::is_reference<T>::value> selector;
|
|
||||||
public:
|
|
||||||
typedef typename selector::template const_ref<T>::type const_reference;
|
|
||||||
};
|
|
||||||
# ifdef BOOST_MSVC
|
|
||||||
# pragma warning(pop)
|
|
||||||
# endif // BOOST_MSVC
|
|
||||||
|
|
||||||
// Full spcialization for void
|
|
||||||
template <>
|
|
||||||
struct parameter_traits<void>
|
|
||||||
{
|
|
||||||
typedef void const_reference;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class reference_parameter
|
|
||||||
{
|
|
||||||
typedef typename parameter_traits<T>::const_reference const_reference;
|
|
||||||
public:
|
|
||||||
reference_parameter(const_reference value)
|
|
||||||
: value(value) {}
|
|
||||||
operator const_reference() { return value; }
|
|
||||||
private:
|
|
||||||
const_reference value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class extension_instance;
|
|
||||||
class instance_holder_base;
|
|
||||||
|
|
||||||
class init;
|
|
||||||
"""
|
|
||||||
+ gen_functions('template <class T%(, class A%n%)> struct init%x;\n', args)
|
|
||||||
+ """
|
|
||||||
template <class T>
|
|
||||||
struct init_function
|
|
||||||
{
|
|
||||||
""" + gen_functions("""%{
|
|
||||||
template <%(class A%n%:, %)>
|
|
||||||
%} static init* create(signature%x%{<%(A%n%:, %)>%}) {
|
|
||||||
return new init%x<T%(,
|
|
||||||
detail::parameter_traits<A%n>::const_reference%)>;
|
|
||||||
}
|
|
||||||
""", args)+"""};
|
|
||||||
|
|
||||||
class init : public function
|
|
||||||
{
|
|
||||||
private: // override function hook
|
|
||||||
PyObject* do_call(PyObject* args, PyObject* keywords) const;
|
|
||||||
private:
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* tail_args, PyObject* keywords) const = 0;
|
|
||||||
};
|
|
||||||
""" + gen_functions("""
|
|
||||||
|
|
||||||
template <class T%(, class A%n%)>
|
|
||||||
struct init%x : init
|
|
||||||
{
|
|
||||||
virtual instance_holder_base* create_holder(extension_instance* self, PyObject* args, PyObject* /*keywords*/) const
|
|
||||||
{
|
|
||||||
%(PyObject* a%n;
|
|
||||||
%)if (!PyArg_ParseTuple(args, const_cast<char*>("%(O%)")%(, &a%n%)))
|
|
||||||
throw argument_error();
|
|
||||||
return new T(self%(,
|
|
||||||
boost::python::detail::reference_parameter<A%n>(from_python(a%n, type<A%n>()))%)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const char* description() const
|
|
||||||
{ return typeid(void (*)(T&%(, A%n%%))).name(); }
|
|
||||||
};""", args) + """
|
|
||||||
|
|
||||||
}}} // namespace boost::python::detail
|
|
||||||
|
|
||||||
#endif // INIT_FUNCTION_DWA052000_H_
|
|
||||||
""")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
|
||||||
args = 5
|
|
||||||
else:
|
|
||||||
args = int(sys.argv[1])
|
|
||||||
|
|
||||||
print gen_init_function(args)
|
|
||||||
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
from gen_function import *
|
|
||||||
import string
|
|
||||||
|
|
||||||
def gen_struct_signatures(args):
|
|
||||||
result = ''
|
|
||||||
for n in range(args, -1, -1):
|
|
||||||
result = (
|
|
||||||
result + gen_function("""%{template <%(class T%n%:, %)>
|
|
||||||
%}struct signature%x {};
|
|
||||||
|
|
||||||
""", n)
|
|
||||||
# + ((n == args) and [""] or
|
|
||||||
# [gen_function("""
|
|
||||||
# template <class X>
|
|
||||||
# static inline signature%1<X%(, T%n%)> prepend(type<X>)
|
|
||||||
# { return signature%1<X%(, T%n%)>(); }""",
|
|
||||||
# n, (str(n+1),))
|
|
||||||
# ]
|
|
||||||
# )[0]
|
|
||||||
#
|
|
||||||
# + ((n != 0) and [""] or
|
|
||||||
# ["""
|
|
||||||
# // This one terminates the chain. Prepending void_t to the head of a void_t
|
|
||||||
# // signature results in a void_t signature again.
|
|
||||||
# static inline signature0 prepend(void_t) { return signature0(); }"""]
|
|
||||||
# )[0]
|
|
||||||
# + """
|
|
||||||
#};
|
|
||||||
#
|
|
||||||
#"""
|
|
||||||
+ ((n == args) and [""] or
|
|
||||||
[gen_function(
|
|
||||||
"""template <%(class T%n%, %)class X>
|
|
||||||
inline signature%1<X%(, T%n%)> prepend(type<X>, signature%x%{<%(T%n%:, %)>%})
|
|
||||||
{ return signature%1<X%(, T%n%)>(); }
|
|
||||||
|
|
||||||
""", n, str(n+1))
|
|
||||||
]
|
|
||||||
)[0]
|
|
||||||
)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def gen_signatures(args):
|
|
||||||
return (
|
|
||||||
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
//
|
|
||||||
// This file automatically generated by gen_signatures.python for %d arguments.
|
|
||||||
#ifndef SIGNATURES_DWA050900_H_
|
|
||||||
# define SIGNATURES_DWA050900_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
// A stand-in for the built-in void. This one can be passed to functions and
|
|
||||||
// (under MSVC, which has a bug, be used as a default template type parameter).
|
|
||||||
struct void_t {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// An envelope in which type information can be delivered for the purposes
|
|
||||||
// of selecting an overloaded from_python() function. This is needed to work
|
|
||||||
// around MSVC's lack of partial specialiation/ordering. Where normally we'd
|
|
||||||
// want to form a function call like void f<const T&>(), We instead pass
|
|
||||||
// type<const T&> as one of the function parameters to select a particular
|
|
||||||
// overload.
|
|
||||||
//
|
|
||||||
// The id typedef helps us deal with the lack of partial ordering by generating
|
|
||||||
// unique types for constructor signatures. In general, type<T>::id is type<T>,
|
|
||||||
// but type<void_t>::id is just void_t.
|
|
||||||
template <class T>
|
|
||||||
struct type
|
|
||||||
{
|
|
||||||
typedef type id;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct type<boost::python::detail::void_t>
|
|
||||||
{
|
|
||||||
typedef boost::python::detail::void_t id;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
// These basically encapsulate a chain of types, , used to make the syntax of
|
|
||||||
// add(constructor<T1, ...>()) work. We need to produce a unique type for each number
|
|
||||||
// of non-default parameters to constructor<>. Q: why not use a recursive
|
|
||||||
// formulation for infinite extensibility? A: MSVC6 seems to choke on constructs
|
|
||||||
// that involve recursive template nesting.
|
|
||||||
//
|
|
||||||
// signature chaining
|
|
||||||
""" % args
|
|
||||||
+ gen_struct_signatures(args)
|
|
||||||
+ """
|
|
||||||
// This one terminates the chain. Prepending void_t to the head of a void_t
|
|
||||||
// signature results in a void_t signature again.
|
|
||||||
inline signature0 prepend(void_t, signature0) { return signature0(); }
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
"""
|
|
||||||
+ gen_function("""
|
|
||||||
template <%(class A%n% = detail::void_t%:, %)>
|
|
||||||
struct constructor
|
|
||||||
{
|
|
||||||
};
|
|
||||||
""", args)
|
|
||||||
+ """
|
|
||||||
namespace detail {
|
|
||||||
// Return value extraction:
|
|
||||||
|
|
||||||
// This is just another little envelope for carrying a typedef (see type,
|
|
||||||
// above). I could have re-used type, but that has a very specific purpose. I
|
|
||||||
// thought this would be clearer.
|
|
||||||
template <class T>
|
|
||||||
struct return_value_select { typedef T type; };
|
|
||||||
|
|
||||||
// free functions"""
|
|
||||||
+ gen_functions("""
|
|
||||||
template <class R%(, class A%n%)>
|
|
||||||
return_value_select<R> return_value(R (*)(%(A%n%:, %))) { return return_value_select<R>(); }
|
|
||||||
""", args)
|
|
||||||
|
|
||||||
+
|
|
||||||
"""
|
|
||||||
// TODO(?): handle 'const void'
|
|
||||||
|
|
||||||
// member functions"""
|
|
||||||
+ gen_functions("""
|
|
||||||
template <class R, class T%(, class A%n%)>
|
|
||||||
return_value_select<R> return_value(R (T::*)(%(A%n%:, %))) { return return_value_select<R>(); }
|
|
||||||
""", args)
|
|
||||||
|
|
||||||
+ gen_functions("""
|
|
||||||
template <class R, class T%(, class A%n%)>
|
|
||||||
return_value_select<R> return_value(R (T::*)(%(A%n%:, %)) const) { return return_value_select<R>(); }
|
|
||||||
""", args)
|
|
||||||
|
|
||||||
+ """
|
|
||||||
}}} // namespace boost::python::detail
|
|
||||||
|
|
||||||
#endif
|
|
||||||
""")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
|
||||||
args = 5
|
|
||||||
else:
|
|
||||||
args = int(sys.argv[1])
|
|
||||||
|
|
||||||
print gen_signatures(args)
|
|
||||||
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
from gen_function import *
|
|
||||||
import string
|
|
||||||
|
|
||||||
def gen_singleton(args):
|
|
||||||
return (
|
|
||||||
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef SINGLETON_DWA051900_H_
|
|
||||||
# define SINGLETON_DWA051900_H_
|
|
||||||
|
|
||||||
# include <boost/python/detail/config.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python { namespace detail {
|
|
||||||
|
|
||||||
struct empty {};
|
|
||||||
template <class Derived, class Base = empty>
|
|
||||||
struct singleton : Base
|
|
||||||
{
|
|
||||||
typedef singleton singleton_base; // Convenience type for derived class constructors
|
|
||||||
|
|
||||||
static Derived* instance();
|
|
||||||
|
|
||||||
// Pass-through constructors
|
|
||||||
"""
|
|
||||||
+ gen_functions("""%{
|
|
||||||
template <%(class A%n%:, %)>
|
|
||||||
%} singleton(%(const A%n& a%n%:, %)) : Base(%(a%n%:, %)) {}
|
|
||||||
""", args)
|
|
||||||
+ """
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Derived, class Base>
|
|
||||||
Derived* singleton<Derived,Base>::instance()
|
|
||||||
{
|
|
||||||
static Derived x;
|
|
||||||
return &x;
|
|
||||||
}
|
|
||||||
|
|
||||||
}}} // namespace boost::python::detail
|
|
||||||
|
|
||||||
#endif
|
|
||||||
""")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
|
||||||
args = 5
|
|
||||||
else:
|
|
||||||
args = int(sys.argv[1])
|
|
||||||
|
|
||||||
print gen_singleton(args)
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#include <boost/python/detail/init_function.hpp>
|
|
||||||
#include <boost/python/objects.hpp>
|
|
||||||
#include <boost/python/detail/extension_class.hpp>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace boost { namespace python { namespace detail {
|
|
||||||
|
|
||||||
PyObject* init::do_call(PyObject* args_, PyObject* keywords) const
|
|
||||||
{
|
|
||||||
tuple args(ref(args_, ref::increment_count));
|
|
||||||
if (args[0]->ob_type->ob_type != extension_meta_class())
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, "argument 1 to __init__ must be an ExtensionInstance");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extension_instance *self = static_cast<extension_instance*>(args[0].get());
|
|
||||||
|
|
||||||
tuple ctor_args = args.slice(1, args.size());
|
|
||||||
|
|
||||||
std::auto_ptr<instance_holder_base> result(
|
|
||||||
create_holder(self, ctor_args.get(), keywords));
|
|
||||||
|
|
||||||
self->add_implementation(result);
|
|
||||||
return none();
|
|
||||||
}
|
|
||||||
|
|
||||||
}}} // namespace boost::python::detail
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#include <boost/python/module_builder.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
ref name_holder;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool module_builder::initializing()
|
|
||||||
{
|
|
||||||
return name_holder.get() != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
string module_builder::name()
|
|
||||||
{
|
|
||||||
// If this fails, you haven't created a module_builder object
|
|
||||||
assert(initializing());
|
|
||||||
return string(name_holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_builder::module_builder(const char* name)
|
|
||||||
: m_module(Py_InitModule(const_cast<char*>(name), initial_methods))
|
|
||||||
{
|
|
||||||
// If this fails, you've created more than 1 module_builder object in your module
|
|
||||||
assert(name_holder.get() == 0);
|
|
||||||
name_holder = ref(PyObject_GetAttrString(m_module, const_cast<char*>("__name__")));
|
|
||||||
}
|
|
||||||
|
|
||||||
module_builder::~module_builder()
|
|
||||||
{
|
|
||||||
name_holder.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
module_builder::add(detail::function* x, const char* name)
|
|
||||||
{
|
|
||||||
reference<detail::function> f(x); // First take possession of the object.
|
|
||||||
detail::function::add_to_namespace(f, name, PyModule_GetDict(m_module));
|
|
||||||
}
|
|
||||||
|
|
||||||
void module_builder::add(ref x, const char* name)
|
|
||||||
{
|
|
||||||
PyObject* dictionary = PyModule_GetDict(m_module);
|
|
||||||
PyDict_SetItemString(dictionary, const_cast<char*>(name), x.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void module_builder::add(PyTypeObject* x, const char* name /*= 0*/)
|
|
||||||
{
|
|
||||||
this->add(ref(as_object(x)), name ? name : x->tp_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyMethodDef module_builder::initial_methods[] = { { 0, 0, 0, 0 } };
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
485
src/objects.cpp
485
src/objects.cpp
@@ -1,485 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
// TODO: Move inline implementations from objects.cpp here
|
|
||||||
|
|
||||||
#include <boost/python/objects.hpp>
|
|
||||||
#include <boost/python/detail/none.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
T object_from_python(PyObject* p, type<T>)
|
|
||||||
{
|
|
||||||
ref x(p, ref::increment_count);
|
|
||||||
if (!T::accepts(x))
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
return T(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PyObject* object_to_python(const object& x)
|
|
||||||
{
|
|
||||||
return x.reference().release();
|
|
||||||
}
|
|
||||||
|
|
||||||
object::object(ref p)
|
|
||||||
: m_p(p) {}
|
|
||||||
|
|
||||||
// Return a reference to the held object
|
|
||||||
ref object::reference() const
|
|
||||||
{
|
|
||||||
return m_p;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a raw pointer to the held object
|
|
||||||
PyObject* object::get() const
|
|
||||||
{
|
|
||||||
return m_p.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
|
|
||||||
BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE
|
|
||||||
|
|
||||||
PyObject* to_python(const boost::python::tuple& x)
|
|
||||||
{
|
|
||||||
return object_to_python(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::python::tuple from_python(PyObject* p, boost::python::type<boost::python::tuple> type)
|
|
||||||
{
|
|
||||||
return boost::python::object_from_python(p, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(const boost::python::list& x)
|
|
||||||
{
|
|
||||||
return object_to_python(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::python::list from_python(PyObject* p, boost::python::type<boost::python::list> type)
|
|
||||||
{
|
|
||||||
return boost::python::object_from_python(p, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(const boost::python::dictionary& x)
|
|
||||||
{
|
|
||||||
return object_to_python(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::python::dictionary from_python(PyObject* p, boost::python::type<boost::python::dictionary> type)
|
|
||||||
{
|
|
||||||
return boost::python::object_from_python(p, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* to_python(const boost::python::string& x)
|
|
||||||
{
|
|
||||||
return object_to_python(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::python::string from_python(PyObject* p, boost::python::type<boost::python::string> type)
|
|
||||||
{
|
|
||||||
return boost::python::object_from_python(p, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
|
||||||
|
|
||||||
namespace boost { namespace python {
|
|
||||||
|
|
||||||
tuple::tuple(std::size_t n)
|
|
||||||
: object(ref(PyTuple_New(n)))
|
|
||||||
{
|
|
||||||
for (std::size_t i = 0; i < n; ++i)
|
|
||||||
PyTuple_SET_ITEM(get(), i, detail::none());
|
|
||||||
}
|
|
||||||
|
|
||||||
tuple::tuple(ref p)
|
|
||||||
: object(p)
|
|
||||||
{
|
|
||||||
assert(accepts(p));
|
|
||||||
if (!accepts(p))
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PyTypeObject* tuple::type_obj()
|
|
||||||
{
|
|
||||||
return &PyTuple_Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool tuple::accepts(ref p)
|
|
||||||
{
|
|
||||||
return PyTuple_Check(p.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t tuple::size() const
|
|
||||||
{
|
|
||||||
return PyTuple_Size(get());
|
|
||||||
}
|
|
||||||
|
|
||||||
ref tuple::operator[](std::size_t pos) const
|
|
||||||
{
|
|
||||||
return ref(PyTuple_GetItem(get(), static_cast<int>(pos)),
|
|
||||||
ref::increment_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tuple::set_item(std::size_t pos, const ref& rhs)
|
|
||||||
{
|
|
||||||
int failed = PyTuple_SetItem(
|
|
||||||
get(), static_cast<int>(pos), ref(rhs).release()); // A reference is stolen here.
|
|
||||||
(void)failed;
|
|
||||||
assert(failed == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
tuple tuple::slice(int low, int high) const
|
|
||||||
{
|
|
||||||
return tuple(ref(PyTuple_GetSlice(get(), low, high)));
|
|
||||||
}
|
|
||||||
|
|
||||||
tuple& tuple::operator+=(const tuple& rhs)
|
|
||||||
{
|
|
||||||
return *this = *this + rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Construct from an owned PyObject*.
|
|
||||||
// Precondition: p must point to a python string.
|
|
||||||
string::string(ref p)
|
|
||||||
: object(p)
|
|
||||||
{
|
|
||||||
assert(accepts(p));
|
|
||||||
if (!accepts(p))
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string::string(const char* s)
|
|
||||||
: object(ref(PyString_FromString(s))) {}
|
|
||||||
|
|
||||||
string::string(const char* s, std::size_t length)
|
|
||||||
: object(ref(PyString_FromStringAndSize(s, length))) {}
|
|
||||||
|
|
||||||
string::string(const char* s, interned_t)
|
|
||||||
: object(ref(PyString_InternFromString(s))) {}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
string::string(const char* s, std::size_t length, interned_t)
|
|
||||||
: object(ref(PyString_InternFromStringAndSize(s, length))) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
string::string(const string& rhs)
|
|
||||||
: object(rhs.reference()) {}
|
|
||||||
|
|
||||||
// Get the type object for Strings
|
|
||||||
PyTypeObject* string::type_obj()
|
|
||||||
{ return &PyString_Type; }
|
|
||||||
|
|
||||||
// Return true if the given object is a python string
|
|
||||||
bool string::accepts(ref o)
|
|
||||||
{ return PyString_Check(o.get()); }
|
|
||||||
|
|
||||||
// Return the length of the string.
|
|
||||||
std::size_t string::size() const
|
|
||||||
{
|
|
||||||
int size = PyString_GET_SIZE(get());
|
|
||||||
assert(size >= 0);
|
|
||||||
return static_cast<std::size_t>(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a null-terminated representation of the contents of string.
|
|
||||||
// The pointer refers to the internal buffer of string, not a copy.
|
|
||||||
// The data must not be modified in any way. It must not be de-allocated.
|
|
||||||
const char* string::c_str() const
|
|
||||||
{ return PyString_AS_STRING(get()); }
|
|
||||||
|
|
||||||
void string::intern()
|
|
||||||
{ // UNTESTED!!
|
|
||||||
*this = string(ref(PyString_InternFromString(c_str()), ref::increment_count));
|
|
||||||
}
|
|
||||||
|
|
||||||
string& string::operator*=(unsigned int repeat_count)
|
|
||||||
{
|
|
||||||
*this = string(ref(PySequence_Repeat(get(), repeat_count)));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
dictionary::dictionary(ref p)
|
|
||||||
: object(p)
|
|
||||||
{
|
|
||||||
assert(accepts(p));
|
|
||||||
if (!accepts(p))
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dictionary::dictionary()
|
|
||||||
: object(ref(PyDict_New())) {}
|
|
||||||
|
|
||||||
PyTypeObject* dictionary::type_obj()
|
|
||||||
{ return &PyDict_Type; }
|
|
||||||
|
|
||||||
bool dictionary::accepts(ref p)
|
|
||||||
{ return PyDict_Check(p.get()); }
|
|
||||||
|
|
||||||
void dictionary::clear()
|
|
||||||
{ PyDict_Clear(get()); }
|
|
||||||
|
|
||||||
const ref& dictionary::proxy::operator=(const ref& rhs)
|
|
||||||
{
|
|
||||||
if (PyDict_SetItem(m_dict.get(), m_key.get(), rhs.get()) == -1)
|
|
||||||
throw error_already_set();
|
|
||||||
return rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
dictionary::proxy::operator ref() const
|
|
||||||
{
|
|
||||||
return ref(m_dict->ob_type->tp_as_mapping->mp_subscript(m_dict.get(), m_key.get()),
|
|
||||||
ref::increment_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
dictionary::proxy::proxy(const ref& dict, const ref& key)
|
|
||||||
: m_dict(dict), m_key(key) {}
|
|
||||||
|
|
||||||
dictionary::proxy dictionary::operator[](ref key)
|
|
||||||
{ return proxy(reference(), key); }
|
|
||||||
|
|
||||||
ref dictionary::operator[](ref key) const {
|
|
||||||
// An odd MSVC bug causes the ".operator Ptr()" to be needed
|
|
||||||
return proxy(reference(), key).operator ref();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ref dictionary::get_item(const ref& key) const
|
|
||||||
{
|
|
||||||
return get_item(key, ref());
|
|
||||||
}
|
|
||||||
|
|
||||||
ref dictionary::get_item(const ref& key, const ref& default_) const
|
|
||||||
{
|
|
||||||
PyObject* value_or_null = PyDict_GetItem(get(), key.get());
|
|
||||||
if (value_or_null == 0 && !PyErr_Occurred())
|
|
||||||
return default_;
|
|
||||||
else
|
|
||||||
return ref(value_or_null, ref::increment_count); // Will throw if there was another error
|
|
||||||
}
|
|
||||||
|
|
||||||
void dictionary::set_item(const ref& key, const ref& value)
|
|
||||||
{
|
|
||||||
if (PyDict_SetItem(get(), key.get(), value.get()) == -1)
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
void dictionary::erase(ref key) {
|
|
||||||
if (PyDict_DelItem(get(), key.get()) == -1)
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
list dictionary::items() const { return list(ref(PyDict_Items(get()))); }
|
|
||||||
list dictionary::keys() const { return list(ref(PyDict_Keys(get()))); }
|
|
||||||
list dictionary::values() const { return list(ref(PyDict_Values(get()))); }
|
|
||||||
|
|
||||||
std::size_t dictionary::size() const { return static_cast<std::size_t>(PyDict_Size(get())); }
|
|
||||||
|
|
||||||
string operator+(string x, string y)
|
|
||||||
{
|
|
||||||
PyObject* io_string = x.reference().release();
|
|
||||||
PyString_Concat(&io_string, y.get());
|
|
||||||
return string(ref(io_string));
|
|
||||||
}
|
|
||||||
|
|
||||||
string& string::operator+=(const string& rhs)
|
|
||||||
{
|
|
||||||
return *this = *this + rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
string& string::operator+=(const char* y)
|
|
||||||
{
|
|
||||||
return *this += string(y);
|
|
||||||
}
|
|
||||||
|
|
||||||
string operator%(const string& format, const tuple& args)
|
|
||||||
{
|
|
||||||
return string(ref(PyString_Format(format.get(), args.reference().get())));
|
|
||||||
}
|
|
||||||
|
|
||||||
string operator+(string x, const char* y)
|
|
||||||
{
|
|
||||||
return x + string(y);
|
|
||||||
}
|
|
||||||
|
|
||||||
string operator+(const char* x, string y)
|
|
||||||
{
|
|
||||||
return string(x) + y;
|
|
||||||
}
|
|
||||||
|
|
||||||
tuple operator+(const tuple& x, const tuple& y)
|
|
||||||
{
|
|
||||||
tuple result(x.size() + y.size());
|
|
||||||
for (std::size_t xi = 0; xi < x.size(); ++xi)
|
|
||||||
result.set_item(xi, x[xi]);
|
|
||||||
for (std::size_t yi = 0; yi < y.size(); ++yi)
|
|
||||||
result.set_item(yi + x.size(), y[yi]);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
list::list(ref p)
|
|
||||||
: object(p)
|
|
||||||
{
|
|
||||||
assert(accepts(p));
|
|
||||||
if (!accepts(p))
|
|
||||||
{
|
|
||||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list::list(std::size_t sz)
|
|
||||||
: object(ref(PyList_New(sz)))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PyTypeObject* list::type_obj()
|
|
||||||
{
|
|
||||||
return &PyList_Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool list::accepts(ref p)
|
|
||||||
{
|
|
||||||
return PyList_Check(p.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t list::size()
|
|
||||||
{
|
|
||||||
return PyList_Size(get());
|
|
||||||
}
|
|
||||||
|
|
||||||
ref list::operator[](std::size_t pos) const
|
|
||||||
{
|
|
||||||
return ref(PyList_GetItem(get(), pos), ref::increment_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
list::proxy list::operator[](std::size_t pos)
|
|
||||||
{
|
|
||||||
return proxy(reference(), pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void list::insert(std::size_t index, const ref& item)
|
|
||||||
{
|
|
||||||
if (PyList_Insert(get(), index, item.get()) == -1)
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
void list::push_back(const ref& item)
|
|
||||||
{
|
|
||||||
if (PyList_Append(get(), item.get()) == -1)
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
void list::append(const ref& item)
|
|
||||||
{
|
|
||||||
this->push_back(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
list list::slice(int low, int high) const
|
|
||||||
{
|
|
||||||
return list(ref(PyList_GetSlice(get(), low, high)));
|
|
||||||
}
|
|
||||||
|
|
||||||
list::slice_proxy list::slice(int low, int high)
|
|
||||||
{
|
|
||||||
return slice_proxy(reference(), low, high);
|
|
||||||
}
|
|
||||||
|
|
||||||
void list::sort()
|
|
||||||
{
|
|
||||||
if (PyList_Sort(get()) == -1)
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
void list::reverse()
|
|
||||||
{
|
|
||||||
if (PyList_Reverse(get()) == -1)
|
|
||||||
throw error_already_set();
|
|
||||||
}
|
|
||||||
|
|
||||||
tuple list::as_tuple() const
|
|
||||||
{
|
|
||||||
return tuple(ref(PyList_AsTuple(get())));
|
|
||||||
}
|
|
||||||
|
|
||||||
const ref& list::proxy::operator=(const ref& rhs)
|
|
||||||
{
|
|
||||||
m_list.set_item(m_index, rhs);
|
|
||||||
return rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
list::proxy::operator ref() const
|
|
||||||
{
|
|
||||||
return ref(PyList_GetItem(m_list.get(), m_index), ref::increment_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
ref list::get_item(std::size_t pos) const
|
|
||||||
{
|
|
||||||
return ref(PyList_GetItem(this->get(), pos), ref::increment_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void list::set_item(std::size_t pos, const ref& rhs)
|
|
||||||
{
|
|
||||||
int result = PyList_SetItem(this->get(), pos, rhs.get());
|
|
||||||
if (result == -1)
|
|
||||||
throw error_already_set();
|
|
||||||
Py_INCREF(rhs.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
list::proxy::proxy(const ref& list, std::size_t index)
|
|
||||||
: m_list(list), m_index(index)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const list& list::slice_proxy::operator=(const list& rhs)
|
|
||||||
{
|
|
||||||
if (PyList_SetSlice(m_list.get(), m_low, m_high, rhs.get()) == -1)
|
|
||||||
throw error_already_set();
|
|
||||||
return rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
list::slice_proxy::operator ref() const
|
|
||||||
{
|
|
||||||
return ref(PyList_GetSlice(m_list.get(), m_low, m_high));
|
|
||||||
}
|
|
||||||
|
|
||||||
list::slice_proxy::operator list() const
|
|
||||||
{
|
|
||||||
return list(this->operator ref());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t list::slice_proxy::size()
|
|
||||||
{
|
|
||||||
return this->operator list().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
ref list::slice_proxy::operator[](std::size_t pos) const
|
|
||||||
{
|
|
||||||
return this->operator list()[pos].operator ref();
|
|
||||||
}
|
|
||||||
|
|
||||||
list::slice_proxy::slice_proxy(const ref& list, int low, int high)
|
|
||||||
: m_list(list), m_low(low), m_high(high)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
}} // namespace boost::python
|
|
||||||
1097
src/types.cpp
1097
src/types.cpp
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,231 +0,0 @@
|
|||||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
|
||||||
// distribute this software is granted provided this copyright notice appears
|
|
||||||
// in all copies. This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
|
||||||
// producing this work.
|
|
||||||
|
|
||||||
#ifndef BPL_TEST_DWA052200_H_
|
|
||||||
# define BPL_TEST_DWA052200_H_
|
|
||||||
//
|
|
||||||
// Example code demonstrating extension class usage
|
|
||||||
//
|
|
||||||
|
|
||||||
# include <boost/python/class_builder.hpp>
|
|
||||||
# include <boost/python/callback.hpp>
|
|
||||||
# include <boost/utility.hpp>
|
|
||||||
# include <cstring>
|
|
||||||
# include <iostream>
|
|
||||||
# include <cstddef>
|
|
||||||
# include <string>
|
|
||||||
# include <map>
|
|
||||||
|
|
||||||
namespace bpl_test {
|
|
||||||
|
|
||||||
//
|
|
||||||
// example: Foo, Bar, and Baz are C++ classes we want to wrap.
|
|
||||||
//
|
|
||||||
|
|
||||||
class Foo // prohibit copying, proving that it doesn't choke
|
|
||||||
: boost::noncopyable // our generation of to_python().
|
|
||||||
{
|
|
||||||
public: // constructor/destructor
|
|
||||||
Foo(int x) : m_x(x) {}
|
|
||||||
virtual ~Foo() {}
|
|
||||||
|
|
||||||
public: // non-virtual functions
|
|
||||||
const char* mumble(); // mumble something
|
|
||||||
void set(long x); // change the held value
|
|
||||||
|
|
||||||
// These two call virtual functions
|
|
||||||
std::string call_pure(); // call a pure virtual fuction
|
|
||||||
int call_add_len(const char* s) const; // virtual function with a default implementation
|
|
||||||
|
|
||||||
private:
|
|
||||||
// by default, sum the held value and the length of s
|
|
||||||
virtual int add_len(const char* s) const;
|
|
||||||
|
|
||||||
// Derived classes can do whatever they want here, but they must do something!
|
|
||||||
virtual std::string pure() const = 0;
|
|
||||||
|
|
||||||
public: // friend declarations
|
|
||||||
// If you have private virtual functions such as add_len which you want to
|
|
||||||
// override in Python and have default implementations, they must be
|
|
||||||
// accessible by the thing making the def() call on the extension_class (in
|
|
||||||
// this case, the nested PythonClass itself), and by the C++ derived class
|
|
||||||
// which is used to cause the Python callbacks (in this case,
|
|
||||||
// FooCallback). See the definition of FooCallback::add_len()
|
|
||||||
struct PythonClass;
|
|
||||||
friend struct PythonClass;
|
|
||||||
friend class FooCallback;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int m_x; // the held value
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Bar and Baz have mutually-recursive type conversion dependencies (see
|
|
||||||
// pass_xxx functions). I've done this to prove that it doesn't cause a
|
|
||||||
// problem for Python class definitions, which happen later.
|
|
||||||
//
|
|
||||||
// Bar and Baz functions are only virtual to increase the likelihood of a crash
|
|
||||||
// if I inadvertently use a pointer to garbage memory (a likely thing to test
|
|
||||||
// for considering the amount of type casting needed to translate to and from
|
|
||||||
// Python).
|
|
||||||
struct Baz;
|
|
||||||
struct Bar
|
|
||||||
{
|
|
||||||
Bar(int x, int y) : m_first(x), m_second(y) {}
|
|
||||||
virtual int first() const { return m_first; }
|
|
||||||
virtual int second() const { return m_second; }
|
|
||||||
virtual Baz pass_baz(Baz x);
|
|
||||||
|
|
||||||
int m_first, m_second;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Baz
|
|
||||||
{
|
|
||||||
virtual Bar pass_bar(const Bar& x) { return x; }
|
|
||||||
|
|
||||||
// We can return smart pointers
|
|
||||||
virtual std::auto_ptr<Baz> clone() { return std::auto_ptr<Baz>(new Baz(*this)); }
|
|
||||||
|
|
||||||
// This illustrates creating a polymorphic derived class of Foo
|
|
||||||
virtual boost::shared_ptr<Foo> create_foo();
|
|
||||||
|
|
||||||
// We can accept smart pointer parameters
|
|
||||||
virtual int get_foo_value(boost::shared_ptr<Foo>);
|
|
||||||
|
|
||||||
// Show what happens in python when we take ownership from an auto_ptr
|
|
||||||
virtual void eat_baz(std::auto_ptr<Baz>);
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::map<std::size_t, std::string> StringMap;
|
|
||||||
typedef std::pair<int, int> IntPair;
|
|
||||||
|
|
||||||
IntPair make_pair(int, int);
|
|
||||||
|
|
||||||
typedef std::less<IntPair> CompareIntPair;
|
|
||||||
typedef std::pair<std::string, std::string> StringPair;
|
|
||||||
|
|
||||||
inline std::string first_string(const StringPair& x)
|
|
||||||
{
|
|
||||||
return x.first;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string second_string(const StringPair& x)
|
|
||||||
{
|
|
||||||
return x.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Range
|
|
||||||
{
|
|
||||||
Range(int x)
|
|
||||||
: m_start(x), m_finish(x) {}
|
|
||||||
|
|
||||||
Range(int start, int finish)
|
|
||||||
: m_start(start), m_finish(finish) {}
|
|
||||||
|
|
||||||
std::size_t length() const
|
|
||||||
{ return m_finish < m_start ? 0 : m_finish - m_start; }
|
|
||||||
|
|
||||||
void length(std::size_t new_length)
|
|
||||||
{ m_finish = m_start + new_length; }
|
|
||||||
|
|
||||||
int operator[](std::size_t n)
|
|
||||||
{ return m_start + n; }
|
|
||||||
|
|
||||||
Range slice(std::size_t start, std::size_t end)
|
|
||||||
{
|
|
||||||
if (start > length())
|
|
||||||
start = length();
|
|
||||||
if (end > length())
|
|
||||||
end = length();
|
|
||||||
return Range(m_start + start, m_start + end);
|
|
||||||
}
|
|
||||||
|
|
||||||
int m_start, m_finish;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
// //
|
|
||||||
// Begin wrapping code. Usually this would live in a separate header. //
|
|
||||||
// //
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Since Foo has virtual functions which we want overriden in Python, we must
|
|
||||||
// derive FooCallback.
|
|
||||||
class FooCallback : public Foo
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Note the additional constructor parameter "self", which is needed to
|
|
||||||
// allow function overriding from Python.
|
|
||||||
FooCallback(PyObject* self, int x);
|
|
||||||
|
|
||||||
friend struct PythonClass; // give it access to the functions below
|
|
||||||
|
|
||||||
private: // implementations of Foo virtual functions that are overridable in python.
|
|
||||||
int add_len(const char* x) const;
|
|
||||||
|
|
||||||
// A function which Python can call in case bar is not overridden from
|
|
||||||
// Python. In true Python style, we use a free function taking an initial
|
|
||||||
// self parameter. You can put this function anywhere; it needn't be a
|
|
||||||
// static member of the wrapping class.
|
|
||||||
static int default_add_len(const Foo* self, const char* x);
|
|
||||||
|
|
||||||
// Since Foo::pure() is pure virtual, we don't need a corresponding
|
|
||||||
// default_pure(). A failure to override it in Python will result in an
|
|
||||||
// exception at runtime when pure() is called.
|
|
||||||
std::string pure() const;
|
|
||||||
|
|
||||||
private: // Required boilerplate if functions will be overridden
|
|
||||||
PyObject* m_self; // No, we don't want a boost::python::ref here, or we'd get an ownership cycle.
|
|
||||||
};
|
|
||||||
|
|
||||||
// Define the Python base class
|
|
||||||
struct Foo::PythonClass : boost::python::class_builder<Foo, FooCallback> { PythonClass(boost::python::module_builder&); };
|
|
||||||
|
|
||||||
// No virtual functions on Bar or Baz which are actually supposed to behave
|
|
||||||
// virtually from C++, so we'll rely on the library to define a wrapper for
|
|
||||||
// us. Even so, Python class_t types for each type we're wrapping should be
|
|
||||||
// _defined_ here in a header where they can be seen by other extension class
|
|
||||||
// definitions, since it is the definition of the boost::python::class_builder<> that
|
|
||||||
// causes to_python/from_python conversion functions to be generated.
|
|
||||||
struct BarPythonClass : boost::python::class_builder<Bar> { BarPythonClass(boost::python::module_builder&); };
|
|
||||||
struct BazPythonClass : boost::python::class_builder<Baz> { BazPythonClass(boost::python::module_builder&); };
|
|
||||||
|
|
||||||
struct StringMapPythonClass
|
|
||||||
: boost::python::class_builder<StringMap>
|
|
||||||
{
|
|
||||||
StringMapPythonClass(boost::python::module_builder&);
|
|
||||||
|
|
||||||
// These static functions implement the right argument protocols for
|
|
||||||
// implementing the Python "special member functions" for mapping on
|
|
||||||
// StringMap. Could just as easily be global functions.
|
|
||||||
static const std::string& get_item(const StringMap& m, std::size_t key);
|
|
||||||
static void set_item(StringMap& m, std::size_t key, const std::string& value);
|
|
||||||
static void del_item(StringMap& m, std::size_t key);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IntPairPythonClass
|
|
||||||
: boost::python::class_builder<IntPair>
|
|
||||||
{
|
|
||||||
IntPairPythonClass(boost::python::module_builder&);
|
|
||||||
|
|
||||||
// The following could just as well be a free function; it implements the
|
|
||||||
// getattr functionality for IntPair.
|
|
||||||
static int getattr(const IntPair&, const std::string& s);
|
|
||||||
static void setattr(IntPair&, const std::string& name, int value);
|
|
||||||
static void delattr(IntPair&, const char* name);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CompareIntPairPythonClass
|
|
||||||
: boost::python::class_builder<CompareIntPair>
|
|
||||||
{
|
|
||||||
CompareIntPairPythonClass(boost::python::module_builder&);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace bpl_test
|
|
||||||
|
|
||||||
#endif // BPL_TEST_DWA052200_H_
|
|
||||||
File diff suppressed because it is too large
Load Diff
1112
test/doctest.py
1112
test/doctest.py
File diff suppressed because it is too large
Load Diff
426
todo.txt
426
todo.txt
@@ -1,426 +0,0 @@
|
|||||||
Check for const reference parameters in all from_python functions in py.h, including implementations.
|
|
||||||
Better python and C++ exception handling/error reporting.
|
|
||||||
long long support
|
|
||||||
use Python generic numeric coercion in from_python() for C++ numeric types
|
|
||||||
Rename PyPtr to Reference.
|
|
||||||
Report Cygwin linker memory issues
|
|
||||||
__init__ stuff
|
|
||||||
Make abstract classes non-instantiable (?)
|
|
||||||
Call default __init__ functions automatically where applicable (?)
|
|
||||||
Support for Python LONG types in Objects.h
|
|
||||||
Throw TypeError after asserting when objects from objects.cpp detect a type mismatch.
|
|
||||||
Figure out how to package everything as a shared library.
|
|
||||||
Unicode string support
|
|
||||||
Add read-only wrapper for __dict__ attribute
|
|
||||||
Objects.h support for generic objects, Sequence objects, etc.
|
|
||||||
empty() member functions for objects.hpp
|
|
||||||
|
|
||||||
Testing
|
|
||||||
Python 2.0
|
|
||||||
object revival in __del__
|
|
||||||
More thorough tests of objects.h/cpp classes
|
|
||||||
Better reference-count checking
|
|
||||||
|
|
||||||
Optimizations
|
|
||||||
Remove one level of indirection on type objects (no vtbl?).
|
|
||||||
Specializations of Caller<> for commmon combinations of argument types (?)
|
|
||||||
Replace uses of XXXable classes
|
|
||||||
Don't allocate instance __dict__ unless used.
|
|
||||||
|
|
||||||
|
|
||||||
Documentation:
|
|
||||||
|
|
||||||
differences between Python classes and ExtensionClasses
|
|
||||||
additional capabilities of ExtensionClasses
|
|
||||||
slice adjustment
|
|
||||||
|
|
||||||
Why special attributes other than __doc__ and __name__ are immutable.
|
|
||||||
|
|
||||||
An example of the problems with the built-in Python classes.
|
|
||||||
|
|
||||||
>>> class A:
|
|
||||||
... def __getattr__(self, name):
|
|
||||||
... return 'A.__getattr__'
|
|
||||||
...
|
|
||||||
>>> class B(A): pass
|
|
||||||
...
|
|
||||||
>>> class C(B): pass
|
|
||||||
...
|
|
||||||
>>> C().x
|
|
||||||
'A.__getattr__'
|
|
||||||
>>> B.__bases__ = ()
|
|
||||||
>>> C().x
|
|
||||||
'A.__getattr__'
|
|
||||||
|
|
||||||
Smart pointers
|
|
||||||
#ifndef PY_NO_INLINE_FRIENDS_IN_NAMESPACE
|
|
||||||
namespace py {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct VtkConverters
|
|
||||||
{
|
|
||||||
typedef py::PyExtensionClassConverters<T> Converters;
|
|
||||||
|
|
||||||
friend vtk_ptr<T>& from_python(PyObject* p, py::Type<vtk_ptr<T>&>)
|
|
||||||
{ return Converters::ptr_from_python(p, py::Type<vtk_ptr<T> >()); }
|
|
||||||
|
|
||||||
friend vtk_ptr<T>& from_python(PyObject* p, py::Type<vtk_ptr<T> >)
|
|
||||||
{ return Converters::ptr_from_python(p, py::Type<vtk_ptr<T> >()); }
|
|
||||||
|
|
||||||
friend const vtk_ptr<T>& from_python(PyObject* p, py::Type<const vtk_ptr<T>&>)
|
|
||||||
{ return Converters::ptr_from_python(p, py::Type<vtk_ptr<T> >()); }
|
|
||||||
|
|
||||||
friend PyObject* to_python(vtk_ptr<T> x)
|
|
||||||
{ return Converters::ptr_to_python(x); }
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef PY_NO_INLINE_FRIENDS_IN_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct VtkWrapper : py::ClassWrapper<T>, py::VtkConverters<T>
|
|
||||||
{
|
|
||||||
typedef py::ClassWrapper<T> Base;
|
|
||||||
VtkWrapper(Module& module, const char* name)
|
|
||||||
: Base(module, name) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
exception handling
|
|
||||||
|
|
||||||
Advanced Topics:
|
|
||||||
Advanced Type Conversion
|
|
||||||
adding conversions for fundamental types
|
|
||||||
generic conversions for template types (with partial spec).
|
|
||||||
|
|
||||||
Interacting with built-in Python objects and types from C++
|
|
||||||
|
|
||||||
dealing with non-const reference/pointer parameters
|
|
||||||
|
|
||||||
extending multiple-argument support using gen_all.py
|
|
||||||
|
|
||||||
|
|
||||||
Fancy wrapping tricks
|
|
||||||
templates
|
|
||||||
Yes. If you look at the examples in extclass_demo.cpp you'll see that I have
|
|
||||||
exposed several template instantiations (e.g. std::pair<int,int>) in Python.
|
|
||||||
Keep in mind, however, that you can only expose a template instantiation,
|
|
||||||
not a template. In other words, MyTemplate<Foo> can be exposed. MyTemplate
|
|
||||||
itself cannot.
|
|
||||||
|
|
||||||
Well, that's not strictly true. Wow, this is more complicated to explain
|
|
||||||
than I thought.
|
|
||||||
You can't make an ExtensionClass<MyTemplate>, since after all MyTemplate is
|
|
||||||
not a type. You can only expose a concrete type to Python.
|
|
||||||
|
|
||||||
What you *can* do (if your compiler supports partial ordering of function
|
|
||||||
templates - MSVC is broken and does not) is to write appropriate
|
|
||||||
from_python() and to_python() functions for converting a whole class of
|
|
||||||
template instantiations to/from Python. That won't let you create an
|
|
||||||
instance of MyTemplate<SomePythonType> from Python, but it will let you
|
|
||||||
pass/return arbitrary MyTemplate<SomeCplusplusType> instances to/from your
|
|
||||||
wrapped C++ functions.
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
MyTemplate<T> from_python(PyObject* x, py::Type<MyTemplate<T> >)
|
|
||||||
{
|
|
||||||
// code to convert x into a MyTemplate<T>... that part is up to you
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
PyObject* from_python(const MyTemplate<T>&)
|
|
||||||
{
|
|
||||||
// code to convert MyTemplate<T> into a PyObject*... that part is up to
|
|
||||||
you
|
|
||||||
}
|
|
||||||
|
|
||||||
For example, you could use this to convert Python lists to/from
|
|
||||||
std::vector<T> automatically.
|
|
||||||
|
|
||||||
Pointer return values
|
|
||||||
|
|
||||||
Case 1:
|
|
||||||
|
|
||||||
> I am now also able to wrap the problematic TextRecordIterator for Python.
|
|
||||||
> However, one of its function compiles with this warning:
|
|
||||||
>
|
|
||||||
> d:\py_cpp/caller.h(33) : warning C4800: 'const class Record *const '
|
|
||||||
> : forcing value to bool 'true' or 'false' (performance warning)
|
|
||||||
> d:\py_cpp/functions.h(54) : see reference to function template
|
|
||||||
> instantiation 'struct _object *__cdecl py::Caller::call(const class Record
|
|
||||||
> *const (__thiscall TextRecordIterator::*)(void),struct _object *,struct
|
|
||||||
> _object *)' being compiled
|
|
||||||
>
|
|
||||||
> If you look at the offending code, you'll see that we really do need to
|
|
||||||
> get back that pointer:
|
|
||||||
>
|
|
||||||
> const Record* const TextRecordIterator::Next() {
|
|
||||||
> if (fStatus != RecordIterator::SUCCESS) {
|
|
||||||
> return 0;
|
|
||||||
> } else {
|
|
||||||
> return &fData;
|
|
||||||
> }
|
|
||||||
> }
|
|
||||||
>
|
|
||||||
> The point of the TextRecordIterator is to hand over one reord after
|
|
||||||
> another. A bool wouldn't do us much good here :-)
|
|
||||||
>
|
|
||||||
> Do you have any suggestions for fixing this?
|
|
||||||
|
|
||||||
In general, py_cpp doesn't automatically convert pointer return values
|
|
||||||
to_python because pointers have too many potential meanings. Is it an
|
|
||||||
iterator? A pointer to a single element? An array? Is ownership being passed
|
|
||||||
to Python or is the pointer really just a reference? If the latter, what
|
|
||||||
happens when some C++ code deletes the referent. The only exception to this
|
|
||||||
rule is const char*, since it has a generally accepted interpretation (could
|
|
||||||
be trouble with some generic code, though!)
|
|
||||||
|
|
||||||
If you have wrapped the Record class, you could add this to namespace py:
|
|
||||||
|
|
||||||
PyObject* to_python(const Record* p) {
|
|
||||||
return to_python(*p);
|
|
||||||
}
|
|
||||||
|
|
||||||
Of course, this will cause the Record class to be copied. If you can't live
|
|
||||||
with that (Record would have to be /really/ heavyweight to make this
|
|
||||||
worthwhile), you can follow one of these dangerous approaches:
|
|
||||||
|
|
||||||
1. Use the technique I described with dangerous_array in
|
|
||||||
http://www.egroups.com/message/boost/6196. You do not have to expose Record
|
|
||||||
explicitly in this case. Instead the class you expose will be more of a
|
|
||||||
Record_proxy
|
|
||||||
|
|
||||||
2. Wrap Record in the usual way, then add the following to namespace py:
|
|
||||||
|
|
||||||
PyObject* to_python(const Record* p)
|
|
||||||
{
|
|
||||||
return ExtensionClass<Record>::ptr_to_python(const_cast<Record*>(p));
|
|
||||||
}
|
|
||||||
|
|
||||||
This will cause the Record* to be treated as though it were an owning smart
|
|
||||||
pointer, even though it's not. Be sure you don't use the reference for
|
|
||||||
anything from Python once the pointer becomes invalid, though. Don't worry
|
|
||||||
too much about the const-correctness issue: Const-correctness is completely
|
|
||||||
lost to Python anyway!
|
|
||||||
|
|
||||||
3. As above, but instead wrap const Record rather than plain Record. Then
|
|
||||||
you can avoid the const_cast, but you obviously can't def() any non-const
|
|
||||||
member functions of Record.
|
|
||||||
|
|
||||||
Case 2:
|
|
||||||
|
|
||||||
> I have yet another question. This is more a general wrapper question.
|
|
||||||
> Let me say that there is a function that returns a float* which most
|
|
||||||
> probably is an array. Similarly if I have a function that takes a
|
|
||||||
> float* as an argument, what is the best way of wrapping this?
|
|
||||||
|
|
||||||
I think you have correctly perceived that it doesn't make sense for me to
|
|
||||||
automatically convert all pointers, since the ownership semantics are so
|
|
||||||
blurry.
|
|
||||||
|
|
||||||
> 1) If the array is small it makes sense to convert it to either a
|
|
||||||
> tuple or list. What is the easiest way to do this?? I am looking
|
|
||||||
> for a way that makes one write the least code. :)
|
|
||||||
|
|
||||||
How can you tell the length of the array from a single pointer?
|
|
||||||
Once you've answered that question, you can expose a wrapper function which
|
|
||||||
returns an instance of the py::Tuple or py::List class from objects.h. If
|
|
||||||
you are using a List, for example, you could write something like this:
|
|
||||||
|
|
||||||
py::List wrap_f()
|
|
||||||
{
|
|
||||||
T* start = f();
|
|
||||||
py::List x;
|
|
||||||
for (T* p = start; p != start + length_constant; ++p)
|
|
||||||
x.push_back(py::to_python(*p));
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
> 2) If the array is large it may not make sense to use a list/tuple
|
|
||||||
> esp. if the values are used for computationally intense programs.
|
|
||||||
|
|
||||||
In this case you can do one of several somewhat dangerous things. Why
|
|
||||||
dangerous? Because python can not control the lifetime of the data, so the
|
|
||||||
data in the array may be destroyed or become invalid before the last
|
|
||||||
reference to it disappears. The basic approach is to make a small C++ class
|
|
||||||
which contains the pointer, and expose that:
|
|
||||||
|
|
||||||
// UNTESTED
|
|
||||||
template <class T>
|
|
||||||
struct dangerous_array
|
|
||||||
{
|
|
||||||
dangerous_array(T* start, T* end)
|
|
||||||
: m_start(start), m_end(end) {}
|
|
||||||
|
|
||||||
// exposed as "__len__"
|
|
||||||
std::size_t length() {
|
|
||||||
return m_end - m_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
// exposed as "__getitem__"
|
|
||||||
T get_item(std::size_t n) {
|
|
||||||
check_range(n);
|
|
||||||
return start[n];
|
|
||||||
}
|
|
||||||
|
|
||||||
// exposed as "__setitem__" if the array is mutable
|
|
||||||
void set_item(std::size_t n, const T& x) {
|
|
||||||
check_range(n);
|
|
||||||
start[n] = x;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
void check_range(std::size_t n) {
|
|
||||||
if (n >= m_end - m_start) {
|
|
||||||
PyErr_SetString(PyExc_IndexError, "array index out of range");
|
|
||||||
throw py::ErrorAlreadySet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
T* m_start;
|
|
||||||
T* m_end;
|
|
||||||
};
|
|
||||||
|
|
||||||
A reasonably safe approach would be to make a wrapper function for each
|
|
||||||
function that returns a T*, and expose that instead. If you're too lazy and
|
|
||||||
you really like to live on the edge, though, you can write to_python(T*) in
|
|
||||||
terms of to_python(const dangerous_array<T>&), and you'll automatically
|
|
||||||
convert all T* return values to a wrapped dangerous_array.
|
|
||||||
|
|
||||||
> 3) For an arbitrary class "class_A", say, can py_cpp handle
|
|
||||||
> references to class_A &instance, or class_A *instance?? i.e. will it
|
|
||||||
> wrap function calls to such objects? This question is obviously
|
|
||||||
> related to the earlier questions.
|
|
||||||
|
|
||||||
Yes, iff class_A has been exposed to python with a ClassWrapper<class_A>.
|
|
||||||
See http://people.ne.mediaone.net/abrahams/downloads/under-the-hood.html for
|
|
||||||
a few details.
|
|
||||||
|
|
||||||
raw C++ arrays
|
|
||||||
You could expose a function like this one to get the desired effect:
|
|
||||||
|
|
||||||
#include <py_cpp/objects.h>
|
|
||||||
void set_len(UnitCell& x, py::Tuple tuple)
|
|
||||||
{
|
|
||||||
double len[3];
|
|
||||||
for (std::size_t i =0; i < 3; ++i)
|
|
||||||
len[i] = py::from_python(tuple[i].get(), py::Type<double>());
|
|
||||||
x.set_len(len);
|
|
||||||
}
|
|
||||||
|
|
||||||
Types that are already wrapped by other libraries
|
|
||||||
|
|
||||||
It's not documented yet, but you should be able to use a raw PyObject* or a
|
|
||||||
py::Ptr as one parameter to your C++ function. Then you can manipulate it as
|
|
||||||
any other generic Python object.
|
|
||||||
|
|
||||||
Alternatively, If the NTL gives you a C/C++ interface, you can also write
|
|
||||||
your own converter function:
|
|
||||||
|
|
||||||
some_ntl_type& from_python(PyObject* p, py::Type<some_NTL_type&>)
|
|
||||||
{
|
|
||||||
// an Example implementation. Basically, you need
|
|
||||||
// to extract the NTL type from the PyObject*.
|
|
||||||
if (p->ob_type != NTL_long_type) {
|
|
||||||
PyErr_SetString(PyExc_TypeErr, "NTL long required");
|
|
||||||
throw py::ArgumentError();
|
|
||||||
}
|
|
||||||
return *static_cast<some_NTL_type*>(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
then the C++ functions you're wrapping can take a some_NTL_type& parameter
|
|
||||||
directly.
|
|
||||||
|
|
||||||
"Thin converting wrappers" for constructors
|
|
||||||
|
|
||||||
hijack some of the functionality
|
|
||||||
described in the section on Overridable Virtual Functions (even though you
|
|
||||||
don't have any virtual functions). I suggest this workaround:
|
|
||||||
|
|
||||||
struct UnitCellWrapper : UnitCell
|
|
||||||
{
|
|
||||||
UnitCellWrapper(PyObject* self, py::Tuple x, py::Tuple y)
|
|
||||||
: UnitCell(from_python(x[1], py::Type<double>()),
|
|
||||||
from_python(x[2], py::Type<double>()),
|
|
||||||
from_python(x[3], py::Type<double>()),
|
|
||||||
from_python(y[1], py::Type<double>()),
|
|
||||||
from_python(y[2], py::Type<double>()),
|
|
||||||
from_python(y[3], py::Type<double>()))
|
|
||||||
{}
|
|
||||||
}
|
|
||||||
|
|
||||||
py::ClassWrapper<UnitCell, UnitCellWrapper> unit_cell_class;
|
|
||||||
unit_cell_class.def(py::Constructor<py::Tuple, py::Tuple>());
|
|
||||||
...
|
|
||||||
|
|
||||||
returning references to wrapped objects
|
|
||||||
|
|
||||||
the importance of declaration order of ClassWrappers/ExtensionInstances
|
|
||||||
|
|
||||||
out parameters and non-const pointers
|
|
||||||
|
|
||||||
Calling back into Python:
|
|
||||||
// caveat: UNTESTED!
|
|
||||||
#include <py_cpp/pyptr.h>
|
|
||||||
#include <py_cpp/callback.h>
|
|
||||||
#include <py_cpp/py.h>
|
|
||||||
#include <Python.h>
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
py::Ptr module(PyImport_ImportModule("weapons"));
|
|
||||||
const int strength = 10;
|
|
||||||
const char* manufacturer = "Vordon Empire";
|
|
||||||
py::Ptr a_blaster(py::Callback<py::Ptr>::call_method(
|
|
||||||
module.get(), "Blaster", strength, manufacturer));
|
|
||||||
py::Callback<void>::call_method(a_blaster.get(), "Fire");
|
|
||||||
int old_strength = py::Callback<int>::call_method(a_blaster.get(), "get_strength");
|
|
||||||
py::Callback<void>::call_method(a_blaster.get(), "set_strength", 5);
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Miscellaneous
|
|
||||||
About the vc6 project and the debug build
|
|
||||||
About doctest.py
|
|
||||||
|
|
||||||
Boost remarks:
|
|
||||||
|
|
||||||
> > One of us is completely nuts ;->. How can I move the test
|
|
||||||
> > (is_prefix(enablers[i].name + 2, name + 2)) outside the loop if it
|
|
||||||
depends
|
|
||||||
> > on the loop index, i?
|
|
||||||
> >
|
|
||||||
> name += 2;
|
|
||||||
> for()
|
|
||||||
> {
|
|
||||||
> if (is_prefix(enablers[i].name + 2, name))
|
|
||||||
> }
|
|
||||||
|
|
||||||
I see now. I guess I should stop pussyfooting and either go for optimization
|
|
||||||
or clarity here, eh?
|
|
||||||
|
|
||||||
------
|
|
||||||
|
|
||||||
> Re: Dict
|
|
||||||
> Why abbreviate this? Code is read 5 or 6 times for every time its
|
|
||||||
> written. The few extra characters don't affect compile time or program
|
|
||||||
> speed. It's part of my personal goal of write what you mean, name them
|
|
||||||
what
|
|
||||||
> they are.
|
|
||||||
|
|
||||||
I completely agree. Abbrevs rub me the wrong way, 2 ;->
|
|
||||||
|
|
||||||
-------
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Later:
|
|
||||||
keyword and varargs?
|
|
||||||
Put explicit Type<> arguments at the beginnings of overloads, to make them look more like template instance specifications.
|
|
||||||
|
|
||||||
Known bugs
|
|
||||||
can't handle 'const void' return values
|
|
||||||
Who returns 'const void'? I did it once, by mistake ;)
|
|
||||||
Reference in New Issue
Block a user