mirror of
https://github.com/boostorg/python.git
synced 2026-01-21 17:12:22 +00:00
This commit was generated by cvs2svn to compensate for changes in r315,
which included commits to RCS files with non-trunk default branches. [SVN r7932]
This commit is contained in:
96
.gitattributes
vendored
Normal file
96
.gitattributes
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
* text=auto !eol svneol=native#text/plain
|
||||
*.gitattributes text svneol=native#text/plain
|
||||
|
||||
# Scriptish formats
|
||||
*.bat text svneol=native#text/plain
|
||||
*.bsh text svneol=native#text/x-beanshell
|
||||
*.cgi text svneol=native#text/plain
|
||||
*.cmd text svneol=native#text/plain
|
||||
*.js text svneol=native#text/javascript
|
||||
*.php text svneol=native#text/x-php
|
||||
*.pl text svneol=native#text/x-perl
|
||||
*.pm text svneol=native#text/x-perl
|
||||
*.py text svneol=native#text/x-python
|
||||
*.sh eol=lf svneol=LF#text/x-sh
|
||||
configure eol=lf svneol=LF#text/x-sh
|
||||
|
||||
# Image formats
|
||||
*.bmp binary svneol=unset#image/bmp
|
||||
*.gif binary svneol=unset#image/gif
|
||||
*.ico binary svneol=unset#image/ico
|
||||
*.jpeg binary svneol=unset#image/jpeg
|
||||
*.jpg binary svneol=unset#image/jpeg
|
||||
*.png binary svneol=unset#image/png
|
||||
*.tif binary svneol=unset#image/tiff
|
||||
*.tiff binary svneol=unset#image/tiff
|
||||
*.svg text svneol=native#image/svg%2Bxml
|
||||
|
||||
# Data formats
|
||||
*.pdf binary svneol=unset#application/pdf
|
||||
*.avi binary svneol=unset#video/avi
|
||||
*.doc binary svneol=unset#application/msword
|
||||
*.dsp text svneol=crlf#text/plain
|
||||
*.dsw text svneol=crlf#text/plain
|
||||
*.eps binary svneol=unset#application/postscript
|
||||
*.gz binary svneol=unset#application/gzip
|
||||
*.mov binary svneol=unset#video/quicktime
|
||||
*.mp3 binary svneol=unset#audio/mpeg
|
||||
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
|
||||
*.ps binary svneol=unset#application/postscript
|
||||
*.psd binary svneol=unset#application/photoshop
|
||||
*.rdf binary svneol=unset#text/rdf
|
||||
*.rss text svneol=unset#text/xml
|
||||
*.rtf binary svneol=unset#text/rtf
|
||||
*.sln text svneol=native#text/plain
|
||||
*.swf binary svneol=unset#application/x-shockwave-flash
|
||||
*.tgz binary svneol=unset#application/gzip
|
||||
*.vcproj text svneol=native#text/xml
|
||||
*.vcxproj text svneol=native#text/xml
|
||||
*.vsprops text svneol=native#text/xml
|
||||
*.wav binary svneol=unset#audio/wav
|
||||
*.xls binary svneol=unset#application/vnd.ms-excel
|
||||
*.zip binary svneol=unset#application/zip
|
||||
|
||||
# Text formats
|
||||
.htaccess text svneol=native#text/plain
|
||||
*.bbk text svneol=native#text/xml
|
||||
*.cmake text svneol=native#text/plain
|
||||
*.css text svneol=native#text/css
|
||||
*.dtd text svneol=native#text/xml
|
||||
*.htm text svneol=native#text/html
|
||||
*.html text svneol=native#text/html
|
||||
*.ini text svneol=native#text/plain
|
||||
*.log text svneol=native#text/plain
|
||||
*.mak text svneol=native#text/plain
|
||||
*.qbk text svneol=native#text/plain
|
||||
*.rst text svneol=native#text/plain
|
||||
*.sql text svneol=native#text/x-sql
|
||||
*.txt text svneol=native#text/plain
|
||||
*.xhtml text svneol=native#text/xhtml%2Bxml
|
||||
*.xml text svneol=native#text/xml
|
||||
*.xsd text svneol=native#text/xml
|
||||
*.xsl text svneol=native#text/xml
|
||||
*.xslt text svneol=native#text/xml
|
||||
*.xul text svneol=native#text/xul
|
||||
*.yml text svneol=native#text/plain
|
||||
boost-no-inspect text svneol=native#text/plain
|
||||
CHANGES text svneol=native#text/plain
|
||||
COPYING text svneol=native#text/plain
|
||||
INSTALL text svneol=native#text/plain
|
||||
Jamfile text svneol=native#text/plain
|
||||
Jamroot text svneol=native#text/plain
|
||||
Jamfile.v2 text svneol=native#text/plain
|
||||
Jamrules text svneol=native#text/plain
|
||||
Makefile* text svneol=native#text/plain
|
||||
README text svneol=native#text/plain
|
||||
TODO text svneol=native#text/plain
|
||||
|
||||
# Code formats
|
||||
*.c text svneol=native#text/plain
|
||||
*.cpp text svneol=native#text/plain
|
||||
*.h text svneol=native#text/plain
|
||||
*.hpp text svneol=native#text/plain
|
||||
*.ipp text svneol=native#text/plain
|
||||
*.tpp text svneol=native#text/plain
|
||||
*.jam text svneol=native#text/plain
|
||||
*.java text svneol=native#text/plain
|
||||
62
base_object.h
Normal file
62
base_object.h
Normal file
@@ -0,0 +1,62 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#ifndef BASE_OBJECT_DWA051600_H_
|
||||
# define BASE_OBJECT_DWA051600_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
# include "signatures.h" // really just for Type<>
|
||||
# include "wrap_python.h"
|
||||
# include <cstring>
|
||||
|
||||
namespace py {
|
||||
|
||||
// BaseObject - adds a constructor and non-virtual destructor to a
|
||||
// base Python type (e.g. PyObject, PyTypeObject).
|
||||
template <class PythonType>
|
||||
struct BaseObject : PythonType
|
||||
{
|
||||
typedef PythonType BasePythonType;
|
||||
|
||||
// Initializes type and reference count. All other fields of BasePythonType are 0
|
||||
BaseObject(PyTypeObject* type_object);
|
||||
|
||||
// Decrements reference count on the type
|
||||
~BaseObject();
|
||||
};
|
||||
|
||||
// Easy typedefs for common usage
|
||||
typedef BaseObject<PyObject> PythonObject;
|
||||
typedef BaseObject<PyTypeObject> PythonType;
|
||||
|
||||
|
||||
//
|
||||
// Class template member function implementations
|
||||
//
|
||||
template <class PythonType>
|
||||
BaseObject<PythonType>::BaseObject(PyTypeObject* type_object)
|
||||
{
|
||||
BasePythonType* bp = this;
|
||||
#if !defined(_MSC_VER) || defined(__STLPORT)
|
||||
std::
|
||||
#endif
|
||||
memset(bp, 0, sizeof(BasePythonType));
|
||||
ob_refcnt = 1;
|
||||
ob_type = type_object;
|
||||
Py_INCREF(type_object);
|
||||
}
|
||||
|
||||
template <class PythonType>
|
||||
inline BaseObject<PythonType>::~BaseObject()
|
||||
{
|
||||
Py_DECREF(ob_type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif BASE_OBJECT_DWA051600_H_
|
||||
83
callback.h
Normal file
83
callback.h
Normal file
@@ -0,0 +1,83 @@
|
||||
// (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 5-argument python callbacks by gen_callback.py
|
||||
|
||||
#ifndef CALLBACK_DWA_052100_H_
|
||||
# define CALLBACK_DWA_052100_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
# include "py.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
// Just like the above, except we decrement p's reference count instead of returning it.
|
||||
void expect_and_absorb_non_null(PyObject* p);
|
||||
|
||||
// Calling Python from C++
|
||||
template <class R>
|
||||
struct Callback
|
||||
{
|
||||
static R call_method(PyObject* self, const char* name)
|
||||
{ return from_python(expect_non_null(PyEval_CallMethod(self, const_cast<char*>(name), const_cast<char*>("()"))), Type<R>()); }
|
||||
|
||||
template <class A1>
|
||||
static R call_method(PyObject* self, const char* name, const A1& a1)
|
||||
{ return from_python(expect_non_null(PyEval_CallMethod(self, const_cast<char*>(name), const_cast<char*>("(N)"), to_python(a1))), Type<R>()); }
|
||||
|
||||
template <class A1, class A2>
|
||||
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2)
|
||||
{ return from_python(expect_non_null(PyEval_CallMethod(self, const_cast<char*>(name), const_cast<char*>("(NN)"), to_python(a1), to_python(a2))), 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)
|
||||
{ return from_python(expect_non_null(PyEval_CallMethod(self, const_cast<char*>(name), const_cast<char*>("(NNN)"), to_python(a1), to_python(a2), to_python(a3))), 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)
|
||||
{ return from_python(expect_non_null(PyEval_CallMethod(self, const_cast<char*>(name), const_cast<char*>("(NNNN)"), to_python(a1), to_python(a2), to_python(a3), to_python(a4))), 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)
|
||||
{ return from_python(expect_non_null(PyEval_CallMethod(self, const_cast<char*>(name), const_cast<char*>("(NNNNN)"), to_python(a1), to_python(a2), to_python(a3), to_python(a4), to_python(a5))), 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)
|
||||
{ expect_and_absorb_non_null(PyEval_CallMethod(self, const_cast<char*>(name), const_cast<char*>("()"))); }
|
||||
|
||||
template <class A1>
|
||||
static void call_method(PyObject* self, const char* name, const A1& a1)
|
||||
{ expect_and_absorb_non_null(PyEval_CallMethod(self, const_cast<char*>(name), const_cast<char*>("(N)"), to_python(a1))); }
|
||||
|
||||
template <class A1, class A2>
|
||||
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2)
|
||||
{ expect_and_absorb_non_null(PyEval_CallMethod(self, const_cast<char*>(name), const_cast<char*>("(NN)"), to_python(a1), to_python(a2))); }
|
||||
|
||||
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)
|
||||
{ expect_and_absorb_non_null(PyEval_CallMethod(self, const_cast<char*>(name), const_cast<char*>("(NNN)"), to_python(a1), to_python(a2), to_python(a3))); }
|
||||
|
||||
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)
|
||||
{ expect_and_absorb_non_null(PyEval_CallMethod(self, const_cast<char*>(name), const_cast<char*>("(NNNN)"), to_python(a1), to_python(a2), to_python(a3), to_python(a4))); }
|
||||
|
||||
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)
|
||||
{ expect_and_absorb_non_null(PyEval_CallMethod(self, const_cast<char*>(name), const_cast<char*>("(NNNNN)"), to_python(a1), to_python(a2), to_python(a3), to_python(a4), to_python(a5))); }
|
||||
|
||||
};
|
||||
|
||||
} // namespace py
|
||||
|
||||
#endif // CALLBACK_DWA_052100_H_
|
||||
507
caller.h
Normal file
507
caller.h
Normal file
@@ -0,0 +1,507 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
//
|
||||
// This file generated for 5-argument member functions and 5-argument free
|
||||
// functions by gen_caller.py
|
||||
|
||||
#ifndef CALLER_DWA05090_H_
|
||||
# define CALLER_DWA05090_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
# include "wrap_python.h"
|
||||
# include <boost/config.hpp>
|
||||
# include "signatures.h"
|
||||
# include "none.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
// Calling C++ from Python
|
||||
template <class R>
|
||||
struct Caller
|
||||
{
|
||||
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)());
|
||||
}
|
||||
|
||||
template <class T, class A1>
|
||||
static PyObject* call(R (T::*pmf)(A1), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &self, &a1))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
return to_python((target.*pmf)(from_python(a1, Type<A1>())));
|
||||
}
|
||||
|
||||
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>())));
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2, class A3>
|
||||
static PyObject* call(R (T::*pmf)(A1, A2, A3), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOO"), &self, &a1, &a2, &a3))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
return to_python((target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>())));
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2, class A3, class A4>
|
||||
static PyObject* call(R (T::*pmf)(A1, A2, A3, A4), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
PyObject* a4;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOO"), &self, &a1, &a2, &a3, &a4))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
return to_python((target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>())));
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2, class A3, class A4, class A5>
|
||||
static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
PyObject* a4;
|
||||
PyObject* a5;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOO"), &self, &a1, &a2, &a3, &a4, &a5))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
return to_python((target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>()),
|
||||
from_python(a5, Type<A5>())));
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
static PyObject* call(R (T::*pmf)() const, 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)());
|
||||
}
|
||||
|
||||
template <class T, class A1>
|
||||
static PyObject* call(R (T::*pmf)(A1) const, PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &self, &a1))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
return to_python((target.*pmf)(from_python(a1, Type<A1>())));
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2>
|
||||
static PyObject* call(R (T::*pmf)(A1, A2) const, PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
if (!PyArg_ParseTuple(args, const_cast<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>())));
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2, class A3>
|
||||
static PyObject* call(R (T::*pmf)(A1, A2, A3) const, PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOO"), &self, &a1, &a2, &a3))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
return to_python((target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>())));
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2, class A3, class A4>
|
||||
static PyObject* call(R (T::*pmf)(A1, A2, A3, A4) const, PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
PyObject* a4;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOO"), &self, &a1, &a2, &a3, &a4))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
return to_python((target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>())));
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2, class A3, class A4, class A5>
|
||||
static PyObject* call(R (T::*pmf)(A1, A2, A3, A4, A5) const, PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
PyObject* a4;
|
||||
PyObject* a5;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOO"), &self, &a1, &a2, &a3, &a4, &a5))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
return to_python((target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>()),
|
||||
from_python(a5, Type<A5>())));
|
||||
}
|
||||
|
||||
// Free functions
|
||||
static PyObject* call(R (*f)(), PyObject* args, PyObject* /* keywords */ ) {
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("")))
|
||||
return 0;
|
||||
return to_python(f());
|
||||
}
|
||||
|
||||
template <class A1>
|
||||
static PyObject* call(R (*f)(A1), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* a1;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("O"), &a1))
|
||||
return 0;
|
||||
return to_python(f(from_python(a1, Type<A1>())));
|
||||
}
|
||||
|
||||
template <class A1, class A2>
|
||||
static PyObject* call(R (*f)(A1, A2), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &a1, &a2))
|
||||
return 0;
|
||||
return to_python(f(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>())));
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3>
|
||||
static PyObject* call(R (*f)(A1, A2, A3), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOO"), &a1, &a2, &a3))
|
||||
return 0;
|
||||
return to_python(f(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>())));
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3, class A4>
|
||||
static PyObject* call(R (*f)(A1, A2, A3, A4), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
PyObject* a4;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOO"), &a1, &a2, &a3, &a4))
|
||||
return 0;
|
||||
return to_python(f(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>())));
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3, class A4, class A5>
|
||||
static PyObject* call(R (*f)(A1, A2, A3, A4, A5), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
PyObject* a4;
|
||||
PyObject* a5;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOO"), &a1, &a2, &a3, &a4, &a5))
|
||||
return 0;
|
||||
return to_python(f(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>()),
|
||||
from_python(a5, Type<A5>())));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Caller<void>
|
||||
{
|
||||
template <class T>
|
||||
static PyObject* call(void (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&>());
|
||||
(target.*pmf)();
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class T, class A1>
|
||||
static PyObject* call(void (T::*pmf)(A1), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &self, &a1))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
(target.*pmf)(from_python(a1, Type<A1>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2>
|
||||
static PyObject* call(void (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&>());
|
||||
(target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2, class A3>
|
||||
static PyObject* call(void (T::*pmf)(A1, A2, A3), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOO"), &self, &a1, &a2, &a3))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
(target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2, class A3, class A4>
|
||||
static PyObject* call(void (T::*pmf)(A1, A2, A3, A4), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
PyObject* a4;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOO"), &self, &a1, &a2, &a3, &a4))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
(target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2, class A3, class A4, class A5>
|
||||
static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
PyObject* a4;
|
||||
PyObject* a5;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOO"), &self, &a1, &a2, &a3, &a4, &a5))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
(target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>()),
|
||||
from_python(a5, Type<A5>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
static PyObject* call(void (T::*pmf)() const, PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("O"), &self))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
(target.*pmf)();
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class T, class A1>
|
||||
static PyObject* call(void (T::*pmf)(A1) const, PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &self, &a1))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
(target.*pmf)(from_python(a1, Type<A1>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2>
|
||||
static PyObject* call(void (T::*pmf)(A1, A2) const, PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOO"), &self, &a1, &a2))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
(target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()));
|
||||
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&>());
|
||||
(target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2, class A3, class A4>
|
||||
static PyObject* call(void (T::*pmf)(A1, A2, A3, A4) const, PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
PyObject* a4;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOO"), &self, &a1, &a2, &a3, &a4))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
(target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class T, class A1, class A2, class A3, class A4, class A5>
|
||||
static PyObject* call(void (T::*pmf)(A1, A2, A3, A4, A5) const, PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
PyObject* a4;
|
||||
PyObject* a5;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOOO"), &self, &a1, &a2, &a3, &a4, &a5))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
(target.*pmf)(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>()),
|
||||
from_python(a5, Type<A5>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
|
||||
// Free functions
|
||||
static PyObject* call(void (*f)(), PyObject* args, PyObject* /* keywords */ ) {
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("")))
|
||||
return 0;
|
||||
f();
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class A1>
|
||||
static PyObject* call(void (*f)(A1), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* a1;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("O"), &a1))
|
||||
return 0;
|
||||
f(from_python(a1, Type<A1>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class A1, class A2>
|
||||
static PyObject* call(void (*f)(A1, A2), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &a1, &a2))
|
||||
return 0;
|
||||
f(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3>
|
||||
static PyObject* call(void (*f)(A1, A2, A3), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOO"), &a1, &a2, &a3))
|
||||
return 0;
|
||||
f(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3, class A4>
|
||||
static PyObject* call(void (*f)(A1, A2, A3, A4), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
PyObject* a4;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOO"), &a1, &a2, &a3, &a4))
|
||||
return 0;
|
||||
f(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3, class A4, class A5>
|
||||
static PyObject* call(void (*f)(A1, A2, A3, A4, A5), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
PyObject* a4;
|
||||
PyObject* a5;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOOO"), &a1, &a2, &a3, &a4, &a5))
|
||||
return 0;
|
||||
f(from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>()),
|
||||
from_python(a5, Type<A5>()));
|
||||
return none();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
79
cast.h
Normal file
79
cast.h
Normal file
@@ -0,0 +1,79 @@
|
||||
// (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 "wrap_python.h"
|
||||
# include <boost/operators.hpp>
|
||||
|
||||
namespace py {
|
||||
|
||||
// The default way of converting a PyObject* or PyTypeObject* to a T*
|
||||
template <class T>
|
||||
struct DowncastTraits
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// 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(DowncastTraits<T>::cast(as_base_object((T*)0, p)))
|
||||
{}
|
||||
|
||||
Downcast(const PyObject* p)
|
||||
: m_p(DowncastTraits<T>::cast(as_base_object((const T*)0, p)))
|
||||
{}
|
||||
|
||||
Downcast(PyTypeObject* p)
|
||||
: m_p(DowncastTraits<T>::cast(p))
|
||||
{}
|
||||
|
||||
Downcast(const PyTypeObject* p)
|
||||
: m_p(DowncastTraits<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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CAST_DWA052500_H_
|
||||
87
class_wrapper.h
Normal file
87
class_wrapper.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#ifndef CLASS_WRAPPER_DWA101000_H_
|
||||
# define CLASS_WRAPPER_DWA101000_H_
|
||||
|
||||
#include "extclass.h"
|
||||
#include "module.h"
|
||||
#include "py.h"
|
||||
#include "cast.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
namespace detail {
|
||||
struct EmptyBase {};
|
||||
}
|
||||
|
||||
// Syntactic sugar to make wrapping classes more convenient
|
||||
template <class T, class U = HeldInstance<T> >
|
||||
class ClassWrapper
|
||||
: PyExtensionClassConverters<T, U> // Works around MSVC6.x/GCC2.95.2 bug described below
|
||||
{
|
||||
public:
|
||||
ClassWrapper(Module& module, const char* name)
|
||||
: m_class(new ExtensionClass<T, U>(name))
|
||||
#if 0 // def PY_MSVC6_OR_EARLIER
|
||||
, m_msvc_hack(name)
|
||||
#endif
|
||||
{
|
||||
module.add(Ptr(as_object(m_class.get()), Ptr::new_ref), name);
|
||||
}
|
||||
|
||||
// define constructors
|
||||
template <class A1, class A2, class A3, class A4, class A5>
|
||||
void def(Constructor<A1, A2, A3, A4, A5> signature)
|
||||
{ m_class->def(signature); }
|
||||
|
||||
// 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>
|
||||
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 instance
|
||||
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 instance
|
||||
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 instance 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 instance 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); }
|
||||
private:
|
||||
PyPtr<ExtensionClass<T, U> > m_class;
|
||||
#if 0 // def PY_MSVC6_OR_EARLIER
|
||||
PyExtensionClassConverters<T, U> m_msvc_hack;
|
||||
#endif
|
||||
};
|
||||
|
||||
// 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.
|
||||
|
||||
}
|
||||
|
||||
#endif // CLASS_WRAPPER_DWA101000_H_
|
||||
4
demo.bdf
Normal file
4
demo.bdf
Normal file
@@ -0,0 +1,4 @@
|
||||
TargetName=demo
|
||||
TargetType=dll
|
||||
SourceFiles=extclass_demo.cpp
|
||||
Libs=py_cpp python utils
|
||||
4
demo_d.bdf
Normal file
4
demo_d.bdf
Normal file
@@ -0,0 +1,4 @@
|
||||
TargetName=demo_d
|
||||
TargetType=dll
|
||||
SourceFiles=extclass_demo_d.cpp
|
||||
Libs=py_cpp_d python_d utils
|
||||
1112
doctest.py
Normal file
1112
doctest.py
Normal file
File diff suppressed because it is too large
Load Diff
708
doxyfile
Normal file
708
doxyfile
Normal file
@@ -0,0 +1,708 @@
|
||||
# Doxyfile 1.2.2
|
||||
|
||||
# This file describes the settings to be used by doxygen for a project
|
||||
#
|
||||
# All text after a hash (#) is considered a comment and will be ignored
|
||||
# The format is:
|
||||
# TAG = value [value, ...]
|
||||
# For lists items can also be appended using:
|
||||
# TAG += value [value, ...]
|
||||
# Values that contain spaces should be placed between quotes (" ")
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# General configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
|
||||
# by quotes) that should identify the project.
|
||||
|
||||
PROJECT_NAME = py_cpp
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
|
||||
# This could be handy for archiving the generated documentation or
|
||||
# if some version control system is used.
|
||||
|
||||
PROJECT_NUMBER = 0.9
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# base path where the generated documentation will be put.
|
||||
# If a relative path is entered, it will be relative to the location
|
||||
# where doxygen was started. If left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = ./docs
|
||||
|
||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
# information to generate all constant output in the proper language.
|
||||
# The default language is English, other supported languages are:
|
||||
# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese,
|
||||
# Korean, Hungarian, Spanish, Romanian, Russian, Croatian, Polish, and
|
||||
# Portuguese.
|
||||
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
|
||||
# documentation are documented, even if no documentation was available.
|
||||
# Private class members and static file members will be hidden unless
|
||||
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
|
||||
|
||||
EXTRACT_ALL = YES
|
||||
|
||||
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
|
||||
# will be included in the documentation.
|
||||
|
||||
EXTRACT_PRIVATE = YES
|
||||
|
||||
# If the EXTRACT_STATIC tag is set to YES all static members of a file
|
||||
# will be included in the documentation.
|
||||
|
||||
EXTRACT_STATIC = NO
|
||||
|
||||
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
|
||||
# undocumented members of documented classes, files or namespaces.
|
||||
# If set to NO (the default) these members will be included in the
|
||||
# various overviews, but no documentation section is generated.
|
||||
# This option has no effect if EXTRACT_ALL is enabled.
|
||||
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
|
||||
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
|
||||
# undocumented classes that are normally visible in the class hierarchy.
|
||||
# If set to NO (the default) these class will be included in the various
|
||||
# overviews. This option has no effect if EXTRACT_ALL is enabled.
|
||||
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
|
||||
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
|
||||
# include brief member descriptions after the members that are listed in
|
||||
# the file and class documentation (similar to JavaDoc).
|
||||
# Set to NO to disable this.
|
||||
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
|
||||
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
|
||||
# the brief description of a member or function before the detailed description.
|
||||
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
|
||||
# brief descriptions will be completely suppressed.
|
||||
|
||||
REPEAT_BRIEF = YES
|
||||
|
||||
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
|
||||
# Doxygen will generate a detailed section even if there is only a brief
|
||||
# description.
|
||||
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
|
||||
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
|
||||
# path before files name in the file list and in the header files. If set
|
||||
# to NO the shortest path that makes the file name unique will be used.
|
||||
|
||||
FULL_PATH_NAMES = NO
|
||||
|
||||
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
|
||||
# can be used to strip a user defined part of the path. Stripping is
|
||||
# only done if one of the specified strings matches the left-hand part of
|
||||
# the path. It is allowed to use relative paths in the argument list.
|
||||
|
||||
STRIP_FROM_PATH =
|
||||
|
||||
# The INTERNAL_DOCS tag determines if documentation
|
||||
# that is typed after a \internal command is included. If the tag is set
|
||||
# to NO (the default) then the documentation will be excluded.
|
||||
# Set it to YES to include the internal documentation.
|
||||
|
||||
INTERNAL_DOCS = NO
|
||||
|
||||
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
|
||||
# generate a class diagram (in Html and LaTeX) for classes with base or
|
||||
# super classes. Setting the tag to NO turns the diagrams off.
|
||||
|
||||
CLASS_DIAGRAMS = YES
|
||||
|
||||
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
|
||||
# be generated. Documented entities will be cross-referenced with these sources.
|
||||
|
||||
SOURCE_BROWSER = NO
|
||||
|
||||
# Setting the INLINE_SOURCES tag to YES will include the body
|
||||
# of functions and classes directly in the documentation.
|
||||
|
||||
INLINE_SOURCES = NO
|
||||
|
||||
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
|
||||
# doxygen to hide any special comment blocks from generated source code
|
||||
# fragments. Normal C and C++ comments will always remain visible.
|
||||
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
|
||||
# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
|
||||
# file names in lower case letters. If set to YES upper case letters are also
|
||||
# allowed. This is useful if you have classes or files whose names only differ
|
||||
# in case and if your file system supports case sensitive file names. Windows
|
||||
# users are adviced to set this option to NO.
|
||||
|
||||
CASE_SENSE_NAMES = NO
|
||||
|
||||
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
|
||||
# will show members with their full class and namespace scopes in the
|
||||
# documentation. If set to YES the scope will be hidden.
|
||||
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
|
||||
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
|
||||
# will generate a verbatim copy of the header file for each class for
|
||||
# which an include is specified. Set to NO to disable this.
|
||||
|
||||
VERBATIM_HEADERS = YES
|
||||
|
||||
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
|
||||
# will put list of the files that are included by a file in the documentation
|
||||
# of that file.
|
||||
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
|
||||
# If the JAVADOC_AUTOBRIEF tag is set to YES (the default) then Doxygen
|
||||
# will interpret the first line (until the first dot) of a JavaDoc-style
|
||||
# comment as the brief description. If set to NO, the Javadoc-style will
|
||||
# behave just like the Qt-style comments.
|
||||
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
|
||||
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
|
||||
# member inherits the documentation from any documented member that it
|
||||
# reimplements.
|
||||
|
||||
INHERIT_DOCS = YES
|
||||
|
||||
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
|
||||
# is inserted in the documentation for inline members.
|
||||
|
||||
INLINE_INFO = YES
|
||||
|
||||
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
|
||||
# will sort the (detailed) documentation of file and class members
|
||||
# alphabetically by member name. If set to NO the members will appear in
|
||||
# declaration order.
|
||||
|
||||
SORT_MEMBER_DOCS = YES
|
||||
|
||||
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
|
||||
# tag is set to YES, then doxygen will reuse the documentation of the first
|
||||
# member in the group (if any) for the other members of the group. By default
|
||||
# all members of a group must be documented explicitly.
|
||||
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
|
||||
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
|
||||
# Doxygen uses this value to replace tabs by spaces in code fragments.
|
||||
|
||||
TAB_SIZE = 4
|
||||
|
||||
# The ENABLE_SECTIONS tag can be used to enable conditional
|
||||
# documentation sections, marked by \if sectionname ... \endif.
|
||||
|
||||
ENABLED_SECTIONS =
|
||||
|
||||
# The GENERATE_TODOLIST tag can be used to enable (YES) or
|
||||
# disable (NO) the todo list. This list is created by putting \todo
|
||||
# commands in the documentation.
|
||||
|
||||
GENERATE_TODOLIST = YES
|
||||
|
||||
# The GENERATE_TESTLIST tag can be used to enable (YES) or
|
||||
# disable (NO) the test list. This list is created by putting \test
|
||||
# commands in the documentation.
|
||||
|
||||
GENERATE_TESTLIST = YES
|
||||
|
||||
# This tag can be used to specify a number of aliases that acts
|
||||
# as commands in the documentation. An alias has the form "name=value".
|
||||
# For example adding "sideeffect=\par Side Effects:\n" will allow you to
|
||||
# put the command \sideeffect (or @sideeffect) in the documentation, which
|
||||
# will result in a user defined paragraph with heading "Side Effects:".
|
||||
# You can put \n's in the value part of an alias to insert newlines.
|
||||
|
||||
ALIASES =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The QUIET tag can be used to turn on/off the messages that are generated
|
||||
# by doxygen. Possible values are YES and NO. If left blank NO is used.
|
||||
|
||||
QUIET = NO
|
||||
|
||||
# The WARNINGS tag can be used to turn on/off the warning messages that are
|
||||
# generated by doxygen. Possible values are YES and NO. If left blank
|
||||
# NO is used.
|
||||
|
||||
WARNINGS = YES
|
||||
|
||||
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
|
||||
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
|
||||
# automatically be disabled.
|
||||
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
|
||||
# The WARN_FORMAT tag determines the format of the warning messages that
|
||||
# doxygen can produce. The string should contain the $file, $line, and $text
|
||||
# tags, which will be replaced by the file and line number from which the
|
||||
# warning originated and the warning text.
|
||||
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The INPUT tag can be used to specify the files and/or directories that contain
|
||||
# documented source files. You may enter file names like "myfile.cpp" or
|
||||
# directories like "/usr/src/myproject". Separate the files or directories
|
||||
# with spaces.
|
||||
|
||||
INPUT = c:/prj/manhattan/py_cpp
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
# and *.h) to filter out the source-files in the directories. If left
|
||||
# blank all files are included.
|
||||
|
||||
FILE_PATTERNS = *.cpp *.h *.py *.hpp
|
||||
|
||||
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
|
||||
# should be searched for input files as well. Possible values are YES and NO.
|
||||
# If left blank NO is used.
|
||||
|
||||
RECURSIVE = NO
|
||||
|
||||
# The EXCLUDE tag can be used to specify files and/or directories that should
|
||||
# excluded from the INPUT source files. This way you can easily exclude a
|
||||
# subdirectory from a directory tree whose root is specified with the INPUT tag.
|
||||
|
||||
EXCLUDE =
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
|
||||
# certain files from those directories.
|
||||
|
||||
EXCLUDE_PATTERNS =
|
||||
|
||||
# The EXAMPLE_PATH tag can be used to specify one or more files or
|
||||
# directories that contain example code fragments that are included (see
|
||||
# the \include command).
|
||||
|
||||
EXAMPLE_PATH = example1.cpp test_extclass.py extclass_demo.cpp extclass_demo.h
|
||||
|
||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
# and *.h) to filter out the source-files in the directories. If left
|
||||
# blank all files are included.
|
||||
|
||||
EXAMPLE_PATTERNS =
|
||||
|
||||
# The IMAGE_PATH tag can be used to specify one or more files or
|
||||
# directories that contain image that are included in the documentation (see
|
||||
# the \image command).
|
||||
|
||||
IMAGE_PATH =
|
||||
|
||||
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
||||
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||
# by executing (via popen()) the command <filter> <input-file>, where <filter>
|
||||
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
|
||||
# input file. Doxygen will then use the output that the filter program writes
|
||||
# to standard output.
|
||||
|
||||
INPUT_FILTER =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
|
||||
# of all compounds will be generated. Enable this if the project
|
||||
# contains a lot of classes, structs, unions or interfaces.
|
||||
|
||||
ALPHABETICAL_INDEX = NO
|
||||
|
||||
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
|
||||
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
|
||||
# in which this list will be split (can be a number in the range [1..20])
|
||||
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
|
||||
# In case all classes in a project start with a common prefix, all
|
||||
# classes will be put under the same header in the alphabetical index.
|
||||
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
|
||||
# should be ignored while generating the index headers.
|
||||
|
||||
IGNORE_PREFIX =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
|
||||
# generate HTML output.
|
||||
|
||||
GENERATE_HTML = YES
|
||||
|
||||
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `html' will be used as the default path.
|
||||
|
||||
HTML_OUTPUT = html
|
||||
|
||||
# The HTML_HEADER tag can be used to specify a personal HTML header for
|
||||
# each generated HTML page. If it is left blank doxygen will generate a
|
||||
# standard header.
|
||||
|
||||
HTML_HEADER =
|
||||
|
||||
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
|
||||
# each generated HTML page. If it is left blank doxygen will generate a
|
||||
# standard footer.
|
||||
|
||||
HTML_FOOTER =
|
||||
|
||||
# The HTML_STYLESHEET tag can be used to specify a user defined cascading
|
||||
# style sheet that is used by each HTML page. It can be used to
|
||||
# fine-tune the look of the HTML output. If the tag is left blank doxygen
|
||||
# will generate a default style sheet
|
||||
|
||||
HTML_STYLESHEET =
|
||||
|
||||
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
|
||||
# files or namespaces will be aligned in HTML using tables. If set to
|
||||
# NO a bullet list will be used.
|
||||
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
|
||||
# will be generated that can be used as input for tools like the
|
||||
# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
|
||||
# of the generated HTML documentation.
|
||||
|
||||
GENERATE_HTMLHELP = NO
|
||||
|
||||
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
|
||||
# top of each HTML page. The value NO (the default) enables the index and
|
||||
# the value YES disables it.
|
||||
|
||||
DISABLE_INDEX = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
|
||||
# generate Latex output.
|
||||
|
||||
GENERATE_LATEX = NO
|
||||
|
||||
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `latex' will be used as the default path.
|
||||
|
||||
LATEX_OUTPUT = latex
|
||||
|
||||
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
|
||||
# LaTeX documents. This may be useful for small projects and may help to
|
||||
# save some trees in general.
|
||||
|
||||
COMPACT_LATEX = NO
|
||||
|
||||
# The PAPER_TYPE tag can be used to set the paper type that is used
|
||||
# by the printer. Possible values are: a4, a4wide, letter, legal and
|
||||
# executive. If left blank a4wide will be used.
|
||||
|
||||
PAPER_TYPE = a4wide
|
||||
|
||||
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
|
||||
# packages that should be included in the LaTeX output.
|
||||
|
||||
EXTRA_PACKAGES =
|
||||
|
||||
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
|
||||
# the generated latex document. The header should contain everything until
|
||||
# the first chapter. If it is left blank doxygen will generate a
|
||||
# standard header. Notice: only use this tag if you know what you are doing!
|
||||
|
||||
LATEX_HEADER =
|
||||
|
||||
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
|
||||
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
|
||||
# contain links (just like the HTML output) instead of page references
|
||||
# This makes the output suitable for online browsing using a pdf viewer.
|
||||
|
||||
PDF_HYPERLINKS = NO
|
||||
|
||||
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
|
||||
# plain latex in the generated Makefile. Set this option to YES to get a
|
||||
# higher quality PDF documentation.
|
||||
|
||||
USE_PDFLATEX = NO
|
||||
|
||||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
|
||||
# command to the generated LaTeX files. This will instruct LaTeX to keep
|
||||
# running if errors occur, instead of asking the user for help.
|
||||
# This option is also used when generating formulas in HTML.
|
||||
|
||||
LATEX_BATCHMODE = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
|
||||
# The RTF output is optimised for Word 97 and may not look very pretty with
|
||||
# other RTF readers or editors.
|
||||
|
||||
GENERATE_RTF = YES
|
||||
|
||||
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `rtf' will be used as the default path.
|
||||
|
||||
RTF_OUTPUT = rtf
|
||||
|
||||
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
|
||||
# RTF documents. This may be useful for small projects and may help to
|
||||
# save some trees in general.
|
||||
|
||||
COMPACT_RTF = NO
|
||||
|
||||
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
|
||||
# will contain hyperlink fields. The RTF file will
|
||||
# contain links (just like the HTML output) instead of page references.
|
||||
# This makes the output suitable for online browsing using a WORD or other.
|
||||
# programs which support those fields.
|
||||
# Note: wordpad (write) and others do not support links.
|
||||
|
||||
RTF_HYPERLINKS = NO
|
||||
|
||||
# Load stylesheet definitions from file. Syntax is similar to doxygen's
|
||||
# config file, i.e. a series of assigments. You only have to provide
|
||||
# replacements, missing definitions are set to their default value.
|
||||
|
||||
RTF_STYLESHEET_FILE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
|
||||
# generate man pages
|
||||
|
||||
GENERATE_MAN = NO
|
||||
|
||||
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `man' will be used as the default path.
|
||||
|
||||
MAN_OUTPUT = man
|
||||
|
||||
# The MAN_EXTENSION tag determines the extension that is added to
|
||||
# the generated man pages (default is the subroutine's section .3)
|
||||
|
||||
MAN_EXTENSION = .3
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_XML tag is set to YES Doxygen will
|
||||
# generate an XML file that captures the structure of
|
||||
# the code including all documentation. Warning: This feature
|
||||
# is still experimental and very incomplete.
|
||||
|
||||
GENERATE_XML = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
|
||||
# evaluate all C-preprocessor directives found in the sources and include
|
||||
# files.
|
||||
|
||||
ENABLE_PREPROCESSING = YES
|
||||
|
||||
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
|
||||
# names in the source code. If set to NO (the default) only conditional
|
||||
# compilation will be performed. Macro expansion can be done in a controlled
|
||||
# way by setting EXPAND_ONLY_PREDEF to YES.
|
||||
|
||||
MACRO_EXPANSION = NO
|
||||
|
||||
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
|
||||
# then the macro expansion is limited to the macros specified with the
|
||||
# PREDEFINED and EXPAND_AS_PREDEFINED tags.
|
||||
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
|
||||
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
|
||||
# in the INCLUDE_PATH (see below) will be search if a #include is found.
|
||||
|
||||
SEARCH_INCLUDES = YES
|
||||
|
||||
# The INCLUDE_PATH tag can be used to specify one or more directories that
|
||||
# contain include files that are not input files but should be processed by
|
||||
# the preprocessor.
|
||||
|
||||
INCLUDE_PATH =
|
||||
|
||||
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
|
||||
# patterns (like *.h and *.hpp) to filter out the header-files in the
|
||||
# directories. If left blank, the patterns specified with FILE_PATTERNS will
|
||||
# be used.
|
||||
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
|
||||
# The PREDEFINED tag can be used to specify one or more macro names that
|
||||
# are defined before the preprocessor is started (similar to the -D option of
|
||||
# gcc). The argument of the tag is a list of macros of the form: name
|
||||
# or name=definition (no spaces). If the definition and the = are
|
||||
# omitted =1 is assumed.
|
||||
|
||||
PREDEFINED =
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
|
||||
# this tag can be used to specify a list of macro names that should be expanded.
|
||||
# The macro definition that is found in the sources will be used.
|
||||
# Use the PREDEFINED tag if you want to use a different macro definition.
|
||||
|
||||
EXPAND_AS_DEFINED =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The TAGFILES tag can be used to specify one or more tagfiles.
|
||||
|
||||
TAGFILES =
|
||||
|
||||
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
|
||||
# a tag file that is based on the input files it reads.
|
||||
|
||||
GENERATE_TAGFILE =
|
||||
|
||||
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
|
||||
# in the class index. If set to NO only the inherited external classes
|
||||
# will be listed.
|
||||
|
||||
ALLEXTERNALS = NO
|
||||
|
||||
# The PERL_PATH should be the absolute path and name of the perl script
|
||||
# interpreter (i.e. the result of `which perl').
|
||||
|
||||
PERL_PATH = c:\dragon\ntbin\perl.exe
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
||||
# available from the path. This tool is part of Graphviz, a graph visualization
|
||||
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
|
||||
# have no effect if this option is set to NO (the default)
|
||||
|
||||
HAVE_DOT = NO
|
||||
|
||||
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
||||
# will generate a graph for each documented class showing the direct and
|
||||
# indirect inheritance relations. Setting this tag to YES will force the
|
||||
# the CLASS_DIAGRAMS tag to NO.
|
||||
|
||||
CLASS_GRAPH = YES
|
||||
|
||||
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
||||
# will generate a graph for each documented class showing the direct and
|
||||
# indirect implementation dependencies (inheritance, containment, and
|
||||
# class references variables) of the class with other documented classes.
|
||||
|
||||
COLLABORATION_GRAPH = YES
|
||||
|
||||
# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to
|
||||
# YES then doxygen will generate a graph for each documented file showing
|
||||
# the direct and indirect include dependencies of the file with other
|
||||
# documented files.
|
||||
|
||||
INCLUDE_GRAPH = YES
|
||||
|
||||
# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to
|
||||
# YES then doxygen will generate a graph for each documented header file showing
|
||||
# the documented files that directly or indirectly include this file
|
||||
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
|
||||
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
|
||||
# will graphical hierarchy of all classes instead of a textual one.
|
||||
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
|
||||
# The tag DOT_PATH can be used to specify the path where the dot tool can be
|
||||
# found. If left blank, it is assumed the dot tool can be found on the path.
|
||||
|
||||
DOT_PATH =
|
||||
|
||||
# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
|
||||
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
|
||||
# this value, doxygen will try to truncate the graph, so that it fits within
|
||||
# the specified constraint. Beware that most browsers cannot cope with very
|
||||
# large images.
|
||||
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
|
||||
# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
|
||||
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
|
||||
# this value, doxygen will try to truncate the graph, so that it fits within
|
||||
# the specified constraint. Beware that most browsers cannot cope with very
|
||||
# large images.
|
||||
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The SEARCHENGINE tag specifies whether or not a search engine should be
|
||||
# used. If set to NO the values of all tags below this one will be ignored.
|
||||
|
||||
SEARCHENGINE = NO
|
||||
|
||||
# The CGI_NAME tag should be the name of the CGI script that
|
||||
# starts the search engine (doxysearch) with the correct parameters.
|
||||
# A script with this name will be generated by doxygen.
|
||||
|
||||
CGI_NAME = search.cgi
|
||||
|
||||
# The CGI_URL tag should be the absolute URL to the directory where the
|
||||
# cgi binaries are located. See the documentation of your http daemon for
|
||||
# details.
|
||||
|
||||
CGI_URL =
|
||||
|
||||
# The DOC_URL tag should be the absolute URL to the directory where the
|
||||
# documentation is located. If left blank the absolute path to the
|
||||
# documentation, with file:// prepended to it, will be used.
|
||||
|
||||
DOC_URL =
|
||||
|
||||
# The DOC_ABSPATH tag should be the absolute path to the directory where the
|
||||
# documentation is located. If left blank the directory on the local machine
|
||||
# will be used.
|
||||
|
||||
DOC_ABSPATH =
|
||||
|
||||
# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
|
||||
# is installed.
|
||||
|
||||
BIN_ABSPATH = C:\tools\doxygen-1.2.2\bin
|
||||
|
||||
# The EXT_DOC_PATHS tag can be used to specify one or more paths to
|
||||
# documentation generated for other projects. This allows doxysearch to search
|
||||
# the documentation for these projects as well.
|
||||
|
||||
EXT_DOC_PATHS =
|
||||
30
errors.h
Normal file
30
errors.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#ifndef ERRORS_DWA052500_H_
|
||||
# define ERRORS_DWA052500_H_
|
||||
|
||||
namespace py {
|
||||
|
||||
struct ErrorAlreadySet {};
|
||||
struct ArgumentError : ErrorAlreadySet {};
|
||||
|
||||
// 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 ErrorAlreadySet();
|
||||
return x;
|
||||
}
|
||||
|
||||
} // namespace py
|
||||
|
||||
#endif // ERRORS_DWA052500_H_
|
||||
4
example1.bdf
Normal file
4
example1.bdf
Normal file
@@ -0,0 +1,4 @@
|
||||
TargetName=example1
|
||||
TargetType=dll
|
||||
SourceFiles=example1.cpp
|
||||
Libs=py_cpp python utils
|
||||
54
example1.cpp
Normal file
54
example1.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#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 <py_cpp/class_wrapper.h>
|
||||
|
||||
// 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
|
||||
py::Module hello("hello");
|
||||
|
||||
// Create the Python type object for our extension class
|
||||
py::ClassWrapper<hello::world> world_class(hello, "world");
|
||||
|
||||
// Add the __init__ function
|
||||
world_class.def(py::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(...)
|
||||
{
|
||||
py::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
|
||||
343
extclass.cpp
Normal file
343
extclass.cpp
Normal file
@@ -0,0 +1,343 @@
|
||||
// (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 "extclass.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace py {
|
||||
|
||||
ExtensionInstance* get_extension_instance(PyObject* p)
|
||||
{
|
||||
// The object's type will just be some Class<ExtensionInstance> object,
|
||||
// but if its meta-type is right, then it is an ExtensionInstance.
|
||||
if (p->ob_type->ob_type != extension_meta_class())
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
||||
throw py::ArgumentError();
|
||||
}
|
||||
return static_cast<ExtensionInstance*>(p);
|
||||
}
|
||||
|
||||
void
|
||||
ExtensionInstance::add_implementation(std::auto_ptr<InstanceHolderBase> holder)
|
||||
{
|
||||
for (WrappedObjects::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 ErrorAlreadySet();
|
||||
}
|
||||
}
|
||||
m_wrapped_objects.push_back(holder.release());
|
||||
}
|
||||
|
||||
ExtensionInstance::ExtensionInstance(PyTypeObject* class_)
|
||||
: Instance(class_)
|
||||
{
|
||||
}
|
||||
|
||||
ExtensionInstance::~ExtensionInstance()
|
||||
{
|
||||
for (WrappedObjects::const_iterator p = m_wrapped_objects.begin(),
|
||||
finish = m_wrapped_objects.end();
|
||||
p != finish; ++p)
|
||||
{
|
||||
delete *p;
|
||||
}
|
||||
}
|
||||
|
||||
MetaClass<ExtensionInstance>* extension_meta_class()
|
||||
{
|
||||
static MetaClass<ExtensionInstance> result;
|
||||
return &result;
|
||||
}
|
||||
|
||||
typedef Class<ExtensionInstance> ExtClass;
|
||||
|
||||
bool is_subclass(const ExtClass* 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 ExtClass* base_class = Downcast<const ExtClass>(base);
|
||||
if (is_subclass(base_class, possible_base))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true iff instance is an instance of target_class
|
||||
bool is_instance(ExtensionInstance* instance,
|
||||
Class<ExtensionInstance>* target_class)
|
||||
{
|
||||
if (instance->ob_type == target_class)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
return is_subclass(
|
||||
Downcast<Class<ExtensionInstance> >(instance->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 = PY_CSTD_::strlen(format);
|
||||
std::size_t length1 = PY_CSTD_::strlen(s1);
|
||||
std::size_t length2 = PY_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 ArgumentError();
|
||||
else
|
||||
throw ErrorAlreadySet();
|
||||
}
|
||||
|
||||
// This is called when an attempt has been made to convert the given instance to
|
||||
// a C++ type for which it doesn't have any instance data. In that case, either
|
||||
// the instance was not derived from the target_class, or the appropriate
|
||||
// __init__ function wasn't called to initialize the instance data of the target class.
|
||||
void report_missing_instance_data(
|
||||
ExtensionInstance* instance, // The object being converted
|
||||
Class<ExtensionInstance>* 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(instance, target_class))
|
||||
{
|
||||
if (target_is_ptr)
|
||||
{
|
||||
two_string_error(PyExc_RuntimeError,
|
||||
"Object of extension class '%.*s' does not wrap <%.*s>.",
|
||||
instance->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 derived from '%.*s'.",
|
||||
instance->ob_type->tp_name, target_class->tp_name);
|
||||
}
|
||||
}
|
||||
|
||||
void report_missing_instance_data(
|
||||
ExtensionInstance* instance, // The object being converted
|
||||
Class<ExtensionInstance>* 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(instance, target_class, target_typeid, false);
|
||||
}
|
||||
|
||||
void report_missing_ptr_data(
|
||||
ExtensionInstance* instance, // The object being converted
|
||||
Class<ExtensionInstance>* 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(instance, 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 ErrorAlreadySet();
|
||||
}
|
||||
|
||||
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 ArgumentError();
|
||||
}
|
||||
|
||||
ReadOnlySetattrFunction::ReadOnlySetattrFunction(const char* name)
|
||||
: m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
PyObject* ReadOnlySetattrFunction::do_call(PyObject* /*args*/, PyObject* /*keywords*/) const
|
||||
{
|
||||
PyErr_SetObject(PyExc_AttributeError, ("'" + m_name + "' attribute is read-only").get());
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* ReadOnlySetattrFunction::description() const
|
||||
{
|
||||
return "uncallable";
|
||||
}
|
||||
|
||||
ExtensionClassBase::ExtensionClassBase(const char* name)
|
||||
: Class<ExtensionInstance>(
|
||||
extension_meta_class(), String(name), Tuple(), Dict())
|
||||
{
|
||||
}
|
||||
|
||||
void ExtensionClassBase::add_method(Function* method, const char* name)
|
||||
{
|
||||
add_method(PyPtr<Function>(method), name);
|
||||
}
|
||||
|
||||
void ExtensionClassBase::add_method(PyPtr<Function> method, const char* name)
|
||||
{
|
||||
// If we have created a special Python base class which wraps C++ classes
|
||||
// derived from T, the method should really be added there. Target will be
|
||||
// that Python class object.
|
||||
Class<ExtensionInstance>* target = (bases().size() == 0)
|
||||
? this
|
||||
: Downcast<Class<ExtensionInstance> >(bases()[0].get()).get();
|
||||
|
||||
// Add the attribute to the computed target
|
||||
Function::add_to_namespace(method, name, target->dict().get());
|
||||
|
||||
// If it is a special member function it should be enabled both here and there.
|
||||
enable_named_method(this, name);
|
||||
}
|
||||
|
||||
void ExtensionClassBase::add_default_method(Function* method, const char* name)
|
||||
{
|
||||
add_default_method(PyPtr<Function>(method), name);
|
||||
}
|
||||
|
||||
// A rather complicated thing is going on here in order to make a very specific
|
||||
// class of cases work. When wrapping the following C++:
|
||||
//
|
||||
// struct Base {
|
||||
// Base(); // will be constructed from Python
|
||||
// virtual int f() const // might be called from C++
|
||||
// { return 1; } // default implementation
|
||||
// };
|
||||
//
|
||||
// struct Derived : Base {
|
||||
// int f() const { return 0; } // overridden in C++
|
||||
// };
|
||||
//
|
||||
// boost::shared_ptr<Base> factory(bool selector) {
|
||||
// return boost::shared_ptr<Base>(selector ? new Base : new Derived);
|
||||
// }
|
||||
//
|
||||
// Normally we would use the same Python ExtensionClass object to represent both
|
||||
// Base and boost::shared_ptr<Base>, since they have essentially the same
|
||||
// operations (see the comment on InstanceHolder in extclass_pygen.h for
|
||||
// details). If there was no need to override Base::f() in Python, that would
|
||||
// work fine. In this case, since f() is virtual, the programmer must provide a
|
||||
// subclass of Base which calls back into Python:
|
||||
//
|
||||
// struct BaseCallback : Base {
|
||||
// BaseCallback(PyObject* self) : m_self(self) {}
|
||||
// int f() const { return py::Callback<int>::call_method(m_self, "f"); }
|
||||
// static int default_f(const Base* self) const { self->Base::f(); }
|
||||
// };
|
||||
//
|
||||
// default_f() is what gets registered under the name "f" in the "Base"
|
||||
// ExtensionClass' attribute dict. When C++ calls f() on a wrapped instance of
|
||||
// Base, we call back into Python to find the "f" attribute, which calls
|
||||
// default_f() (unless it has been overridden in Python) and in turn the default
|
||||
// implementation (Base::f()) is called.
|
||||
//
|
||||
// Now consider what happens when the Python programmer writes
|
||||
// >>> factory(0).f()
|
||||
//
|
||||
// The shared_ptr<Derived> which is created on the C++ side is converted by
|
||||
// to_python() into a Python instance of the "Base" ExtensionClass. Then Python
|
||||
// looks up the "f" attribute, and finds the wrapper for default_f(), which it
|
||||
// calls. That calls Base::f(), returning 1. What we really wanted was a call to
|
||||
// Derived::f(), returning 0.
|
||||
//
|
||||
// In this case we actually need a different Python ExtensionClass to represent
|
||||
// C++ subclasses of Base. When the first default method implementation is added
|
||||
// to an ExtensionClass, we "push" all of the non-default methods up into a
|
||||
// newly-created base class of the "Base" ExtensionClass, called
|
||||
// "Base_base". "Base's" attribute dict contains only default method
|
||||
// implementations.
|
||||
//
|
||||
// A Python call to factory() then results in an object of class "Base_base",
|
||||
// whose "f" method is bound to Base::f() - since this is a virtual function
|
||||
// pointer, the member function actually called is determined by the
|
||||
// most-derived class that implements f().
|
||||
//
|
||||
// A Python call to Base() results in an object of class "Base" wrapping a
|
||||
// BaseCallback object, whose "f" method is bound to BaseCallback::default_f()
|
||||
// ...which calls Base::f() explicitly.
|
||||
void ExtensionClassBase::add_default_method(PyPtr<Function> method, const char* name)
|
||||
{
|
||||
if (bases().size() == 0)
|
||||
{
|
||||
Class<ExtensionInstance>* new_base
|
||||
= new Class<ExtensionInstance>(
|
||||
extension_meta_class(), this->name() + String("_base"), Tuple(),
|
||||
dict());
|
||||
|
||||
add_base(Ptr(as_object(new_base)));
|
||||
|
||||
// We have transferred everything in our dict into the base class, so
|
||||
// clear our dict now. It will henceforth contain only default method
|
||||
// implementations.
|
||||
dict() = Dict();
|
||||
}
|
||||
Function::add_to_namespace(method, name, dict().get());
|
||||
}
|
||||
|
||||
void ExtensionClassBase::add_constructor_object(Function* init_function)
|
||||
{
|
||||
add_method(init_function, "__init__");
|
||||
}
|
||||
|
||||
void ExtensionClassBase::add_setter_method(Function* setter_, const char* name)
|
||||
{
|
||||
PyPtr<Function> setter(setter_);
|
||||
add_method(setter, (detail::setattr_string() + name + "__").c_str());
|
||||
}
|
||||
|
||||
void ExtensionClassBase::add_getter_method(Function* getter_, const char* name)
|
||||
{
|
||||
PyPtr<Function> getter(getter_);
|
||||
add_method(getter, (detail::getattr_string() + name + "__").c_str());
|
||||
}
|
||||
|
||||
} // namespace py
|
||||
439
extclass.h
Normal file
439
extclass.h
Normal file
@@ -0,0 +1,439 @@
|
||||
// (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 EXTENSION_CLASS_DWA052000_H_
|
||||
# define EXTENSION_CLASS_DWA052000_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
# include "subclass.h"
|
||||
# include <vector>
|
||||
# include "none.h"
|
||||
# include "objects.h"
|
||||
# include "functions.h"
|
||||
# include <memory>
|
||||
# include "init_function.h"
|
||||
# include <typeinfo>
|
||||
# include <boost/smart_ptr.hpp>
|
||||
|
||||
namespace py {
|
||||
|
||||
// forward declarations
|
||||
class ExtensionInstance;
|
||||
template <class T> class InstanceHolder;
|
||||
template <class T, class U> class InstanceValueHolder;
|
||||
template <class Ptr, class T> class InstancePtrHolder;
|
||||
|
||||
MetaClass<ExtensionInstance>* extension_meta_class();
|
||||
ExtensionInstance* get_extension_instance(PyObject* p);
|
||||
void report_missing_instance_data(ExtensionInstance*, Class<ExtensionInstance>*, const std::type_info&);
|
||||
void report_missing_ptr_data(ExtensionInstance*, Class<ExtensionInstance>*, 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, class U>
|
||||
struct ExtensionClassFromPython
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
T* check_non_null(T* p)
|
||||
{
|
||||
if (p == 0)
|
||||
report_released_smart_pointer(typeid(T));
|
||||
return p;
|
||||
}
|
||||
|
||||
template <class T> class HeldInstance;
|
||||
|
||||
class ExtensionClassBase : public Class<ExtensionInstance>
|
||||
{
|
||||
public:
|
||||
ExtensionClassBase(const char* name);
|
||||
protected:
|
||||
void add_method(PyPtr<Function> method, const char* name);
|
||||
void add_default_method(PyPtr<Function> method, const char* name);
|
||||
void add_method(Function* method, const char* name);
|
||||
void add_default_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 ClassRegistry
|
||||
{
|
||||
public:
|
||||
static Class<ExtensionInstance>* class_object()
|
||||
{ return static_class_object; }
|
||||
static void register_class(py::Class<py::ExtensionInstance>*);
|
||||
static void unregister_class(py::Class<py::ExtensionInstance>*);
|
||||
private:
|
||||
static py::Class<py::ExtensionInstance>* static_class_object;
|
||||
};
|
||||
|
||||
#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE // back to global namespace for this GCC bug
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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 = HeldInstance<T>.
|
||||
template <class T, class U = py::HeldInstance<T> >
|
||||
class PyExtensionClassConverters
|
||||
{
|
||||
public:
|
||||
#ifdef BOOST_MSVC
|
||||
// Convert return values of type T to python objects. What happens if T is
|
||||
// not copyable? Apparently there is no problem with g++ or MSVC unless this
|
||||
// is actually used. With a conforming compiler we will have a problem.
|
||||
friend PyObject* to_python(const T& x)
|
||||
{
|
||||
py::PyPtr<py::ExtensionInstance> result(create_instance(false));
|
||||
result->add_implementation(
|
||||
std::auto_ptr<py::InstanceHolderBase>(
|
||||
new py::InstanceValueHolder<T,U>(result.get(), x)));
|
||||
return result.release();
|
||||
}
|
||||
#else
|
||||
friend py::Type<U> py_holder_type(const T&)
|
||||
{ return py::Type<U>(); }
|
||||
#endif
|
||||
|
||||
PyExtensionClassConverters() {}
|
||||
|
||||
// Convert to T*
|
||||
friend T* from_python(PyObject* obj, py::Type<T*>)
|
||||
{
|
||||
// Downcast to an ExtensionInstance, then find the actual T
|
||||
py::ExtensionInstance* self = py::get_extension_instance(obj);
|
||||
typedef std::vector<py::InstanceHolderBase*>::const_iterator Iterator;
|
||||
for (Iterator p = self->wrapped_objects().begin();
|
||||
p != self->wrapped_objects().end(); ++p)
|
||||
{
|
||||
py::InstanceHolder<T>* held = dynamic_cast<py::InstanceHolder<T>*>(*p);
|
||||
if (held != 0)
|
||||
return held->target();
|
||||
}
|
||||
py::report_missing_instance_data(self, py::ClassRegistry<T>::class_object(), typeid(T));
|
||||
throw py::ArgumentError();
|
||||
}
|
||||
|
||||
// Convert to PtrType, where PtrType can be dereferenced to obtain a T.
|
||||
template <class PtrType>
|
||||
static PtrType& ptr_from_python(PyObject* obj, py::Type<PtrType>)
|
||||
{
|
||||
// Downcast to an ExtensionInstance, then find the actual T
|
||||
py::ExtensionInstance* self = py::get_extension_instance(obj);
|
||||
typedef std::vector<py::InstanceHolderBase*>::const_iterator Iterator;
|
||||
for (Iterator p = self->wrapped_objects().begin();
|
||||
p != self->wrapped_objects().end(); ++p)
|
||||
{
|
||||
py::InstancePtrHolder<PtrType, T>* held =
|
||||
dynamic_cast<py::InstancePtrHolder<PtrType, T>*>(*p);
|
||||
if (held != 0)
|
||||
return held->ptr();
|
||||
}
|
||||
py::report_missing_ptr_data(self, py::ClassRegistry<T>::class_object(), typeid(T));
|
||||
throw py::ArgumentError();
|
||||
}
|
||||
|
||||
template <class PtrType>
|
||||
static PyObject* ptr_to_python(PtrType x)
|
||||
{
|
||||
py::PyPtr<py::ExtensionInstance> result(create_instance(true));
|
||||
result->add_implementation(
|
||||
std::auto_ptr<py::InstanceHolderBase>(
|
||||
new py::InstancePtrHolder<PtrType,T>(x)));
|
||||
return result.release();
|
||||
}
|
||||
|
||||
static py::PyPtr<py::ExtensionInstance> create_instance(bool seek_base)
|
||||
{
|
||||
if (py::ClassRegistry<T>::class_object() == 0)
|
||||
py::report_missing_class_object(typeid(T));
|
||||
|
||||
py::Class<py::ExtensionInstance>* class_
|
||||
= seek_base && py::ClassRegistry<T>::class_object()->bases().size() > 0
|
||||
? py::Downcast<py::Class<py::ExtensionInstance> >(
|
||||
py::ClassRegistry<T>::class_object()->bases()[0].get()).get()
|
||||
: py::ClassRegistry<T>::class_object();
|
||||
|
||||
return py::PyPtr<py::ExtensionInstance>(new py::ExtensionInstance(class_));
|
||||
}
|
||||
|
||||
|
||||
// Convert to const T*
|
||||
friend const T* from_python(PyObject* p, py::Type<const T*>)
|
||||
{ return from_python(p, py::Type<T*>()); }
|
||||
|
||||
// Convert to T&
|
||||
friend T& from_python(PyObject* p, py::Type<T&>)
|
||||
{ return *py::check_non_null(from_python(p, py::Type<T*>())); }
|
||||
|
||||
// Convert to const T&
|
||||
friend const T& from_python(PyObject* p, py::Type<const T&>)
|
||||
{ return from_python(p, py::Type<T&>()); }
|
||||
|
||||
// Convert to T
|
||||
friend const T& from_python(PyObject* p, py::Type<T>)
|
||||
{ return from_python(p, py::Type<T&>()); }
|
||||
|
||||
friend std::auto_ptr<T>& from_python(PyObject* p, py::Type<std::auto_ptr<T>&>)
|
||||
{ return ptr_from_python(p, py::Type<std::auto_ptr<T> >()); }
|
||||
|
||||
friend std::auto_ptr<T>& from_python(PyObject* p, py::Type<std::auto_ptr<T> >)
|
||||
{ return ptr_from_python(p, py::Type<std::auto_ptr<T> >()); }
|
||||
|
||||
friend const std::auto_ptr<T>& from_python(PyObject* p, py::Type<const std::auto_ptr<T>&>)
|
||||
{ return ptr_from_python(p, py::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, py::Type<boost::shared_ptr<T>&>)
|
||||
{ return ptr_from_python(p, py::Type<boost::shared_ptr<T> >()); }
|
||||
|
||||
friend boost::shared_ptr<T>& from_python(PyObject* p, py::Type<boost::shared_ptr<T> >)
|
||||
{ return ptr_from_python(p, py::Type<boost::shared_ptr<T> >()); }
|
||||
|
||||
friend const boost::shared_ptr<T>& from_python(PyObject* p, py::Type<const boost::shared_ptr<T>&>)
|
||||
{ return ptr_from_python(p, py::Type<boost::shared_ptr<T> >()); }
|
||||
|
||||
friend PyObject* to_python(boost::shared_ptr<T> x)
|
||||
{ return ptr_to_python(x); }
|
||||
};
|
||||
|
||||
#ifndef BOOST_MSVC
|
||||
template <class T, class U>
|
||||
py::InstanceHolderBase*
|
||||
py_copy_to_new_value_holder(py::ExtensionInstance* p, const T& x, py::Type<U>)
|
||||
{
|
||||
return new py::InstanceValueHolder<T,U>(p, x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PyObject* to_python(const T& x)
|
||||
{
|
||||
py::PyPtr<py::ExtensionInstance> result(
|
||||
PyExtensionClassConverters<T>::create_instance(false));
|
||||
result->add_implementation(
|
||||
std::auto_ptr<py::InstanceHolderBase>(
|
||||
py_copy_to_new_value_holder(result.get(), x, py_holder_type(x))));
|
||||
return result.release();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE // back from global namespace for this GCC bug
|
||||
namespace py {
|
||||
using ::PyExtensionClassConverters;
|
||||
#endif
|
||||
|
||||
template <class T> class InstanceHolder;
|
||||
|
||||
class ReadOnlySetattrFunction : public Function
|
||||
{
|
||||
public:
|
||||
ReadOnlySetattrFunction(const char* name);
|
||||
PyObject* do_call(PyObject* args, PyObject* keywords) const;
|
||||
const char* description() const;
|
||||
private:
|
||||
String m_name;
|
||||
};
|
||||
|
||||
// An easy way to make an extension base class which wraps T. Note that Python
|
||||
// subclasses of this class will simply be Class<ExtensionInstance> 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 = HeldInstance<T> >
|
||||
class ExtensionClass
|
||||
: public PyExtensionClassConverters<T, U>, // This generates the to_python/from_python functions
|
||||
public ExtensionClassBase
|
||||
{
|
||||
public:
|
||||
typedef T WrappedType;
|
||||
typedef U CallbackType;
|
||||
|
||||
// Construct with a name that comes from typeid(T).name(). The name only
|
||||
// affects the objects of this class are represented through repr()
|
||||
ExtensionClass();
|
||||
|
||||
// Construct with the given name. The name only affects the objects of this
|
||||
// class are represented through repr()
|
||||
ExtensionClass(const char* name);
|
||||
|
||||
~ExtensionClass();
|
||||
|
||||
// define constructors
|
||||
template <class A1, class A2, class A3, class A4, class A5>
|
||||
void def(Constructor<A1, A2, A3, A4, A5>)
|
||||
{ add_constructor( // the following incantation builds a Signature1,
|
||||
prepend(Type<A1>::Id(), // Signature2, ... constructor. It _should_ all
|
||||
prepend(Type<A2>::Id(), // get optimized away. Just another workaround
|
||||
prepend(Type<A3>::Id(), // for the lack of partial specialization in MSVC
|
||||
prepend(Type<A4>::Id(),
|
||||
prepend(Type<A5>::Id(),
|
||||
Signature0()))))));
|
||||
}
|
||||
|
||||
// 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>
|
||||
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>
|
||||
void def(Fn fn, const char* name, DefaultFn default_fn)
|
||||
{
|
||||
this->add_default_method(new_wrapped_function(default_fn), name);
|
||||
this->add_method(new_wrapped_function(fn), name);
|
||||
}
|
||||
|
||||
// Provide a function which implements x.<name>, reading from the given
|
||||
// member (pm) of the T instance
|
||||
template <class MemberType>
|
||||
void def_getter(MemberType T::*pm, const char* name)
|
||||
{
|
||||
this->add_getter_method(new GetterFunction<T, MemberType>(pm), name);
|
||||
}
|
||||
|
||||
// Provide a function which implements assignment to x.<name>, writing to
|
||||
// the given member (pm) of the T instance
|
||||
template <class MemberType>
|
||||
void def_setter(MemberType T::*pm, const char* name)
|
||||
{
|
||||
this->add_setter_method(new SetterFunction<T, MemberType>(pm), name);
|
||||
}
|
||||
|
||||
// Expose the given member (pm) of the T instance as a read-only attribute
|
||||
template <class MemberType>
|
||||
void def_readonly(MemberType T::*pm, const char* name)
|
||||
{
|
||||
this->add_setter_method(new ReadOnlySetattrFunction(name), name);
|
||||
this->def_getter(pm, name);
|
||||
}
|
||||
|
||||
// Expose the given member (pm) of the T instance as a read/write attribute
|
||||
template <class MemberType>
|
||||
void def_read_write(MemberType T::*pm, const char* name)
|
||||
{
|
||||
this->def_getter(pm, name);
|
||||
this->def_setter(pm, name);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef InstanceValueHolder<T,U> Holder;
|
||||
|
||||
template <class Signature>
|
||||
void add_constructor(Signature sig)
|
||||
{
|
||||
this->add_constructor_object(InitFunction<Holder>::create(sig));
|
||||
}
|
||||
};
|
||||
|
||||
#include "extclass_pygen.h"
|
||||
|
||||
template <class PtrType, class HeldType>
|
||||
class InstancePtrHolder : public InstanceHolder<HeldType>
|
||||
{
|
||||
public:
|
||||
HeldType* target() { return &*m_ptr; }
|
||||
PtrType& ptr() { return m_ptr; }
|
||||
|
||||
InstancePtrHolder(PtrType ptr) : m_ptr(ptr) {}
|
||||
private:
|
||||
PtrType m_ptr;
|
||||
};
|
||||
|
||||
class ExtensionInstance : public Instance
|
||||
{
|
||||
public:
|
||||
ExtensionInstance(PyTypeObject* class_);
|
||||
~ExtensionInstance();
|
||||
|
||||
void add_implementation(std::auto_ptr<InstanceHolderBase> holder);
|
||||
|
||||
typedef std::vector<InstanceHolderBase*> WrappedObjects;
|
||||
const WrappedObjects& wrapped_objects() const
|
||||
{ return m_wrapped_objects; }
|
||||
private:
|
||||
WrappedObjects m_wrapped_objects;
|
||||
};
|
||||
|
||||
//
|
||||
// Template function implementations
|
||||
//
|
||||
|
||||
template <class T, class U>
|
||||
ExtensionClass<T, U>::ExtensionClass()
|
||||
: ExtensionClassBase(typeid(T).name())
|
||||
{
|
||||
ClassRegistry<T>::register_class(this);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
ExtensionClass<T, U>::ExtensionClass(const char* name)
|
||||
: ExtensionClassBase(name)
|
||||
{
|
||||
ClassRegistry<T>::register_class(this);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
ExtensionClass<T, U>::~ExtensionClass()
|
||||
{
|
||||
ClassRegistry<T>::unregister_class(this);
|
||||
}
|
||||
|
||||
#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE // Back to the global namespace for this GCC bug
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Static data member declaration.
|
||||
//
|
||||
#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE // Back from the global namespace for this GCC bug
|
||||
namespace py {
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
Class<py::ExtensionInstance>* ClassRegistry<T>::static_class_object;
|
||||
|
||||
template <class T>
|
||||
inline void ClassRegistry<T>::register_class(Class<ExtensionInstance>* 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 ClassRegistry<T>::unregister_class(Class<ExtensionInstance>* 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;
|
||||
}
|
||||
|
||||
} // namespace py
|
||||
|
||||
#endif // EXTENSION_CLASS_DWA052000_H_
|
||||
3
extclass_d.cpp
Normal file
3
extclass_d.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
#define DEBUG_PYTHON
|
||||
#include "extclass.cpp"
|
||||
|
||||
382
extclass_demo.cpp
Normal file
382
extclass_demo.cpp
Normal file
@@ -0,0 +1,382 @@
|
||||
// (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 "extclass_demo.h"
|
||||
#include "class_wrapper.h"
|
||||
#include <stdio.h> // used for portability on broken compilers
|
||||
|
||||
namespace extclass_demo {
|
||||
|
||||
FooCallback::FooCallback(PyObject* self, int x)
|
||||
: Foo(x), m_self(self)
|
||||
{
|
||||
}
|
||||
|
||||
int FooCallback::add_len(const char* x) const
|
||||
{
|
||||
// Try to call the "add_len" method on the corresponding Python object.
|
||||
return py::Callback<int>::call_method(m_self, "add_len", x);
|
||||
}
|
||||
|
||||
// A function which Python can call in case bar is not overridden from
|
||||
// Python. In true Python style, we use a free function taking an initial self
|
||||
// parameter. This function anywhere needn't be a static member of the callback
|
||||
// class. The only reason to do it this way is that Foo::add_len is private, and
|
||||
// FooCallback is already a friend of Foo.
|
||||
int FooCallback::default_add_len(const Foo* self, const char* x)
|
||||
{
|
||||
// Don't forget the Foo:: qualification, or you'll get an infinite
|
||||
// recursion!
|
||||
return self->Foo::add_len(x);
|
||||
}
|
||||
|
||||
// Since Foo::pure() is pure virtual, we don't need a corresponding
|
||||
// default_pure(). A failure to override it in Python will result in an
|
||||
// exception at runtime when pure() is called.
|
||||
const char* FooCallback::pure() const
|
||||
{
|
||||
return py::Callback<const char*>::call_method(m_self, "pure");
|
||||
}
|
||||
|
||||
// The initializer for ExtensionClass<Foo,FooCallback> is entirely optional. It
|
||||
// only affects the way that instances of this class _print_ in Python. If you
|
||||
// need an absolutely predictable name for the type, use the
|
||||
// initializer. Otherwise, C++ will generate an implementation-dependent
|
||||
// representation of the type name, usually something like "class
|
||||
// extclass_demo::Foo". I've supplied it here in part so that I can write
|
||||
// doctests that exactly anticipate the generated error messages.
|
||||
Foo::PythonClass::PythonClass()
|
||||
: py::ExtensionClass<Foo,FooCallback>("Foo") // optional
|
||||
{
|
||||
def(py::Constructor<int>());
|
||||
def(&Foo::mumble, "mumble");
|
||||
def(&Foo::set, "set");
|
||||
def(&Foo::call_pure, "call_pure");
|
||||
def(&Foo::call_add_len, "call_add_len");
|
||||
|
||||
// This is the way we add a virtual function that has a default implementation.
|
||||
def(&Foo::add_len, "add_len", &FooCallback::default_add_len);
|
||||
|
||||
// Since pure() is pure virtual, we are leaving it undefined.
|
||||
}
|
||||
|
||||
BarPythonClass::BarPythonClass()
|
||||
: py::ExtensionClass<Bar>("Bar") // optional
|
||||
{
|
||||
def(py::Constructor<int, int>());
|
||||
def(&Bar::first, "first");
|
||||
def(&Bar::second, "second");
|
||||
def(&Bar::pass_baz, "pass_baz");
|
||||
}
|
||||
|
||||
BazPythonClass::BazPythonClass()
|
||||
: py::ExtensionClass<Baz>("Baz") // optional
|
||||
{
|
||||
def(py::Constructor<py::Void>());
|
||||
def(&Baz::pass_bar, "pass_bar");
|
||||
def(&Baz::clone, "clone");
|
||||
def(&Baz::create_foo, "create_foo");
|
||||
def(&Baz::get_foo_value, "get_foo_value");
|
||||
def(&Baz::eat_baz, "eat_baz");
|
||||
}
|
||||
|
||||
StringMapPythonClass::StringMapPythonClass()
|
||||
: py::ExtensionClass<StringMap >("StringMap")
|
||||
{
|
||||
def(py::Constructor<py::Void>());
|
||||
def(&StringMap::size, "__len__");
|
||||
def(&get_item, "__getitem__");
|
||||
def(&set_item, "__setitem__");
|
||||
def(&del_item, "__delitem__");
|
||||
}
|
||||
|
||||
int get_first(const IntPair& p)
|
||||
{
|
||||
return p.first;
|
||||
}
|
||||
|
||||
void set_first(IntPair& p, int value)
|
||||
{
|
||||
p.first = -value;
|
||||
}
|
||||
|
||||
void del_first(const IntPair&)
|
||||
{
|
||||
PyErr_SetString(PyExc_AttributeError, "first can't be deleted!");
|
||||
throw py::ErrorAlreadySet();
|
||||
}
|
||||
|
||||
IntPairPythonClass::IntPairPythonClass()
|
||||
: py::ExtensionClass<IntPair>("IntPair")
|
||||
{
|
||||
def(py::Constructor<int, int>());
|
||||
def(&getattr, "__getattr__");
|
||||
def(&setattr, "__setattr__");
|
||||
def(&delattr, "__delattr__");
|
||||
def(&get_first, "__getattr__first__");
|
||||
def(&set_first, "__setattr__first__");
|
||||
def(&del_first, "__delattr__first__");
|
||||
}
|
||||
|
||||
void IntPairPythonClass::setattr(IntPair& x, const std::string& name, int value)
|
||||
{
|
||||
if (name == "second")
|
||||
{
|
||||
x.second = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_AttributeError, name.c_str());
|
||||
throw py::ErrorAlreadySet();
|
||||
}
|
||||
}
|
||||
|
||||
void IntPairPythonClass::delattr(IntPair&, const char*)
|
||||
{
|
||||
PyErr_SetString(PyExc_AttributeError, "Attributes can't be deleted!");
|
||||
throw py::ErrorAlreadySet();
|
||||
}
|
||||
|
||||
int IntPairPythonClass::getattr(const IntPair& p, const std::string& s)
|
||||
{
|
||||
if (s == "second")
|
||||
{
|
||||
return p.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_SetString(PyExc_AttributeError, s.c_str());
|
||||
throw py::ErrorAlreadySet();
|
||||
}
|
||||
#if defined(__MWERKS__) && __MWERKS__ <= 0x6000
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace { namespace file_local {
|
||||
void throw_key_error_if_end(const StringMap& m, StringMap::const_iterator p, std::size_t key)
|
||||
{
|
||||
if (p == m.end())
|
||||
{
|
||||
PyErr_SetObject(PyExc_KeyError, py::converters::to_python(key));
|
||||
throw py::ErrorAlreadySet();
|
||||
}
|
||||
}
|
||||
}} // namespace <anonymous>::file_local
|
||||
|
||||
const std::string& StringMapPythonClass::get_item(const StringMap& m, std::size_t key)
|
||||
{
|
||||
const StringMap::const_iterator p = m.find(key);
|
||||
file_local::throw_key_error_if_end(m, p, key);
|
||||
return p->second;
|
||||
}
|
||||
|
||||
void StringMapPythonClass::set_item(StringMap& m, std::size_t key, const std::string& value)
|
||||
{
|
||||
m[key] = value;
|
||||
}
|
||||
|
||||
void StringMapPythonClass::del_item(StringMap& m, std::size_t key)
|
||||
{
|
||||
const StringMap::iterator p = m.find(key);
|
||||
file_local::throw_key_error_if_end(m, p, key);
|
||||
m.erase(p);
|
||||
}
|
||||
|
||||
//
|
||||
// Show that polymorphism can work. a DerivedFromFoo object will be passed to
|
||||
// Python in a smart pointer object.
|
||||
//
|
||||
class DerivedFromFoo : public Foo
|
||||
{
|
||||
public:
|
||||
DerivedFromFoo(int x) : Foo(x) {}
|
||||
|
||||
private:
|
||||
const char* pure() const
|
||||
{ return "this was never pure!"; }
|
||||
|
||||
int add_len(const char*) const
|
||||
{ return 1000; }
|
||||
};
|
||||
|
||||
//
|
||||
// function implementations
|
||||
//
|
||||
|
||||
IntPair make_pair(int x, int y)
|
||||
{
|
||||
return std::make_pair(x, y);
|
||||
}
|
||||
|
||||
const char* Foo::mumble()
|
||||
{
|
||||
return "mumble";
|
||||
}
|
||||
|
||||
void Foo::set(long x)
|
||||
{
|
||||
m_x = x;
|
||||
}
|
||||
|
||||
const char* Foo::call_pure()
|
||||
{
|
||||
return this->pure();
|
||||
}
|
||||
|
||||
int Foo::call_add_len(const char* s) const
|
||||
{
|
||||
return this->add_len(s);
|
||||
}
|
||||
|
||||
int Foo::add_len(const char* s) const // sum the held value and the length of s
|
||||
{
|
||||
return PY_CSTD_::strlen(s) + static_cast<int>(m_x);
|
||||
}
|
||||
|
||||
boost::shared_ptr<Foo> Baz::create_foo()
|
||||
{
|
||||
return boost::shared_ptr<Foo>(new DerivedFromFoo(0));
|
||||
}
|
||||
|
||||
// We can accept smart pointer parameters
|
||||
int Baz::get_foo_value(boost::shared_ptr<Foo> foo)
|
||||
{
|
||||
return foo->call_add_len("");
|
||||
}
|
||||
|
||||
// Show what happens in python when we take ownership from an auto_ptr
|
||||
void Baz::eat_baz(std::auto_ptr<Baz> baz)
|
||||
{
|
||||
baz->clone(); // just do something to show that it is valid.
|
||||
}
|
||||
|
||||
Baz Bar::pass_baz(Baz b)
|
||||
{
|
||||
return b;
|
||||
}
|
||||
|
||||
std::string stringpair_repr(const StringPair& sp)
|
||||
{
|
||||
return "('" + sp.first + "', '" + sp.second + "')";
|
||||
}
|
||||
|
||||
int stringpair_compare(const StringPair& sp1, const StringPair& sp2)
|
||||
{
|
||||
return sp1 < sp2 ? -1 : sp2 < sp1 ? 1 : 0;
|
||||
}
|
||||
|
||||
py::String range_str(const Range& r)
|
||||
{
|
||||
char buf[200];
|
||||
sprintf(buf, "(%d, %d)", r.m_start, r.m_finish);
|
||||
return py::String(buf);
|
||||
}
|
||||
|
||||
int range_compare(const Range& r1, const Range& r2)
|
||||
{
|
||||
int d = r1.m_start - r2.m_start;
|
||||
if (d == 0)
|
||||
d = r1.m_finish - r2.m_finish;
|
||||
return d;
|
||||
}
|
||||
|
||||
long range_hash(const Range& r)
|
||||
{
|
||||
return r.m_start * 123 + r.m_finish;
|
||||
}
|
||||
|
||||
void init_module(py::Module& m)
|
||||
{
|
||||
m.add(new Foo::PythonClass);
|
||||
m.add(new BarPythonClass);
|
||||
m.add(new BazPythonClass);
|
||||
m.add(new StringMapPythonClass);
|
||||
m.add(new IntPairPythonClass);
|
||||
m.def(make_pair, "make_pair");
|
||||
m.add(new CompareIntPairPythonClass);
|
||||
|
||||
py::ClassWrapper<StringPair> string_pair(m, "StringPair");
|
||||
string_pair.def(py::Constructor<std::string, std::string>());
|
||||
string_pair.def_readonly(&StringPair::first, "first");
|
||||
string_pair.def_read_write(&StringPair::second, "second");
|
||||
string_pair.def(&stringpair_repr, "__repr__");
|
||||
string_pair.def(&stringpair_compare, "__cmp__");
|
||||
m.def(first_string, "first_string");
|
||||
m.def(second_string, "second_string");
|
||||
|
||||
py::ClassWrapper<Range> range(m, "Range");
|
||||
range.def(py::Constructor<int>());
|
||||
range.def(py::Constructor<int, int>());
|
||||
range.def((void (Range::*)(std::size_t))&Range::length, "__len__");
|
||||
range.def((std::size_t (Range::*)() const)&Range::length, "__len__");
|
||||
range.def(&Range::operator[], "__getitem__");
|
||||
range.def(&Range::slice, "__getslice__");
|
||||
range.def(&range_str, "__str__");
|
||||
range.def(&range_compare, "__cmp__");
|
||||
range.def(&range_hash, "__hash__");
|
||||
range.def_readonly(&Range::m_start, "start");
|
||||
range.def_readonly(&Range::m_finish, "finish");
|
||||
}
|
||||
|
||||
void init_module()
|
||||
{
|
||||
py::Module demo("demo");
|
||||
init_module(demo);
|
||||
|
||||
// Just for giggles, add a raw metaclass.
|
||||
demo.add(new py::MetaClass<py::Instance>);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
void initdemo()
|
||||
{
|
||||
try {
|
||||
extclass_demo::init_module();
|
||||
}
|
||||
catch(...) {
|
||||
py::handle_exception();
|
||||
} // Need a way to report other errors here
|
||||
}
|
||||
|
||||
CompareIntPairPythonClass::CompareIntPairPythonClass()
|
||||
: py::ExtensionClass<CompareIntPair>("CompareIntPair")
|
||||
{
|
||||
def(py::Constructor<py::Void>());
|
||||
def(&CompareIntPair::operator(), "__call__");
|
||||
}
|
||||
|
||||
} // namespace extclass_demo
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
extern "C" BOOL WINAPI DllMain ( HINSTANCE hInst, DWORD wDataSeg, LPVOID lpvReserved );
|
||||
|
||||
# ifdef PY_COMPILER_IS_MSVC
|
||||
extern "C" void structured_exception_translator(unsigned int, EXCEPTION_POINTERS*)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
# endif
|
||||
|
||||
BOOL WINAPI DllMain(
|
||||
HINSTANCE, //hDllInst
|
||||
DWORD fdwReason,
|
||||
LPVOID // lpvReserved
|
||||
)
|
||||
{
|
||||
# ifdef PY_COMPILER_IS_MSVC
|
||||
_set_se_translator(structured_exception_translator);
|
||||
#endif
|
||||
return 1;
|
||||
(void)fdwReason; // warning suppression.
|
||||
}
|
||||
#endif // _WIN32
|
||||
231
extclass_demo.h
Normal file
231
extclass_demo.h
Normal file
@@ -0,0 +1,231 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#ifndef EXTCLASS_DEMO_DWA052200_H_
|
||||
# define EXTCLASS_DEMO_DWA052200_H_
|
||||
//
|
||||
// Example code demonstrating extension class usage
|
||||
//
|
||||
|
||||
# include "extclass.h"
|
||||
# include "callback.h"
|
||||
# include <boost/utility.hpp>
|
||||
# include <cstring>
|
||||
# include <iostream>
|
||||
# include <cstddef>
|
||||
# include <string>
|
||||
# include <map>
|
||||
|
||||
namespace extclass_demo {
|
||||
|
||||
//
|
||||
// example: Foo, Bar, and Baz are C++ classes we want to wrap.
|
||||
//
|
||||
|
||||
class Foo // prohibit copying, proving that it doesn't choke
|
||||
: boost::noncopyable // our generation of to_python().
|
||||
{
|
||||
public: // constructor/destructor
|
||||
Foo(int x) : m_x(x) {}
|
||||
virtual ~Foo() {}
|
||||
|
||||
public: // non-virtual functions
|
||||
const char* mumble(); // mumble something
|
||||
void set(long x); // change the held value
|
||||
|
||||
// These two call virtual functions
|
||||
const char* 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 const char* 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 ExtensionClass (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.
|
||||
const char* pure() const;
|
||||
|
||||
private: // Required boilerplate if functions will be overridden
|
||||
PyObject* m_self; // No, we don't want a py::Ptr here, or we'd get an ownership cycle.
|
||||
};
|
||||
|
||||
// Define the Python base class
|
||||
struct Foo::PythonClass : py::ExtensionClass<Foo, FooCallback> { PythonClass(); };
|
||||
|
||||
// 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 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 py::ExtensionClass<> that
|
||||
// causes to_python/from_python conversion functions to be generated.
|
||||
struct BarPythonClass : py::ExtensionClass<Bar> { BarPythonClass(); };
|
||||
struct BazPythonClass : py::ExtensionClass<Baz> { BazPythonClass(); };
|
||||
|
||||
struct StringMapPythonClass
|
||||
: py::ExtensionClass<StringMap>
|
||||
{
|
||||
StringMapPythonClass();
|
||||
|
||||
// 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
|
||||
: py::ExtensionClass<IntPair>
|
||||
{
|
||||
IntPairPythonClass();
|
||||
|
||||
// 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
|
||||
: py::ExtensionClass<CompareIntPair>
|
||||
{
|
||||
CompareIntPairPythonClass();
|
||||
};
|
||||
|
||||
} // namespace extclass_demo
|
||||
|
||||
#endif // EXTCLASS_DEMO_DWA052200_H_
|
||||
23
extclass_demo.py
Normal file
23
extclass_demo.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# A stand-in for the real extension module. We're just using this one to
|
||||
# simulate it while we have all the parts linked together into cpp.dll
|
||||
|
||||
# using "import*-safe" imports
|
||||
import sys
|
||||
_sys = sys
|
||||
del sys
|
||||
|
||||
import os
|
||||
_os = os
|
||||
del os
|
||||
|
||||
_savecwd = _os.getcwd()
|
||||
|
||||
if len(_sys.argv) > 1:
|
||||
_os.chdir(_sys.argv[1])
|
||||
|
||||
try:
|
||||
from cpp import *
|
||||
finally:
|
||||
if len(_sys.argv) > 1:
|
||||
_os.chdir(_savecwd)
|
||||
|
||||
2
extclass_demo_d.cpp
Normal file
2
extclass_demo_d.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#define DEBUG_PYTHON
|
||||
#include "extclass_demo.cpp"
|
||||
80
extclass_pygen.h
Normal file
80
extclass_pygen.h
Normal file
@@ -0,0 +1,80 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
//
|
||||
// This file automatically generated for 5-argument constructors by
|
||||
// gen_extclass.py
|
||||
|
||||
#ifndef EXTCLASS_PYGEN_DWA070900_H_
|
||||
# define EXTCLASS_PYGEN_DWA070900_H_
|
||||
|
||||
|
||||
// A simple wrapper over a T which allows us to use ExtensionClass<T> with a
|
||||
// single template parameter only. See ExtensionClass<T>, above.
|
||||
template <class T>
|
||||
class HeldInstance : public T
|
||||
{
|
||||
// There are no member functions: we want to avoid inadvertently overriding
|
||||
// any virtual functions in T.
|
||||
public:
|
||||
HeldInstance(PyObject* p) : T(), m_self(p) {}
|
||||
template <class A1>
|
||||
HeldInstance(PyObject* p, const A1& a1) : T(a1), m_self(p) {}
|
||||
template <class A1, class A2>
|
||||
HeldInstance(PyObject* p, const A1& a1, const A2& a2) : T(a1, a2), m_self(p) {}
|
||||
template <class A1, class A2, class A3>
|
||||
HeldInstance(PyObject* p, const A1& a1, const A2& a2, const A3& a3) : T(a1, a2, a3), m_self(p) {}
|
||||
template <class A1, class A2, class A3, class A4>
|
||||
HeldInstance(PyObject* p, const A1& a1, const A2& a2, const A3& a3, const A4& a4) : T(a1, a2, a3, a4), m_self(p) {}
|
||||
template <class A1, class A2, class A3, class A4, class A5>
|
||||
HeldInstance(PyObject* p, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) : T(a1, a2, a3, a4, a5), m_self(p) {}
|
||||
protected:
|
||||
PyObject* m_self; // Not really needed; doesn't really hurt.
|
||||
};
|
||||
|
||||
class InstanceHolderBase
|
||||
{
|
||||
public:
|
||||
virtual ~InstanceHolderBase() {}
|
||||
};
|
||||
|
||||
template <class Held>
|
||||
class InstanceHolder : public InstanceHolderBase
|
||||
{
|
||||
public:
|
||||
virtual Held *target() = 0;
|
||||
};
|
||||
|
||||
template <class Held, class Wrapper>
|
||||
class InstanceValueHolder : public InstanceHolder<Held>
|
||||
{
|
||||
public:
|
||||
Held* target() { return &m_held; }
|
||||
Wrapper* value_target() { return &m_held; }
|
||||
|
||||
InstanceValueHolder(ExtensionInstance* p) :
|
||||
m_held(p) {}
|
||||
template <class A1>
|
||||
InstanceValueHolder(ExtensionInstance* p, const A1& a1) :
|
||||
m_held(p, a1) {}
|
||||
template <class A1, class A2>
|
||||
InstanceValueHolder(ExtensionInstance* p, const A1& a1, const A2& a2) :
|
||||
m_held(p, a1, a2) {}
|
||||
template <class A1, class A2, class A3>
|
||||
InstanceValueHolder(ExtensionInstance* p, const A1& a1, const A2& a2, const A3& a3) :
|
||||
m_held(p, a1, a2, a3) {}
|
||||
template <class A1, class A2, class A3, class A4>
|
||||
InstanceValueHolder(ExtensionInstance* p, const A1& a1, const A2& a2, const A3& a3, const A4& a4) :
|
||||
m_held(p, a1, a2, a3, a4) {}
|
||||
template <class A1, class A2, class A3, class A4, class A5>
|
||||
InstanceValueHolder(ExtensionInstance* p, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) :
|
||||
m_held(p, a1, a2, a3, a4, a5) {}
|
||||
private:
|
||||
Wrapper m_held;
|
||||
};
|
||||
|
||||
#endif
|
||||
161
functions.cpp
Normal file
161
functions.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
// (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 "functions.h"
|
||||
#include "newtypes.h"
|
||||
#include "singleton.h"
|
||||
#include "objects.h"
|
||||
#include "errors.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
struct Function::TypeObject :
|
||||
Singleton<Function::TypeObject, Callable<py::TypeObject<Function> > >
|
||||
{
|
||||
TypeObject() : SingletonBase(&PyType_Type) {}
|
||||
};
|
||||
|
||||
|
||||
void Function::add_to_namespace(PyPtr<Function> new_function, const char* name, PyObject* dict)
|
||||
{
|
||||
Dict d(Ptr(dict, Ptr::borrowed));
|
||||
String key(name);
|
||||
|
||||
Ptr existing_object = d.get_item(key.reference());
|
||||
if (existing_object.get() == 0)
|
||||
{
|
||||
d[key] = Ptr(new_function.get(), Ptr::borrowed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (existing_object->ob_type == TypeObject::singleton())
|
||||
{
|
||||
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 ErrorAlreadySet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Function::Function()
|
||||
: PythonObject(TypeObject::singleton())
|
||||
{
|
||||
}
|
||||
|
||||
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 ArgumentError&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (m_overloads.get() == 0)
|
||||
return 0;
|
||||
|
||||
PyErr_Clear();
|
||||
String message("No overloaded functions match (");
|
||||
Tuple arguments(Ptr(args, Ptr::borrowed));
|
||||
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;
|
||||
}
|
||||
|
||||
Ptr BoundFunction::create(Ptr target, Ptr fn)
|
||||
{
|
||||
BoundFunction* result = free_list;
|
||||
if (result != 0)
|
||||
{
|
||||
free_list = result->m_free_list_link;
|
||||
result->m_target = target;
|
||||
result->m_unbound_function = fn;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = new BoundFunction(target, fn);
|
||||
}
|
||||
return Ptr(result, Ptr::new_ref);
|
||||
}
|
||||
|
||||
struct BoundFunction::TypeObject :
|
||||
Singleton<BoundFunction::TypeObject, Callable<py::TypeObject<BoundFunction> > >
|
||||
{
|
||||
TypeObject() : SingletonBase(&PyType_Type) {}
|
||||
|
||||
private: // TypeObject<BoundFunction> hook override
|
||||
void dealloc(BoundFunction*) const;
|
||||
};
|
||||
|
||||
BoundFunction::BoundFunction(Ptr target, Ptr fn)
|
||||
: PythonObject(TypeObject::singleton()),
|
||||
m_target(target),
|
||||
m_unbound_function(fn),
|
||||
m_free_list_link(0)
|
||||
{
|
||||
}
|
||||
|
||||
PyObject*
|
||||
BoundFunction::call(PyObject* args, PyObject* keywords) const
|
||||
{
|
||||
// Build a new tuple which prepends the target to the arguments
|
||||
Tuple tail_arguments(Ptr(args, Ptr::borrowed));
|
||||
Ptr 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);
|
||||
}
|
||||
|
||||
void BoundFunction::TypeObject::dealloc(BoundFunction* instance) const
|
||||
{
|
||||
instance->m_free_list_link = free_list;
|
||||
free_list = instance;
|
||||
instance->m_target.reset();
|
||||
instance->m_unbound_function.reset();
|
||||
}
|
||||
|
||||
BoundFunction* BoundFunction::free_list;
|
||||
|
||||
}
|
||||
175
functions.h
Normal file
175
functions.h
Normal file
@@ -0,0 +1,175 @@
|
||||
// (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 "pyconfig.h"
|
||||
# include "wrap_python.h"
|
||||
# include "pyptr.h"
|
||||
# include "signatures.h"
|
||||
# include "caller.h"
|
||||
# include <boost/call_traits.hpp>
|
||||
# include "objects.h"
|
||||
# include "base_object.h"
|
||||
# include <typeinfo>
|
||||
|
||||
namespace py {
|
||||
|
||||
class Function : public PythonObject
|
||||
{
|
||||
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(PyPtr<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 TypeObject;
|
||||
private:
|
||||
PyPtr<Function> m_overloads;
|
||||
};
|
||||
|
||||
template <class R, class F>
|
||||
struct WrappedFunctionPointer : Function
|
||||
{
|
||||
typedef F PtrFun; // pointer-to--function or pointer-to-member-function
|
||||
|
||||
WrappedFunctionPointer(PtrFun 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 PtrFun m_pf;
|
||||
};
|
||||
|
||||
// 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 ReturnType;
|
||||
return new WrappedFunctionPointer<ReturnType, 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);
|
||||
}
|
||||
|
||||
// A function with a bundled "bound target" object. This is what is produced by
|
||||
// the expression a.b where a is an Instance or ExtensionInstance object and b
|
||||
// is a callable object not found in the instance namespace but on its class or
|
||||
// a base class.
|
||||
class BoundFunction : public PythonObject
|
||||
{
|
||||
public:
|
||||
static Ptr create(Ptr target, Ptr fn);
|
||||
|
||||
BoundFunction(Ptr target, Ptr fn);
|
||||
PyObject* call(PyObject*args, PyObject* keywords) const;
|
||||
|
||||
private:
|
||||
struct TypeObject;
|
||||
friend struct TypeObject;
|
||||
|
||||
Ptr m_target;
|
||||
Ptr m_unbound_function;
|
||||
|
||||
private: // data members for allocation/deallocation optimization
|
||||
BoundFunction* m_free_list_link;
|
||||
|
||||
static BoundFunction* free_list;
|
||||
};
|
||||
|
||||
// Special functions designed to access data members of a wrapped C++ object.
|
||||
template <class ClassType, class MemberType>
|
||||
class GetterFunction : public Function
|
||||
{
|
||||
public:
|
||||
typedef MemberType ClassType::* PointerToMember;
|
||||
|
||||
GetterFunction(PointerToMember pm)
|
||||
: m_pm(pm) {}
|
||||
|
||||
private:
|
||||
PyObject* do_call(PyObject* args, PyObject* keywords) const;
|
||||
|
||||
const char* description() const
|
||||
{ return typeid(MemberType (*)(const ClassType&)).name(); }
|
||||
private:
|
||||
PointerToMember m_pm;
|
||||
};
|
||||
|
||||
template <class ClassType, class MemberType>
|
||||
class SetterFunction : public Function
|
||||
{
|
||||
public:
|
||||
typedef MemberType ClassType::* PointerToMember;
|
||||
|
||||
SetterFunction(PointerToMember 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:
|
||||
PointerToMember m_pm;
|
||||
};
|
||||
|
||||
template <class ClassType, class MemberType>
|
||||
PyObject* GetterFunction<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* SetterFunction<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 ExtractType;
|
||||
from_python(self, Type<ClassType*>())->*m_pm
|
||||
= from_python(value, Type<ExtractType>());
|
||||
|
||||
return none();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // FUNCTIONS_DWA051400_H_
|
||||
2
functions_d.cpp
Normal file
2
functions_d.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#define DEBUG_PYTHON
|
||||
#include "functions.cpp"
|
||||
40
gcc.mak
Normal file
40
gcc.mak
Normal file
@@ -0,0 +1,40 @@
|
||||
LIBSRC = \
|
||||
extclass.cpp \
|
||||
init_function.cpp \
|
||||
py.cpp \
|
||||
module.cpp \
|
||||
subclass.cpp \
|
||||
functions.cpp \
|
||||
newtypes.cpp \
|
||||
objects.cpp
|
||||
|
||||
LIBOBJ = $(LIBSRC:.cpp=.o)
|
||||
OBJ = $(LIBOBJ) extclass_demo.o
|
||||
|
||||
INC = -I/home/koethe/include -I/home/koethe/C++/boost -I/home/koethe/python/include/python1.5
|
||||
|
||||
%.o: %.cpp
|
||||
g++ -fPIC $(INC) -c $*.cpp
|
||||
|
||||
%.d: %.cpp
|
||||
@echo creating $@
|
||||
@set -e; g++ -M $(INC) -c $*.cpp \
|
||||
| sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
|
||||
[ -s $@ ] || rm -f $@
|
||||
|
||||
demo: extclass_demo.o libpycpp.a
|
||||
g++ -shared -o demomodule.so extclass_demo.o -L. -lpycpp
|
||||
python test_extclass.py
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.so *.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
|
||||
26
gen_all.py
Normal file
26
gen_all.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from gen_callback import *
|
||||
from gen_caller import *
|
||||
from gen_init_function import *
|
||||
from gen_signatures import *
|
||||
from gen_singleton import *
|
||||
from gen_extclass import *
|
||||
|
||||
def gen_all(args):
|
||||
open('callback.h', 'w').write(gen_callback(args))
|
||||
open('caller.h', 'w').write(gen_caller(args))
|
||||
open('init_function.h', 'w').write(gen_init_function(args))
|
||||
open('signatures.h', 'w').write(gen_signatures(args))
|
||||
open('singleton.h', 'w').write(gen_singleton(args))
|
||||
open('extclass_pygen.h', 'w').write(gen_extclass(args))
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
args = 5
|
||||
else:
|
||||
args = int(sys.argv[1])
|
||||
|
||||
print gen_all(args)
|
||||
|
||||
|
||||
71
gen_callback.py
Normal file
71
gen_callback.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from gen_function import *
|
||||
import string
|
||||
|
||||
def gen_callback(args):
|
||||
# A template for the call_method function which we're going to generate
|
||||
call_method = '''%{ template <%(class A%n%:, %)>
|
||||
%} static %1 call_method(PyObject* self, const char* name%(, const A%n& a%n%))
|
||||
{ %2PyEval_CallMethod(self, const_cast<char*>(name), const_cast<char*>("(%(N%))")%(, to_python(a%n)%))%3; }
|
||||
|
||||
'''
|
||||
non_void = ('R', 'return from_python(expect_non_null(', '), Type<R>())')
|
||||
void = ('void', 'expect_and_absorb_non_null(', ')')
|
||||
|
||||
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.py
|
||||
|
||||
#ifndef CALLBACK_DWA_052100_H_
|
||||
# define CALLBACK_DWA_052100_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
# include "py.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
// Just like the above, except we decrement p's reference count instead of returning it.
|
||||
void expect_and_absorb_non_null(PyObject* p);
|
||||
|
||||
// Calling Python from C++
|
||||
template <class R>
|
||||
struct Callback
|
||||
{
|
||||
""" % args
|
||||
+ gen_functions(call_method, args, 'R', 'return from_python(expect_non_null(', '), 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>
|
||||
{
|
||||
"""
|
||||
+ gen_functions(call_method, args, 'void', 'expect_and_absorb_non_null(', ')')
|
||||
+
|
||||
"""};
|
||||
|
||||
} // namespace py
|
||||
|
||||
#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)
|
||||
|
||||
|
||||
138
gen_caller.py
Normal file
138
gen_caller.py
Normal file
@@ -0,0 +1,138 @@
|
||||
# (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
# distribute this software is granted provided this copyright notice appears
|
||||
# in all copies. This software is provided "as is" without express or implied
|
||||
# warranty, and with no claim as to its suitability for any purpose.
|
||||
#
|
||||
# The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
# producing this work.
|
||||
|
||||
from gen_function import *
|
||||
import string
|
||||
|
||||
header = '''// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
//
|
||||
// This file generated for %d-argument member functions and %d-argument free
|
||||
// functions by gen_caller.py
|
||||
'''
|
||||
|
||||
body_sections = (
|
||||
'''
|
||||
#ifndef CALLER_DWA05090_H_
|
||||
# define CALLER_DWA05090_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
# include "wrap_python.h"
|
||||
# include <boost/config.hpp>
|
||||
# include "signatures.h"
|
||||
# include "none.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
// Calling C++ from Python
|
||||
template <class R>
|
||||
struct Caller
|
||||
{
|
||||
''',
|
||||
'''
|
||||
''',
|
||||
''' // Free functions
|
||||
''',
|
||||
'''};
|
||||
|
||||
template <>
|
||||
struct Caller<void>
|
||||
{
|
||||
''',
|
||||
'''
|
||||
''',
|
||||
'''
|
||||
// Free functions
|
||||
''',
|
||||
'''};
|
||||
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
return_none = ''';
|
||||
return 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)
|
||||
|
||||
|
||||
81
gen_extclass.py
Normal file
81
gen_extclass.py
Normal file
@@ -0,0 +1,81 @@
|
||||
from gen_function import *
|
||||
import string
|
||||
|
||||
def gen_extclass(args):
|
||||
held_instance = """%{
|
||||
template <%(class A%n%:, %)>%}
|
||||
HeldInstance(PyObject* p%(, const A%n%& a%n%)) : T(%(a%n%:, %)), m_self(p) {}"""
|
||||
|
||||
instance_value_holder = """%{
|
||||
template <%(class A%n%:, %)>%}
|
||||
InstanceValueHolder(ExtensionInstance* p%(, const A%n& a%n%)) :
|
||||
m_held(p%(, a%n%)) {}"""
|
||||
|
||||
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.py
|
||||
|
||||
#ifndef EXTCLASS_PYGEN_DWA070900_H_
|
||||
# define EXTCLASS_PYGEN_DWA070900_H_
|
||||
|
||||
|
||||
// A simple wrapper over a T which allows us to use ExtensionClass<T> with a
|
||||
// single template parameter only. See ExtensionClass<T>, above.
|
||||
template <class T>
|
||||
class HeldInstance : public T
|
||||
{
|
||||
// There are no member functions: we want to avoid inadvertently overriding
|
||||
// any virtual functions in T.
|
||||
public:""" % args
|
||||
+ gen_functions(held_instance, args)
|
||||
+ """
|
||||
protected:
|
||||
PyObject* m_self; // Not really needed; doesn't really hurt.
|
||||
};
|
||||
|
||||
class InstanceHolderBase
|
||||
{
|
||||
public:
|
||||
virtual ~InstanceHolderBase() {}
|
||||
};
|
||||
|
||||
template <class Held>
|
||||
class InstanceHolder : public InstanceHolderBase
|
||||
{
|
||||
public:
|
||||
virtual Held *target() = 0;
|
||||
};
|
||||
|
||||
template <class Held, class Wrapper>
|
||||
class InstanceValueHolder : public InstanceHolder<Held>
|
||||
{
|
||||
public:
|
||||
Held* target() { return &m_held; }
|
||||
Wrapper* value_target() { return &m_held; }
|
||||
"""
|
||||
+ gen_functions(instance_value_holder, args)
|
||||
+ """
|
||||
private:
|
||||
Wrapper m_held;
|
||||
};
|
||||
|
||||
#endif
|
||||
""")
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
args = 5
|
||||
else:
|
||||
args = int(sys.argv[1])
|
||||
|
||||
print gen_extclass(args)
|
||||
184
gen_function.py
Normal file
184
gen_function.py
Normal file
@@ -0,0 +1,184 @@
|
||||
import string
|
||||
|
||||
def _find(s, sub, start=0, end=None):
|
||||
"""Just like string.find, except it returns end or len(s) when not found.
|
||||
"""
|
||||
if end == None:
|
||||
end = len(s)
|
||||
|
||||
pos = string.find(s, sub, start, end)
|
||||
if pos < 0:
|
||||
return end
|
||||
else:
|
||||
return pos
|
||||
|
||||
def _gen_common_key(key, n, args):
|
||||
if len(key) > 0 and key in '123456789':
|
||||
return str(args[int(key) - 1])
|
||||
elif key == 'x':
|
||||
return str(n)
|
||||
else:
|
||||
return key
|
||||
|
||||
def _gen_arg(template, n, args, delimiter = '%'):
|
||||
result = ''
|
||||
i = 0
|
||||
while i < len(template): # until the template is consumed
|
||||
# consume everything up to the first delimiter
|
||||
delimiter_pos = _find(template, delimiter, i)
|
||||
result = result + template[i:delimiter_pos]
|
||||
|
||||
# The start position of whatever comes after the delimiter+key
|
||||
start = delimiter_pos + 2
|
||||
key = template[start - 1 : start] # the key character. If there were no
|
||||
# delimiters left, key will be empty
|
||||
|
||||
if key == 'n':
|
||||
result = result + `n`
|
||||
else:
|
||||
result = result + _gen_common_key(key, n, args)
|
||||
|
||||
i = start
|
||||
|
||||
return result
|
||||
|
||||
def gen_function(template, n, *args, **keywords):
|
||||
r"""gen_function(template, n, [args...] ) -> string
|
||||
|
||||
Generate a function declaration based on the given template.
|
||||
|
||||
Sections of the template between '%(', '%)' pairs are repeated n times. If '%:'
|
||||
appears in the middle, it denotes the beginning of a delimiter.
|
||||
|
||||
Sections of the template between '%{', '%}' pairs are ommitted if n == 0.
|
||||
|
||||
%n is transformed into the string representation of 1..n for each repetition
|
||||
of n.
|
||||
|
||||
%x, where x is a digit, is transformed into the corresponding additional
|
||||
argument.
|
||||
|
||||
for example,
|
||||
|
||||
>>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 2, 'void')
|
||||
'void abc(int a1, int a2); // all args are ints'
|
||||
>>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 0, 'x')
|
||||
'x abc();'
|
||||
|
||||
|
||||
>>> template = ''' template <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()
|
||||
82
gen_init_function.py
Normal file
82
gen_init_function.py
Normal file
@@ -0,0 +1,82 @@
|
||||
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.py
|
||||
|
||||
#ifndef INIT_FUNCTION_DWA052000_H_
|
||||
# define INIT_FUNCTION_DWA052000_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
# include "functions.h"
|
||||
# include "signatures.h"
|
||||
# include <typeinfo>
|
||||
|
||||
namespace py {
|
||||
|
||||
class ExtensionInstance;
|
||||
class InstanceHolderBase;
|
||||
|
||||
class Init;
|
||||
"""
|
||||
+ gen_functions('template <class T%(, class A%n%)> struct Init%x;\n', args)
|
||||
+ """
|
||||
template <class T>
|
||||
struct InitFunction
|
||||
{
|
||||
""" + gen_functions("""%{
|
||||
template <%(class A%n%:, %)>
|
||||
%} static Init* create(Signature%x%{<%(A%n%:, %)>%})
|
||||
{ return new Init%x<T%(, A%n%)>; }
|
||||
""", args)+"""};
|
||||
|
||||
class Init : public Function
|
||||
{
|
||||
private: // override Function hook
|
||||
PyObject* do_call(PyObject* args, PyObject* keywords) const;
|
||||
private:
|
||||
virtual InstanceHolderBase* create_holder(ExtensionInstance* self, PyObject* tail_args, PyObject* keywords) const = 0;
|
||||
};
|
||||
""" + gen_functions("""
|
||||
|
||||
template <class T%(, class A%n%)>
|
||||
struct Init%x : Init
|
||||
{
|
||||
virtual InstanceHolderBase* create_holder(ExtensionInstance* self, PyObject* args, PyObject* /*keywords*/) const
|
||||
{
|
||||
%(PyObject* a%n;
|
||||
%)if (!PyArg_ParseTuple(args, const_cast<char*>("%(O%)")%(, &a%n%)))
|
||||
throw ArgumentError();
|
||||
return new T(self%(,
|
||||
from_python(a%n, Type<A%n>())%)
|
||||
);
|
||||
}
|
||||
const char* description() const
|
||||
{ return typeid(void (*)(%(A%n%:, %))).name(); }
|
||||
};""", args) + """
|
||||
|
||||
}
|
||||
|
||||
#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)
|
||||
|
||||
152
gen_signatures.py
Normal file
152
gen_signatures.py
Normal file
@@ -0,0 +1,152 @@
|
||||
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 to the head of a Void
|
||||
# // signature results in a Void signature again.
|
||||
# static inline Signature0 prepend(Void) { 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.py for %d arguments.
|
||||
#ifndef SIGNATURES_DWA050900_H_
|
||||
# define SIGNATURES_DWA050900_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
// 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 {};
|
||||
|
||||
// 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>::Id is just Void.
|
||||
template <class T>
|
||||
struct Type
|
||||
{
|
||||
typedef Type Id;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type<Void>
|
||||
{
|
||||
typedef Void Id;
|
||||
};
|
||||
|
||||
// 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 to the head of a Void
|
||||
// signature results in a Void signature again.
|
||||
inline Signature0 prepend(Void, Signature0) { return Signature0(); }
|
||||
"""
|
||||
+ gen_function("""
|
||||
template <%(class A%n% = Void%:, %)>
|
||||
struct Constructor
|
||||
{
|
||||
};
|
||||
""", args)
|
||||
+ """
|
||||
// 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 ReturnValue { typedef T Type; };
|
||||
|
||||
// free functions"""
|
||||
+ gen_functions("""
|
||||
template <class R%(, class A%n%)>
|
||||
ReturnValue<R> return_value(R (*)(%(A%n%:, %))) { return ReturnValue<R>(); }
|
||||
""", args)
|
||||
|
||||
+
|
||||
"""
|
||||
// TODO(?): handle 'const void'
|
||||
|
||||
// member functions"""
|
||||
+ gen_functions("""
|
||||
template <class R, class T%(, class A%n%)>
|
||||
ReturnValue<R> return_value(R (T::*)(%(A%n%:, %))) { return ReturnValue<R>(); }
|
||||
""", args)
|
||||
|
||||
+ gen_functions("""
|
||||
template <class R, class T%(, class A%n%)>
|
||||
ReturnValue<R> return_value(R (T::*)(%(A%n%:, %)) const) { return ReturnValue<R>(); }
|
||||
""", args)
|
||||
|
||||
+ """
|
||||
}
|
||||
|
||||
#endif
|
||||
""")
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
args = 5
|
||||
else:
|
||||
args = int(sys.argv[1])
|
||||
|
||||
print gen_signatures(args)
|
||||
|
||||
58
gen_singleton.py
Normal file
58
gen_singleton.py
Normal file
@@ -0,0 +1,58 @@
|
||||
from gen_function import *
|
||||
import string
|
||||
|
||||
def gen_singleton(args):
|
||||
return (
|
||||
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#ifndef SINGLETON_DWA051900_H_
|
||||
# define SINGLETON_DWA051900_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
struct Empty {};
|
||||
template <class Derived, class Base = Empty>
|
||||
struct Singleton : Base
|
||||
{
|
||||
typedef Singleton SingletonBase; // Convenience type for derived class constructors
|
||||
|
||||
static Derived* singleton();
|
||||
|
||||
// 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>::singleton()
|
||||
{
|
||||
static Derived x;
|
||||
return &x;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
""")
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
args = 5
|
||||
else:
|
||||
args = int(sys.argv[1])
|
||||
|
||||
print gen_singleton(args)
|
||||
36
init_function.cpp
Normal file
36
init_function.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#include "init_function.h"
|
||||
#include "objects.h"
|
||||
#include "extclass.h"
|
||||
#include <utility>
|
||||
|
||||
namespace py {
|
||||
|
||||
PyObject* Init::do_call(PyObject* args_, PyObject* keywords) const
|
||||
{
|
||||
Tuple args(Ptr(args_, Ptr::borrowed));
|
||||
if (args[0]->ob_type->ob_type != extension_meta_class())
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "argument 1 to __init__ must be an ExtensionInstance");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ExtensionInstance *self = static_cast<ExtensionInstance*>(args[0].get());
|
||||
|
||||
Tuple ctor_args = args.slice(1, args.size());
|
||||
|
||||
std::auto_ptr<InstanceHolderBase> result(
|
||||
create_holder(self, ctor_args.get(), keywords));
|
||||
|
||||
self->add_implementation(result);
|
||||
return none();
|
||||
}
|
||||
|
||||
}
|
||||
184
init_function.h
Normal file
184
init_function.h
Normal file
@@ -0,0 +1,184 @@
|
||||
// (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.py
|
||||
|
||||
#ifndef INIT_FUNCTION_DWA052000_H_
|
||||
# define INIT_FUNCTION_DWA052000_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
# include "functions.h"
|
||||
# include "signatures.h"
|
||||
# include <typeinfo>
|
||||
|
||||
namespace py {
|
||||
|
||||
class ExtensionInstance;
|
||||
class InstanceHolderBase;
|
||||
|
||||
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>
|
||||
struct InitFunction
|
||||
{
|
||||
static Init* create(Signature0)
|
||||
{ return new Init0<T>; }
|
||||
|
||||
template <class A1>
|
||||
static Init* create(Signature1<A1>)
|
||||
{ return new Init1<T, A1>; }
|
||||
|
||||
template <class A1, class A2>
|
||||
static Init* create(Signature2<A1, A2>)
|
||||
{ return new Init2<T, A1, A2>; }
|
||||
|
||||
template <class A1, class A2, class A3>
|
||||
static Init* create(Signature3<A1, A2, A3>)
|
||||
{ return new Init3<T, A1, A2, A3>; }
|
||||
|
||||
template <class A1, class A2, class A3, class A4>
|
||||
static Init* create(Signature4<A1, A2, A3, A4>)
|
||||
{ return new Init4<T, A1, A2, A3, A4>; }
|
||||
|
||||
template <class A1, class A2, class A3, class A4, class A5>
|
||||
static Init* create(Signature5<A1, A2, A3, A4, A5>)
|
||||
{ return new Init5<T, A1, A2, A3, A4, A5>; }
|
||||
};
|
||||
|
||||
class Init : public Function
|
||||
{
|
||||
private: // override Function hook
|
||||
PyObject* do_call(PyObject* args, PyObject* keywords) const;
|
||||
private:
|
||||
virtual InstanceHolderBase* create_holder(ExtensionInstance* self, PyObject* tail_args, PyObject* keywords) const = 0;
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
struct Init0 : Init
|
||||
{
|
||||
virtual InstanceHolderBase* create_holder(ExtensionInstance* self, PyObject* args, PyObject* /*keywords*/) const
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("")))
|
||||
throw ArgumentError();
|
||||
return new T(self
|
||||
);
|
||||
}
|
||||
const char* description() const
|
||||
{ return typeid(void (*)()).name(); }
|
||||
};
|
||||
|
||||
template <class T, class A1>
|
||||
struct Init1 : Init
|
||||
{
|
||||
virtual InstanceHolderBase* create_holder(ExtensionInstance* self, PyObject* args, PyObject* /*keywords*/) const
|
||||
{
|
||||
PyObject* a1;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("O"), &a1))
|
||||
throw ArgumentError();
|
||||
return new T(self,
|
||||
from_python(a1, Type<A1>())
|
||||
);
|
||||
}
|
||||
const char* description() const
|
||||
{ return typeid(void (*)(A1)).name(); }
|
||||
};
|
||||
|
||||
template <class T, class A1, class A2>
|
||||
struct Init2 : Init
|
||||
{
|
||||
virtual InstanceHolderBase* create_holder(ExtensionInstance* self, PyObject* args, PyObject* /*keywords*/) const
|
||||
{
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OO"), &a1, &a2))
|
||||
throw ArgumentError();
|
||||
return new T(self,
|
||||
from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>())
|
||||
);
|
||||
}
|
||||
const char* description() const
|
||||
{ return typeid(void (*)(A1, A2)).name(); }
|
||||
};
|
||||
|
||||
template <class T, class A1, class A2, class A3>
|
||||
struct Init3 : Init
|
||||
{
|
||||
virtual InstanceHolderBase* create_holder(ExtensionInstance* self, PyObject* args, PyObject* /*keywords*/) const
|
||||
{
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOO"), &a1, &a2, &a3))
|
||||
throw ArgumentError();
|
||||
return new T(self,
|
||||
from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>())
|
||||
);
|
||||
}
|
||||
const char* description() const
|
||||
{ return typeid(void (*)(A1, A2, A3)).name(); }
|
||||
};
|
||||
|
||||
template <class T, class A1, class A2, class A3, class A4>
|
||||
struct Init4 : Init
|
||||
{
|
||||
virtual InstanceHolderBase* create_holder(ExtensionInstance* 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 ArgumentError();
|
||||
return new T(self,
|
||||
from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>())
|
||||
);
|
||||
}
|
||||
const char* description() const
|
||||
{ return typeid(void (*)(A1, A2, A3, A4)).name(); }
|
||||
};
|
||||
|
||||
template <class T, class A1, class A2, class A3, class A4, class A5>
|
||||
struct Init5 : Init
|
||||
{
|
||||
virtual InstanceHolderBase* create_holder(ExtensionInstance* 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 ArgumentError();
|
||||
return new T(self,
|
||||
from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>()),
|
||||
from_python(a4, Type<A4>()),
|
||||
from_python(a5, Type<A5>())
|
||||
);
|
||||
}
|
||||
const char* description() const
|
||||
{ return typeid(void (*)(A1, A2, A3, A4, A5)).name(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // INIT_FUNCTION_DWA052000_H_
|
||||
2
init_function_d.cpp
Normal file
2
init_function_d.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#define DEBUG_PYTHON
|
||||
#include "init_function.cpp"
|
||||
48
makefile
Normal file
48
makefile
Normal file
@@ -0,0 +1,48 @@
|
||||
#########################################################
|
||||
#
|
||||
# makefile - Manhattan py_cpp makefile
|
||||
#
|
||||
# Author: David Abrahams
|
||||
# Date: 04-May-2000
|
||||
# Copyright (c) 2000 Dragon Systems, Inc.
|
||||
#
|
||||
# Revision history at bottom.
|
||||
#
|
||||
#########################################################
|
||||
|
||||
# Set up $(ROOT_DIR)
|
||||
include ../make/userdirs.mak
|
||||
include $(ROOT_DIR)/make/common.mak
|
||||
include $(ROOT_DIR)/python/pythonhelp.mak
|
||||
include $(ROOT_DIR)/utils/utilhelp.mak
|
||||
include $(ROOT_DIR)/py_cpp/py_cpphelp.mak
|
||||
|
||||
MAKEFILE_INCLUDES = $(PYTHON_INCLUDES)
|
||||
|
||||
# Look in this directory, then the output subdirectory (BIN_DIR) for modules to load without qualification.
|
||||
export PYTHONPATH := $(THISDIR)$(PYTHONPATH_SEP)$(THISDIR)/$(BIN_DIR)$(PYTHONPATH_SEP)$(PYTHONPATH)
|
||||
|
||||
# In order to get the automatic dependency generation working correctly, it
|
||||
# is necessary to list the source files here.
|
||||
SRC_FILES = extclass.cpp init_function.cpp subclass.cpp functions.cpp module.cpp newtypes.cpp py.cpp objects.cpp
|
||||
SRC_FILES += extclass_demo.cpp example1.cpp
|
||||
|
||||
SRC_FILES += extclass_d.cpp init_function_d.cpp subclass_d.cpp functions_d.cpp module_d.cpp newtypes_d.cpp py_d.cpp objects_d.cpp
|
||||
SRC_FILES += extclass_demo_d.cpp
|
||||
LIBS=$(PYTHON_LIB) $(PYTHON_D_LIB)
|
||||
|
||||
test : demo
|
||||
$(PYTHON_EXE) test_extclass.py $(ARGS)
|
||||
|
||||
test_d : demo_d
|
||||
$(DEBUGGER) $(PYTHON_D_EXE) test_extclass.py $(ARGS)
|
||||
|
||||
ifndef PYTHON_D_LIB
|
||||
PYTHON_D_LIB = $(SPACE_CHAR)
|
||||
endif
|
||||
|
||||
-include py_cpp.mk1
|
||||
-include py_cpp_d.mk1
|
||||
-include demo.mk1
|
||||
-include demo_d.mk1
|
||||
-include example1.mk1
|
||||
39
module.cpp
Normal file
39
module.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// (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 "module.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
Module::Module(const char* name)
|
||||
: m_module(Py_InitModule(const_cast<char*>(name), initial_methods))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Module::add(Function* x, const char* name)
|
||||
{
|
||||
PyPtr<Function> f(x); // First take possession of the object.
|
||||
Function::add_to_namespace(f, name, PyModule_GetDict(m_module));
|
||||
}
|
||||
|
||||
void Module::add(Ptr x, const char* name)
|
||||
{
|
||||
PyObject* dictionary = PyModule_GetDict( m_module );
|
||||
PyDict_SetItemString(dictionary, const_cast<char*>(name), x.get());
|
||||
};
|
||||
|
||||
void Module::add(PyTypeObject* x, const char* name /*= 0*/)
|
||||
{
|
||||
this->add(Ptr(as_object(x), Ptr::new_ref),
|
||||
name ? name : x->tp_name);
|
||||
}
|
||||
|
||||
PyMethodDef Module::initial_methods[] = { { 0, 0, 0, 0 } };
|
||||
|
||||
}
|
||||
43
module.h
Normal file
43
module.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// (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 "pyconfig.h"
|
||||
# include "pyptr.h"
|
||||
# include "functions.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
class ExtensionType;
|
||||
|
||||
class Module
|
||||
{
|
||||
public:
|
||||
Module(const char* name);
|
||||
|
||||
void add(Function* x, const char* name);
|
||||
|
||||
void add(PyTypeObject* x, const char* name = 0);
|
||||
|
||||
void add(Ptr x, const char*name);
|
||||
|
||||
template <class Fn>
|
||||
void def(Fn fn, const char* name)
|
||||
{
|
||||
add(new_wrapped_function(fn), name);
|
||||
}
|
||||
private:
|
||||
PyObject* m_module;
|
||||
static PyMethodDef initial_methods[1];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
2
module_d.cpp
Normal file
2
module_d.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#define DEBUG_PYTHON
|
||||
#include "module.cpp"
|
||||
628
newtypes.cpp
Normal file
628
newtypes.cpp
Normal file
@@ -0,0 +1,628 @@
|
||||
// (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 "newtypes.h"
|
||||
#include "pyptr.h" // for handle_exception()
|
||||
#include "module.h"
|
||||
#include "none.h"
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <boost/smart_ptr.hpp>
|
||||
#include "objects.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
namespace detail {
|
||||
UniquePodSet& UniquePodSet::instance()
|
||||
{
|
||||
static UniquePodSet me;
|
||||
return me;
|
||||
}
|
||||
|
||||
struct UniquePodSet::Compare
|
||||
{
|
||||
bool operator()(const std::pair<const char*, const char*>& x1,
|
||||
const std::pair<const char*, const char*>& x2) const
|
||||
{
|
||||
const std::ptrdiff_t n1 = x1.second - x1.first;
|
||||
const std::ptrdiff_t n2 = x2.second - x2.first;
|
||||
return n1 < n2 || n1 == n2 && PY_CSTD_::memcmp(x1.first, x2.first, n1) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
const void* UniquePodSet::get_element(const void* buffer, std::size_t size)
|
||||
{
|
||||
const Holder element(static_cast<const char*>(buffer),
|
||||
static_cast<const char*>(buffer) + size);
|
||||
|
||||
const Storage::iterator found
|
||||
= std::lower_bound(m_storage.begin(), m_storage.end(), element, Compare());
|
||||
|
||||
if (found != m_storage.end() && !Compare()(element, *found))
|
||||
return found->first;
|
||||
|
||||
std::size_t length = element.second - element.first;
|
||||
char* base_address = new char[length];
|
||||
try {
|
||||
PY_CSTD_::memcpy(base_address, element.first, length);
|
||||
Holder new_element(base_address, base_address + length);
|
||||
m_storage.insert(found, new_element);
|
||||
}
|
||||
catch(...) {
|
||||
delete[] base_address;
|
||||
throw;
|
||||
}
|
||||
return base_address;
|
||||
}
|
||||
|
||||
UniquePodSet::~UniquePodSet()
|
||||
{
|
||||
for (Storage::const_iterator p = m_storage.begin(), finish = m_storage.end();
|
||||
p != finish; ++p)
|
||||
{
|
||||
delete[] const_cast<char*>(p->first);
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <class MethodStruct, class MemberPtr, class Fn>
|
||||
static MethodStruct* enable_method(const MethodStruct* base, MemberPtr p, Fn f)
|
||||
{
|
||||
MethodStruct new_value;
|
||||
|
||||
if (base != 0)
|
||||
new_value = *base;
|
||||
else
|
||||
PY_CSTD_::memset(&new_value, 0, sizeof(PyMappingMethods));
|
||||
|
||||
new_value.*p = f;
|
||||
|
||||
return const_cast<MethodStruct*>(detail::UniquePodSet::instance().get(new_value));
|
||||
}
|
||||
|
||||
// TODO: is there a problem with calling convention here, or can I really pass a
|
||||
// pointer to a C++ linkage function as a C-linkage function pointer? The
|
||||
// compilers seem to swallow it, but is it legal? Symantec C++ for Mac didn't
|
||||
// behave this way, FWIW.
|
||||
// Using C++ linkage allows us to keep the virtual function members of
|
||||
// TypeObjectBase private and use friendship to get them called.
|
||||
|
||||
extern "C" {
|
||||
|
||||
static PyObject* do_instance_repr(PyObject* instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_repr(instance);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_instance_compare(PyObject* instance, PyObject* other)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_compare(instance, other);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject* do_instance_str(PyObject* instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_str(instance);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static long do_instance_hash(PyObject* instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_hash(instance);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject* do_instance_call(PyObject* instance, PyObject* args, PyObject* keywords)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_call(instance, args, keywords);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_instance_dealloc(PyObject* instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_dealloc(instance);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
assert(!"exception during destruction!");
|
||||
handle_exception();
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject* do_instance_getattr(PyObject* instance, char* name)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_getattr(instance, name);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_instance_setattr(PyObject* instance, char* name, PyObject* value)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_setattr(instance, name, value);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_instance_mp_length(PyObject* instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
const int outcome =
|
||||
static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_mapping_length(instance);
|
||||
|
||||
if (outcome < 0)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "__len__() should return >= 0");
|
||||
return -1;
|
||||
}
|
||||
return outcome;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_instance_sq_length(PyObject* instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
const int outcome =
|
||||
static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_sequence_length(instance);
|
||||
|
||||
if (outcome < 0)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "__len__() should return >= 0");
|
||||
return -1;
|
||||
}
|
||||
return outcome;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject* do_instance_mp_subscript(PyObject* instance, PyObject* index)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_mapping_subscript(instance, index);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject* do_instance_sq_item(PyObject* instance, int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
const PyTypeObject* const type = instance->ob_type;
|
||||
|
||||
// This is an extension to standard class behavior. If sequence_length
|
||||
// is implemented and n >= sequence_length(), raise an IndexError. That
|
||||
// keeps users from having to worry about raising it themselves
|
||||
if (type->tp_as_sequence != 0 && type->tp_as_sequence->sq_length != 0
|
||||
&& index >= type->tp_as_sequence->sq_length(instance))
|
||||
{
|
||||
PyErr_SetString(PyExc_IndexError, type->tp_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_sequence_item(instance, index);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_instance_mp_ass_subscript(PyObject* instance, PyObject* index, PyObject* value)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_mapping_ass_subscript(instance, index, value);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_instance_sq_ass_item(PyObject* instance, int index, PyObject* value)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_sequence_ass_item(instance, index, value);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject* do_instance_sq_concat(PyObject* instance, PyObject* other)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_sequence_concat(instance, other);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject* do_instance_sq_repeat(PyObject* instance, int n)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_sequence_repeat(instance, n);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject* do_instance_sq_slice(
|
||||
PyObject* instance, int start, int finish)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_sequence_slice(instance, start, finish);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int do_instance_sq_ass_slice(
|
||||
PyObject* instance, int start, int finish, PyObject* value)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<TypeObjectBase*>(instance->ob_type)
|
||||
->instance_sequence_ass_slice(instance, start, finish, value);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handle_exception();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <std::size_t> struct category_type;
|
||||
|
||||
#define DECLARE_CAPABILITY_TYPE(field, sub_structure) \
|
||||
template <> \
|
||||
struct category_type<(offsetof(PyTypeObject, tp_as_##field))> \
|
||||
{ \
|
||||
typedef sub_structure type; \
|
||||
}
|
||||
|
||||
#define CAPABILITY(field) \
|
||||
{ offsetof(PyTypeObject, tp_##field), 0, Dispatch(do_instance_##field), 0, -1 }
|
||||
|
||||
#define CAPABILITY2(category, field) \
|
||||
{ offsetof(PyTypeObject, tp_as_##category), \
|
||||
offsetof(category_type<offsetof(PyTypeObject, tp_as_##category)>::type, field), \
|
||||
Dispatch(do_instance_##field), \
|
||||
sizeof(category_type<offsetof(PyTypeObject, tp_as_##category)>::type), \
|
||||
offsetof(AllMethods, category) \
|
||||
}
|
||||
|
||||
DECLARE_CAPABILITY_TYPE(mapping, PyMappingMethods);
|
||||
DECLARE_CAPABILITY_TYPE(sequence, PySequenceMethods);
|
||||
|
||||
const CapabilityEntry capabilities[] = {
|
||||
CAPABILITY(hash),
|
||||
CAPABILITY(call),
|
||||
CAPABILITY(str),
|
||||
CAPABILITY(getattr),
|
||||
CAPABILITY(setattr),
|
||||
CAPABILITY(compare),
|
||||
CAPABILITY(repr),
|
||||
|
||||
CAPABILITY2(mapping, mp_length),
|
||||
CAPABILITY2(mapping, mp_subscript),
|
||||
CAPABILITY2(mapping, mp_ass_subscript),
|
||||
|
||||
CAPABILITY2(sequence, sq_length),
|
||||
CAPABILITY2(sequence, sq_item),
|
||||
CAPABILITY2(sequence, sq_ass_item),
|
||||
CAPABILITY2(sequence, sq_concat),
|
||||
CAPABILITY2(sequence, sq_repeat),
|
||||
CAPABILITY2(sequence, sq_slice),
|
||||
CAPABILITY2(sequence, sq_ass_slice)
|
||||
};
|
||||
|
||||
const std::size_t num_capabilities = PY_ARRAY_LENGTH(capabilities);
|
||||
|
||||
void add_capability(
|
||||
std::size_t n,
|
||||
PyTypeObject* dest_,
|
||||
AllMethods& all_methods,
|
||||
const PyTypeObject* src_)
|
||||
{
|
||||
assert(n < PY_ARRAY_LENGTH(capabilities));
|
||||
const CapabilityEntry& c = capabilities[n];
|
||||
|
||||
const char* const* src = src_ ? reinterpret_cast<const char* const*>(
|
||||
reinterpret_cast<const char*>(src_) + c.offset1) : 0;
|
||||
|
||||
char** const dest = reinterpret_cast<char**>(
|
||||
reinterpret_cast<char*>(dest_) + c.offset1);
|
||||
|
||||
if (c.substructure_size == 0)
|
||||
{
|
||||
if (src == 0 ||
|
||||
#if defined(__MWERKS__) && __MWERKS__ <= 0x4000
|
||||
((const Dispatch*)src)
|
||||
#else
|
||||
reinterpret_cast<const Dispatch*>(src)
|
||||
#endif
|
||||
!= 0) {
|
||||
*reinterpret_cast<Dispatch*>(dest) = c.dispatch;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (src == 0 ||
|
||||
*src != 0 && *reinterpret_cast<const Dispatch*>(*src + c.offset2) != 0)
|
||||
{
|
||||
*dest = reinterpret_cast<char*>(&all_methods) + c.allmethods_offset;
|
||||
*reinterpret_cast<Dispatch*>(*dest + c.offset2) = c.dispatch;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
namespace {
|
||||
union SubStructures {
|
||||
PyMappingMethods mapping;
|
||||
PySequenceMethods sequence;
|
||||
PyNumberMethods number;
|
||||
PyBufferProcs buffer;
|
||||
};
|
||||
}
|
||||
|
||||
void TypeObjectBase::enable(TypeObjectBase::Capability capability)
|
||||
{
|
||||
using detail::capabilities;
|
||||
using detail::CapabilityEntry;
|
||||
using detail::Dispatch;
|
||||
|
||||
assert((std::size_t)capability < PY_ARRAY_LENGTH(capabilities));
|
||||
const CapabilityEntry& c = capabilities[capability];
|
||||
|
||||
PyTypeObject* const me = this;
|
||||
char* const base_address = reinterpret_cast<char*>(me);
|
||||
|
||||
if (c.substructure_size == 0)
|
||||
{
|
||||
// Stuff the dispatch function directly into the PyTypeObject
|
||||
*reinterpret_cast<Dispatch*>(base_address + c.offset1) = c.dispatch;
|
||||
return;
|
||||
}
|
||||
|
||||
const char*& sub_structure = *reinterpret_cast<const char**>(base_address + c.offset1);
|
||||
|
||||
// Initialize this POD union with the current state-of-the-world
|
||||
SubStructures sub;
|
||||
if (sub_structure == 0)
|
||||
PY_CSTD_::memset(&sub, 0, c.substructure_size);
|
||||
else
|
||||
PY_CSTD_::memcpy(&sub, sub_structure, c.substructure_size);
|
||||
|
||||
// Stuff the dispatch function into the sub-structure
|
||||
*reinterpret_cast<Dispatch*>(reinterpret_cast<char*>(&sub) + c.offset2) = c.dispatch;
|
||||
|
||||
// Retrieve the unique dynamically-allocated substructure and stuff it into
|
||||
// the PyTypeObject.
|
||||
sub_structure = static_cast<const char*>(
|
||||
detail::UniquePodSet::instance().get_element(&sub, c.substructure_size));
|
||||
}
|
||||
|
||||
|
||||
TypeObjectBase::TypeObjectBase(PyTypeObject* t)
|
||||
: PythonType(t)
|
||||
{
|
||||
this->tp_dealloc = do_instance_dealloc;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct ErrorType {
|
||||
operator PyObject*() const { return 0; }
|
||||
operator int() const { return -1; }
|
||||
};
|
||||
|
||||
ErrorType unimplemented(const char* name)
|
||||
{
|
||||
assert(!"Control should never reach here");
|
||||
String s("Unimplemented ");
|
||||
s += String(name);
|
||||
PyErr_SetObject(PyExc_RuntimeError, s.get());
|
||||
return ErrorType();
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* TypeObjectBase::instance_repr(PyObject*) const
|
||||
{
|
||||
return unimplemented("instance_repr");
|
||||
}
|
||||
|
||||
int TypeObjectBase::instance_compare(PyObject*, PyObject*) const
|
||||
{
|
||||
return unimplemented("instance_compare");
|
||||
}
|
||||
|
||||
PyObject* TypeObjectBase::instance_str(PyObject*) const
|
||||
{
|
||||
return unimplemented("instance_str");
|
||||
}
|
||||
|
||||
long TypeObjectBase::instance_hash(PyObject* /* instance */) const
|
||||
{
|
||||
return unimplemented("instance_hash");
|
||||
}
|
||||
|
||||
PyObject* TypeObjectBase::instance_call(PyObject* /*instance*/, PyObject* /*args*/, PyObject* /*kw*/) const
|
||||
{
|
||||
return unimplemented("instance_call");
|
||||
}
|
||||
|
||||
PyObject* TypeObjectBase::instance_getattr(PyObject* /*instance*/, const char* /*name*/) const
|
||||
{
|
||||
return unimplemented("instance_getattr");
|
||||
}
|
||||
|
||||
int TypeObjectBase::instance_setattr(PyObject* /*instance*/, const char* /*name*/, PyObject* /*value*/) const
|
||||
{
|
||||
return unimplemented("instance_setattr");
|
||||
}
|
||||
|
||||
int TypeObjectBase::instance_mapping_length(PyObject*) const
|
||||
{
|
||||
return unimplemented("instance_mapping_length");
|
||||
}
|
||||
|
||||
int TypeObjectBase::instance_sequence_length(PyObject*) const
|
||||
{
|
||||
return unimplemented("instance_sequence_length");
|
||||
}
|
||||
|
||||
PyObject* TypeObjectBase::instance_mapping_subscript(PyObject*, PyObject*) const
|
||||
{
|
||||
return unimplemented("instance_mapping_subscript");
|
||||
}
|
||||
|
||||
PyObject* TypeObjectBase::instance_sequence_item(PyObject*, int) const
|
||||
{
|
||||
return unimplemented("instance_sequence_item");
|
||||
}
|
||||
|
||||
int TypeObjectBase::instance_mapping_ass_subscript(PyObject*, PyObject*, PyObject*) const
|
||||
{
|
||||
return unimplemented("instance_mapping_ass_subscript");
|
||||
}
|
||||
|
||||
int TypeObjectBase::instance_sequence_ass_item(PyObject*, int, PyObject*) const
|
||||
{
|
||||
return unimplemented("instance_sequence_ass_item");
|
||||
}
|
||||
|
||||
PyObject* TypeObjectBase::instance_sequence_concat(PyObject*, PyObject*) const
|
||||
{
|
||||
return unimplemented("instance_sequence_concat");
|
||||
}
|
||||
|
||||
PyObject* TypeObjectBase::instance_sequence_repeat(PyObject*, int) const
|
||||
{
|
||||
return unimplemented("instance_sequence_repeat");
|
||||
}
|
||||
|
||||
PyObject* TypeObjectBase::instance_sequence_slice(PyObject*, int, int) const
|
||||
{
|
||||
return unimplemented("instance_sequence_slice");
|
||||
}
|
||||
|
||||
int TypeObjectBase::instance_sequence_ass_slice(PyObject*, int, int, PyObject*) const
|
||||
{
|
||||
return unimplemented("instance_sequence_ass_slice");
|
||||
}
|
||||
|
||||
TypeObjectBase::~TypeObjectBase()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
264
newtypes.h
Normal file
264
newtypes.h
Normal file
@@ -0,0 +1,264 @@
|
||||
// (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
|
||||
// py::Callable<
|
||||
// py::Getattrable <
|
||||
// py::Setattrable<PythonObject, X> > >
|
||||
// {
|
||||
// public:
|
||||
// Ptr call(args, kw);
|
||||
// Ptr getattr(args, kw);
|
||||
// Ptr setattr(args, kw);
|
||||
// };
|
||||
|
||||
# include "pyconfig.h"
|
||||
# include "signatures.h" // really just for Type<>
|
||||
# include "cast.h"
|
||||
# include "base_object.h"
|
||||
# include <typeinfo>
|
||||
# include <vector>
|
||||
|
||||
namespace py {
|
||||
|
||||
class TypeObjectBase : public PythonType
|
||||
{
|
||||
public:
|
||||
explicit TypeObjectBase(PyTypeObject* type_type);
|
||||
virtual ~TypeObjectBase();
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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* instance, PyObject* args, PyObject* kw) const;
|
||||
virtual PyObject* instance_getattr(PyObject* instance, const char* name) const;
|
||||
virtual int instance_setattr(PyObject* instance, 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* instance) const;
|
||||
virtual PyObject* instance_sequence_concat(PyObject* instance, PyObject* other) const;
|
||||
virtual PyObject* instance_sequence_repeat(PyObject* instance, int n) const;
|
||||
virtual PyObject* instance_sequence_item(PyObject* instance, int n) const;
|
||||
virtual PyObject* instance_sequence_slice(PyObject* instance, int start, int finish) const;
|
||||
virtual int instance_sequence_ass_item(PyObject* instance, int n, PyObject* value) const;
|
||||
virtual int instance_sequence_ass_slice(PyObject* instance, int start, int finish, PyObject* value) const;
|
||||
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class TypeObject : public TypeObjectBase
|
||||
{
|
||||
public:
|
||||
typedef T Instance;
|
||||
|
||||
TypeObject(PyTypeObject* type_type, const char* name = 0)
|
||||
: TypeObjectBase(type_type)
|
||||
{
|
||||
this->tp_name = const_cast<char*>(name ? name : 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 TypeObjectBase 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 = 0);
|
||||
private:
|
||||
PyObject* instance_call(PyObject* instance, 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 = 0);
|
||||
private:
|
||||
PyObject* instance_getattr(PyObject* instance, 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 = 0);
|
||||
private:
|
||||
int instance_setattr(PyObject* instance, const char* name, PyObject* value) const;
|
||||
};
|
||||
|
||||
//
|
||||
// Member function definitions
|
||||
//
|
||||
|
||||
// TypeObject<>
|
||||
template <class T>
|
||||
void TypeObject<T>::instance_dealloc(PyObject* instance) const
|
||||
{
|
||||
this->dealloc(Downcast<Instance>(instance).get());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void TypeObject<T>::dealloc(T* instance) const
|
||||
{
|
||||
delete instance;
|
||||
}
|
||||
|
||||
// Callable
|
||||
template <class Base>
|
||||
Callable<Base>::Callable(PyTypeObject* type_type, const char* name)
|
||||
: Base(type_type, name)
|
||||
{
|
||||
this->enable(call);
|
||||
}
|
||||
|
||||
template <class Base>
|
||||
PyObject* Callable<Base>::instance_call(PyObject* instance, PyObject* args, PyObject* kw) const
|
||||
{
|
||||
return Downcast<Instance>(instance)->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>
|
||||
PyObject* Getattrable<Base>::instance_getattr(PyObject* instance, const char* name) const
|
||||
{
|
||||
return Downcast<Instance>(instance)->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>
|
||||
int Setattrable<Base>::instance_setattr(PyObject* instance, const char* name, PyObject* value) const
|
||||
{
|
||||
return Downcast<Instance>(instance)->setattr(name, value);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct AllMethods {
|
||||
PyMappingMethods mapping;
|
||||
PySequenceMethods sequence;
|
||||
PyNumberMethods number;
|
||||
PyBufferProcs buffer;
|
||||
};
|
||||
|
||||
typedef void (*Dispatch)();
|
||||
struct CapabilityEntry
|
||||
{
|
||||
std::size_t offset1;
|
||||
std::size_t offset2;
|
||||
Dispatch dispatch;
|
||||
std::size_t substructure_size;
|
||||
int allmethods_offset;
|
||||
};
|
||||
|
||||
extern const CapabilityEntry capabilities[];
|
||||
extern const std::size_t num_capabilities;
|
||||
|
||||
void add_capability(std::size_t index, PyTypeObject* dest, AllMethods&, const PyTypeObject* src = 0);
|
||||
|
||||
class UniquePodSet
|
||||
{
|
||||
typedef std::pair<const char*, const char*> Holder;
|
||||
typedef std::vector<Holder> Storage;
|
||||
public:
|
||||
static UniquePodSet& instance();
|
||||
~UniquePodSet();
|
||||
|
||||
template <class T>
|
||||
T* get(const T& x)
|
||||
{
|
||||
char* base = const_cast<char*>(
|
||||
reinterpret_cast<const char*>(&x));
|
||||
return const_cast<T*>(
|
||||
static_cast<const T*>(
|
||||
get_element(base, sizeof(T))));
|
||||
}
|
||||
|
||||
const void* get_element(const void* buffer, std::size_t size);
|
||||
|
||||
private:
|
||||
struct Compare;
|
||||
|
||||
private:
|
||||
UniquePodSet() {} // singleton
|
||||
|
||||
private:
|
||||
Storage m_storage;
|
||||
};
|
||||
|
||||
# define PY_ARRAY_LENGTH(a) \
|
||||
(sizeof(::py::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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // TYPES_DWA051800_H_
|
||||
2
newtypes_d.cpp
Normal file
2
newtypes_d.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#define DEBUG_PYTHON
|
||||
#include "newtypes.cpp"
|
||||
21
none.h
Normal file
21
none.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#ifndef NONE_DWA_052000_H_
|
||||
# define NONE_DWA_052000_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
# include "wrap_python.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
inline PyObject* none() { Py_INCREF(Py_None); return Py_None; }
|
||||
|
||||
}
|
||||
|
||||
#endif // NONE_DWA_052000_H_
|
||||
454
objects.cpp
Normal file
454
objects.cpp
Normal file
@@ -0,0 +1,454 @@
|
||||
// (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 "objects.h"
|
||||
#include "none.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
template <class T>
|
||||
T object_from_python(PyObject* p, Type<T>)
|
||||
{
|
||||
Ptr x(p);
|
||||
if (!T::accepts(x))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
|
||||
throw ErrorAlreadySet();
|
||||
}
|
||||
return T(x);
|
||||
}
|
||||
|
||||
inline PyObject* object_to_python(const Object& x)
|
||||
{
|
||||
return x.reference().release();
|
||||
}
|
||||
|
||||
Object::Object(Ptr p)
|
||||
: m_p(p) {}
|
||||
|
||||
// Return a reference to the held object
|
||||
Ptr Object::reference() const
|
||||
{
|
||||
return m_p;
|
||||
}
|
||||
|
||||
// Return a raw pointer to the held object
|
||||
PyObject* Object::get() const
|
||||
{
|
||||
return m_p.get();
|
||||
}
|
||||
|
||||
#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE
|
||||
} // Back to the global namespace for this GCC bug
|
||||
#endif
|
||||
|
||||
PyObject* to_python(const py::Tuple& x)
|
||||
{
|
||||
return object_to_python(x);
|
||||
}
|
||||
|
||||
py::Tuple from_python(PyObject* p, py::Type<py::Tuple> type)
|
||||
{
|
||||
return py::object_from_python(p, type);
|
||||
}
|
||||
|
||||
PyObject* to_python(const py::List& x)
|
||||
{
|
||||
return object_to_python(x);
|
||||
}
|
||||
|
||||
py::List from_python(PyObject* p, py::Type<py::List> type)
|
||||
{
|
||||
return py::object_from_python(p, type);
|
||||
}
|
||||
|
||||
PyObject* to_python(const py::Dict& x)
|
||||
{
|
||||
return object_to_python(x);
|
||||
}
|
||||
|
||||
py::Dict from_python(PyObject* p, py::Type<py::Dict> type)
|
||||
{
|
||||
return py::object_from_python(p, type);
|
||||
}
|
||||
|
||||
PyObject* to_python(const py::String& x)
|
||||
{
|
||||
return object_to_python(x);
|
||||
}
|
||||
|
||||
py::String from_python(PyObject* p, py::Type<py::String> type)
|
||||
{
|
||||
return py::object_from_python(p, type);
|
||||
}
|
||||
|
||||
#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE
|
||||
namespace py {
|
||||
#endif
|
||||
|
||||
Tuple::Tuple(std::size_t n)
|
||||
: Object(Ptr(PyTuple_New(n)))
|
||||
{
|
||||
for (std::size_t i = 0; i < n; ++i)
|
||||
PyTuple_SET_ITEM(get(), i, none());
|
||||
}
|
||||
|
||||
Tuple::Tuple(Ptr p)
|
||||
: Object(p)
|
||||
{
|
||||
assert(accepts(p));
|
||||
}
|
||||
|
||||
PyTypeObject* Tuple::type_object()
|
||||
{
|
||||
return &PyTuple_Type;
|
||||
}
|
||||
|
||||
bool Tuple::accepts(Ptr p)
|
||||
{
|
||||
return PyTuple_Check(p.get());
|
||||
}
|
||||
|
||||
std::size_t Tuple::size() const
|
||||
{
|
||||
return PyTuple_Size(get());
|
||||
}
|
||||
|
||||
Ptr Tuple::operator[](std::size_t pos) const
|
||||
{
|
||||
return Ptr(PyTuple_GetItem(get(), static_cast<int>(pos)),
|
||||
Ptr::new_ref);
|
||||
}
|
||||
|
||||
void Tuple::set_item(std::size_t pos, const Ptr& rhs)
|
||||
{
|
||||
int failed = PyTuple_SetItem(
|
||||
get(), static_cast<int>(pos), Ptr(rhs).release()); // A reference is stolen here.
|
||||
(void)failed;
|
||||
assert(failed == 0);
|
||||
}
|
||||
|
||||
Tuple Tuple::slice(int low, int high) const
|
||||
{
|
||||
return Tuple(Ptr(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(Ptr p)
|
||||
: Object(p) { assert(accepts(p)); }
|
||||
|
||||
String::String(const char* s)
|
||||
: Object(Ptr(PyString_FromString(s))) {}
|
||||
|
||||
String::String(const char* s, std::size_t length)
|
||||
: Object(Ptr(PyString_FromStringAndSize(s, length))) {}
|
||||
|
||||
String::String(const char* s, Interned)
|
||||
: Object(Ptr(PyString_InternFromString(s))) {}
|
||||
|
||||
#if 0
|
||||
String::String(const char* s, std::size_t length, Interned)
|
||||
: Object(Ptr(PyString_InternFromStringAndSize(s, length))) {}
|
||||
#endif
|
||||
|
||||
String::String(const String& rhs)
|
||||
: Object(rhs.reference()) {}
|
||||
|
||||
// Get the type object for Strings
|
||||
PyTypeObject* String::type_object()
|
||||
{ return &PyString_Type; }
|
||||
|
||||
// Return true if the given object is a python String
|
||||
bool String::accepts(Ptr 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(Ptr(PyString_InternFromString(c_str()), Ptr::borrowed));
|
||||
}
|
||||
|
||||
Dict::Dict(Ptr p)
|
||||
: Object(p) { assert(accepts(p)); }
|
||||
|
||||
Dict::Dict()
|
||||
: Object(Ptr(PyDict_New())) {}
|
||||
|
||||
PyTypeObject* Dict::type_object()
|
||||
{ return &PyDict_Type; }
|
||||
|
||||
bool Dict::accepts(Ptr p)
|
||||
{ return PyDict_Check(p.get()); }
|
||||
|
||||
void Dict::clear()
|
||||
{ PyDict_Clear(get()); }
|
||||
|
||||
const Ptr& Dict::Proxy::operator=(const Ptr& rhs) {
|
||||
if (PyDict_SetItem(m_dict.get(), m_key.get(), rhs.get()) == -1)
|
||||
throw ErrorAlreadySet();
|
||||
return rhs;
|
||||
}
|
||||
|
||||
Dict::Proxy::operator Ptr() const
|
||||
{
|
||||
return Ptr(m_dict->ob_type->tp_as_mapping->mp_subscript(m_dict.get(), m_key.get()),
|
||||
Ptr::borrowed);
|
||||
}
|
||||
|
||||
Dict::Proxy::Proxy(const Ptr& dict, const Ptr& key)
|
||||
: m_dict(dict), m_key(key) {}
|
||||
|
||||
Dict::Proxy Dict::operator[](Ptr key)
|
||||
{ return Proxy(reference(), key); }
|
||||
|
||||
Ptr Dict::operator[](Ptr key) const {
|
||||
// An odd MSVC bug causes the ".operator Ptr()" to be needed
|
||||
return Proxy(reference(), key).operator Ptr();
|
||||
}
|
||||
|
||||
|
||||
Ptr Dict::get_item(const Ptr& key, const Ptr& _default /* = Ptr() */)
|
||||
{
|
||||
PyObject* value_or_null = PyDict_GetItem(get(), key.get());
|
||||
if (value_or_null == 0 && !PyErr_Occurred())
|
||||
return _default;
|
||||
else
|
||||
return Ptr(value_or_null, Ptr::borrowed); // Will throw if there was another error
|
||||
}
|
||||
|
||||
void Dict::erase(Ptr key) {
|
||||
if (PyDict_DelItem(get(), key.get()) == -1)
|
||||
throw ErrorAlreadySet();
|
||||
}
|
||||
|
||||
Ptr Dict::items() const { return Ptr(PyDict_Items(get())); }
|
||||
Ptr Dict::keys() const { return Ptr(PyDict_Keys(get())); }
|
||||
Ptr Dict::values() const { return Ptr(PyDict_Values(get())); }
|
||||
|
||||
std::size_t Dict::size() const { return static_cast<std::size_t>(PyDict_Size(get())); }
|
||||
|
||||
Dict::Proxy Dict::operator[](const Object& key)
|
||||
{
|
||||
return this->operator[](key.reference());
|
||||
}
|
||||
|
||||
Ptr Dict::operator[](const Object& key) const
|
||||
{
|
||||
return this->operator[](key.reference());
|
||||
}
|
||||
|
||||
Ptr Dict::get_item(const Object& key, Ptr default_)
|
||||
{
|
||||
return this->get_item(key.reference(), default_);
|
||||
}
|
||||
|
||||
void Dict::erase(const Object& key)
|
||||
{
|
||||
this->erase(key.reference());
|
||||
}
|
||||
|
||||
|
||||
// TODO: iterator support
|
||||
|
||||
String operator+(String x, String y)
|
||||
{
|
||||
PyObject* io_string = x.reference().release();
|
||||
PyString_Concat(&io_string, y.get());
|
||||
return String(Ptr(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(Ptr(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(Ptr p)
|
||||
: Object(p)
|
||||
{
|
||||
assert(accepts(p));
|
||||
}
|
||||
|
||||
List::List(std::size_t sz)
|
||||
: Object(Ptr(PyList_New(sz)))
|
||||
{
|
||||
}
|
||||
|
||||
PyTypeObject* List::type_object()
|
||||
{
|
||||
return &PyList_Type;
|
||||
}
|
||||
|
||||
bool List::accepts(Ptr p)
|
||||
{
|
||||
return PyList_Check(p.get());
|
||||
}
|
||||
|
||||
std::size_t List::size()
|
||||
{
|
||||
return PyList_Size(get());
|
||||
}
|
||||
|
||||
Ptr List::operator[](std::size_t pos) const
|
||||
{
|
||||
return Ptr(PyList_GetItem(get(), pos), Ptr::borrowed);
|
||||
}
|
||||
|
||||
List::Proxy List::operator[](std::size_t pos)
|
||||
{
|
||||
return Proxy(reference(), pos);
|
||||
}
|
||||
|
||||
void List::insert(std::size_t index, Ptr item)
|
||||
{
|
||||
if (PyList_Insert(get(), index, item.get()) == -1)
|
||||
throw ErrorAlreadySet();
|
||||
}
|
||||
|
||||
void List::push_back(Ptr item)
|
||||
{
|
||||
if (PyList_Append(get(), item.get()) == -1)
|
||||
throw ErrorAlreadySet();
|
||||
}
|
||||
|
||||
void List::append(Ptr item)
|
||||
{
|
||||
this->push_back(item);
|
||||
}
|
||||
|
||||
List List::slice(int low, int high) const
|
||||
{
|
||||
return List(Ptr(PyList_GetSlice(get(), low, high)));
|
||||
}
|
||||
|
||||
List::SliceProxy List::slice(int low, int high)
|
||||
{
|
||||
return SliceProxy(reference(), low, high);
|
||||
}
|
||||
|
||||
void List::sort()
|
||||
{
|
||||
if (PyList_Sort(get()) == -1)
|
||||
throw ErrorAlreadySet();
|
||||
}
|
||||
|
||||
void List::reverse()
|
||||
{
|
||||
if (PyList_Reverse(get()) == -1)
|
||||
throw ErrorAlreadySet();
|
||||
}
|
||||
|
||||
Tuple List::as_tuple() const
|
||||
{
|
||||
return Tuple(Ptr(PyList_AsTuple(get())));
|
||||
}
|
||||
|
||||
const Ptr& List::Proxy::operator=(const Ptr& rhs)
|
||||
{
|
||||
int result = PyList_SetItem(m_list.get(), m_index, rhs.get());
|
||||
if (result == -1)
|
||||
throw ErrorAlreadySet();
|
||||
Py_INCREF(rhs.get());
|
||||
return rhs;
|
||||
}
|
||||
|
||||
List::Proxy::operator Ptr() const
|
||||
{
|
||||
return Ptr(PyList_GetItem(m_list.get(), m_index), Ptr::borrowed);
|
||||
}
|
||||
|
||||
List::Proxy::Proxy(const Ptr& list, std::size_t index)
|
||||
: m_list(list), m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
const List& List::SliceProxy::operator=(const List& rhs)
|
||||
{
|
||||
if (PyList_SetSlice(m_list.get(), m_low, m_high, rhs.get()) == -1)
|
||||
throw ErrorAlreadySet();
|
||||
return rhs;
|
||||
}
|
||||
|
||||
List::SliceProxy::operator Ptr() const
|
||||
{
|
||||
return Ptr(PyList_GetSlice(m_list.get(), m_low, m_high));
|
||||
}
|
||||
|
||||
List::SliceProxy::operator List() const
|
||||
{
|
||||
return List(this->operator Ptr());
|
||||
}
|
||||
|
||||
std::size_t List::SliceProxy::size()
|
||||
{
|
||||
return this->operator List().size();
|
||||
}
|
||||
|
||||
Ptr List::SliceProxy::operator[](std::size_t pos) const
|
||||
{
|
||||
return this->operator List()[pos].operator Ptr();
|
||||
}
|
||||
|
||||
List::SliceProxy::SliceProxy(const Ptr& list, int low, int high)
|
||||
: m_list(list), m_low(low), m_high(high)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
233
objects.h
Normal file
233
objects.h
Normal file
@@ -0,0 +1,233 @@
|
||||
// (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 "wrap_python.h"
|
||||
# include "pyconfig.h"
|
||||
# include "pyptr.h"
|
||||
# include "boost/operators.hpp"
|
||||
|
||||
namespace py {
|
||||
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
explicit Object(Ptr p);
|
||||
|
||||
// Return a reference to the held object
|
||||
Ptr reference() const;
|
||||
|
||||
// Return a raw pointer to the held object
|
||||
PyObject* get() const;
|
||||
|
||||
private:
|
||||
Ptr m_p;
|
||||
};
|
||||
|
||||
class Tuple : public Object
|
||||
{
|
||||
public:
|
||||
Tuple(std::size_t n = 0);
|
||||
explicit Tuple(Ptr p);
|
||||
|
||||
Tuple(const Ptr* start, const Ptr* finish); // not yet implemented.
|
||||
|
||||
static PyTypeObject* type_object();
|
||||
static bool accepts(Ptr p);
|
||||
std::size_t size() const;
|
||||
Ptr operator[](std::size_t pos) const;
|
||||
|
||||
void set_item(std::size_t pos, const Ptr& 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 SliceProxy;
|
||||
public:
|
||||
explicit List(Ptr p);
|
||||
explicit List(std::size_t sz = 0);
|
||||
static PyTypeObject* type_object();
|
||||
static bool accepts(Ptr p);
|
||||
std::size_t size();
|
||||
Ptr operator[](std::size_t pos) const;
|
||||
Proxy operator[](std::size_t pos);
|
||||
void insert(std::size_t index, Ptr item);
|
||||
void push_back(Ptr item);
|
||||
void append(Ptr item);
|
||||
List slice(int low, int high) const;
|
||||
SliceProxy slice(int low, int high);
|
||||
void sort();
|
||||
void reverse();
|
||||
Tuple as_tuple() const;
|
||||
};
|
||||
|
||||
class String : public Object
|
||||
{
|
||||
public:
|
||||
// Construct from an owned PyObject*.
|
||||
// Precondition: p must point to a python string.
|
||||
explicit String(Ptr p);
|
||||
explicit String(const char* s);
|
||||
String(const char* s, std::size_t length);
|
||||
String(const String& rhs);
|
||||
|
||||
enum Interned { interned };
|
||||
String(const char* s, Interned);
|
||||
#if 0
|
||||
String(const char* s, std::size_t length, Interned);
|
||||
#endif
|
||||
|
||||
// Get the type object for Strings
|
||||
static PyTypeObject* type_object();
|
||||
|
||||
// Return true if the given object is a python String
|
||||
static bool accepts(Ptr 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+=(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(); // UNTESTED!!
|
||||
|
||||
friend String operator%(const String& format, const Tuple& args);
|
||||
};
|
||||
|
||||
class Dict : public Object
|
||||
{
|
||||
private:
|
||||
struct Proxy;
|
||||
|
||||
public:
|
||||
explicit Dict(Ptr p);
|
||||
Dict();
|
||||
void clear();
|
||||
|
||||
static PyTypeObject* type_object();
|
||||
static bool accepts(Ptr p);
|
||||
|
||||
public:
|
||||
Proxy operator[](Ptr key);
|
||||
Ptr operator[](Ptr key) const;
|
||||
|
||||
Ptr get_item(const Ptr& key, const Ptr& _default = Ptr());
|
||||
|
||||
void erase(Ptr key);
|
||||
|
||||
Proxy operator[](const Object& key);
|
||||
Ptr operator[](const Object& key) const;
|
||||
|
||||
Ptr get_item(const Object& key, Ptr default_ = Ptr());
|
||||
|
||||
void erase(const Object& key);
|
||||
|
||||
Ptr items() const;
|
||||
Ptr keys() const;
|
||||
Ptr values() const;
|
||||
|
||||
std::size_t size() const;
|
||||
// TODO: iterator support
|
||||
};
|
||||
|
||||
struct Dict::Proxy
|
||||
{
|
||||
const Ptr& operator=(const Ptr& rhs);
|
||||
operator Ptr() const;
|
||||
private:
|
||||
friend class Dict;
|
||||
Proxy(const Ptr& dict, const Ptr& key);
|
||||
private:
|
||||
Ptr m_dict;
|
||||
Ptr m_key;
|
||||
};
|
||||
|
||||
struct List::Proxy
|
||||
{
|
||||
const Ptr& operator=(const Ptr& rhs);
|
||||
operator Ptr() const;
|
||||
private:
|
||||
friend class List;
|
||||
Proxy(const Ptr& list, std::size_t index);
|
||||
private:
|
||||
Ptr m_list;
|
||||
std::size_t m_index;
|
||||
};
|
||||
|
||||
struct List::SliceProxy
|
||||
{
|
||||
const List& operator=(const List& rhs);
|
||||
operator Ptr() const;
|
||||
operator List() const;
|
||||
std::size_t size();
|
||||
Ptr operator[](std::size_t pos) const;
|
||||
private:
|
||||
friend class List;
|
||||
SliceProxy(const Ptr& list, int low, int high);
|
||||
private:
|
||||
Ptr m_list;
|
||||
int m_low, m_high;
|
||||
};
|
||||
|
||||
#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE
|
||||
} // Back to the global namespace for this GCC bug
|
||||
#endif
|
||||
|
||||
PyObject* to_python(const py::Tuple&);
|
||||
py::Tuple from_python(PyObject* p, py::Type<py::Tuple>);
|
||||
|
||||
inline py::Tuple from_python(PyObject* p, py::Type<const py::Tuple&>)
|
||||
{
|
||||
return from_python(p, py::Type<py::Tuple>());
|
||||
}
|
||||
|
||||
PyObject* to_python(const py::List&);
|
||||
py::List from_python(PyObject* p, py::Type<py::List>);
|
||||
|
||||
inline py::List from_python(PyObject* p, py::Type<const py::List&>)
|
||||
{
|
||||
return from_python(p, py::Type<py::List>());
|
||||
}
|
||||
|
||||
PyObject* to_python(const py::String&);
|
||||
py::String from_python(PyObject* p, py::Type<py::String>);
|
||||
|
||||
inline py::String from_python(PyObject* p, py::Type<const py::String&>)
|
||||
{
|
||||
return from_python(p, py::Type<py::String>());
|
||||
}
|
||||
|
||||
PyObject* to_python(const py::Dict&);
|
||||
py::Dict from_python(PyObject* p, py::Type<py::Dict>);
|
||||
|
||||
inline py::Dict from_python(PyObject* p, py::Type<const py::Dict&>)
|
||||
{
|
||||
return from_python(p, py::Type<py::Dict>());
|
||||
}
|
||||
|
||||
#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE
|
||||
namespace py {
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif
|
||||
2
objects_d.cpp
Normal file
2
objects_d.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#define DEBUG_PYTHON
|
||||
#include "objects.cpp"
|
||||
204
py.cpp
Normal file
204
py.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
// (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 "py.h"
|
||||
#include <boost/cast.hpp>
|
||||
|
||||
namespace py {
|
||||
|
||||
void expect_and_absorb_non_null(PyObject* p)
|
||||
{
|
||||
Py_XDECREF(expect_non_null(p));
|
||||
}
|
||||
|
||||
// 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 py::ErrorAlreadySet&)
|
||||
{
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE
|
||||
}
|
||||
#endif
|
||||
|
||||
long from_python(PyObject* p, py::Type<long>)
|
||||
{
|
||||
// Why am I clearing the error here before trying to convert? I know there's a reason...
|
||||
long result;
|
||||
{
|
||||
// py::SuspendError suspended_error(py::SuspendError::discard_old_error);
|
||||
result = PyInt_AsLong(p);
|
||||
if (PyErr_Occurred())
|
||||
throw py::ArgumentError();
|
||||
// suspended_error.throw_if_error();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double from_python(PyObject* p, py::Type<double>)
|
||||
{
|
||||
// Why am I clearing the error here before trying to convert? I know there's a reason...
|
||||
double result;
|
||||
{
|
||||
// py::SuspendError suspended_error(py::SuspendError::discard_old_error);
|
||||
result = PyFloat_AsDouble(p);
|
||||
if (PyErr_Occurred())
|
||||
throw py::ArgumentError();
|
||||
// suspended_error.throw_if_error();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T integer_from_python(PyObject* p, py::Type<T>)
|
||||
{
|
||||
const long long_result = from_python(p, py::Type<long>());
|
||||
|
||||
try
|
||||
{
|
||||
return boost::numeric_cast<T>(long_result);
|
||||
}
|
||||
catch(const boost::bad_numeric_cast&)
|
||||
{
|
||||
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 py::ArgumentError();
|
||||
}
|
||||
#if defined(__MWERKS__) && __MWERKS__ < 0x6000
|
||||
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;
|
||||
|
||||
try
|
||||
{
|
||||
value_as_long = boost::numeric_cast<T>(value);
|
||||
}
|
||||
catch(const boost::bad_numeric_cast&)
|
||||
{
|
||||
const char message[] = "value out of range for Python int";
|
||||
PyErr_SetString(PyExc_ValueError, message);
|
||||
throw py::ErrorAlreadySet();
|
||||
}
|
||||
|
||||
return to_python(value_as_long);
|
||||
}
|
||||
|
||||
int from_python(PyObject* p, py::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, py::Type<unsigned int> type)
|
||||
{
|
||||
return integer_from_python(p, type);
|
||||
}
|
||||
|
||||
short from_python(PyObject* p, py::Type<short> type)
|
||||
{
|
||||
return integer_from_python(p, type);
|
||||
}
|
||||
|
||||
float from_python(PyObject* p, py::Type<float>)
|
||||
{
|
||||
return static_cast<float>(from_python(p, py::Type<double>()));
|
||||
}
|
||||
|
||||
PyObject* to_python(unsigned short i)
|
||||
{
|
||||
return integer_to_python(i);
|
||||
}
|
||||
|
||||
unsigned short from_python(PyObject* p, py::Type<unsigned short> type)
|
||||
{
|
||||
return integer_from_python(p, type);
|
||||
}
|
||||
|
||||
PyObject* to_python(unsigned long x)
|
||||
{
|
||||
return integer_to_python(x);
|
||||
}
|
||||
|
||||
unsigned long from_python(PyObject* p, py::Type<unsigned long> type)
|
||||
{
|
||||
return integer_from_python(p, type);
|
||||
}
|
||||
|
||||
void from_python(PyObject* p, py::Type<void>)
|
||||
{
|
||||
if (p != Py_None) {
|
||||
PyErr_SetString(PyExc_TypeError, "expected argument of type None");
|
||||
throw py::ArgumentError();
|
||||
}
|
||||
}
|
||||
|
||||
const char* from_python(PyObject* p, py::Type<const char*>)
|
||||
{
|
||||
const char* s = PyString_AsString(p);
|
||||
if (!s) throw py::ArgumentError();
|
||||
return s;
|
||||
}
|
||||
|
||||
PyObject* to_python(const std::string& s)
|
||||
{
|
||||
return PyString_FromString(s.c_str());
|
||||
}
|
||||
|
||||
std::string from_python(PyObject* p, py::Type<std::string>)
|
||||
{
|
||||
return std::string(from_python(p, py::Type<const char*>()));
|
||||
}
|
||||
|
||||
bool from_python(PyObject* p, py::Type<bool>)
|
||||
{
|
||||
int value = from_python(p, py::Type<int>());
|
||||
if (value == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE
|
||||
namespace py {
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
266
py.h
Normal file
266
py.h
Normal file
@@ -0,0 +1,266 @@
|
||||
// (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 "wrap_python.h"
|
||||
# include "none.h"
|
||||
# include "signatures.h"
|
||||
# include <boost/smart_ptr.hpp>
|
||||
# include "errors.h"
|
||||
# include <string>
|
||||
|
||||
namespace py {
|
||||
|
||||
template <class P, class T> class WrappedPointer;
|
||||
|
||||
//#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));
|
||||
}
|
||||
|
||||
#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Converters
|
||||
//
|
||||
PyObject* to_python(long);
|
||||
long from_python(PyObject* p, py::Type<long>);
|
||||
long from_python(PyObject* p, py::Type<const long&>);
|
||||
|
||||
PyObject* to_python(unsigned long);
|
||||
unsigned long from_python(PyObject* p, py::Type<unsigned long>);
|
||||
unsigned long from_python(PyObject* p, py::Type<const unsigned long&>);
|
||||
|
||||
PyObject* to_python(int);
|
||||
int from_python(PyObject*, py::Type<int>);
|
||||
int from_python(PyObject*, py::Type<const int&>);
|
||||
|
||||
PyObject* to_python(unsigned int);
|
||||
unsigned int from_python(PyObject*, py::Type<unsigned int>);
|
||||
unsigned int from_python(PyObject*, py::Type<const unsigned int&>);
|
||||
|
||||
PyObject* to_python(short);
|
||||
short from_python(PyObject*, py::Type<short>);
|
||||
short from_python(PyObject*, py::Type<const short&>);
|
||||
|
||||
PyObject* to_python(unsigned short);
|
||||
unsigned short from_python(PyObject*, py::Type<unsigned short>);
|
||||
unsigned short from_python(PyObject*, py::Type<const unsigned short&>);
|
||||
|
||||
PyObject* to_python(float);
|
||||
float from_python(PyObject*, py::Type<float>);
|
||||
float from_python(PyObject*, py::Type<const float&>);
|
||||
|
||||
PyObject* to_python(double);
|
||||
double from_python(PyObject*, py::Type<double>);
|
||||
double from_python(PyObject*, py::Type<const double&>);
|
||||
|
||||
PyObject* to_python(bool);
|
||||
bool from_python(PyObject*, py::Type<bool>);
|
||||
bool from_python(PyObject*, py::Type<const bool&>);
|
||||
|
||||
PyObject* to_python(void);
|
||||
void from_python(PyObject*, py::Type<void>);
|
||||
|
||||
PyObject* to_python(const char* s);
|
||||
const char* from_python(PyObject*, py::Type<const char*>);
|
||||
|
||||
PyObject* to_python(const std::string& s);
|
||||
std::string from_python(PyObject*, py::Type<std::string>);
|
||||
std::string from_python(PyObject*, py::Type<const std::string&>);
|
||||
|
||||
// For when your C++ function really wants to pass/return a PyObject*
|
||||
PyObject* to_python(PyObject*);
|
||||
PyObject* from_python(PyObject*, py::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
|
||||
// WrappedPointer 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 WrappedType<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 py {
|
||||
// #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
|
||||
// }
|
||||
|
||||
#if !defined(PY_MSVC6_OR_EARLIER)
|
||||
template <class T>
|
||||
boost::shared_ptr<T> from_python(PyObject*p, py::Type<boost::shared_ptr<T> >)
|
||||
{
|
||||
return smart_ptr_from_python(p, py::Type<boost::shared_ptr<T> >(), py::Type<T>());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
template <class T>
|
||||
PyObject* to_python(std::auto_ptr<T> p)
|
||||
{
|
||||
return new py::WrappedPointer<std::auto_ptr<T>, T>(p);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PyObject* to_python(boost::shared_ptr<T> p)
|
||||
{
|
||||
return new py::WrappedPointer<boost::shared_ptr<T>, T>(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// inline implementations
|
||||
//
|
||||
|
||||
inline PyObject* to_python(long l)
|
||||
{
|
||||
return PyInt_FromLong(l);
|
||||
}
|
||||
|
||||
inline PyObject* to_python(int x)
|
||||
{
|
||||
return PyInt_FromLong(x);
|
||||
}
|
||||
|
||||
inline int from_python(PyObject* p, py::Type<const int&>)
|
||||
{
|
||||
return from_python(p, py::Type<int>());
|
||||
}
|
||||
|
||||
inline PyObject* to_python(short x)
|
||||
{
|
||||
return PyInt_FromLong(x);
|
||||
}
|
||||
|
||||
inline short from_python(PyObject* p, py::Type<const short&>)
|
||||
{
|
||||
return from_python(p, py::Type<short>());
|
||||
}
|
||||
|
||||
inline PyObject* to_python(bool b)
|
||||
{
|
||||
return PyInt_FromLong(b);
|
||||
}
|
||||
|
||||
inline bool from_python(PyObject* p, py::Type<const bool&>)
|
||||
{
|
||||
return from_python(p, py::Type<bool>());
|
||||
}
|
||||
|
||||
inline PyObject* to_python(void)
|
||||
{
|
||||
return py::none();
|
||||
}
|
||||
|
||||
// const char*
|
||||
inline PyObject* to_python(const char* s)
|
||||
{
|
||||
return PyString_FromString(s);
|
||||
}
|
||||
|
||||
inline std::string from_python(PyObject* p, py::Type<const std::string&>)
|
||||
{
|
||||
return from_python(p, py::Type<std::string>());
|
||||
}
|
||||
|
||||
inline PyObject* to_python(PyObject* p)
|
||||
{
|
||||
Py_INCREF(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
inline PyObject* from_python(PyObject* p, py::Type<PyObject*>)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
inline unsigned int from_python(PyObject* p, py::Type<const unsigned int&>)
|
||||
{
|
||||
return from_python(p, py::Type<unsigned int>());
|
||||
}
|
||||
|
||||
inline unsigned short from_python(PyObject* p, py::Type<const unsigned short&>)
|
||||
{
|
||||
return from_python(p, py::Type<unsigned short>());
|
||||
}
|
||||
|
||||
inline unsigned long from_python(PyObject* p, py::Type<const unsigned long&>)
|
||||
{
|
||||
return from_python(p, py::Type<unsigned long>());
|
||||
}
|
||||
|
||||
inline long from_python(PyObject* p, py::Type<const long&>)
|
||||
{
|
||||
return from_python(p, py::Type<long>());
|
||||
}
|
||||
|
||||
|
||||
#ifdef PY_NO_INLINE_FRIENDS_IN_NAMESPACE
|
||||
namespace py {
|
||||
namespace converters { // bringing these into namespace py tended to confuse gcc;
|
||||
using ::to_python; // they are in namespace py::converters for use by clients
|
||||
using ::from_python;
|
||||
}
|
||||
#else
|
||||
namespace converters {
|
||||
using ::py::to_python;
|
||||
using ::py::from_python;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace py
|
||||
|
||||
#endif
|
||||
4
py_cpp.bdf
Normal file
4
py_cpp.bdf
Normal file
@@ -0,0 +1,4 @@
|
||||
TargetName=py_cpp
|
||||
TargetType=lib
|
||||
SourceFiles=extclass.cpp init_function.cpp subclass.cpp functions.cpp objects.cpp
|
||||
SourceFiles+=module.cpp newtypes.cpp py.cpp
|
||||
BIN
py_cpp_20001013.zip
Normal file
BIN
py_cpp_20001013.zip
Normal file
Binary file not shown.
4
py_cpp_d.bdf
Normal file
4
py_cpp_d.bdf
Normal file
@@ -0,0 +1,4 @@
|
||||
TargetName=py_cpp_d
|
||||
TargetType=lib
|
||||
SourceFiles=extclass_d.cpp init_function_d.cpp subclass_d.cpp functions_d.cpp objects_d.cpp
|
||||
SourceFiles+=module_d.cpp newtypes_d.cpp py_d.cpp
|
||||
21
py_cpphelp.mak
Normal file
21
py_cpphelp.mak
Normal file
@@ -0,0 +1,21 @@
|
||||
ifndef PY_CPPHELP_MAK_INCLUDED
|
||||
PY_CPPHELP_MAK_INCLUDED=1
|
||||
|
||||
ifndef DONT_BUILD_IMPORTS
|
||||
|
||||
|
||||
PY_CPP_DIR=$(ROOT_DIR)/py_cpp
|
||||
PY_CPP_LIB=$(PY_CPP_DIR)/$(OBJDIR)/py_cpp.lib
|
||||
PY_CPP_D_LIB=$(PY_CPP_DIR)/$(OBJDIR)/py_cpp_d.lib
|
||||
|
||||
$(PY_CPP_LIB) : FORCE
|
||||
$(RECURSIVE_MAKE) -C $(PY_CPP_DIR) py_cpp
|
||||
|
||||
$(PY_CPP_D_LIB) : FORCE
|
||||
$(RECURSIVE_MAKE) -C $(PY_CPP_DIR) py_cpp_d
|
||||
|
||||
# end ifndef DONT_BUILD_IMPORTS
|
||||
endif
|
||||
|
||||
# end ifndef PY_CPPHELP_MAK_INCLUDED
|
||||
endif
|
||||
40
pyconfig.h
Normal file
40
pyconfig.h
Normal file
@@ -0,0 +1,40 @@
|
||||
// (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
|
||||
# define PY_NO_INLINE_FRIENDS_IN_NAMESPACE 1 // A more accurate name
|
||||
# define PY_INLINE_FRIEND
|
||||
# else
|
||||
# define PY_INLINE_FRIEND ::py
|
||||
# endif
|
||||
|
||||
# if !defined(__GNUC__) && !defined(__MWERKS__) && !defined(__BORLANDC__) && defined(_MSC_VER)
|
||||
# define PY_COMPILER_IS_MSVC 1
|
||||
# if _MSC_VER <= 1200
|
||||
# define PY_MSVC6_OR_EARLIER 1
|
||||
# endif
|
||||
|
||||
# pragma warning (disable : 4786)
|
||||
|
||||
# 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(PY_MSVC6_OR_EARLIER) && !defined(__STLPORT)
|
||||
# define PY_CSTD_
|
||||
# else
|
||||
# define PY_CSTD_ std
|
||||
# endif
|
||||
|
||||
#endif // CONFIG_DWA052200_H_
|
||||
143
pyptr.h
Normal file
143
pyptr.h
Normal file
@@ -0,0 +1,143 @@
|
||||
// (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 "pyconfig.h"
|
||||
# include <boost/operators.hpp>
|
||||
# include "wrap_python.h"
|
||||
# include "cast.h"
|
||||
# include <cassert>
|
||||
# include "signatures.h"
|
||||
# include "errors.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
template <class T>
|
||||
class PyPtr
|
||||
: public boost::dereferenceable<PyPtr<T>, T*> // supplies op->
|
||||
{
|
||||
public:
|
||||
PyPtr(const PyPtr& rhs)
|
||||
: m_p(rhs.m_p)
|
||||
{
|
||||
Py_XINCREF(object());
|
||||
}
|
||||
|
||||
#if !defined(PY_MSVC6_OR_EARLIER)
|
||||
template <class T2>
|
||||
PyPtr(const PyPtr<T2>& rhs)
|
||||
: m_p(rhs.object())
|
||||
{
|
||||
Py_XINCREF(object());
|
||||
}
|
||||
#endif
|
||||
|
||||
PyPtr() : 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 NewRef { new_ref, borrowed = new_ref };
|
||||
|
||||
enum AllowNull { null_ok };
|
||||
|
||||
template <class T2>
|
||||
explicit PyPtr(T2* x)
|
||||
: m_p(expect_non_null(x)) {}
|
||||
|
||||
template <class T2>
|
||||
PyPtr(T2* x, NewRef)
|
||||
: m_p(expect_non_null(x)) { Py_INCREF(object()); }
|
||||
|
||||
template <class T2>
|
||||
PyPtr(T2* x, AllowNull)
|
||||
: m_p(x) {}
|
||||
|
||||
template <class T2>
|
||||
PyPtr(T2* x, AllowNull, NewRef)
|
||||
: m_p(x) { Py_XINCREF(object()); }
|
||||
|
||||
template <class T2>
|
||||
PyPtr(T2* x, NewRef, AllowNull)
|
||||
: m_p(x) { Py_XINCREF(object()); }
|
||||
|
||||
#if !defined(PY_MSVC6_OR_EARLIER)
|
||||
template <class T2>
|
||||
PyPtr& operator=(const PyPtr<T2>& rhs)
|
||||
{
|
||||
Py_XDECREF(object());
|
||||
m_p = rhs.m_p;
|
||||
Py_XINCREF(object());
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
PyPtr& operator=(const PyPtr& rhs)
|
||||
{
|
||||
Py_XINCREF(static_cast<PyObject*>(rhs.m_p));
|
||||
Py_XDECREF(object());
|
||||
m_p = rhs.m_p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~PyPtr()
|
||||
{
|
||||
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, NewRef)
|
||||
{ Py_XDECREF(m_p); m_p = expect_non_null(x); Py_INCREF(object()); }
|
||||
|
||||
template <class T2>
|
||||
void reset(T2* x, AllowNull)
|
||||
{ Py_XDECREF(m_p); m_p = x;}
|
||||
|
||||
template <class T2>
|
||||
void reset(T2* x, AllowNull, NewRef)
|
||||
{ Py_XDECREF(m_p); m_p = x; Py_XINCREF(object()); }
|
||||
|
||||
template <class T2>
|
||||
void reset(T2* x, NewRef, AllowNull)
|
||||
{ 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 PyPtr<PyObject> Ptr;
|
||||
|
||||
}
|
||||
|
||||
#endif // PYPTR_DWA050400_H_
|
||||
165
signatures.h
Normal file
165
signatures.h
Normal file
@@ -0,0 +1,165 @@
|
||||
// (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.py for 5 arguments.
|
||||
#ifndef SIGNATURES_DWA050900_H_
|
||||
# define SIGNATURES_DWA050900_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
// 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 {};
|
||||
|
||||
// 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>::Id is just Void.
|
||||
template <class T>
|
||||
struct Type
|
||||
{
|
||||
typedef Type Id;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type<Void>
|
||||
{
|
||||
typedef Void Id;
|
||||
};
|
||||
|
||||
// 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>
|
||||
struct Signature5 {};
|
||||
|
||||
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 to the head of a Void
|
||||
// signature results in a Void signature again.
|
||||
inline Signature0 prepend(Void, Signature0) { return Signature0(); }
|
||||
|
||||
template <class A1 = Void, class A2 = Void, class A3 = Void, class A4 = Void, class A5 = Void>
|
||||
struct Constructor
|
||||
{
|
||||
};
|
||||
|
||||
// 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 ReturnValue { typedef T Type; };
|
||||
|
||||
// free functions
|
||||
template <class R>
|
||||
ReturnValue<R> return_value(R (*)()) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class A1>
|
||||
ReturnValue<R> return_value(R (*)(A1)) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class A1, class A2>
|
||||
ReturnValue<R> return_value(R (*)(A1, A2)) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class A1, class A2, class A3>
|
||||
ReturnValue<R> return_value(R (*)(A1, A2, A3)) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class A1, class A2, class A3, class A4>
|
||||
ReturnValue<R> return_value(R (*)(A1, A2, A3, A4)) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class A1, class A2, class A3, class A4, class A5>
|
||||
ReturnValue<R> return_value(R (*)(A1, A2, A3, A4, A5)) { return ReturnValue<R>(); }
|
||||
|
||||
// TODO(?): handle 'const void'
|
||||
|
||||
// member functions
|
||||
template <class R, class T>
|
||||
ReturnValue<R> return_value(R (T::*)()) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class T, class A1>
|
||||
ReturnValue<R> return_value(R (T::*)(A1)) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class T, class A1, class A2>
|
||||
ReturnValue<R> return_value(R (T::*)(A1, A2)) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class T, class A1, class A2, class A3>
|
||||
ReturnValue<R> return_value(R (T::*)(A1, A2, A3)) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class T, class A1, class A2, class A3, class A4>
|
||||
ReturnValue<R> return_value(R (T::*)(A1, A2, A3, A4)) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5>
|
||||
ReturnValue<R> return_value(R (T::*)(A1, A2, A3, A4, A5)) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class T>
|
||||
ReturnValue<R> return_value(R (T::*)() const) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class T, class A1>
|
||||
ReturnValue<R> return_value(R (T::*)(A1) const) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class T, class A1, class A2>
|
||||
ReturnValue<R> return_value(R (T::*)(A1, A2) const) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class T, class A1, class A2, class A3>
|
||||
ReturnValue<R> return_value(R (T::*)(A1, A2, A3) const) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class T, class A1, class A2, class A3, class A4>
|
||||
ReturnValue<R> return_value(R (T::*)(A1, A2, A3, A4) const) { return ReturnValue<R>(); }
|
||||
|
||||
template <class R, class T, class A1, class A2, class A3, class A4, class A5>
|
||||
ReturnValue<R> return_value(R (T::*)(A1, A2, A3, A4, A5) const) { return ReturnValue<R>(); }
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
53
singleton.h
Normal file
53
singleton.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#ifndef SINGLETON_DWA051900_H_
|
||||
# define SINGLETON_DWA051900_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
struct Empty {};
|
||||
template <class Derived, class Base = Empty>
|
||||
struct Singleton : Base
|
||||
{
|
||||
typedef Singleton SingletonBase; // Convenience type for derived class constructors
|
||||
|
||||
static Derived* singleton();
|
||||
|
||||
// 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 Derived, class Base>
|
||||
Derived* Singleton<Derived,Base>::singleton()
|
||||
{
|
||||
static Derived x;
|
||||
return &x;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
398
subclass.cpp
Normal file
398
subclass.cpp
Normal file
@@ -0,0 +1,398 @@
|
||||
// (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 "subclass.h"
|
||||
#include "functions.h"
|
||||
#include "singleton.h"
|
||||
#include <cstddef>
|
||||
#include "callback.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
Instance::Instance(PyTypeObject* class_)
|
||||
: PythonObject(class_)
|
||||
{
|
||||
}
|
||||
|
||||
PyObject* Instance::getattr(const char* name, bool use_special_function)
|
||||
{
|
||||
Ptr 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));
|
||||
|
||||
Ptr class_attribute;
|
||||
if (!use_special_function || function != 0)
|
||||
{
|
||||
// This will throw if the attribute wasn't found
|
||||
class_attribute = Ptr(function);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Suspend the error while we try special methods method (if any).
|
||||
#if 0
|
||||
SuspendError suspended_error(SuspendError::discard_new_error);
|
||||
#else
|
||||
PyErr_Clear();
|
||||
#endif
|
||||
|
||||
// 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 0
|
||||
suspended_error.throw_if_error();
|
||||
#else
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_SetString(PyExc_AttributeError, name);
|
||||
throw ErrorAlreadySet();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Take ownership of the method
|
||||
Ptr 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 new BoundFunction(Ptr(this, Ptr::borrowed), class_attribute);
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// 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 + "__");
|
||||
|
||||
Ptr special_method(
|
||||
PyObject_GetAttr(as_object(this->ob_type), specific_method_name.get()),
|
||||
Ptr::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()),
|
||||
Ptr::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)
|
||||
{
|
||||
expect_and_absorb_non_null(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(
|
||||
Ptr(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);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct NamedCapability
|
||||
{
|
||||
const char* name;
|
||||
TypeObjectBase::Capability capability;
|
||||
};
|
||||
|
||||
const NamedCapability enablers[] =
|
||||
{
|
||||
{ "__hash__", TypeObjectBase::hash },
|
||||
{ "__cmp__", TypeObjectBase::compare },
|
||||
{ "__repr__", TypeObjectBase::repr },
|
||||
{ "__str__", TypeObjectBase::str },
|
||||
{ "__call__", TypeObjectBase::call },
|
||||
{ "__getattr__", TypeObjectBase::getattr },
|
||||
{ "__setattr__", TypeObjectBase::setattr },
|
||||
{ "__len__", TypeObjectBase::mapping_length },
|
||||
{ "__len__", TypeObjectBase::sequence_length },
|
||||
{ "__getitem__", TypeObjectBase::mapping_subscript },
|
||||
{ "__getitem__", TypeObjectBase::sequence_item },
|
||||
{ "__setitem__", TypeObjectBase::mapping_ass_subscript },
|
||||
{ "__setitem__", TypeObjectBase::sequence_ass_item },
|
||||
{ "__delitem__", TypeObjectBase::mapping_ass_subscript },
|
||||
{ "__delitem__", TypeObjectBase::sequence_ass_item },
|
||||
{ "__getslice__", TypeObjectBase::sequence_slice },
|
||||
{ "__setslice__", TypeObjectBase::sequence_ass_slice },
|
||||
{ "__delslice__", TypeObjectBase::sequence_ass_slice }
|
||||
};
|
||||
|
||||
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 = PY_CSTD_::strlen(name);
|
||||
return name[name_length - 1] == '_' && name[name_length - 2] == '_';
|
||||
}
|
||||
}
|
||||
|
||||
// Enable any special methods which are enabled in the base class.
|
||||
void enable_special_methods(TypeObjectBase* derived, const Tuple& bases, const Dict& name_space)
|
||||
{
|
||||
detail::AllMethods all_methods;
|
||||
PY_CSTD_::memset(&all_methods, 0, sizeof(all_methods));
|
||||
|
||||
for (std::size_t i = 0; i < bases.size(); ++i)
|
||||
{
|
||||
PyTypeObject* base = Downcast<PyTypeObject>(bases[i].get());
|
||||
|
||||
for (std::size_t n = 0; n < detail::num_capabilities; ++n)
|
||||
{
|
||||
detail::add_capability(n, derived, all_methods, base);
|
||||
}
|
||||
}
|
||||
|
||||
Ptr keys = name_space.keys();
|
||||
for (std::size_t j = 0, len = PyList_GET_SIZE(keys.get()); j < len; ++j)
|
||||
{
|
||||
const char* name = PyString_AsString(PyList_GetItem(keys.get(), j));
|
||||
|
||||
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, all_methods, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now replace those pointers with a persistent copy
|
||||
using detail::UniquePodSet;
|
||||
if (derived->tp_as_buffer)
|
||||
derived->tp_as_buffer = UniquePodSet::instance().get(*derived->tp_as_buffer);
|
||||
|
||||
if (derived->tp_as_number)
|
||||
derived->tp_as_number = UniquePodSet::instance().get(*derived->tp_as_number);
|
||||
|
||||
if (derived->tp_as_sequence)
|
||||
derived->tp_as_sequence = UniquePodSet::instance().get(*derived->tp_as_sequence);
|
||||
|
||||
if (derived->tp_as_mapping)
|
||||
derived->tp_as_mapping = UniquePodSet::instance().get(*derived->tp_as_mapping);
|
||||
}
|
||||
|
||||
// Enable the special handler for methods of the given name, if any.
|
||||
void enable_named_method(TypeObjectBase* type_object, 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_object->enable(enablers[i].capability);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_current_module_name(Dict& name_space)
|
||||
{
|
||||
static String module_key("__module__", String::interned);
|
||||
static String name_key("__name__", String::interned);
|
||||
|
||||
Ptr existing_value = name_space.get_item(module_key);
|
||||
if (existing_value.get() == 0)
|
||||
{
|
||||
PyObject* globals = PyEval_GetGlobals();
|
||||
if (globals != 0) // Why don't we throw in this case? Who knows? This is
|
||||
{ // what Python does for class objects!
|
||||
PyObject* module_name = PyDict_GetItem(globals, name_key.get());
|
||||
if (module_name != 0)
|
||||
{
|
||||
name_space[module_key] = Ptr(module_name, Ptr::borrowed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void adjust_slice_indices(PyObject* instance, int& start, int& finish)
|
||||
{
|
||||
int length = Callback<int>::call_method(instance, "__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 py
|
||||
371
subclass.h
Normal file
371
subclass.h
Normal file
@@ -0,0 +1,371 @@
|
||||
// (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 "pyconfig.h"
|
||||
# include "newtypes.h"
|
||||
# include "objects.h"
|
||||
# include "singleton.h"
|
||||
# include <boost/utility.hpp>
|
||||
# include "py.h"
|
||||
# include "callback.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
// A simple type which acts something like a built-in Python class instance.
|
||||
// TODO: implement all the special methods, like __call__, __getattr__, etc.,
|
||||
// and the other special attributes, like __dict__.
|
||||
class Instance : public PythonObject
|
||||
{
|
||||
public:
|
||||
Instance(PyTypeObject* class_);
|
||||
|
||||
// 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);
|
||||
|
||||
private: // noncopyable, without the size bloat
|
||||
Instance(const Instance&);
|
||||
void operator=(const Instance&);
|
||||
|
||||
private:
|
||||
Dict m_name_space;
|
||||
};
|
||||
|
||||
template <class T> class MetaClass;
|
||||
|
||||
// A type which acts a lot like a built-in Python class. T is the instance type,
|
||||
// so Class<Instance> is a very simple "class-alike".
|
||||
template <class T>
|
||||
class Class
|
||||
: public Getattrable<Setattrable<TypeObject<T> > >
|
||||
{
|
||||
public:
|
||||
Class(MetaClass<T>* meta_class, String name, Tuple bases, const Dict& name_space);
|
||||
|
||||
Tuple bases() const;
|
||||
String name() const;
|
||||
Dict& dict();
|
||||
|
||||
// Standard Python functions.
|
||||
PyObject* getattr(const char* name);
|
||||
int setattr(const char* name, PyObject* value);
|
||||
PyObject* call(PyObject* args, PyObject* keywords);
|
||||
|
||||
protected:
|
||||
void add_base(Ptr base);
|
||||
|
||||
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* instance, int n) const;
|
||||
int instance_sequence_ass_item(PyObject* instance, 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: // Miscellaneous "special" methods
|
||||
PyObject* instance_call(PyObject* instance, PyObject* args, PyObject* keywords) const;
|
||||
|
||||
private: // noncopyable, without the size bloat
|
||||
Class(const Class<T>&);
|
||||
void operator=(const Class&);
|
||||
|
||||
private:
|
||||
String m_name;
|
||||
Tuple m_bases;
|
||||
Dict m_name_space;
|
||||
};
|
||||
|
||||
// Don't really need to be friends, but are essentially part of the Class interface.
|
||||
// These operate on TypeObjectBase just to save on code space.
|
||||
void enable_special_methods(TypeObjectBase*, const Tuple& bases, const Dict& name_space);
|
||||
void enable_named_method(TypeObjectBase*, const char*);
|
||||
|
||||
// The type of a Class<T> object.
|
||||
template <class T>
|
||||
class MetaClass
|
||||
: public Callable<Getattrable<Setattrable<TypeObject<Class<T> > > > >,
|
||||
boost::noncopyable
|
||||
{
|
||||
public:
|
||||
MetaClass();
|
||||
|
||||
// Standard Python functions.
|
||||
PyObject* call(PyObject* args, PyObject* keywords);
|
||||
private:
|
||||
|
||||
struct TypeObject
|
||||
: Singleton<TypeObject, Callable<py::TypeObject<MetaClass> > >
|
||||
{
|
||||
TypeObject() : SingletonBase(&PyType_Type) {}
|
||||
};
|
||||
};
|
||||
|
||||
// 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<>::Class() below.
|
||||
void add_current_module_name(Dict&);
|
||||
|
||||
//
|
||||
// Member function implementations.
|
||||
//
|
||||
template <class T>
|
||||
MetaClass<T>::MetaClass()
|
||||
: Properties(TypeObject::singleton())
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Class<T>::Class(MetaClass<T>* meta_class, String name, Tuple bases, const Dict& name_space)
|
||||
: Properties(meta_class, name.c_str()),
|
||||
m_name(name),
|
||||
m_bases(bases),
|
||||
m_name_space(name_space)
|
||||
{
|
||||
add_current_module_name(m_name_space);
|
||||
enable_special_methods(this, bases, name_space);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
String Class<T>::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PyObject* Class<T>::getattr(const char* name)
|
||||
{
|
||||
Ptr 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)
|
||||
return base_attribute;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int Class<T>::setattr(const char* name, PyObject* value)
|
||||
{
|
||||
if (PyCallable_Check(value))
|
||||
enable_named_method(this, name);
|
||||
|
||||
return PyDict_SetItemString(
|
||||
m_name_space.reference().get(), const_cast<char*>(name), value);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PyObject* Class<T>::call(PyObject* args, PyObject* keywords)
|
||||
{
|
||||
PyPtr<T> result(new T(this));
|
||||
|
||||
// Getting the init function off the result instance should result in a
|
||||
// bound method.
|
||||
PyObject* const init_function = result->getattr("__init__", false);
|
||||
|
||||
if (init_function == 0)
|
||||
{
|
||||
if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
PyErr_Clear(); // no __init__? That's legal.
|
||||
}
|
||||
else {
|
||||
return 0; // Something else? Keep the error
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Manage the reference to the bound function
|
||||
Ptr init_function_holder(init_function);
|
||||
|
||||
// Declare a Ptr to manage the result of calling __init__ (which should be None).
|
||||
Ptr init_result(
|
||||
PyEval_CallObjectWithKeywords(init_function, args, keywords));
|
||||
}
|
||||
|
||||
return result.release();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PyObject* Class<T>::instance_repr(PyObject* instance) const
|
||||
{
|
||||
return Downcast<T>(instance)->repr();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int Class<T>::instance_compare(PyObject* instance, PyObject* other) const
|
||||
{
|
||||
return Downcast<T>(instance)->compare(other);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PyObject* Class<T>::instance_str(PyObject* instance) const
|
||||
{
|
||||
return Downcast<T>(instance)->str();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
long Class<T>::instance_hash(PyObject* instance) const
|
||||
{
|
||||
return Downcast<T>(instance)->hash();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int Class<T>::instance_mapping_length(PyObject* instance) const
|
||||
{
|
||||
return Downcast<T>(instance)->length();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int Class<T>::instance_sequence_length(PyObject* instance) const
|
||||
{
|
||||
return Downcast<T>(instance)->length();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PyObject* Class<T>::instance_mapping_subscript(PyObject* instance, PyObject* key) const
|
||||
{
|
||||
return Downcast<T>(instance)->get_subscript(key);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PyObject* Class<T>::instance_sequence_item(PyObject* instance, int n) const
|
||||
{
|
||||
Ptr key(to_python(n));
|
||||
return Downcast<T>(instance)->get_subscript(key.get());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int Class<T>::instance_sequence_ass_item(PyObject* instance, int n, PyObject* value) const
|
||||
{
|
||||
Ptr key(to_python(n));
|
||||
Downcast<T>(instance)->set_subscript(key.get(), value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int Class<T>::instance_mapping_ass_subscript(PyObject* instance, PyObject* key, PyObject* value) const
|
||||
{
|
||||
Downcast<T>(instance)->set_subscript(key, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void adjust_slice_indices(PyObject* instance, int& start, int& finish);
|
||||
|
||||
template <class T>
|
||||
PyObject* Class<T>::instance_sequence_slice(PyObject* instance, int start, int finish) const
|
||||
{
|
||||
adjust_slice_indices(instance, start, finish);
|
||||
return Downcast<T>(instance)->get_slice(start, finish);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int Class<T>::instance_sequence_ass_slice(PyObject* instance, int start, int finish, PyObject* value) const
|
||||
{
|
||||
adjust_slice_indices(instance, start, finish);
|
||||
Downcast<T>(instance)->set_slice(start, finish, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PyObject* Class<T>::instance_call(PyObject* instance, PyObject* args, PyObject* keywords) const
|
||||
{
|
||||
return Downcast<T>(instance)->call(args, keywords);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Dict& Class<T>::dict()
|
||||
{
|
||||
return m_name_space;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Tuple Class<T>::bases() const
|
||||
{
|
||||
return m_bases;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Class<T>::add_base(Ptr 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;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
PyObject* MetaClass<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>(this, String(Ptr(name, Ptr::borrowed)),
|
||||
Tuple(Ptr(bases, Ptr::borrowed)),
|
||||
Dict(Ptr(name_space, Ptr::borrowed)))
|
||||
);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
const String& setattr_string();
|
||||
const String& getattr_string();
|
||||
const String& delattr_string();
|
||||
}
|
||||
|
||||
|
||||
} // namespace py
|
||||
#endif
|
||||
2
subclass_d.cpp
Normal file
2
subclass_d.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#define DEBUG_PYTHON
|
||||
#include "subclass.cpp"
|
||||
50
test_example1.py
Normal file
50
test_example1.py
Normal file
@@ -0,0 +1,50 @@
|
||||
r'''
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
That's it! If we build this shared library and put it on our PYTHONPATH we can
|
||||
now access our C++ class and function from Python.
|
||||
|
||||
>>> import hello
|
||||
>>> hi_world = hello.world(3)
|
||||
>>> hi_world.get()
|
||||
'hi, world'
|
||||
>>> hello.length(hi_world)
|
||||
9
|
||||
|
||||
We can even make a subclass of hello.world:
|
||||
|
||||
|
||||
>>> class my_subclass(hello.world):
|
||||
... def get(self):
|
||||
... return 'hello, world'
|
||||
...
|
||||
>>> y = my_subclass(2)
|
||||
>>> y.get()
|
||||
'hello, world'
|
||||
|
||||
Pretty cool! You can't do that with an ordinary Python extension type!
|
||||
|
||||
>>> hello.length(y)
|
||||
9
|
||||
|
||||
Of course, you may now have a slightly empty feeling in the pit of your little
|
||||
pythonic stomach. Perhaps you feel your subclass deserves to have a length() of
|
||||
12? If so, read on...
|
||||
'''
|
||||
from hello import *
|
||||
|
||||
def run(args = None):
|
||||
if args is not None:
|
||||
import sys
|
||||
sys.argv = args
|
||||
import doctest, test_example1
|
||||
doctest.testmod(test_example1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
423
test_extclass.py
Normal file
423
test_extclass.py
Normal file
@@ -0,0 +1,423 @@
|
||||
r'''
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
Automatic checking of the number and type of arguments. Foo's constructor takes
|
||||
a single long parameter.
|
||||
|
||||
>>> ext = Foo()
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
TypeError: function requires exactly 1 argument; 0 given
|
||||
|
||||
>>> ext = Foo('foo')
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
TypeError: illegal argument type for built-in operation
|
||||
|
||||
>>> ext = Foo(1)
|
||||
|
||||
Call a virtual function. This call takes a trip into C++ where
|
||||
FooCallback::add_len() looks up the Python "add_len" attribute and finds the
|
||||
wrapper for FooCallback::default_add_len(), which in turn calls Foo::add_len().
|
||||
|
||||
>>> ext.add_len('hello')
|
||||
6
|
||||
>>> ext.set(3)
|
||||
>>> ext.add_len('hello')
|
||||
8
|
||||
|
||||
Call a pure virtual function which should have been overridden, but was not.
|
||||
|
||||
>>> ext.call_pure()
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
AttributeError: pure
|
||||
|
||||
We can subclass Foo.
|
||||
|
||||
>>> class Subclass(Foo):
|
||||
... def __init__(self, seq):
|
||||
... Foo.__init__(self, len(seq))
|
||||
...
|
||||
... def pure(self):
|
||||
... return 'not pure anymore!'
|
||||
...
|
||||
... def get(self):
|
||||
... return Foo.add_len(self, '')
|
||||
...
|
||||
... def add_len(self, s):
|
||||
... print 'called add_len()'
|
||||
... return self.get() + len(s)
|
||||
...
|
||||
>>> b = Subclass('yippee')
|
||||
>>> b.get()
|
||||
6
|
||||
>>> b.mumble()
|
||||
'mumble'
|
||||
>>> b.call_pure()
|
||||
'not pure anymore!'
|
||||
|
||||
If no __init__ function is defined, the one from the base class takes effect, just
|
||||
like in a Python class.
|
||||
|
||||
>>> class DemonstrateInitPassthru(Foo): pass
|
||||
...
|
||||
>>> q = DemonstrateInitPassthru(1)
|
||||
>>> q.add_len("x")
|
||||
2
|
||||
|
||||
If we don't initialize the base class, we'll get a RuntimeError when we try to
|
||||
use its methods. The test illustrates the kind of error to expect.
|
||||
|
||||
>>> class BadSubclass(Foo):
|
||||
... def __init__(self): pass
|
||||
...
|
||||
>>> barf = BadSubclass()
|
||||
>>> barf.set(4)
|
||||
Traceback (innermost last):
|
||||
...
|
||||
RuntimeError: __init__ function for extension class 'Foo' was never called.
|
||||
|
||||
Here we are tesing that the simple definition procedure used in the C++ demo
|
||||
file for classes without any virtual functions actually worked.
|
||||
|
||||
>>> bar = Bar(3, 4)
|
||||
>>> bar.first()
|
||||
3
|
||||
>>> bar.second()
|
||||
4
|
||||
>>> baz = Baz()
|
||||
|
||||
We can actually return the wrapped classes by value
|
||||
|
||||
>>> baz.pass_bar(bar).first()
|
||||
3
|
||||
>>> bar.pass_baz(baz) is baz # A copy of the return value is made.
|
||||
0
|
||||
>>> type(bar.pass_baz(baz)) is type(baz)
|
||||
1
|
||||
|
||||
And, yes, we can multiply inherit from these classes.
|
||||
|
||||
>>> class MISubclass(Subclass, Bar):
|
||||
... def __init__(self, s):
|
||||
... Subclass.__init__(self, s)
|
||||
... Bar.__init__(self, 0, len(s))
|
||||
...
|
||||
>>> mi = MISubclass('xx')
|
||||
>>> mi.first()
|
||||
0
|
||||
>>> mi.second()
|
||||
2
|
||||
>>> mi.mumble()
|
||||
'mumble'
|
||||
|
||||
Any object whose class is derived from Bar can be passed to a function expecting
|
||||
a Bar parameter:
|
||||
|
||||
>>> baz.pass_bar(mi).first()
|
||||
0
|
||||
|
||||
But objects not derived from Bar cannot:
|
||||
|
||||
>>> baz.pass_bar(baz)
|
||||
Traceback (innermost last):
|
||||
...
|
||||
TypeError: extension class 'Baz' is not derived from 'Bar'.
|
||||
|
||||
The clone function on Baz returns a smart pointer; we wrap it into an
|
||||
ExtensionInstance and make it look just like any other Baz instance.
|
||||
|
||||
>>> baz_clone = baz.clone()
|
||||
>>> baz_clone.pass_bar(mi).first()
|
||||
0
|
||||
|
||||
Functions expecting an std::auto_ptr<Baz> parameter will not accept a raw Baz
|
||||
|
||||
>>> try: baz.eat_baz(Baz())
|
||||
... except RuntimeError, err:
|
||||
... assert re.match("Object of extension class 'Baz' does not wrap <.*>.",
|
||||
... str(err))
|
||||
|
||||
We can pass std::auto_ptr<Baz> where it is expected
|
||||
|
||||
>>> baz.eat_baz(baz_clone)
|
||||
|
||||
And if the auto_ptr has given up ownership?
|
||||
|
||||
# MSVC6 ships with an outdated auto_ptr that doesn't get zeroed out when it
|
||||
# gives up ownership. If you are using MSVC6 without the new Dinkumware
|
||||
# library, SGI STL or the STLport, expect this test to crash unless you put
|
||||
# --broken-auto-ptr on the command line.
|
||||
>>> if not '--broken-auto-ptr' in sys.argv:
|
||||
... try: baz_clone.clone()
|
||||
... except RuntimeError, err:
|
||||
... assert re.match('Converting from python, pointer or smart pointer to <.*> is NULL.', str(err))
|
||||
|
||||
Polymorphism also works:
|
||||
|
||||
>>> polymorphic_foo = baz.create_foo()
|
||||
>>> polymorphic_foo.call_pure()
|
||||
'this was never pure!'
|
||||
>>> baz.get_foo_value(polymorphic_foo)
|
||||
1000
|
||||
|
||||
Special member functions in action
|
||||
|
||||
>>> m = StringMap()
|
||||
|
||||
__getitem__(<unknown key>)
|
||||
>>> m[1]
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
KeyError: 1
|
||||
|
||||
__setitem__()
|
||||
|
||||
>>> m[1] = 'hello'
|
||||
|
||||
__getitem__(<known key>)
|
||||
>>> m[1]
|
||||
'hello'
|
||||
|
||||
__delitem__(<known key>)
|
||||
>>> del m[1]
|
||||
>>> m[1] # prove that it's gone
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
KeyError: 1
|
||||
|
||||
__delitem__(<unknown key>)
|
||||
>>> del m[2]
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
KeyError: 2
|
||||
|
||||
__length__()
|
||||
>>> len(m)
|
||||
0
|
||||
>>> m[3] = 'farther'
|
||||
>>> len(m)
|
||||
1
|
||||
|
||||
Check for sequence/mapping confusion:
|
||||
>>> for x in m:
|
||||
... print x
|
||||
...
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
KeyError: 0
|
||||
|
||||
Overloading tests:
|
||||
>>> r = Range(3)
|
||||
>>> print str(r)
|
||||
(3, 3)
|
||||
>>> r.start
|
||||
3
|
||||
>>> r.finish
|
||||
3
|
||||
>>> r.__len__()
|
||||
0
|
||||
>>> r.__len__(4)
|
||||
>>> r.finish
|
||||
7
|
||||
>>> try: r = Range('yikes')
|
||||
... except TypeError, e:
|
||||
... assert re.match(
|
||||
... 'No overloaded functions match [(]Range, string[)]\. Candidates are:\n.*\n.*',
|
||||
... str(e))
|
||||
|
||||
Sequence tests:
|
||||
>>> len(Range(3, 10))
|
||||
7
|
||||
|
||||
>>> map(lambda x:x, Range(3, 10))
|
||||
[3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
>>> map(lambda x:x, Range(3, 10)[-2:])
|
||||
[8, 9]
|
||||
|
||||
>>> map(lambda x:x, Range(3, 10)[:-4])
|
||||
[3, 4, 5]
|
||||
|
||||
>>> map(lambda x:x, Range(3, 10)[4:])
|
||||
[7, 8, 9]
|
||||
|
||||
>>> map(lambda x:x, Range(3, 10)[4:100])
|
||||
[7, 8, 9]
|
||||
|
||||
>>> map(lambda x:x, Range(3, 10)[20:])
|
||||
[]
|
||||
|
||||
>>> map(lambda x:x, Range(3, 10)[0:4])
|
||||
[3, 4, 5, 6]
|
||||
|
||||
delete non-existent attribute:
|
||||
del m.foobar
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
AttributeError: delete non-existing instance attribute
|
||||
|
||||
Testing __getattr__ and __getattr__<name>:
|
||||
|
||||
>>> n = IntPair(1, 2)
|
||||
>>> n.first
|
||||
1
|
||||
>>> n.second
|
||||
2
|
||||
>>> n.third
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
AttributeError: third
|
||||
|
||||
Testing __setattr__ and __setattr__<name>:
|
||||
>>> n.first = 33 # N.B __setattr__first sets first to
|
||||
>>> n.first # the negative of its argument.
|
||||
-33
|
||||
>>> n.second = 66
|
||||
>>> n.second
|
||||
66
|
||||
|
||||
Testing __delattr__ and __delattr__<name>:
|
||||
>>> del n.first
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
AttributeError: first can't be deleted!
|
||||
>>> del n.second
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
AttributeError: Attributes can't be deleted!
|
||||
>>> del n.third
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
AttributeError: Attributes can't be deleted!
|
||||
|
||||
# Now show that we can override it.
|
||||
|
||||
>>> class IntTriple(IntPair):
|
||||
... def __getattr__(self, s):
|
||||
... if s in ['first', 'second']:
|
||||
... return IntPair.__getattr__(self, s)
|
||||
... elif s == 'third':
|
||||
... return 3
|
||||
... else:
|
||||
... raise AttributeError(s)
|
||||
...
|
||||
... # Also show that __setattr__ is supported
|
||||
... def __setattr__(self, name, value):
|
||||
... raise AttributeError('no writable attributes')
|
||||
...
|
||||
>>> p = IntTriple(0, 1)
|
||||
>>> p.first
|
||||
0
|
||||
>>> p.second
|
||||
1
|
||||
>>> p.third
|
||||
3
|
||||
>>> p.bax
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
AttributeError: bax
|
||||
>>> p.third = 'yes'
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
AttributeError: no writable attributes
|
||||
>>> del p.third
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
AttributeError: Attributes can't be deleted!
|
||||
|
||||
demonstrate def_readonly, def_read_write:
|
||||
>>> sp = StringPair("hello", "world")
|
||||
>>> sp.first # first is read-only
|
||||
'hello'
|
||||
>>> first_string(sp) # prove that we're not just looking in sp's __dict__
|
||||
'hello'
|
||||
>>> sp.first = 'hi' # we're not allowed to change it
|
||||
Traceback (innermost last):
|
||||
File "<string>", line 1, in ?
|
||||
AttributeError: 'first' attribute is read-only
|
||||
>>> first_string(sp) # prove that it hasn't changed
|
||||
'hello'
|
||||
|
||||
>>> sp.second # second is read/write
|
||||
'world'
|
||||
>>> second_string(sp)
|
||||
'world'
|
||||
>>> sp.second = 'universe' # set the second attribute
|
||||
>>> sp.second
|
||||
'universe'
|
||||
>>> second_string(sp) # this proves we didn't just set it in sp's __dict__
|
||||
'universe'
|
||||
|
||||
some __str__ and __repr__ tests:
|
||||
>>> sp
|
||||
('hello', 'universe')
|
||||
>>> repr(sp)
|
||||
"('hello', 'universe')"
|
||||
>>> str(sp)
|
||||
"('hello', 'universe')"
|
||||
|
||||
Range has a __str__ function but not a __repr__ function
|
||||
>>> range = Range(5, 20)
|
||||
>>> str(range)
|
||||
'(5, 20)'
|
||||
>>> assert re.match('<Range object at [0-9a-f]+>', repr(range))
|
||||
|
||||
|
||||
__hash__ and __cmp__ tests:
|
||||
# Range has both __hash__ and __cmp__, thus is hashable
|
||||
>>> colors = { Range(3,4): 'blue', Range(7,9): 'red' }
|
||||
>>> colors[Range(3,4)]
|
||||
'blue'
|
||||
|
||||
# StringPair has only __cmp__
|
||||
>>> { StringPair('yo', 'eddy'): 1 }
|
||||
Traceback (innermost last):
|
||||
File "<string>", line 1, in ?
|
||||
TypeError: unhashable type
|
||||
|
||||
# But it can be sorted
|
||||
>>> stringpairs = [ StringPair('yo', 'eddy'), StringPair('yo', 'betty'), sp ]
|
||||
>>> stringpairs.sort()
|
||||
>>> stringpairs
|
||||
[('hello', 'universe'), ('yo', 'betty'), ('yo', 'eddy')]
|
||||
|
||||
make_pair is a global function in the module.
|
||||
|
||||
>>> couple = make_pair(3,12)
|
||||
>>> couple.first
|
||||
3
|
||||
>>> couple.second
|
||||
12
|
||||
|
||||
Testing __call__:
|
||||
>>> couple2 = make_pair(3, 7)
|
||||
>>> comparator = CompareIntPair()
|
||||
>>> comparator(couple, couple)
|
||||
0
|
||||
>>> comparator(couple, couple2)
|
||||
0
|
||||
>>> comparator(couple2, couple)
|
||||
1
|
||||
'''
|
||||
|
||||
from demo import *
|
||||
import string
|
||||
import re
|
||||
import sys
|
||||
|
||||
def run(args = None):
|
||||
if args is not None:
|
||||
sys.argv = args
|
||||
import doctest, test_extclass
|
||||
doctest.testmod(test_extclass)
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
63
todo.txt
Normal file
63
todo.txt
Normal file
@@ -0,0 +1,63 @@
|
||||
Better python and C++ exception handling/error reporting.
|
||||
long long support
|
||||
use Python generic numeric coercion in from_python() for C++ numeric types
|
||||
Document error-handling
|
||||
Consider renaming PyPtr to Reference.
|
||||
Report Cygwin linker memory issues
|
||||
handle more arguments
|
||||
Remove one level of indirection on type objects (no vtbl?).
|
||||
Much more testing, especially of things in objects.h
|
||||
Make multiple inheritance from real Python classes work.
|
||||
Handle polymorphism (passing a Wrapped<Derived> as a Base*).
|
||||
Specializations of Caller<> for commmon combinations of argument types (?)
|
||||
|
||||
Documentation:
|
||||
special member functions
|
||||
adding conversions for fundamental types
|
||||
generic conversions for template types (with partial spec).
|
||||
extending multiple-argument support.
|
||||
differences between Python classes and ExtensionClasses
|
||||
additional capabilities of ExtensionClasses
|
||||
exception handling
|
||||
building
|
||||
dealing with non-const reference/pointer parameters
|
||||
|
||||
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 ;)
|
||||
41
vc6_prj/ReadMe.txt
Normal file
41
vc6_prj/ReadMe.txt
Normal file
@@ -0,0 +1,41 @@
|
||||
========================================================================
|
||||
DYNAMIC LINK LIBRARY : vc6_prj
|
||||
========================================================================
|
||||
|
||||
|
||||
AppWizard has created this vc6_prj DLL for you.
|
||||
|
||||
This file contains a summary of what you will find in each of the files that
|
||||
make up your vc6_prj application.
|
||||
|
||||
vc6_prj.dsp
|
||||
This file (the project file) contains information at the project level and
|
||||
is used to build a single project or subproject. Other users can share the
|
||||
project (.dsp) file, but they should export the makefiles locally.
|
||||
|
||||
vc6_prj.cpp
|
||||
This is the main DLL source file.
|
||||
|
||||
When created, this DLL does not export any symbols. As a result, it
|
||||
will not produce a .lib file when it is built. If you wish this project
|
||||
to be a project dependency of some other project, you will either need to
|
||||
add code to export some symbols from the DLL so that an export library
|
||||
will be produced, or you can check the "doesn't produce lib" checkbox in
|
||||
the Linker settings page for this project.
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Other standard files:
|
||||
|
||||
StdAfx.h, StdAfx.cpp
|
||||
These files are used to build a precompiled header (PCH) file
|
||||
named vc6_prj.pch and a precompiled types file named StdAfx.obj.
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
Other notes:
|
||||
|
||||
AppWizard uses "TODO:" to indicate parts of the source code you
|
||||
should add to or customize.
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
8
vc6_prj/StdAfx.cpp
Normal file
8
vc6_prj/StdAfx.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// vc6_prj.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
24
vc6_prj/StdAfx.h
Normal file
24
vc6_prj/StdAfx.h
Normal file
@@ -0,0 +1,24 @@
|
||||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#if !defined(AFX_STDAFX_H__A41B37EF_17F7_406A_95AC_FE67BDB05B1E__INCLUDED_)
|
||||
#define AFX_STDAFX_H__A41B37EF_17F7_406A_95AC_FE67BDB05B1E__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
|
||||
// Insert your headers here
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
||||
|
||||
//{{AFX_INSERT_LOCATION}}
|
||||
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
|
||||
|
||||
#endif // !defined(AFX_STDAFX_H__A41B37EF_17F7_406A_95AC_FE67BDB05B1E__INCLUDED_)
|
||||
6
vc6_prj/test_demo.py
Normal file
6
vc6_prj/test_demo.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import demo # Get demo imported now so test_extclass won't look in its own directory
|
||||
import os
|
||||
os.chdir('..')
|
||||
import test_extclass
|
||||
test_extclass.run(['-v', '--broken-auto-ptr'])
|
||||
|
||||
6
vc6_prj/test_hello.py
Normal file
6
vc6_prj/test_hello.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import hello # Get demo imported now so test_extclass won't look in its own directory
|
||||
import os
|
||||
os.chdir('..')
|
||||
import test_example1
|
||||
test_example1.run(["-v"])
|
||||
|
||||
13
vc6_prj/vc6_prj.cpp
Normal file
13
vc6_prj/vc6_prj.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
// vc6_prj.cpp : Defines the entry point for the DLL application.
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
BOOL APIENTRY DllMain( HANDLE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
157
vc6_prj/vc6_prj.dsp
Normal file
157
vc6_prj/vc6_prj.dsp
Normal file
@@ -0,0 +1,157 @@
|
||||
# Microsoft Developer Studio Project File - Name="vc6_prj" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=vc6_prj - 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 "vc6_prj.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 "vc6_prj.mak" CFG="vc6_prj - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "vc6_prj - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "vc6_prj - 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)" == "vc6_prj - 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 1
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "VC6_PRJ_EXPORTS" /Yu"stdafx.h" /FD /c
|
||||
# ADD CPP /nologo /MT /W3 /GR /GX /Ox /Ot /Og /Oi /Os /Gy /I "c:\boost" /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "VC6_PRJ_EXPORTS" /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:"demo.dll" /libpath:"c:/tools/python/libs"
|
||||
# SUBTRACT LINK32 /pdb:none /debug
|
||||
|
||||
!ELSEIF "$(CFG)" == "vc6_prj - 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 "VC6_PRJ_EXPORTS" /Yu"stdafx.h" /FD /GZ /c
|
||||
# ADD CPP /nologo /MTd /Gm /GR /GX /ZI /Od /I "c:\boost" /I "c:\tools\python\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "VC6_PRJ_EXPORTS" /FR /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:"demo_d.dll" /pdbtype:sept /libpath:"c:/tools/python/src/pcbuild"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "vc6_prj - Win32 Release"
|
||||
# Name "vc6_prj - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\extclass.cpp
|
||||
|
||||
!IF "$(CFG)" == "vc6_prj - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "vc6_prj - Win32 Debug"
|
||||
|
||||
# ADD CPP /I "c:\tools\python\src\include" /D "DEBUG_PYTHON"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\extclass_demo.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\functions.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\init_function.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\module.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\newtypes.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\objects.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\py.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\subclass.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\StdAfx.h
|
||||
# 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
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ReadMe.txt
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
||||
29
vc6_prj/vc6_prj.dsw
Normal file
29
vc6_prj/vc6_prj.dsw
Normal file
@@ -0,0 +1,29 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "vc6_prj"=.\vc6_prj.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
BIN
vc6_prj/vc6_prj.opt
Normal file
BIN
vc6_prj/vc6_prj.opt
Normal file
Binary file not shown.
61
wrap_python.h
Normal file
61
wrap_python.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifdef _DEBUG
|
||||
# ifndef DEBUG_PYTHON
|
||||
# undef _DEBUG // Don't let Python force the debug library just because we're debugging.
|
||||
# define DEBUG_UNDEFINED_FROM_WRAP_PYTHON_H
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//
|
||||
// Some things we need in order to get Python.h to work with compilers other
|
||||
// than MSVC on Win32
|
||||
//
|
||||
#if defined(_WIN32)
|
||||
# ifdef __GNUC__
|
||||
|
||||
typedef int pid_t;
|
||||
# define WORD_BIT 32
|
||||
# define hypot _hypot
|
||||
# include <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
|
||||
|
||||
Reference in New Issue
Block a user