2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-27 07:02:15 +00:00

This commit was manufactured by cvs2svn to create branch 'data_driven'.

[SVN r8230]
This commit is contained in:
nobody
2000-11-16 17:14:05 +00:00
parent bc922755f3
commit 2212cbfd9e
65 changed files with 0 additions and 15441 deletions

View File

@@ -1,62 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef BASE_OBJECT_DWA051600_H_
# define BASE_OBJECT_DWA051600_H_
# include "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_

View File

@@ -1,43 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>
Building a Module with Py_cpp
</title>
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" align="center"
src="c++boost.gif" alt= "c++boost.gif (8819 bytes)">Building a Module with Py_cpp
</h1>
<p>
Right now, the only supported configuration is one in which the py_cpp
source files are statically linked with the source for your extension
module. You may first build them into a library and link it with your
extension module source, but the effect is the same as compiling all
the source files together. Some users have successfully built the
py_cpp sources into a shared library, and support for a shared library
build is planned, but not yet implemented. The py_cpp source files are:
<blockquote>
<pre>
<a href="extclass.cpp">extclass.cpp</a>
<a href="functions.cpp">functions.cpp</a>
<a href="init_function.cpp">init_function.cpp</a>
<a href="module.cpp">module.cpp</a>
<a href="newtypes.cpp">newtypes.cpp</a>
<a href="objects.cpp">objects.cpp</a>
<a href="py.cpp">py.cpp</a>
<a href="subclass.cpp">subclass.cpp</a>
</pre>
</blockquote>
<p>
Previous: <a href="under-the-hood.html">A Peek Under the Hood</a>
Up: <a href="py_cpp.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided "as is" without
express or implied warranty, and with no claim as to its suitability
for any purpose.
<p>
Updated: Oct 30, 2000
</div>

View File

@@ -1,339 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
//
// This file was generated for 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 {
namespace detail {
template <class T>
inline void callback_adjust_refcount(PyObject*, Type<T>) {}
inline void callback_adjust_refcount(PyObject* p, Type<PyObject*>)
{ Py_INCREF(p); }
}
// Calling Python from C++
template <class R>
struct Callback
{
static R call_method(PyObject* self, const char* name)
{
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("()")));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
static R call(PyObject* self)
{
Ptr result(PyEval_CallFunction(self, const_cast<char*>("()")));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
template <class A1>
static R call_method(PyObject* self, const char* name, const A1& a1)
{
Ptr p1(to_python(a1));
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("(O)"),
p1.get()));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
template <class A1>
static R call(PyObject* self, const A1& a1)
{
Ptr p1(to_python(a1));
Ptr result(PyEval_CallFunction(self, const_cast<char*>("(O)"),
p1.get()));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
template <class A1, class A2>
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("(OO)"),
p1.get(),
p2.get()));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
template <class A1, class A2>
static R call(PyObject* self, const A1& a1, const A2& a2)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr result(PyEval_CallFunction(self, const_cast<char*>("(OO)"),
p1.get(),
p2.get()));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
template <class A1, class A2, class A3>
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr p3(to_python(a3));
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("(OOO)"),
p1.get(),
p2.get(),
p3.get()));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
template <class A1, class A2, class A3>
static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr p3(to_python(a3));
Ptr result(PyEval_CallFunction(self, const_cast<char*>("(OOO)"),
p1.get(),
p2.get(),
p3.get()));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
template <class A1, class A2, class A3, class A4>
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr p3(to_python(a3));
Ptr p4(to_python(a4));
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("(OOOO)"),
p1.get(),
p2.get(),
p3.get(),
p4.get()));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
template <class A1, class A2, class A3, class A4>
static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr p3(to_python(a3));
Ptr p4(to_python(a4));
Ptr result(PyEval_CallFunction(self, const_cast<char*>("(OOOO)"),
p1.get(),
p2.get(),
p3.get(),
p4.get()));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
template <class A1, class A2, class A3, class A4, class A5>
static R call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr p3(to_python(a3));
Ptr p4(to_python(a4));
Ptr p5(to_python(a5));
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("(OOOOO)"),
p1.get(),
p2.get(),
p3.get(),
p4.get(),
p5.get()));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
template <class A1, class A2, class A3, class A4, class A5>
static R call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr p3(to_python(a3));
Ptr p4(to_python(a4));
Ptr p5(to_python(a5));
Ptr result(PyEval_CallFunction(self, const_cast<char*>("(OOOOO)"),
p1.get(),
p2.get(),
p3.get(),
p4.get(),
p5.get()));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
};
// 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)
{
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("()")));
}
static void call(PyObject* self)
{
Ptr result(PyEval_CallFunction(self, const_cast<char*>("()")));
}
template <class A1>
static void call_method(PyObject* self, const char* name, const A1& a1)
{
Ptr p1(to_python(a1));
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("(O)"),
p1.get()));
}
template <class A1>
static void call(PyObject* self, const A1& a1)
{
Ptr p1(to_python(a1));
Ptr result(PyEval_CallFunction(self, const_cast<char*>("(O)"),
p1.get()));
}
template <class A1, class A2>
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("(OO)"),
p1.get(),
p2.get()));
}
template <class A1, class A2>
static void call(PyObject* self, const A1& a1, const A2& a2)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr result(PyEval_CallFunction(self, const_cast<char*>("(OO)"),
p1.get(),
p2.get()));
}
template <class A1, class A2, class A3>
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr p3(to_python(a3));
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("(OOO)"),
p1.get(),
p2.get(),
p3.get()));
}
template <class A1, class A2, class A3>
static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr p3(to_python(a3));
Ptr result(PyEval_CallFunction(self, const_cast<char*>("(OOO)"),
p1.get(),
p2.get(),
p3.get()));
}
template <class A1, class A2, class A3, class A4>
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr p3(to_python(a3));
Ptr p4(to_python(a4));
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("(OOOO)"),
p1.get(),
p2.get(),
p3.get(),
p4.get()));
}
template <class A1, class A2, class A3, class A4>
static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr p3(to_python(a3));
Ptr p4(to_python(a4));
Ptr result(PyEval_CallFunction(self, const_cast<char*>("(OOOO)"),
p1.get(),
p2.get(),
p3.get(),
p4.get()));
}
template <class A1, class A2, class A3, class A4, class A5>
static void call_method(PyObject* self, const char* name, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr p3(to_python(a3));
Ptr p4(to_python(a4));
Ptr p5(to_python(a5));
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("(OOOOO)"),
p1.get(),
p2.get(),
p3.get(),
p4.get(),
p5.get()));
}
template <class A1, class A2, class A3, class A4, class A5>
static void call(PyObject* self, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5)
{
Ptr p1(to_python(a1));
Ptr p2(to_python(a2));
Ptr p3(to_python(a3));
Ptr p4(to_python(a4));
Ptr p5(to_python(a5));
Ptr result(PyEval_CallFunction(self, const_cast<char*>("(OOOOO)"),
p1.get(),
p2.get(),
p3.get(),
p4.get(),
p5.get()));
}
};
} // namespace py
#endif // CALLBACK_DWA_052100_H_

507
caller.h
View File

@@ -1,507 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
//
// This file 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
View File

@@ -1,79 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef CAST_DWA052500_H_
# define CAST_DWA052500_H_
# include "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_

View File

@@ -1,149 +0,0 @@
#ifndef CLASS_WRAPPER_DWA101000_H_
# define CLASS_WRAPPER_DWA101000_H_
#include "extclass.h"
#include "operators.h"
#include "module.h"
#include "py.h"
#include "cast.h"
#include "pyptr.h"
namespace py {
// 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))
{
module.add(Ptr(as_object(m_class.get()), Ptr::new_ref), name);
}
// define constructors
template <class Signature>
void def(const Signature& signature)
{ m_class->def(signature); }
// export heterogeneous reverse-argument operators
// (type of lhs: 'left', of rhs: 'right')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(),
// py::left_operand<int const &>());
template <int which, class left, class right>
void def(operators<which, right> o1, left_operand<left> o2)
{ m_class->def(o1, o2); }
// export heterogeneous operators (type of lhs: 'left', of rhs: 'right')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(),
// py::right_operand<int const &>());
template <int which, class left, class right>
void def(operators<which, left> o1, right_operand<right> o2)
{ m_class->def(o1, o2); }
// define a function that passes Python arguments and keywords
// to C++ verbatim (as a 'Tuple const &' and 'Dict const &'
// respectively). This is useful for manual argument passing.
// It's also the only possibility to pass keyword arguments to C++.
// Fn must have a signatur that is compatible to
// PyObject * (*)(PyObject * aTuple, PyObject * aDictionary)
template <class Fn>
void def_raw(Fn fn, const char* name)
{ m_class->def_raw(fn, name); }
// define member functions. In fact this works for free functions, too -
// they act like static member functions, or if they start with the
// appropriate self argument (as a pointer or reference), they can be used
// just like ordinary member functions -- just like Python!
template <class Fn>
void def(Fn fn, const char* name)
{ m_class->def(fn, name); }
// Define a virtual member function with a default implementation.
// default_fn should be a function which provides the default implementation.
// Be careful that default_fn does not in fact call fn virtually!
template <class Fn, class DefaultFn>
void def(Fn fn, const char* name, DefaultFn default_fn)
{ m_class->def(fn, name, default_fn); }
// Provide a function which implements x.<name>, reading from the given
// member (pm) of the T 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); }
// declare the given class a base class of this one and register
// conversion functions
template <class S, class V>
void declare_base(ClassWrapper<S, V> const & base)
{
m_class->declare_base(base.get_extension_class());
}
// declare the given class a base class of this one and register
// upcast conversion function
template <class S, class V>
void declare_base(ClassWrapper<S, V> const & base, WithoutDowncast)
{
m_class->declare_base(base.get_extension_class(), without_downcast);
}
// declare the given class a base class of this one and register
// conversion functions
template <class S, class V>
void declare_base(ExtensionClass<S, V> * base)
{
m_class->declare_base(base);
}
// declare the given class a base class of this one and register
// upcast conversion function
template <class S, class V>
void declare_base(ExtensionClass<S, V> * base, WithoutDowncast)
{
m_class->declare_base(base, without_downcast);
}
// get the embedded ExtensioClass object
ExtensionClass<T, U> * get_extension_class() const
{
return m_class.get();
}
// set an arbitrary attribute. Useful for non-function class data members,
// e.g. enums
void add(PyObject* x, const char* name)
{ m_class->set_attribute(name, x); }
void add(Ptr x, const char* name)
{ m_class->set_attribute(name, x); }
private:
PyPtr<ExtensionClass<T, U> > m_class;
};
// The bug mentioned at the top of this file is that on certain compilers static
// global functions declared within the body of a class template will only be
// generated when the class template is constructed, and when (for some reason)
// the construction does not occur via a new-expression. Otherwise, we could
// rely on the initialization of the m_class data member to cause all of the
// to_/from_python functions to come into being.
}
#endif // CLASS_WRAPPER_DWA101000_H_

View File

@@ -1,216 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>
Comparisons with Other Systems
</title>
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" align="center"
src="c++boost.gif" alt= "c++boost.gif (8819 bytes)">Comparisons with
Other Systems
</h1>
<h2>CXX</h2>
<p>
Like py_cpp, <a href="http://cxx.sourceforge.net/">CXX</a> attempts to
provide a C++-oriented interface to Python. In most cases, like py_cpp,
it relieves the user from worrying about reference-counts. As far as I
can tell, there is no support for subclassing C++ extension types in
Python. An even more-significant difference is that a user's C++ code is
still basically "dealing with Python objects", though they are wrapped
in C++ classes. This means such jobs as argument parsing and conversion
are still left to be done explicitly by the user. This is not entirely a
bad thing, as you can do some Pythonic things with CXX (e.g. variable
and keyword arguments) that I haven't yet figured out how to enable with
py_cpp.
<p>
As far as I can tell, CXX enables one to write what is essentially
idiomatic Python code in C++, manipulating Python objects through the
same fully-generic interfaces we use in Python. That use is also
supported by the py_cpp object wrappers. CXX claims to interoperate well
with the C++ Standard Library (a.k.a. STL) by providing iterators into
Python Lists and Dictionaries, but the claim is unfortunately
unsupportable. The problem is that in general, access to Python sequence and
mapping elements through iterators requires the use of Proxy objects as
the return value of iterator dereference operations. This usage
conflicts with the basic ForwardIterator requirements in <a
href="http://anubis.dkuug.dk/jtc1/sc22/open/n2356/lib-iterators.html#lib.forward.iterators">
section 24.1.3 of the standard</a> (dereferencing must produce a
reference). Although you may be able to use these iterators with some
operations in some standard library implementations, it is neither
guaranteed to work nor portable.
<p>
<a href="mailto:dubois1@llnl.gov">Paul F. Dubois</a>, the original
author of CXX, has told me that what I've described is only half of the
picture with CXX, but I never understood his explanation well-enough to
fill in the other half. Here is his response to the commentary above:
<blockquote>
"My intention with CXX was not to do what you are doing. It was to enable a
person to write an extension directly in C++ rather than C. I figured others had
the wrapping business covered. I thought maybe CXX would provide an easier
target language for those making wrappers, but I never explored
that."<br><i>-<a href="mailto:dubois1@llnl.gov">Paul Dubois</a></i>
</blockquote>
<h2>SWIG</h2>
<p>
<a href= "http://www.swig.org/">SWIG</a> is an impressively mature tool
for exporting an existing ANSI 'C' interface into various scripting
languages. Swig relies on a parser to read your source code and produce
additional source code files which can be compiled into a Python (or
Perl or Tcl) extension module. It has been successfully used to create
many Python extension modules. Like py_cpp, SWIG is trying to allow an
existing interface to be wrapped with little or no change to the
existing code. The documentation says "SWIG parses a form of ANSI C
syntax that has been extended with a number of special directives. As a
result, interfaces are usually built by grabbing a header file and
tweaking it a little bit." For C++ interfaces, the tweaking has often
proven to amount to more than just a little bit. One user
writes:
<blockquote> "The problem with swig (when I used it) is that it
couldnt handle templates, didnt do func overloading properly etc. For
ANSI C libraries this was fine. But for usual C++ code this was a
problem. Simple things work. But for anything very complicated (or
realistic), one had to write code by hand. I believe py_cpp doesn't have
this problem[<a href="#sic">sic</a>]... IMHO overloaded functions are very important to
wrap correctly."<br><i>-Prabhu Ramachandran</i>
</blockquote>
<p>
By contrast, py_cpp doesn't attempt to parse C++ - the problem is simply
too complex to do correctly. <a name="sic">Technically</a>, one does
write code by hand to use py_cpp. The goal, however, has been to make
that code nearly as simple as listing the names of the classes and
member functions you want to expose in Python.
<h2>SIP</h2>
<p>
<a
href="http://www.thekompany.com/projects/pykde/background.php3?dhtml_ok=1">SIP</a>
is a system similar to SWIG, though seemingly more
C++-oriented. The author says that like py_cpp, SIP supports overriding
extension class member functions in Python subclasses. It appears to
have been designed specifically to directly support some features of
PyQt/PyKDE, which is its primary client. Documentation is almost
entirely missing at the time of this writing, so a detailed comparison
is difficult.
<h2>ILU</h2>
<p>
<a
href="http://www.cl.cam.ac.uk/Research/Rainbow/projects/origami/ilu-1.8-manual">ILU</a>
is a very ambitious project which tries to describe a module's interface
(types and functions) in terms of an <a
href="http://www.cl.cam.ac.uk/Research/Rainbow/projects/origami/ilu-1.8-manual/manual_2.html">Interface
Specification Language</a> (ISL) so that it can be uniformly interfaced
to a wide range of computer languages, including Common Lisp, C++, C,
Modula-3, and Python. ILU can parse the ISL to generate a C++ language
header file describing the interface, of which the user is expected to
provide an implementation. Unlike py_cpp, this means that the system
imposes implementation details on your C++ code at the deepest level. It
is worth noting that some of the C++ names generated by ILU are supposed
to be reserved to the C++ implementation. It is unclear from the
documentation whether ILU supports overriding C++ virtual functions in Python.
<h2>GRAD</h2>
<p>
<a
href="http://www.python.org/workshops/1996-11/papers/GRAD/html/GRADcover.html">GRAD</a>
is another very ambitious project aimed at generating Python wrappers for
interfaces written in "legacy languages", among which C++ is the first one
implemented. Like SWIG, it aims to parse source code and automatically
generate wrappers, though it appears to take a more sophisticated approach
to parsing in general and C++ in particular, so it should do a much better
job with C++. It appears to support function overloading. The
documentation is missing a lot of information I'd like to see, so it is
difficult to give an accurate and fair assessment. I am left with the
following questions:
<ul>
<li>Does it support overriding of virtual functions?
<li>What about overriding private or protected virtual functions (the documentation indicates
that only public interfaces are supported)?
<li>Which C++ language constructs are supportd?
<li>Does it support implicit conversions between wrapped C++ classes that have
an inheritance relationship?
<li>Does it support smart pointers?
</ul>
<p>
Anyone in the possession of the answers to these questions will earn my
gratitude for a write-up <code>;-)</code>
<h2>Zope ExtensionClasses</h2>
<p>
<a href="http:http://www.digicool.com/releases/ExtensionClass">
ExtensionClasses in Zope</a> use the same underlying mechanism as py_cpp
to support subclassing of extension types in Python, including
multiple-inheritance. Both systems rely on the same "<a
href="http://www.python.org/workshops/1994-11/BuiltInClasses/Welcome.html">Don
Beaudry Hack</a>" that also inspired Don's MESS System.
<p>
The major differences are:
<ul>
<li>
py_cpp lifts the burden on the user to parse and convert function
argument types. Zope provides no such facility.
<li>
py_cpp lifts the burden on the user to maintain Python
reference-counts.
<li>
py_cpp supports function overloading; Zope does not.
<li>
py_cpp supplies a simple mechanism for exposing read-only and
read/write access to data members of the wrapped C++ type as Python
attributes.
<li>
Writing a Zope ExtensionClass is significantly more complex than
exposing a C++ class to python using py_cpp (mostly a summary of the
previous 4 items). <a href=
"http://www.digicool.com/releases/ExtensionClass/MultiMapping.html">A
Zope Example</a> illustrates the differences.
<li>
Zope's ExtensionClasses are specifically motivated by "the need for a
C-based persistence mechanism". Py_cpp's are motivated by the desire
to simply reflect a C++ API into Python with as little modification as
possible.
<li>
Thus, Zope's ExtensionClasses support pickling. Currently py_cpp
ExtensionClasses do not.
<li>
The following Zope restriction does not apply to py_cpp: "At most one
base extension direct or indirect super class may define C data
members. If an extension subclass inherits from multiple base
extension classes, then all but one must be mix-in classes that
provide extension methods but no data."
<li>
Zope requires use of the somewhat funky inheritedAttribute (search for
"inheritedAttribute" on <a
href="http://www.digicool.com/releases/ExtensionClass">this page</a>)
method to access base class methods. In py_cpp, base class methods can
be accessed in the usual way by writing
"<code>BaseClass.method</code>".
<li>
Zope supplies some creative but esoteric idioms such as <a href=
"http://www.digicool.com/releases/ExtensionClass/Acquisition.html">
Acquisition</a>.
<li>
Zope's ComputedAttribute support is designed to be used from Python.
<a href="special.html#getter_setter">The analogous feature of
py_cpp</a> can be used from C++ or Python. The feature is arguably
easier to use in py_cpp.
</ul>
<p>
Previous: <a href="extending.html">A Brief Introduction to writing Python Extension Modules</a>
Next: <a href="example1.html">A Simple Example Using py_cpp</a>
Up: <a href="py_cpp.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided "as is" without
express or implied warranty, and with no claim as to its suitability
for any purpose.
<p>
Updated: Oct 30, 2000
</div>

View File

@@ -1,192 +0,0 @@
Given a real Python class 'A', a wrapped C++ class 'B', and this definition:
class C(A, B):
def __init__(self):
B.__init__(self)
self.x = 1
...
c = C()
this diagram describes the internal structure of an instance of 'C', including
its inheritance relationships. Note that ExtensionClass<B> is derived from
Class<ExtensionInstance>, and is in fact identical for all intents and purposes.
MetaClass<ExtensionInstance>
+---------+ +---------+
types.ClassType: | | | |
| | | |
| | | |
+---------+ +---------+
^ ^ ^
PyClassObject | ExtensionClass<B> | |
A: +------------+ | B: +------------+ | |
| ob_type -+-+ | ob_type -+-----+ |
| | ()<--+- __bases__ | |
| | | __dict__ -+->{...} |
| | 'B'<-+- __name__ | |
+------------+ +------------+ |
^ ^ |
| | |
+-----+ +-------------+ |
| | |
| | Class<ExtensionInstance> |
| | C: +------------+ |
| | | ob_type -+------------+
tuple:(*, *)<--+- __bases__ |
| __dict__ -+->{__module__, <methods, etc.>}
'C' <-+- __name__ |
+------------+
^ (in case of inheritance from more than one
| extension class, this vector would contain
+---------------+ a pointer to an instance holder for the data
| of each corresponding C++ class)
| ExtensionInstance
| c: +---------------------+ std::vector<InstanceHolderBase>
+----+- __class__ | +---+--
| m_wrapped_objects -+->| * | ...
{'x': 1}<-+- __dict__ | +-|-+--
+---------------------+ | InstanceValueHolder<B>
| +--------------------------------+
+-->| (contains a C++ instance of B) |
+--------------------------------+
In our inheritance test cases in extclass_demo.cpp/test_extclass.py, we have the
following C++ inheritance hierarchy:
+-----+ +----+
| A1 | | A2 |
+-----+ +----+
^ ^ ^ ^ ^
| | | | |
+-----+ | +---------+-----+
| | | |
| +---+----------+
.......!...... | |
: A_callback : +-+--+ +-+--+
:............: | B1 | | B2 |
+----+ +----+
^
|
+-------+---------+
| |
+-+-+ ......!.......
| C | : B_callback :
+---+ :............:
A_callback and B_callback are used as part of the wrapping mechanism but not
represented in Python. C is also not represented in Python but is delivered
there polymorphically through a smart pointer.
This is the data structure in Python.
ExtensionClass<A1>
A1: +------------+
()<--+- __bases__ |
| __dict__ -+->{...}
+------------+
^
| ExtensionInstance
| a1: +---------------------+ vec InstanceValueHolder<A1,A_callback>
+---------+- __class__ | +---+ +---------------------+
| | m_wrapped_objects -+->| *-+-->| contains A_callback |
| +---------------------+ +---+ +---------------------+
|
| ExtensionInstance
| pa1_a1: +---------------------+ vec InstancePtrHolder<auto_ptr<A1>,A1>
+---------+- __class__ | +---+ +---+
| | m_wrapped_objects -+->| *-+-->| *-+-+ A1
| +---------------------+ +---+ +---+ | +---+
| +->| |
| ExtensionInstance +---+
| pb1_a1: +---------------------+ vec InstancePtrHolder<auto_ptr<A1>,A1>
+---------+- __class__ | +---+ +---+
| | m_wrapped_objects -+->| *-+-->| *-+-+ B1
| +---------------------+ +---+ +---+ | +---+
| +->| |
| ExtensionInstance +---+
| pb2_a1: +---------------------+ vec InstancePtrHolder<auto_ptr<A1>,A1>
+---------+- __class__ | +---+ +---+
| | m_wrapped_objects -+->| *-+-->| *-+-+ B2
| +---------------------+ +---+ +---+ | +---+
| +->| |
| +---+
| ExtensionClass<A1>
| A2: +------------+
| ()<--+- __bases__ |
| | __dict__ -+->{...}
| +------------+
| ^
| | ExtensionInstance
| a2: | +---------------------+ vec InstanceValueHolder<A2>
| +-+- __class__ | +---+ +-------------+
| | | m_wrapped_objects -+->| *-+-->| contains A2 |
| | +---------------------+ +---+ +-------------+
| |
| | ExtensionInstance
| pa2_a2: | +---------------------+ vec InstancePtrHolder<auto_ptr<A2>,A2>
| +-+- __class__ | +---+ +---+
| | | m_wrapped_objects -+->| *-+-->| *-+-+ A2
| | +---------------------+ +---+ +---+ | +---+
| | +->| |
| | ExtensionInstance +---+
| pb1_a2: | +---------------------+ vec InstancePtrHolder<auto_ptr<A2>,A2>
| +-+- __class__ | +---+ +---+
| | | m_wrapped_objects -+->| *-+-->| *-+-+ B1
| | +---------------------+ +---+ +---+ | +---+
| | +->| |
| | +---+
| |
| +---------------+------------------------------+
| | |
+------+-------------------------+-|----------------------------+ |
| | | | |
| Class<ExtensionInstance> | | ExtensionClass<B1> | | ExtensionClass<B1>
| DA1: +------------+ | | B1: +------------+ | | B2: +------------+
(*,)<---+- __bases__ | (*,*)<---+- __bases__ | (*,*)<---+- __bases__ |
| __dict__ -+->{...} | __dict__ -+->{...} | __dict__ -+->{...}
+------------+ +------------+ +------------+
^ ^ ^
| ExtensionInstance | |
| da1: +---------------------+ | vec InstanceValueHolder<A1,A_callback>
+-------+- __class__ | | +---+ +---------------------+ |
| m_wrapped_objects -+--|-->| *-+-->| contains A_callback | |
+---------------------+ | +---+ +---------------------+ |
+--------------------------------------+ |
| ExtensionInstance |
b1: | +---------------------+ vec InstanceValueHolder<B1,B_callback> |
+-+- __class__ | +---+ +---------------------+ |
| | m_wrapped_objects -+->| *-+-->| contains B_callback | |
| +---------------------+ +---+ +---------------------+ |
| |
| ExtensionInstance |
pb1_b1: | +---------------------+ vec InstancePtrHolder<auto_ptr<B1>,B1> |
+-+- __class__ | +---+ +---+ |
| | m_wrapped_objects -+->| *-+-->| *-+-+ B1 |
| +---------------------+ +---+ +---+ | +---+ |
| +->| | |
| ExtensionInstance +---+ |
pc_b1: | +---------------------+ vec InstancePtrHolder<auto_ptr<B1>,B1> |
+-+- __class__ | +---+ +---+ |
| | m_wrapped_objects -+->| *-+-->| *-+-+ C |
| +---------------------+ +---+ +---+ | +---+ |
| +->| | |
| +---+ |
| |
| Class<ExtensionInstance> +---------------------------------------+
| DB1: +------------+ | ExtensionInstance
(*,)<---+- __bases__ | a2: | +---------------------+ vec InstanceValueHolder<A2>
| __dict__ -+->{...} +-+- __class__ | +---+ +-------------+
+------------+ | m_wrapped_objects -+->| *-+-->| contains A2 |
^ +---------------------+ +---+ +-------------+
| ExtensionInstance
db1: | +---------------------+ vec InstanceValueHolder<B1,B_callback>
+-+- __class__ | +---+ +----------------------+
| m_wrapped_objects -+-->| *-+-->| contains B1_callback |
+---------------------+ +---+ +----------------------+

1112
doctest.py

File diff suppressed because it is too large Load Diff

708
doxyfile
View File

@@ -1,708 +0,0 @@
# 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 =

View File

@@ -1,94 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>
Wrapping enums
</title>
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" align="center"
src="c++boost.gif" alt= "c++boost.gif (8819 bytes)">Wrapping enums
</h1>
<p>Because there is in general no way to deduce that a value of arbitrary type T
is an enumeration constant, py_cpp cannot automatically convert enum values to
and from Python. To handle this case, you need to decide how you want the enum
to show up in Python (since Python doesn't have enums). Once you have done that,
you can write some simple <code>from_python()</code> and
<code>to_python()</code> functions.
<p>If you are satisfied with a Python int as a way to represent your enum
values, py_cpp provides a shorthand for these functions. You just need to
instantiate <code>py::enum_as_int_converters&lt;EnumType&gt;</code> where
<code>EnumType</code> is your enumerated type. There are two convenient ways to do this:
<ol>
<li><blockquote>
<pre>
// drop into namespace py and explicitly instantiate
namespace py {
template class enum_as_int_converters<extclass_demo::EnumOwner::enum_type>;
}
</pre>
</blockquote>
<li><blockquote><pre>
// instantiate as base class in any namespace
struct EnumTypeConverters
: py::py_enum_as_int_converters<EnumType>
{
};
</blockquote></pre>
</ol>
<p>Either of the above is equivalent to the following declarations:
<blockquote><pre>
PY_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
MyEnumType from_python(PyObject* x, py::Type&lt;MyEnumType&gt;)
{
return static_cast&lt;MyEnum&gt;(
from_python(x, py::Type&lt;long&gt;()));
}
MyEnumType from_python(PyObject* x, py::Type&lt;const MyEnumType&amp;&gt;)
{
return static_cast&lt;MyEnum&gt;(
from_python(x, py::Type&lt;long&gt;()));
}
PyObject* to_python(MyEnumType x)
{
return to_python(static_cast&lt;long&gt;(x));
}
PY_END_CONVERSION_NAMESPACE
</pre></blockquote>
<p>This technique defines the conversions of
<code>MyEnumType</code> in terms of the conversions for the built-in
<code>long</code> type.
You may also want to add a bunch of lines like this to your module
initialization:
<blockquote><pre>
mymodule.add(py::to_python(enum_value_1), "enum_value_1");
mymodule.add(py::to_python(enum_value_2), "enum_value_2");
...
</pre></blockquote>
You can also add these to an extension class definition, if your enum happens to
be local to a class and you want the analogous interface in Python:
<blockquote><pre>
my_class.add(py::to_python(enum_value_1), "enum_value_1");
my_class.add(py::to_python(enum_value_2), "enum_value_2");
...
</pre></blockquote>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided "as is" without
express or implied warranty, and with no claim as to its suitability
for any purpose.
<p>
Updated: Nov 12, 2000
</div>

View File

@@ -1,30 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef ERRORS_DWA052500_H_
# define ERRORS_DWA052500_H_
namespace 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_

View File

@@ -1,54 +0,0 @@
#include <string.h>
namespace hello {
class world
{
public:
world(int) {}
~world() {}
const char* get() const { return "hi, world"; }
};
size_t length(const world& x) { return strlen(x.get()); }
}
#include <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

View File

@@ -1,127 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>
A Simple Example Using py_cpp
</title>
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" src="c++boost.gif" alt=
"c++boost.gif (8819 bytes)">
</h1>
<h1>
A Simple Example Using py_cpp
</h1>
<p>
Suppose we have the following C++ API which we want to expose in
Python:
<blockquote>
<pre>
namespace hello {
  class world
  {
   public:
      world(int);
      ~world();
      const char* get() const { return "hi, world"; }
    ...
  };
  std::size_t length(const world&amp; x) { return std::strlen(x.get()); }
}
</pre>
</blockquote>
<p>
Here is the C++ code for a python module called <code>hello</code>
which exposes the API using py_cpp:
<blockquote>
<pre>
#include &lt;py_cpp/class_wrapper.h&gt;
// Python requires an exported function called init&lt;module-name&gt; 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&lt;hello::world&gt; world_class(hello, "world");
       // Add the __init__ function
       world_class.def(py::Constructor&lt;int&gt;());
       // Add a regular member function
       world_class.def(&amp;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 &lt;windows.h&gt;
extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID)
{
    return 1;
}
#endif // _WIN32
</pre>
</blockquote>
<p>
That's it! If we build this shared library and put it on our <code>
PYTHONPATH</code> we can now access our C++ class and function from
Python.
<blockquote>
<pre>
&gt;&gt;&gt; import hello
&gt;&gt;&gt; hi_world = hello.world(3)
&gt;&gt;&gt; hi_world.get()
'hi, world'
&gt;&gt;&gt; hello.length(hi_world)
9
</pre>
</blockquote>
<p>
We can even make a subclass of <code>hello.world</code>:
<blockquote>
<pre>
&gt;&gt;&gt; class my_subclass(hello.world):
...     def get(self):
...         return 'hello, world'
...
&gt;&gt;&gt; y = my_subclass(4)
&gt;&gt;&gt; y.get()
'hello, world'
</pre>
</blockquote>
<p>
Pretty cool! You can't do that with an ordinary Python extension type!
<blockquote>
<pre>
&gt;&gt;&gt; hello.length(y)
9
</pre>
</blockquote>
<p>
Of course, you may now have a slightly empty feeling in the pit of
your little pythonic stomach. Perhaps you feel your subclass deserves
to have a <code>length()</code> of <code>12</code>? If so, <a href=
"overriding.html">read on</a>...
<p>
Previous: <a href="comparisons.html">Comparisons with other systems</a> Next: <a href="overriding.html">Overridable virtual functions</a> Up:
<a href="py_cpp.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided "as is" without
express or implied warranty, and with no claim as to its suitability
for any purpose.
<p>
Updated: Oct 30, 2000
</div>

View File

@@ -1,661 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#include "extclass.h"
#include <cstring>
#include <boost/utility.hpp>
namespace py {
namespace detail {
struct operator_dispatcher
: public PyObject
#ifndef NDEBUG
, boost::noncopyable
#endif
{
static PyTypeObject type_object;
static PyNumberMethods number_methods;
operator_dispatcher(const Ptr& o, const Ptr& s);
#ifndef NDEBUG
~operator_dispatcher();
#endif
static void dealloc(PyObject* self);
static int coerce(PyObject** l, PyObject** r);
static PyObject* call_add(PyObject*, PyObject*);
static PyObject* call_sub(PyObject*, PyObject*);
static PyObject* call_mul(PyObject*, PyObject*);
static PyObject* call_div(PyObject*, PyObject*);
static PyObject* call_mod(PyObject*, PyObject*);
static PyObject* call_divmod(PyObject*, PyObject*);
static PyObject* call_lshift(PyObject*, PyObject*);
static PyObject* call_rshift(PyObject*, PyObject*);
static PyObject* call_and(PyObject*, PyObject*);
static PyObject* call_xor(PyObject*, PyObject*);
static PyObject* call_or(PyObject*, PyObject*);
static PyObject* call_pow(PyObject*, PyObject*, PyObject*);
static int call_cmp(PyObject*, PyObject*);
Ptr m_object;
Ptr m_self;
};
}}
PY_BEGIN_CONVERSION_NAMESPACE
inline PyObject* to_python(py::detail::operator_dispatcher* n) { return n; }
PY_END_CONVERSION_NAMESPACE
namespace py{ namespace detail {
Tuple extension_class_coerce(Ptr l, Ptr r)
{
// Introduced sequence points for exception-safety.
Ptr first(new operator_dispatcher(l, l));
Ptr second(new operator_dispatcher(r, Ptr()));
return py::Tuple(first, second);
}
enum { unwrap_exception_code = -1000 };
int unwrap_args(PyObject* left, PyObject* right, PyObject*& self, PyObject*& other)
{
if (left->ob_type != &operator_dispatcher::type_object ||
right->ob_type != &operator_dispatcher::type_object)
{
String format("operator_dispatcher::unwrap_args(): internal error (%d, %d)");
String message(format % Tuple(__FILE__, __LINE__));
PyErr_SetObject(PyExc_RuntimeError, message.get());
return unwrap_exception_code;
}
operator_dispatcher* lwrapper = static_cast<operator_dispatcher*>(left);
operator_dispatcher* rwrapper = static_cast<operator_dispatcher*>(right);
if (lwrapper->m_self.get() != 0)
{
self = lwrapper->m_self.get();
other = rwrapper->m_object.get();
return false;
}
else
{
self = rwrapper->m_self.get();
other = lwrapper->m_object.get();
return true;
}
}
int unwrap_pow_args(PyObject* left, PyObject* right, PyObject* m,
PyObject*& self, PyObject*& first, PyObject*& second)
{
if (left->ob_type != &operator_dispatcher::type_object ||
right->ob_type != &operator_dispatcher::type_object ||
m->ob_type != &operator_dispatcher::type_object)
{
String format("operator_dispatcher::unwrap_pow_args(): internal error (%d, %d)");
String message(format % Tuple(__FILE__, __LINE__));
PyErr_SetObject(PyExc_RuntimeError, message.get());
return unwrap_exception_code;
}
operator_dispatcher* lwrapper = static_cast<operator_dispatcher*>(left);
operator_dispatcher* rwrapper = static_cast<operator_dispatcher*>(right);
operator_dispatcher* mwrapper = static_cast<operator_dispatcher*>(m);
if (mwrapper->m_object->ob_type == &operator_dispatcher::type_object)
{
mwrapper = static_cast<operator_dispatcher*>(mwrapper->m_object.get());
}
if (lwrapper->m_self.get() != 0)
{
self = lwrapper->m_self.get();
first = rwrapper->m_object.get();
second = mwrapper->m_object.get();
return 0;
}
else if (rwrapper->m_self.get() != 0)
{
self = rwrapper->m_self.get();
first = lwrapper->m_object.get();
second = mwrapper->m_object.get();
return 1;
}
else
{
self = mwrapper->m_self.get();
first = lwrapper->m_object.get();
second = rwrapper->m_object.get();
return 2;
}
}
} // namespace detail
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 convertible into '%.*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())
{
}
// This function is used in from_python() to convert wrapped classes that are
// related by inheritance. The problem is this: although C++ provides all necessary
// conversion operators, source and target of a conversion must be known at compile
// time. However, in Python we want to convert classes at runtime. The solution is to
// generate conversion functions at compile time, register them within the appropriate
// class objects and call them when a particular runtime conversion is required.
// If functions for any possible conversion have to be stored, their number will grow
// qudratically. To reduce this number, we actually store only conversion functions
// between adjacent levels in the inheritance tree. By traversing the tree recursively,
// we can build any allowed conversion as a concatenation of simple conversions. This
// traversal is done in the functions try_base_class_conversions() and
// try_derived_class_conversions(). If a particular conversion is impossible, all
// conversion functions will return a NULL pointer.
// The function extract_object_from_holder() attempts to actually extract the pointer
// to the contained object from an InstanceHolderBase (a wrapper class). A conversion
// of the held object to 'T *' is allowed when the conversion
// 'dynamic_cast<InstanceHolder<T> *>(an_instance_holder_base)' succeeds.
void* ExtensionClassBase::try_class_conversions(InstanceHolderBase* object) const
{
void* result = try_derived_class_conversions(object);
if (result)
return result;
if (!object->held_by_value())
return try_base_class_conversions(object);
else
return 0;
}
void* ExtensionClassBase::try_base_class_conversions(InstanceHolderBase* object) const
{
for (std::size_t i = 0; i < base_classes().size(); ++i)
{
if (base_classes()[i].convert == 0)
continue;
void* result1 = base_classes()[i].class_object->extract_object_from_holder(object);
if (result1)
return (*base_classes()[i].convert)(result1);
void* result2 = base_classes()[i].class_object->try_base_class_conversions(object);
if (result2)
return (*base_classes()[i].convert)(result2);
}
return 0;
}
void* ExtensionClassBase::try_derived_class_conversions(InstanceHolderBase* object) const
{
for (std::size_t i = 0; i < derived_classes().size(); ++i)
{
void* result1 = derived_classes()[i].class_object->extract_object_from_holder(object);
if (result1)
return (*derived_classes()[i].convert)(result1);
void* result2 = derived_classes()[i].class_object->try_derived_class_conversions(object);
if (result2)
return (*derived_classes()[i].convert)(result2);
}
return 0;
}
void ExtensionClassBase::add_method(Function* method, const char* name)
{
add_method(PyPtr<Function>(method), name);
}
void ExtensionClassBase::add_method(PyPtr<Function> method, const char* name)
{
// Add the attribute to the computed target
Function::add_to_namespace(method, name, this->dict().get());
// If it is a special member function it should be enabled both here and there.
detail::enable_named_method(this, name);
}
void 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());
}
void ExtensionClassBase::set_attribute(const char* name, PyObject* x_)
{
Ptr x(x_);
set_attribute(name, x);
}
void ExtensionClassBase::set_attribute(const char* name, Ptr x)
{
dict().set_item(String(name), x);
if (PyCallable_Check(x.get()))
detail::enable_named_method(this, name);
}
namespace detail
{
PyTypeObject operator_dispatcher::type_object =
{
PyObject_HEAD_INIT(&PyType_Type)
0,
const_cast<char*>("operator_dispatcher"),
sizeof(operator_dispatcher),
0,
(destructor)&operator_dispatcher::dealloc,
0,
0,
0,
&operator_dispatcher::call_cmp,
0,
&operator_dispatcher::number_methods,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
};
PyNumberMethods operator_dispatcher::number_methods =
{
&operator_dispatcher::call_add,
&operator_dispatcher::call_sub,
&operator_dispatcher::call_mul,
&operator_dispatcher::call_div,
&operator_dispatcher::call_mod,
&operator_dispatcher::call_divmod,
&operator_dispatcher::call_pow,
0,
0,
0,
0,
0,
&operator_dispatcher::call_lshift,
&operator_dispatcher::call_rshift,
&operator_dispatcher::call_and,
&operator_dispatcher::call_xor,
&operator_dispatcher::call_or,
&operator_dispatcher::coerce,
0,
0,
0,
0,
0
};
#ifndef NDEBUG
int total_Dispatchers = 0;
operator_dispatcher::~operator_dispatcher() { --total_Dispatchers; }
#endif
operator_dispatcher::operator_dispatcher(const Ptr& o, const Ptr& s)
: m_object(o), m_self(s)
{
ob_refcnt = 1;
ob_type = &type_object;
#ifndef NDEBUG
++total_Dispatchers;
#endif
}
void operator_dispatcher::dealloc(PyObject* self)
{
delete static_cast<operator_dispatcher*>(self);
}
int operator_dispatcher::coerce(PyObject** l, PyObject** r)
{
Py_INCREF(*l);
*r = new operator_dispatcher(Ptr(*r, Ptr::new_ref), Ptr());
return 0;
}
#define PY_DEFINE_OPERATOR(id, symbol) \
PyObject* operator_dispatcher::call_##id(PyObject* left, PyObject* right) \
{ \
/* unwrap the arguments from their OperatorDispatcher */ \
PyObject* self; \
PyObject* other; \
int reverse = unwrap_args(left, right, self, other); \
if (reverse == unwrap_exception_code) \
return 0; \
\
/* call the function */ \
PyObject* result = \
PyEval_CallMethod(self, \
const_cast<char*>(reverse ? "__r" #id "__" : "__" #id "__"), \
const_cast<char*>("(O)"), \
other); \
if (result == 0 && PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)) \
{ \
PyErr_Clear(); \
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for " #symbol); \
} \
return result; \
}
PY_DEFINE_OPERATOR(add, +)
PY_DEFINE_OPERATOR(sub, -)
PY_DEFINE_OPERATOR(mul, *)
PY_DEFINE_OPERATOR(div, /)
PY_DEFINE_OPERATOR(mod, %)
PY_DEFINE_OPERATOR(divmod, divmod)
PY_DEFINE_OPERATOR(lshift, <<)
PY_DEFINE_OPERATOR(rshift, >>)
PY_DEFINE_OPERATOR(and, &)
PY_DEFINE_OPERATOR(xor, ^)
PY_DEFINE_OPERATOR(or, |)
/* coercion rules for heterogeneous pow():
pow(Foo, int): left, right coerced; m: None => reverse = 0
pow(int, Foo): left, right coerced; m: None => reverse = 1
pow(Foo, int, int): left, right, m coerced => reverse = 0
pow(int, Foo, int): left, right, m coerced => reverse = 1
pow(int, int, Foo): left, right, m coerced => reverse = 2
pow(Foo, Foo, int): left, right coerced; m coerced twice => reverse = 0
pow(Foo, int, Foo): left, right, m coerced => reverse = 0
pow(int, Foo, Foo): left, right, m coerced => reverse = 1
*/
PyObject* operator_dispatcher::call_pow(PyObject* left, PyObject* right, PyObject* m)
{
int reverse;
PyObject* self;
PyObject* first;
PyObject* second;
if (m->ob_type == Py_None->ob_type)
{
reverse = unwrap_args(left, right, self, first);
second = m;
}
else
{
reverse = unwrap_pow_args(left, right, m, self, first, second);
}
if (reverse == unwrap_exception_code)
return 0;
// call the function
PyObject* result =
PyEval_CallMethod(self,
const_cast<char*>((reverse == 0)
? "__pow__"
: (reverse == 1)
? "__rpow__"
: "__rrpow__"),
const_cast<char*>("(OO)"),
first, second);
if (result == 0 &&
(PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_TypeError) ||
PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_AttributeError)))
{
PyErr_Clear();
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for pow()");
}
return result;
}
int operator_dispatcher::call_cmp(PyObject* left, PyObject* right)
{
// unwrap the arguments from their OperatorDispatcher
PyObject* self;
PyObject* other;
int reverse = unwrap_args(left, right, self, other);
if (reverse == unwrap_exception_code)
return -1;
// call the function
PyObject* result =
PyEval_CallMethod(self,
const_cast<char*>(reverse ? "__rcmp__" : "__cmp__"),
const_cast<char*>("(O)"),
other);
if (result == 0)
{
PyErr_Clear();
PyErr_SetString(PyExc_TypeError, "bad operand type(s) for cmp()");
return -1;
}
else
{
return PY_CONVERSION::from_python(result, Type<int>());
}
}
} // namespace detail
} // namespace py

View File

@@ -1,886 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
//
// This file automatically generated for 5-argument constructors by
// gen_extclass.py
#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;
class ExtensionClassBase;
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>
T* check_non_null(T* p)
{
if (p == 0)
report_released_smart_pointer(typeid(T));
return p;
}
template <class T> class HeldInstance;
namespace detail {
typedef void* (*ConversionFunction)(void*);
struct BaseClassInfo
{
BaseClassInfo(ExtensionClassBase* t, ConversionFunction f)
:class_object(t), convert(f)
{}
ExtensionClassBase* class_object;
ConversionFunction convert;
};
typedef BaseClassInfo DerivedClassInfo;
struct add_operator_base;
}
class ExtensionClassBase : public Class<ExtensionInstance>
{
public:
ExtensionClassBase(const char* name);
public:
// the purpose of try_class_conversions() and its related functions
// is explained in extclass.cpp
void* try_class_conversions(InstanceHolderBase*) const;
void* try_base_class_conversions(InstanceHolderBase*) const;
void* try_derived_class_conversions(InstanceHolderBase*) const;
void set_attribute(const char* name, PyObject* x);
void set_attribute(const char* name, Ptr x);
private:
virtual void* extract_object_from_holder(InstanceHolderBase* v) const = 0;
virtual std::vector<py::detail::BaseClassInfo> const& base_classes() const = 0;
virtual std::vector<py::detail::DerivedClassInfo> const& derived_classes() const = 0;
protected:
friend struct detail::add_operator_base;
void add_method(PyPtr<Function> method, const char* name);
void add_method(Function* method, const char* name);
void add_constructor_object(Function*);
void add_setter_method(Function*, const char* name);
void add_getter_method(Function*, const char* name);
};
template <class T>
class ClassRegistry
{
public:
static ExtensionClassBase* class_object()
{ return static_class_object; }
// Register/unregister the Python class object corresponding to T
static void register_class(ExtensionClassBase*);
static void unregister_class(ExtensionClassBase*);
// Establish C++ inheritance relationships
static void register_base_class(py::detail::BaseClassInfo const&);
static void register_derived_class(py::detail::DerivedClassInfo const&);
// Query the C++ inheritance relationships
static std::vector<py::detail::BaseClassInfo> const& base_classes();
static std::vector<py::detail::DerivedClassInfo> const& derived_classes();
private:
static ExtensionClassBase* static_class_object;
static std::vector<py::detail::BaseClassInfo> static_base_class_info;
static std::vector<py::detail::DerivedClassInfo> static_derived_class_info;
};
}
PY_BEGIN_CONVERSION_NAMESPACE
// This class' only job is to define from_python and to_python converters for T
// and U. T is the class the user really intends to wrap. U is a class derived
// from T with some virtual function overriding boilerplate, or if there are no
// virtual functions, U = HeldInstance<T>.
template <class T, class U = py::HeldInstance<T> >
class PyExtensionClassConverters
{
public:
// Get an object which can be used to convert T to/from python. This is used
// as a kind of concept check by the global template
//
// PyObject* to_python(const T& x)
//
// below this class, to prevent the confusing messages that would otherwise
// pop up. Now, if T hasn't been wrapped as an extension class, the user
// will see an error message about the lack of an eligible
// py_extension_class_converters() function.
friend PyExtensionClassConverters py_extension_class_converters(py::Type<T>)
{
return PyExtensionClassConverters();
}
// This is a member function because in a conforming implementation, friend
// funcitons defined inline in the class body are all instantiated as soon
// as the enclosing class is instantiated. If T is not copyable, that causes
// a compiler error. Instead, we access this function through the global
// template
//
// PyObject* to_python(const T& x)
//
// defined below this class. Since template functions are instantiated only
// on demand, errors will be avoided unless T is noncopyable and the user
// writes code which causes us to try to copy a T.
PyObject* to_python(const T& x) const
{
py::PyPtr<py::ExtensionInstance> result(create_instance());
result->add_implementation(
std::auto_ptr<py::InstanceHolderBase>(
new py::InstanceValueHolder<T,U>(result.get(), x)));
return result.release();
}
// 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();
// see extclass.cpp for an explanation of try_class_conversions()
void* target = py::ClassRegistry<T>::class_object()->try_class_conversions(*p);
if(target)
return static_cast<T*>(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());
result->add_implementation(
std::auto_ptr<py::InstanceHolderBase>(
new py::InstancePtrHolder<PtrType,T>(x)));
return result.release();
}
static py::PyPtr<py::ExtensionInstance> create_instance()
{
PyTypeObject* class_object = py::ClassRegistry<T>::class_object();
if (class_object == 0)
py::report_missing_class_object(typeid(T));
return py::PyPtr<py::ExtensionInstance>(
new py::ExtensionInstance(class_object));
}
// Convert to const T*
friend const T* from_python(PyObject* p, py::Type<const T*>)
{ return from_python(p, py::Type<T*>()); }
// Convert to const T* const&
friend const T* from_python(PyObject* p, py::Type<const T*const&>)
{ return from_python(p, py::Type<const T*>()); }
// Convert to T* const&
friend T* from_python(PyObject* p, py::Type<T* const&>)
{ 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); }
};
// Convert T to_python, instantiated on demand and only if there isn't a
// non-template overload for this function. This version is the one invoked when
// T is a wrapped class. See the first 2 functions declared in
// PyExtensionClassConverters above for more info.
template <class T>
PyObject* to_python(const T& x)
{
return py_extension_class_converters(py::Type<T>()).to_python(x);
}
PY_END_CONVERSION_NAMESPACE
namespace py {
PY_IMPORT_CONVERSION(PyExtensionClassConverters);
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;
};
enum operator_id
{
op_add = 0x1,
op_sub = 0x2,
op_mul = 0x4,
op_div = 0x8,
op_mod = 0x10,
op_divmod =0x20,
op_pow = 0x40,
op_lshift = 0x80,
op_rshift = 0x100,
op_and = 0x200,
op_xor = 0x400,
op_or = 0x800,
op_neg = 0x1000,
op_pos = 0x2000,
op_abs = 0x4000,
op_invert = 0x8000,
op_int = 0x10000,
op_long = 0x20000,
op_float = 0x40000,
op_str = 0x80000,
op_cmp = 0x100000
};
namespace detail
{
struct auto_operand {};
template <class Specified>
struct operand_select
{
template <class WrappedType>
struct wrapped
{
typedef Specified type;
};
};
template <>
struct operand_select<auto_operand>
{
template <class WrappedType>
struct wrapped
{
typedef const WrappedType& type;
};
};
template <long> struct define_operator;
template <long> struct choose_op;
template <long> struct choose_rop;
template <long> struct choose_unary_op;
}
template <long which, class operand = py::detail::auto_operand>
struct operators {};
template <class T>
struct left_operand {};
template <class T>
struct right_operand {};
namespace detail
{
template <class From, class To>
struct DefineConversion
{
static void* upcast_ptr(void* v)
{
return static_cast<To*>(static_cast<From*>(v));
}
static void* downcast_ptr(void* v)
{
return dynamic_cast<To*>(static_cast<From*>(v));
}
};
}
enum WithoutDowncast { without_downcast };
// 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>
inline void def(Constructor<A1, A2, A3, A4, A5>)
// The following incantation builds a Signature1, Signature2,... object. It
// should _all_ get optimized away.
{ add_constructor(
prepend(Type<A1>::Id(),
prepend(Type<A2>::Id(),
prepend(Type<A3>::Id(),
prepend(Type<A4>::Id(),
prepend(Type<A5>::Id(),
Signature0()))))));
}
// export homogeneous operators (type of both lhs and rhs is 'operator')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>());
// export homogeneous operators (type of both lhs and rhs is 'T const&')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>());
template <long which, class Operand>
inline void def(operators<which,Operand>)
{
typedef typename detail::operand_select<Operand>::template wrapped<T>::type true_operand;
def_operators(operators<which,true_operand>());
}
// export heterogeneous operators (type of lhs: 'left', of rhs: 'right')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(),
// py::right_operand<int const&>());
// export heterogeneous operators (type of lhs: 'T const&', of rhs: 'right')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>(),
// py::right_operand<int const&>());
template <long which, class Left, class Right>
inline void def(operators<which,Left>, right_operand<Right> r)
{
typedef typename detail::operand_select<Left>::template wrapped<T>::type true_left;
def_operators(operators<which,true_left>(), r);
}
// export heterogeneous reverse-argument operators
// (type of lhs: 'left', of rhs: 'right')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(),
// py::left_operand<int const&>());
// export heterogeneous reverse-argument operators
// (type of lhs: 'left', of rhs: 'T const&')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>(),
// py::left_operand<int const&>());
template <long which, class Left, class Right>
inline void def(operators<which,Right>, left_operand<Left> l)
{
typedef typename detail::operand_select<Right>::template wrapped<T>::type true_right;
def_operators(operators<which,true_right>(), l);
}
// define a function that passes Python arguments and keywords
// to C++ verbatim (as a 'Tuple const&' and 'Dict const&'
// respectively). This is useful for manual argument passing.
// It's also the only possibility to pass keyword arguments to C++.
// Fn must have a signatur that is compatible to
// PyObject* (*)(PyObject* aTuple, PyObject* aDictionary)
template <class Fn>
inline void def_raw(Fn fn, const char* name)
{
this->add_method(py::detail::new_raw_arguments_function(fn), name);
}
// define member functions. In fact this works for free functions, too -
// they act like static member functions, or if they start with the
// appropriate self argument (as a pointer), they can be used just like
// ordinary member functions -- just like Python!
template <class Fn>
inline void def(Fn fn, const char* name)
{
this->add_method(new_wrapped_function(fn), name);
}
// Define a virtual member function with a default implementation.
// default_fn should be a function which provides the default implementation.
// Be careful that default_fn does not in fact call fn virtually!
template <class Fn, class DefaultFn>
inline void def(Fn fn, const char* name, DefaultFn default_fn)
{
this->add_method(py::detail::new_virtual_function(Type<T>(), fn, default_fn), name);
}
// Provide a function which implements x.<name>, reading from the given
// member (pm) of the T instance
template <class MemberType>
inline 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>
inline 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>
inline 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>
inline void def_read_write(MemberType T::*pm, const char* name)
{
this->def_getter(pm, name);
this->def_setter(pm, name);
}
// declare the given class a base class of this one and register
// up and down conversion functions
template <class S, class V>
void declare_base(ExtensionClass<S, V>* base)
{
// see extclass.cpp for an explanation of why we need to register
// conversion functions
detail::BaseClassInfo baseInfo(base,
&detail::DefineConversion<S, T>::downcast_ptr);
ClassRegistry<T>::register_base_class(baseInfo);
add_base(Ptr(as_object(base), Ptr::new_ref));
detail::DerivedClassInfo derivedInfo(this,
&detail::DefineConversion<T, S>::upcast_ptr);
ClassRegistry<S>::register_derived_class(derivedInfo);
}
// declare the given class a base class of this one and register
// only up conversion function
template <class S, class V>
void declare_base(ExtensionClass<S, V>* base, WithoutDowncast)
{
// see extclass.cpp for an explanation of why we need to register
// conversion functions
detail::BaseClassInfo baseInfo(base, 0);
ClassRegistry<T>::register_base_class(baseInfo);
add_base(Ptr(as_object(base), Ptr::new_ref));
detail::DerivedClassInfo derivedInfo(this,
&detail::DefineConversion<T, S>::upcast_ptr);
ClassRegistry<S>::register_derived_class(derivedInfo);
}
private: // types
typedef InstanceValueHolder<T,U> Holder;
private: // ExtensionClassBase virtual function implementations
std::vector<detail::BaseClassInfo> const& base_classes() const;
std::vector<detail::DerivedClassInfo> const& derived_classes() const;
void* extract_object_from_holder(InstanceHolderBase* v) const;
private: // Utility functions
template <long which, class Operand>
inline void def_operators(operators<which,Operand>)
{
register_coerce();
detail::choose_op<(which & op_add)>::template args<Operand>::add(this);
detail::choose_op<(which & op_sub)>::template args<Operand>::add(this);
detail::choose_op<(which & op_mul)>::template args<Operand>::add(this);
detail::choose_op<(which & op_div)>::template args<Operand>::add(this);
detail::choose_op<(which & op_mod)>::template args<Operand>::add(this);
detail::choose_op<(which & op_divmod)>::template args<Operand>::add(this);
detail::choose_op<(which & op_pow)>::template args<Operand>::add(this);
detail::choose_op<(which & op_lshift)>::template args<Operand>::add(this);
detail::choose_op<(which & op_rshift)>::template args<Operand>::add(this);
detail::choose_op<(which & op_and)>::template args<Operand>::add(this);
detail::choose_op<(which & op_xor)>::template args<Operand>::add(this);
detail::choose_op<(which & op_or)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_neg)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_pos)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_abs)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_invert)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_int)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_long)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_float)>::template args<Operand>::add(this);
detail::choose_op<(which & op_cmp)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_str)>::template args<Operand>::add(this);
}
template <long which, class Left, class Right>
inline void def_operators(operators<which,Left>, right_operand<Right>)
{
register_coerce();
detail::choose_op<(which & op_add)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_sub)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_mul)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_div)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_mod)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_divmod)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_pow)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_lshift)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_rshift)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_and)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_xor)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_or)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_cmp)>::template args<Left,Right>::add(this);
}
template <long which, class Left, class Right>
inline void def_operators(operators<which,Right>, left_operand<Left>)
{
register_coerce();
detail::choose_rop<(which & op_add)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_sub)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_mul)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_div)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_mod)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_divmod)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_pow)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_lshift)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_rshift)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_and)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_xor)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_or)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_cmp)>::template args<Left,Right>::add(this);
}
template <class Signature>
void add_constructor(Signature sig)
{
this->add_constructor_object(InitFunction<Holder>::create(sig));
}
void register_coerce();
};
// 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*) : T() {}
template <class A1>
HeldInstance(PyObject*, A1 a1) : T(a1) {}
template <class A1, class A2>
HeldInstance(PyObject*, A1 a1, A2 a2) : T(a1, a2) {}
template <class A1, class A2, class A3>
HeldInstance(PyObject*, A1 a1, A2 a2, A3 a3) : T(a1, a2, a3) {}
template <class A1, class A2, class A3, class A4>
HeldInstance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4) : T(a1, a2, a3, a4) {}
template <class A1, class A2, class A3, class A4, class A5>
HeldInstance(PyObject*, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : T(a1, a2, a3, a4, a5) {}
};
// Abstract base class for all instance holders. Base for template class
// InstanceHolder<>, below.
class InstanceHolderBase
{
public:
virtual ~InstanceHolderBase() {}
virtual bool held_by_value() = 0;
};
// Abstract base class which holds a Held, somehow. Provides a uniform way to
// get a pointer to the held object
template <class Held>
class InstanceHolder : public InstanceHolderBase
{
public:
virtual Held*target() = 0;
};
// Concrete class which holds a Held by way of a wrapper class Wrapper. If Held
// can be constructed with arguments (A1...An), Wrapper must have a
// corresponding constructor for arguments (PyObject*, A1...An). Wrapper is
// neccessary to implement virtual function callbacks (there must be a
// back-pointer to the actual Python object so that we can call any
// overrides). HeldInstance (above) is used as a default Wrapper class when
// there are no virtual functions.
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, A1 a1) :
m_held(p, a1) {}
template <class A1, class A2>
InstanceValueHolder(ExtensionInstance* p, A1 a1, A2 a2) :
m_held(p, a1, a2) {}
template <class A1, class A2, class A3>
InstanceValueHolder(ExtensionInstance* p, A1 a1, A2 a2, A3 a3) :
m_held(p, a1, a2, a3) {}
template <class A1, class A2, class A3, class A4>
InstanceValueHolder(ExtensionInstance* p, A1 a1, A2 a2, A3 a3, A4 a4) :
m_held(p, a1, a2, a3, a4) {}
template <class A1, class A2, class A3, class A4, class A5>
InstanceValueHolder(ExtensionInstance* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) :
m_held(p, a1, a2, a3, a4, a5) {}
public: // implementation of InstanceHolderBase required interface
bool held_by_value() { return true; }
private:
Wrapper m_held;
};
// Concrete class which holds a HeldType by way of a (possibly smart) pointer
// PtrType. By default, these are only generated for PtrType ==
// std::auto_ptr<HeldType> and PtrType == boost::shared_ptr<HeldType>.
template <class PtrType, class HeldType>
class InstancePtrHolder : public InstanceHolder<HeldType>
{
public:
HeldType* target() { return &*m_ptr; }
PtrType& ptr() { return m_ptr; }
InstancePtrHolder(PtrType ptr) : m_ptr(ptr) {}
public: // implementation of InstanceHolderBase required interface
bool held_by_value() { return false; }
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
//
namespace detail
{
Tuple extension_class_coerce(Ptr l, Ptr r);
}
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>
void ExtensionClass<T, U>::register_coerce()
{
Ptr coerce_fct = dict().get_item(String("__coerce__"));
if(coerce_fct.get() == 0) // not yet defined
this->def(&py::detail::extension_class_coerce, "__coerce__");
}
template <class T, class U>
inline
std::vector<detail::BaseClassInfo> const&
ExtensionClass<T, U>::base_classes() const
{
return ClassRegistry<T>::base_classes();
}
template <class T, class U>
inline
std::vector<detail::DerivedClassInfo> const&
ExtensionClass<T, U>::derived_classes() const
{
return ClassRegistry<T>::derived_classes();
}
template <class T, class U>
void* ExtensionClass<T, U>::extract_object_from_holder(InstanceHolderBase* v) const
{
py::InstanceHolder<T>* held = dynamic_cast<py::InstanceHolder<T>*>(v);
if(held)
return held->target();
return 0;
}
template <class T, class U>
ExtensionClass<T, U>::~ExtensionClass()
{
ClassRegistry<T>::unregister_class(this);
}
template <class T>
inline void ClassRegistry<T>::register_class(ExtensionClassBase* 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(ExtensionClassBase* p)
{
// The user should be destroying the same object they created.
assert(static_class_object == p);
(void)p; // unused in shipping version
static_class_object = 0;
}
template <class T>
void ClassRegistry<T>::register_base_class(py::detail::BaseClassInfo const& i)
{
static_base_class_info.push_back(i);
}
template <class T>
void ClassRegistry<T>::register_derived_class(py::detail::DerivedClassInfo const& i)
{
static_derived_class_info.push_back(i);
}
template <class T>
std::vector<py::detail::BaseClassInfo> const& ClassRegistry<T>::base_classes()
{
return static_base_class_info;
}
template <class T>
std::vector<py::detail::DerivedClassInfo> const& ClassRegistry<T>::derived_classes()
{
return static_derived_class_info;
}
//
// Static data member declaration.
//
template <class T>
ExtensionClassBase* ClassRegistry<T>::static_class_object;
template <class T>
std::vector<py::detail::BaseClassInfo> ClassRegistry<T>::static_base_class_info;
template <class T>
std::vector<py::detail::DerivedClassInfo> ClassRegistry<T>::static_derived_class_info;
} // namespace py
#endif // EXTENSION_CLASS_DWA052000_H_

File diff suppressed because it is too large Load Diff

View File

@@ -1,231 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef 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_

View File

@@ -1,23 +0,0 @@
# 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)

View File

@@ -1,73 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>
A Brief Introduction to writing Python extension modules
</title>
<h1>
<img src="c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
width="277" height="86">
</h1>
<h1>
A Brief Introduction to writing Python extension modules
</h1>
<p>
Interfacing any language to Python involves building a module which can
be loaded by the Python interpreter, but which isn't written in Python.
This is known as an <em>extension module</em>. Many of the <a href=
"http://www.python.org/doc/current/lib/lib.html">built-in Python
libraries</a> are constructed in 'C' this way; Python even supplies its
<a href="http://www.python.org/doc/current/lib/types.html">fundamental
types</a> using the same mechanism. An extension module can be statically
linked with the Python interpreter, but it more commonly resides in a
shared library or DLL.
<p>
As you can see from <a href=
"http://www.python.org/doc/current/ext/ext.html"> The Python Extending
and Embedding Tutorial</a>, writing an extension module normally means
worrying about
<ul>
<li>
<a href="http://www.python.org/doc/current/ext/refcounts.html">
maintaining reference counts</a>
<li>
<a href="http://www.python.org/doc/current/ext/callingPython.html"> how
to call back into Python</a>
<li>
<a href="http://www.python.org/doc/current/ext/parseTuple.html">
function argument parsing and typechecking</a>
</ul>
This last item typically occupies a great deal of code in an extension
module. Remember that Python is a completely dynamic language. A callable
object receives its arguments in a tuple; it is up to that object to
extract those arguments from the tuple, check their types, and raise
appropriate exceptions. There are numerous other tedious details that need
to be managed; too many to mention here. Py_cpp is designed to lift most of
that burden.<br>
<br>
<p>
Another obstacle that most people run into eventually when extending
Python is that there's no way to make a true Python class in an extension
module. The typical solution is to create a new Python type in the
extension module, and then write an additional module in 100% Python. The
Python module defines a Python class which dispatches to an instance of
the extension type, which it contains. This allows users to write
subclasses of the class in the Python module, almost as though they were
sublcassing the extension type. Aside from being tedious, it's not really
the same as having a true class, because there's no way for the user to
override a method of the extension type which is called from the
extension module. Py_cpp solves this problem by taking advantage of <a
href="http://www.python.org/doc/essays/metaclasses/">Python's metaclass
feature</a> to provide objects which look, walk, and hiss almost exactly
like regular Python classes. Py_cpp classes are actually cleaner than
Python classes in some subtle ways; a more detailed discussion will
follow (someday).</p>
<p>Next: <a href="comparisons.html">Comparisons with Other Systems</a> Up: <a
href="py_cpp.html">Top</a> </p>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided "as is" without
express or implied warranty, and with no claim as to its suitability for
any purpose.</p>

View File

@@ -1,167 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#include "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;
}
BoundFunction* BoundFunction::create(const Ptr& target, const Ptr& fn)
{
BoundFunction* const result = free_list;
if (result == 0)
return new BoundFunction(target, fn);
free_list = result->m_free_list_link;
result->m_target = target;
result->m_unbound_function = fn;
Py_INCREF(result);
return result;
}
// The singleton class whose instance represents the type of BoundFunction
// objects in Python. BoundFunctions must be GetAttrable so the __doc__
// attribute of built-in Python functions can be accessed when bound.
struct BoundFunction::TypeObject :
Singleton<BoundFunction::TypeObject,
Getattrable<Callable<py::TypeObject<BoundFunction> > > >
{
TypeObject() : SingletonBase(&PyType_Type) {}
private: // TypeObject<BoundFunction> hook override
void dealloc(BoundFunction*) const;
};
BoundFunction::BoundFunction(const Ptr& target, const 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);
}
PyObject* BoundFunction::getattr(const char* name) const
{
return PyObject_GetAttrString(m_unbound_function.get(), const_cast<char*>(name));
}
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;
}

View File

@@ -1,309 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef FUNCTIONS_DWA051400_H_
# define FUNCTIONS_DWA051400_H_
# include "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>
# include <vector>
namespace py {
// forward declaration
class ExtensionInstance;
// Function --
// the common base class for all overloadable function and method objects
// supplied by the library.
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;
};
// WrappedFunctionPointer<> --
// A single function or member function pointer wrapped and presented to
// Python as a callable object.
//
// Template parameters:
// R - the return type of the function pointer
// F - the complete type of the wrapped function pointer
template <class R, class F>
struct 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;
};
// raw_arguments_function
// A function that passes the Python argument tuple and keyword dictionary
// verbatim to C++ (useful for customized argument parsing and variable
// argument lists)
template <class Ret, class Args, class Keywords>
struct raw_arguments_function : Function
{
typedef Ret (*PtrFun)(Args, Keywords);
raw_arguments_function(PtrFun pf)
: m_pf(pf) {}
private:
PyObject* do_call(PyObject* args, PyObject* keywords) const
{
Ptr dict(keywords ?
Ptr(keywords, Ptr::new_ref) :
Ptr(PyDict_New()));
return to_python(
(*m_pf)(from_python(args, py::Type<Args>()),
from_python(dict.get(), py::Type<Keywords>())));
}
const char* description() const
{ return typeid(PtrFun).name(); }
private:
const PtrFun m_pf;
};
// virtual_function<> --
// A virtual function with a default implementation wrapped and presented
// to Python as a callable object.
//
// Template parameters:
// T - the type of the target class
// R - the return type of the function pointer
// V - the virtual function pointer being wrapped
// (should be of the form R(T::*)(<args>), or R (*)(T, <args>))
// D - a function which takes a T&, const T&, T*, or const T* first
// parameter and calls T::f on it /non-virtually/, where V
// approximates &T::f.
template <class T, class R, class V, class D>
class virtual_function : public Function
{
public:
virtual_function(V virtual_function_ptr, D default_implementation)
: m_virtual_function_ptr(virtual_function_ptr),
m_default_implementation(default_implementation)
{}
private:
PyObject* do_call(PyObject* args, PyObject* keywords) const;
const char* description() const
{ return typeid(V).name(); }
private:
const V m_virtual_function_ptr;
const D m_default_implementation;
};
// A helper function for new_member_function(), below. Implements the core
// functionality once the return type has already been deduced. R is expected to
// be Type<X>, where X is the actual return type of pmf.
template <class F, class R>
Function* new_wrapped_function_aux(R, F pmf)
{
// We can't just use "typename R::Type" below because MSVC (incorrectly) pukes.
typedef typename R::Type 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);
}
namespace detail {
template <class R, class Args, class Keywords>
Function* new_raw_arguments_function(R (*pmf)(Args, Keywords))
{
return new raw_arguments_function<R, Args, Keywords>(pmf);
}
// A helper function for new_virtual_function(), below. Implements the core
// functionality once the return type has already been deduced. R is expected to
// be Type<X>, where X is the actual return type of V.
template <class T, class R, class V, class D>
inline Function* new_virtual_function_aux(
Type<T>, R, V virtual_function_ptr, D default_implementation
)
{
// We can't just use "typename R::Type" below because MSVC (incorrectly) pukes.
typedef typename R::Type ReturnType;
return new virtual_function<T, ReturnType, V, D>(
virtual_function_ptr, default_implementation);
}
// Create and return a new virtual_function object wrapping the given
// virtual_function_ptr and default_implementation
template <class T, class V, class D>
inline Function* new_virtual_function(
Type<T>, V virtual_function_ptr, D default_implementation
)
{
// Deduce the return type and pass it off to the helper function above
return new_virtual_function_aux(
Type<T>(), return_value(virtual_function_ptr),
virtual_function_ptr, default_implementation);
}
} // namespace detail
// 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 BoundFunction* create(const Ptr& target, const Ptr& fn);
BoundFunction(const Ptr& target, const Ptr& fn);
PyObject* call(PyObject*args, PyObject* keywords) const;
PyObject* getattr(const char* name) 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();
}
template <class T, class R, class V, class D>
PyObject* virtual_function<T,R,V,D>::do_call(PyObject* args, PyObject* keywords) const
{
// If the target object is held by pointer, we must call through the virtual
// function pointer to the most-derived override.
PyObject* target = PyTuple_GetItem(args, 0);
if (target != 0)
{
ExtensionInstance* self = get_extension_instance(target);
if (self->wrapped_objects().size() == 1
&& !self->wrapped_objects()[0]->held_by_value())
{
return Caller<R>::call(m_virtual_function_ptr, args, keywords);
}
}
return Caller<R>::call(m_default_implementation, args, keywords);
}
}
#endif // FUNCTIONS_DWA051400_H_

48
gcc.mak
View File

@@ -1,48 +0,0 @@
LIBSRC = \
extclass.cpp \
init_function.cpp \
py.cpp \
module.cpp \
subclass.cpp \
functions.cpp \
newtypes.cpp \
objects.cpp
LIBOBJ = $(LIBSRC:.cpp=.o)
OBJ = $(LIBOBJ) extclass_demo.o
ifeq "$(OS)" "Windows_NT"
PYTHON_LIB=c:/tools/python/libs/python15.lib
INC = -Ic:/cygnus/usr/include/g++-3 -Ic:/cygnus/usr/include -Ic:/boost -Ic:/tools/python/include
MODULE_EXTENSION=dll
else
INC = -I/home/koethe/include -I/home/koethe/C++/boost -I/home/koethe/python/include/python1.5
MODULE_EXTENSION=so
endif
%.o: %.cpp
g++ -fPIC $(INC) -c $*.cpp
%.d: %.cpp
@echo creating $@
@set -e; g++ -M $(INC) -c $*.cpp \
| sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
[ -s $@ ] || rm -f $@
demo: extclass_demo.o libpycpp.a
g++ -shared -o demomodule.$(MODULE_EXTENSION) $(PYTHON_LIB) extclass_demo.o -L. -lpycpp
python test_extclass.py
clean:
rm -rf *.o *.$(MODULE_EXTENSION) *.a *.d *.pyc *.bak a.out
libpycpp.a: $(LIBOBJ)
rm -f libpycpp.a
ar cq libpycpp.a $(LIBOBJ)
DEP = $(OBJ:.o=.d)
ifneq "$(MAKECMDGOALS)" "clean"
include $(DEP)
endif

View File

@@ -1,26 +0,0 @@
from gen_callback import *
from gen_caller import *
from gen_init_function import *
from gen_signatures import *
from gen_singleton import *
from gen_extclass import *
def gen_all(args):
open('callback.h', 'w').write(gen_callback(args))
open('caller.h', 'w').write(gen_caller(args))
open('init_function.h', 'w').write(gen_init_function(args))
open('signatures.h', 'w').write(gen_signatures(args))
open('singleton.h', 'w').write(gen_singleton(args))
open('extclass.h', 'w').write(gen_extclass(args))
if __name__ == '__main__':
import sys
if len(sys.argv) == 1:
args = 5
else:
args = int(sys.argv[1])
print gen_all(args)

View File

@@ -1,103 +0,0 @@
from gen_function import *
import string
def gen_callback(args):
return (
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
//
// This file was generated for %d-argument python callbacks by gen_callback.py
#ifndef CALLBACK_DWA_052100_H_
# define CALLBACK_DWA_052100_H_
# include "pyconfig.h"
# include "py.h"
namespace py {
namespace detail {
template <class T>
inline void callback_adjust_refcount(PyObject*, Type<T>) {}
inline void callback_adjust_refcount(PyObject* p, Type<PyObject*>)
{ Py_INCREF(p); }
}
// Calling Python from C++
template <class R>
struct Callback
{""" % args
+ gen_functions('''
%{ template <%(class A%n%:, %)>
%} static R call_method(PyObject* self, const char* name%(, const A%n& a%n%))
{%(
Ptr p%n(to_python(a%n));%)
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("(%(O%))")%(,
p%n.get()%)));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
%{ template <%(class A%n%:, %)>
%} static R call(PyObject* self%(, const A%n& a%n%))
{%(
Ptr p%n(to_python(a%n));%)
Ptr result(PyEval_CallFunction(self, const_cast<char*>("(%(O%))")%(,
p%n.get()%)));
detail::callback_adjust_refcount(result.get(), Type<R>());
return from_python(result.get(), Type<R>());
}
''', args)
+
"""};
// This specialization wouldn't be needed, but MSVC6 doesn't correctly allow the following:
// void g();
// void f() { return g(); }
template <>
struct Callback<void>
{
"""
+ gen_functions('''
%{ template <%(class A%n%:, %)>
%} static void call_method(PyObject* self, const char* name%(, const A%n& a%n%))
{%(
Ptr p%n(to_python(a%n));%)
Ptr result(PyEval_CallMethod(self, const_cast<char*>(name),
const_cast<char*>("(%(O%))")%(,
p%n.get()%)));
}
%{ template <%(class A%n%:, %)>
%} static void call(PyObject* self%(, const A%n& a%n%))
{%(
Ptr p%n(to_python(a%n));%)
Ptr result(PyEval_CallFunction(self, const_cast<char*>("(%(O%))")%(,
p%n.get()%)));
}
''', args)
+
"""};
} // 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)

View File

@@ -1,138 +0,0 @@
# (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
# distribute this software is granted provided this copyright notice appears
# in all copies. This software is provided "as is" without express or implied
# warranty, and with no claim as to its suitability for any purpose.
#
# The author gratefully acknowleges the support of Dragon Systems, Inc., in
# producing this work.
from gen_function import *
import string
header = '''// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
//
// This file generated for %d-argument member functions and %d-argument free
// functions by gen_caller.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 + 1
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)

View File

@@ -1,883 +0,0 @@
from gen_function import *
import string
def gen_extclass(args):
return (
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
//
// This file automatically generated for %d-argument constructors by
// gen_extclass.py
#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;
class ExtensionClassBase;
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>
T* check_non_null(T* p)
{
if (p == 0)
report_released_smart_pointer(typeid(T));
return p;
}
template <class T> class HeldInstance;
namespace detail {
typedef void* (*ConversionFunction)(void*);
struct BaseClassInfo
{
BaseClassInfo(ExtensionClassBase* t, ConversionFunction f)
:class_object(t), convert(f)
{}
ExtensionClassBase* class_object;
ConversionFunction convert;
};
typedef BaseClassInfo DerivedClassInfo;
struct add_operator_base;
}
class ExtensionClassBase : public Class<ExtensionInstance>
{
public:
ExtensionClassBase(const char* name);
public:
// the purpose of try_class_conversions() and its related functions
// is explained in extclass.cpp
void* try_class_conversions(InstanceHolderBase*) const;
void* try_base_class_conversions(InstanceHolderBase*) const;
void* try_derived_class_conversions(InstanceHolderBase*) const;
void set_attribute(const char* name, PyObject* x);
void set_attribute(const char* name, Ptr x);
private:
virtual void* extract_object_from_holder(InstanceHolderBase* v) const = 0;
virtual std::vector<py::detail::BaseClassInfo> const& base_classes() const = 0;
virtual std::vector<py::detail::DerivedClassInfo> const& derived_classes() const = 0;
protected:
friend struct detail::add_operator_base;
void add_method(PyPtr<Function> method, const char* name);
void add_method(Function* method, const char* name);
void add_constructor_object(Function*);
void add_setter_method(Function*, const char* name);
void add_getter_method(Function*, const char* name);
};
template <class T>
class ClassRegistry
{
public:
static ExtensionClassBase* class_object()
{ return static_class_object; }
// Register/unregister the Python class object corresponding to T
static void register_class(ExtensionClassBase*);
static void unregister_class(ExtensionClassBase*);
// Establish C++ inheritance relationships
static void register_base_class(py::detail::BaseClassInfo const&);
static void register_derived_class(py::detail::DerivedClassInfo const&);
// Query the C++ inheritance relationships
static std::vector<py::detail::BaseClassInfo> const& base_classes();
static std::vector<py::detail::DerivedClassInfo> const& derived_classes();
private:
static ExtensionClassBase* static_class_object;
static std::vector<py::detail::BaseClassInfo> static_base_class_info;
static std::vector<py::detail::DerivedClassInfo> static_derived_class_info;
};
}
PY_BEGIN_CONVERSION_NAMESPACE
// This class' only job is to define from_python and to_python converters for T
// and U. T is the class the user really intends to wrap. U is a class derived
// from T with some virtual function overriding boilerplate, or if there are no
// virtual functions, U = HeldInstance<T>.
template <class T, class U = py::HeldInstance<T> >
class PyExtensionClassConverters
{
public:
// Get an object which can be used to convert T to/from python. This is used
// as a kind of concept check by the global template
//
// PyObject* to_python(const T& x)
//
// below this class, to prevent the confusing messages that would otherwise
// pop up. Now, if T hasn't been wrapped as an extension class, the user
// will see an error message about the lack of an eligible
// py_extension_class_converters() function.
friend PyExtensionClassConverters py_extension_class_converters(py::Type<T>)
{
return PyExtensionClassConverters();
}
// This is a member function because in a conforming implementation, friend
// funcitons defined inline in the class body are all instantiated as soon
// as the enclosing class is instantiated. If T is not copyable, that causes
// a compiler error. Instead, we access this function through the global
// template
//
// PyObject* to_python(const T& x)
//
// defined below this class. Since template functions are instantiated only
// on demand, errors will be avoided unless T is noncopyable and the user
// writes code which causes us to try to copy a T.
PyObject* to_python(const T& x) const
{
py::PyPtr<py::ExtensionInstance> result(create_instance());
result->add_implementation(
std::auto_ptr<py::InstanceHolderBase>(
new py::InstanceValueHolder<T,U>(result.get(), x)));
return result.release();
}
// 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();
// see extclass.cpp for an explanation of try_class_conversions()
void* target = py::ClassRegistry<T>::class_object()->try_class_conversions(*p);
if(target)
return static_cast<T*>(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());
result->add_implementation(
std::auto_ptr<py::InstanceHolderBase>(
new py::InstancePtrHolder<PtrType,T>(x)));
return result.release();
}
static py::PyPtr<py::ExtensionInstance> create_instance()
{
PyTypeObject* class_object = py::ClassRegistry<T>::class_object();
if (class_object == 0)
py::report_missing_class_object(typeid(T));
return py::PyPtr<py::ExtensionInstance>(
new py::ExtensionInstance(class_object));
}
// Convert to const T*
friend const T* from_python(PyObject* p, py::Type<const T*>)
{ return from_python(p, py::Type<T*>()); }
// Convert to const T* const&
friend const T* from_python(PyObject* p, py::Type<const T*const&>)
{ return from_python(p, py::Type<const T*>()); }
// Convert to T* const&
friend T* from_python(PyObject* p, py::Type<T* const&>)
{ 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); }
};
// Convert T to_python, instantiated on demand and only if there isn't a
// non-template overload for this function. This version is the one invoked when
// T is a wrapped class. See the first 2 functions declared in
// PyExtensionClassConverters above for more info.
template <class T>
PyObject* to_python(const T& x)
{
return py_extension_class_converters(py::Type<T>()).to_python(x);
}
PY_END_CONVERSION_NAMESPACE
namespace py {
PY_IMPORT_CONVERSION(PyExtensionClassConverters);
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;
};
enum operator_id
{
op_add = 0x1,
op_sub = 0x2,
op_mul = 0x4,
op_div = 0x8,
op_mod = 0x10,
op_divmod =0x20,
op_pow = 0x40,
op_lshift = 0x80,
op_rshift = 0x100,
op_and = 0x200,
op_xor = 0x400,
op_or = 0x800,
op_neg = 0x1000,
op_pos = 0x2000,
op_abs = 0x4000,
op_invert = 0x8000,
op_int = 0x10000,
op_long = 0x20000,
op_float = 0x40000,
op_str = 0x80000,
op_cmp = 0x100000
};
namespace detail
{
struct auto_operand {};
template <class Specified>
struct operand_select
{
template <class WrappedType>
struct wrapped
{
typedef Specified type;
};
};
template <>
struct operand_select<auto_operand>
{
template <class WrappedType>
struct wrapped
{
typedef const WrappedType& type;
};
};
template <long> struct define_operator;
template <long> struct choose_op;
template <long> struct choose_rop;
template <long> struct choose_unary_op;
}
template <long which, class operand = py::detail::auto_operand>
struct operators {};
template <class T>
struct left_operand {};
template <class T>
struct right_operand {};
namespace detail
{
template <class From, class To>
struct DefineConversion
{
static void* upcast_ptr(void* v)
{
return static_cast<To*>(static_cast<From*>(v));
}
static void* downcast_ptr(void* v)
{
return dynamic_cast<To*>(static_cast<From*>(v));
}
};
}
enum WithoutDowncast { without_downcast };
// 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
""" % args
+ gen_function(
""" template <%(class A%n%:, %)>
inline void def(Constructor<%(A%n%:, %)>)
// The following incantation builds a Signature1, Signature2,... object. It
// should _all_ get optimized away.
{ add_constructor(
%(prepend(Type<A%n>::Id(),
%) Signature0()%()%));
}
""", args)
+
"""
// export homogeneous operators (type of both lhs and rhs is 'operator')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>());
// export homogeneous operators (type of both lhs and rhs is 'T const&')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>());
template <long which, class Operand>
inline void def(operators<which,Operand>)
{
typedef typename detail::operand_select<Operand>::template wrapped<T>::type true_operand;
def_operators(operators<which,true_operand>());
}
// export heterogeneous operators (type of lhs: 'left', of rhs: 'right')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(),
// py::right_operand<int const&>());
// export heterogeneous operators (type of lhs: 'T const&', of rhs: 'right')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>(),
// py::right_operand<int const&>());
template <long which, class Left, class Right>
inline void def(operators<which,Left>, right_operand<Right> r)
{
typedef typename detail::operand_select<Left>::template wrapped<T>::type true_left;
def_operators(operators<which,true_left>(), r);
}
// export heterogeneous reverse-argument operators
// (type of lhs: 'left', of rhs: 'right')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub), Foo>(),
// py::left_operand<int const&>());
// export heterogeneous reverse-argument operators
// (type of lhs: 'left', of rhs: 'T const&')
// usage: foo_class.def(py::operators<(py::op_add | py::op_sub)>(),
// py::left_operand<int const&>());
template <long which, class Left, class Right>
inline void def(operators<which,Right>, left_operand<Left> l)
{
typedef typename detail::operand_select<Right>::template wrapped<T>::type true_right;
def_operators(operators<which,true_right>(), l);
}
// define a function that passes Python arguments and keywords
// to C++ verbatim (as a 'Tuple const&' and 'Dict const&'
// respectively). This is useful for manual argument passing.
// It's also the only possibility to pass keyword arguments to C++.
// Fn must have a signatur that is compatible to
// PyObject* (*)(PyObject* aTuple, PyObject* aDictionary)
template <class Fn>
inline void def_raw(Fn fn, const char* name)
{
this->add_method(py::detail::new_raw_arguments_function(fn), name);
}
// define member functions. In fact this works for free functions, too -
// they act like static member functions, or if they start with the
// appropriate self argument (as a pointer), they can be used just like
// ordinary member functions -- just like Python!
template <class Fn>
inline void def(Fn fn, const char* name)
{
this->add_method(new_wrapped_function(fn), name);
}
// Define a virtual member function with a default implementation.
// default_fn should be a function which provides the default implementation.
// Be careful that default_fn does not in fact call fn virtually!
template <class Fn, class DefaultFn>
inline void def(Fn fn, const char* name, DefaultFn default_fn)
{
this->add_method(py::detail::new_virtual_function(Type<T>(), fn, default_fn), name);
}
// Provide a function which implements x.<name>, reading from the given
// member (pm) of the T instance
template <class MemberType>
inline 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>
inline 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>
inline 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>
inline void def_read_write(MemberType T::*pm, const char* name)
{
this->def_getter(pm, name);
this->def_setter(pm, name);
}
// declare the given class a base class of this one and register
// up and down conversion functions
template <class S, class V>
void declare_base(ExtensionClass<S, V>* base)
{
// see extclass.cpp for an explanation of why we need to register
// conversion functions
detail::BaseClassInfo baseInfo(base,
&detail::DefineConversion<S, T>::downcast_ptr);
ClassRegistry<T>::register_base_class(baseInfo);
add_base(Ptr(as_object(base), Ptr::new_ref));
detail::DerivedClassInfo derivedInfo(this,
&detail::DefineConversion<T, S>::upcast_ptr);
ClassRegistry<S>::register_derived_class(derivedInfo);
}
// declare the given class a base class of this one and register
// only up conversion function
template <class S, class V>
void declare_base(ExtensionClass<S, V>* base, WithoutDowncast)
{
// see extclass.cpp for an explanation of why we need to register
// conversion functions
detail::BaseClassInfo baseInfo(base, 0);
ClassRegistry<T>::register_base_class(baseInfo);
add_base(Ptr(as_object(base), Ptr::new_ref));
detail::DerivedClassInfo derivedInfo(this,
&detail::DefineConversion<T, S>::upcast_ptr);
ClassRegistry<S>::register_derived_class(derivedInfo);
}
private: // types
typedef InstanceValueHolder<T,U> Holder;
private: // ExtensionClassBase virtual function implementations
std::vector<detail::BaseClassInfo> const& base_classes() const;
std::vector<detail::DerivedClassInfo> const& derived_classes() const;
void* extract_object_from_holder(InstanceHolderBase* v) const;
private: // Utility functions
template <long which, class Operand>
inline void def_operators(operators<which,Operand>)
{
register_coerce();
detail::choose_op<(which & op_add)>::template args<Operand>::add(this);
detail::choose_op<(which & op_sub)>::template args<Operand>::add(this);
detail::choose_op<(which & op_mul)>::template args<Operand>::add(this);
detail::choose_op<(which & op_div)>::template args<Operand>::add(this);
detail::choose_op<(which & op_mod)>::template args<Operand>::add(this);
detail::choose_op<(which & op_divmod)>::template args<Operand>::add(this);
detail::choose_op<(which & op_pow)>::template args<Operand>::add(this);
detail::choose_op<(which & op_lshift)>::template args<Operand>::add(this);
detail::choose_op<(which & op_rshift)>::template args<Operand>::add(this);
detail::choose_op<(which & op_and)>::template args<Operand>::add(this);
detail::choose_op<(which & op_xor)>::template args<Operand>::add(this);
detail::choose_op<(which & op_or)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_neg)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_pos)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_abs)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_invert)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_int)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_long)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_float)>::template args<Operand>::add(this);
detail::choose_op<(which & op_cmp)>::template args<Operand>::add(this);
detail::choose_unary_op<(which & op_str)>::template args<Operand>::add(this);
}
template <long which, class Left, class Right>
inline void def_operators(operators<which,Left>, right_operand<Right>)
{
register_coerce();
detail::choose_op<(which & op_add)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_sub)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_mul)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_div)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_mod)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_divmod)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_pow)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_lshift)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_rshift)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_and)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_xor)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_or)>::template args<Left,Right>::add(this);
detail::choose_op<(which & op_cmp)>::template args<Left,Right>::add(this);
}
template <long which, class Left, class Right>
inline void def_operators(operators<which,Right>, left_operand<Left>)
{
register_coerce();
detail::choose_rop<(which & op_add)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_sub)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_mul)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_div)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_mod)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_divmod)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_pow)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_lshift)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_rshift)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_and)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_xor)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_or)>::template args<Left,Right>::add(this);
detail::choose_rop<(which & op_cmp)>::template args<Left,Right>::add(this);
}
template <class Signature>
void add_constructor(Signature sig)
{
this->add_constructor_object(InitFunction<Holder>::create(sig));
}
void register_coerce();
};
// 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:"""
+ gen_functions("""%{
template <%(class A%n%:, %)>%}
HeldInstance(PyObject*%(, A%n% a%n%)) : T(%(a%n%:, %)) {}""", args)
+ """
};
// Abstract base class for all instance holders. Base for template class
// InstanceHolder<>, below.
class InstanceHolderBase
{
public:
virtual ~InstanceHolderBase() {}
virtual bool held_by_value() = 0;
};
// Abstract base class which holds a Held, somehow. Provides a uniform way to
// get a pointer to the held object
template <class Held>
class InstanceHolder : public InstanceHolderBase
{
public:
virtual Held*target() = 0;
};
// Concrete class which holds a Held by way of a wrapper class Wrapper. If Held
// can be constructed with arguments (A1...An), Wrapper must have a
// corresponding constructor for arguments (PyObject*, A1...An). Wrapper is
// neccessary to implement virtual function callbacks (there must be a
// back-pointer to the actual Python object so that we can call any
// overrides). HeldInstance (above) is used as a default Wrapper class when
// there are no virtual functions.
template <class Held, class Wrapper>
class InstanceValueHolder : public InstanceHolder<Held>
{
public:
Held* target() { return &m_held; }
Wrapper* value_target() { return &m_held; }
"""
+ gen_functions("""%{
template <%(class A%n%:, %)>%}
InstanceValueHolder(ExtensionInstance* p%(, A%n a%n%)) :
m_held(p%(, a%n%)) {}""", args)
+ """
public: // implementation of InstanceHolderBase required interface
bool held_by_value() { return true; }
private:
Wrapper m_held;
};
// Concrete class which holds a HeldType by way of a (possibly smart) pointer
// PtrType. By default, these are only generated for PtrType ==
// std::auto_ptr<HeldType> and PtrType == boost::shared_ptr<HeldType>.
template <class PtrType, class HeldType>
class InstancePtrHolder : public InstanceHolder<HeldType>
{
public:
HeldType* target() { return &*m_ptr; }
PtrType& ptr() { return m_ptr; }
InstancePtrHolder(PtrType ptr) : m_ptr(ptr) {}
public: // implementation of InstanceHolderBase required interface
bool held_by_value() { return false; }
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
//
namespace detail
{
Tuple extension_class_coerce(Ptr l, Ptr r);
}
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>
void ExtensionClass<T, U>::register_coerce()
{
Ptr coerce_fct = dict().get_item(String("__coerce__"));
if(coerce_fct.get() == 0) // not yet defined
this->def(&py::detail::extension_class_coerce, "__coerce__");
}
template <class T, class U>
inline
std::vector<detail::BaseClassInfo> const&
ExtensionClass<T, U>::base_classes() const
{
return ClassRegistry<T>::base_classes();
}
template <class T, class U>
inline
std::vector<detail::DerivedClassInfo> const&
ExtensionClass<T, U>::derived_classes() const
{
return ClassRegistry<T>::derived_classes();
}
template <class T, class U>
void* ExtensionClass<T, U>::extract_object_from_holder(InstanceHolderBase* v) const
{
py::InstanceHolder<T>* held = dynamic_cast<py::InstanceHolder<T>*>(v);
if(held)
return held->target();
return 0;
}
template <class T, class U>
ExtensionClass<T, U>::~ExtensionClass()
{
ClassRegistry<T>::unregister_class(this);
}
template <class T>
inline void ClassRegistry<T>::register_class(ExtensionClassBase* 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(ExtensionClassBase* p)
{
// The user should be destroying the same object they created.
assert(static_class_object == p);
(void)p; // unused in shipping version
static_class_object = 0;
}
template <class T>
void ClassRegistry<T>::register_base_class(py::detail::BaseClassInfo const& i)
{
static_base_class_info.push_back(i);
}
template <class T>
void ClassRegistry<T>::register_derived_class(py::detail::DerivedClassInfo const& i)
{
static_derived_class_info.push_back(i);
}
template <class T>
std::vector<py::detail::BaseClassInfo> const& ClassRegistry<T>::base_classes()
{
return static_base_class_info;
}
template <class T>
std::vector<py::detail::DerivedClassInfo> const& ClassRegistry<T>::derived_classes()
{
return static_derived_class_info;
}
//
// Static data member declaration.
//
template <class T>
ExtensionClassBase* ClassRegistry<T>::static_class_object;
template <class T>
std::vector<py::detail::BaseClassInfo> ClassRegistry<T>::static_base_class_info;
template <class T>
std::vector<py::detail::DerivedClassInfo> ClassRegistry<T>::static_derived_class_info;
} // namespace py
#endif // EXTENSION_CLASS_DWA052000_H_
""")
if __name__ == '__main__':
import sys
if len(sys.argv) == 1:
args = 5
else:
args = int(sys.argv[1])
print gen_extclass(args)

View File

@@ -1,184 +0,0 @@
import string
def _find(s, sub, start=0, end=None):
"""Just like string.find, except it returns end or len(s) when not found.
"""
if end == None:
end = len(s)
pos = string.find(s, sub, start, end)
if pos < 0:
return end
else:
return pos
def _gen_common_key(key, n, args):
if len(key) > 0 and key in '123456789':
return str(args[int(key) - 1])
elif key == 'x':
return str(n)
else:
return key
def _gen_arg(template, n, args, delimiter = '%'):
result = ''
i = 0
while i < len(template): # until the template is consumed
# consume everything up to the first delimiter
delimiter_pos = _find(template, delimiter, i)
result = result + template[i:delimiter_pos]
# The start position of whatever comes after the delimiter+key
start = delimiter_pos + 2
key = template[start - 1 : start] # the key character. If there were no
# delimiters left, key will be empty
if key == 'n':
result = result + `n`
else:
result = result + _gen_common_key(key, n, args)
i = start
return result
def gen_function(template, n, *args, **keywords):
r"""gen_function(template, n, [args...] ) -> string
Generate a function declaration based on the given template.
Sections of the template between '%(', '%)' pairs are repeated n times. If '%:'
appears in the middle, it denotes the beginning of a delimiter.
Sections of the template between '%{', '%}' pairs are ommitted if n == 0.
%n is transformed into the string representation of 1..n for each repetition
of n.
%x, where x is a digit, is transformed into the corresponding additional
argument.
for example,
>>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 2, 'void')
'void abc(int a1, int a2); // all args are ints'
>>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 0, 'x')
'x abc();'
>>> template = ''' template <class T%(, class A%n%)>
... static PyObject* call( %1(T::*pmf)(%(A%n%:, %))%2, PyObject* args, PyObject* /* keywords */ ) {
... PyObject* self;
... %( PyObject* a%n;
... %) if (!PyArg_ParseTuple(args, const_cast<char*>("O%(O%)"), &self%(, &a%n%)))
... return 0;
... T& target = from_python(self, Type<T&>());
... %3to_python((target.*pmf)(%(
... from_python(a%n, Type<A%n>())%:,%)
... ));%4
... }'''
>>> print gen_function(template, 0, 'R ', '', 'return ', '')
template <class T>
static PyObject* call( R (T::*pmf)(), PyObject* args, PyObject* /* keywords */ ) {
PyObject* self;
if (!PyArg_ParseTuple(args, const_cast<char*>("O"), &self))
return 0;
T& target = from_python(self, Type<T&>());
return to_python((target.*pmf)(
));
}
>>> print gen_function(template, 2, 'R ', '', 'return ', '')
template <class T, class A1, class A2>
static PyObject* call( R (T::*pmf)(A1, A2), PyObject* args, PyObject* /* keywords */ ) {
PyObject* self;
PyObject* a1;
PyObject* a2;
if (!PyArg_ParseTuple(args, const_cast<char*>("OOO"), &self, &a1, &a2))
return 0;
T& target = from_python(self, Type<T&>());
return to_python((target.*pmf)(
from_python(a1, Type<A1>()),
from_python(a2, Type<A2>())
));
}
>>> print gen_function(template, 3, 'void ', ' const', '', '\n'+8*' ' + 'return none();')
template <class T, class A1, class A2, class A3>
static PyObject* call( void (T::*pmf)(A1, A2, A3) const, PyObject* args, PyObject* /* keywords */ ) {
PyObject* self;
PyObject* a1;
PyObject* a2;
PyObject* a3;
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOO"), &self, &a1, &a2, &a3))
return 0;
T& target = from_python(self, Type<T&>());
to_python((target.*pmf)(
from_python(a1, Type<A1>()),
from_python(a2, Type<A2>()),
from_python(a3, Type<A3>())
));
return none();
}
"""
delimiter = keywords.get('delimiter', '%')
result = ''
i = 0
while i < len(template): # until the template is consumed
# consume everything up to the first delimiter
delimiter_pos = _find(template, delimiter, i)
result = result + template[i:delimiter_pos]
# The start position of whatever comes after the delimiter+key
start = delimiter_pos + 2
key = template[start - 1 : start] # the key character. If there were no
# delimiters left, key will be empty
pairs = { '(':')', '{':'}' }
if key in pairs.keys():
end = string.find(template, delimiter + pairs[key], start)
assert end >= 0, "Matching '" + delimiter + pairs[key] +"' not found!"
delimiter_pos = end
if key == '{':
if n > 0:
result = result + gen_function(template[start:end], n, args, delimiter)
else:
separator_pos = _find(template, delimiter + ':', start, end)
separator = template[separator_pos+2 : end]
for x in range(1, n + 1):
result = result + _gen_arg(template[start:separator_pos], x, args,
delimiter)
if x != n:
result = result + separator
else:
result = result + _gen_common_key(key, n, args)
i = delimiter_pos + 2
return result
def gen_functions(template, n, *args):
r"""gen_functions(template, n, [args...]) -> string
Call gen_function repeatedly with from 0..n and the given optional
arguments.
>>> print gen_functions('%1 abc(%(int a%n%:, %));%{ // all args are ints%}\n', 2, 'void'),
void abc();
void abc(int a1); // all args are ints
void abc(int a1, int a2); // all args are ints
"""
result = ''
for x in range(n + 1):
result = result + apply(gen_function, (template, x) + args)
return result
if __name__ == '__main__':
import doctest
doctest.testmod()

View File

@@ -1,167 +0,0 @@
from gen_function import *
import string
def gen_init_function(args):
return (
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
//
// This file was generated for %d-argument constructors by gen_init_function.py
#ifndef INIT_FUNCTION_DWA052000_H_
# define INIT_FUNCTION_DWA052000_H_
# include "pyconfig.h"
# include "functions.h"
# include "signatures.h"
# include <typeinfo>
namespace py {
namespace detail {
// parameter_traits - so far, this is a way to pass a const T& when we can be
// sure T is not a reference type, and a raw T otherwise. This should be
// rolled into boost::call_traits. Ordinarily, parameter_traits would be
// written:
//
// template <class T> struct parameter_traits
// {
// typedef const T& const_reference;
// };
//
// template <class T> struct parameter_traits<T&>
// {
// typedef T& const_reference;
// };
//
// template <> struct parameter_traits<void>
// {
// typedef void const_reference;
// };
//
// ...but since we can't partially specialize on reference types, we need this
// long-winded but equivalent incantation.
// const_ref_selector -- an implementation detail of parameter_traits (below). This uses
// the usual "poor man's partial specialization" hack for MSVC.
template <bool is_ref>
struct const_ref_selector
{
template <class T>
struct const_ref
{
typedef const T& type;
};
};
template <>
struct const_ref_selector<true>
{
template <class T>
struct const_ref
{
typedef T type;
};
};
# ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4181)
# endif // BOOST_MSVC
template <class T>
struct parameter_traits
{
private:
typedef const_ref_selector<boost::is_reference<T>::value> selector;
public:
typedef typename selector::template const_ref<T>::type const_reference;
};
# ifdef BOOST_MSVC
# pragma warning(pop)
# endif // BOOST_MSVC
// Full spcialization for void
template <>
struct parameter_traits<void>
{
typedef void const_reference;
};
template <class T>
class reference_parameter
{
typedef typename parameter_traits<T>::const_reference const_reference;
public:
reference_parameter(const_reference value)
: value(value) {}
operator const_reference() { return value; }
private:
const_reference value;
};
}
class 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%(,
detail::parameter_traits<A%n>::const_reference%)>;
}
""", args)+"""};
class Init : public Function
{
private: // override Function hook
PyObject* do_call(PyObject* args, PyObject* keywords) const;
private:
virtual 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%(,
py::detail::reference_parameter<A%n>(from_python(a%n, Type<A%n>()))%)
);
}
const char* description() const
{ return typeid(void (*)(T&%(, 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)

View File

@@ -1,152 +0,0 @@
from gen_function import *
import string
def gen_struct_signatures(args):
result = ''
for n in range(args, -1, -1):
result = (
result + gen_function("""%{template <%(class T%n%:, %)>
%}struct Signature%x {};
""", n)
# + ((n == args) and [""] or
# [gen_function("""
# template <class X>
# static inline Signature%1<X%(, T%n%)> prepend(Type<X>)
# { return Signature%1<X%(, T%n%)>(); }""",
# n, (str(n+1),))
# ]
# )[0]
#
# + ((n != 0) and [""] or
# ["""
# // This one terminates the chain. Prepending Void 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)

View File

@@ -1,58 +0,0 @@
from gen_function import *
import string
def gen_singleton(args):
return (
"""// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef SINGLETON_DWA051900_H_
# define SINGLETON_DWA051900_H_
# include "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)

View File

@@ -1,165 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>
Inheritance
</title>
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" align="center"
src="c++boost.gif" alt= "c++boost.gif (8819 bytes)">Inheritance
</h1>
<h2>Inheritance in Python</h2>
<p>
Py_cpp extension classes support single and multiple-inheritance in
Python, just like regular Python classes. You can mix built-in Python
classes with py_cpp extension classes in a derived class' tuple of
bases. Whenever a py_cpp extension class is among the bases for a new
class in Python, the result is an extension class:
<blockquote>
<pre>
&gt;&gt;&gt; class MyPythonClass:
... def f(): return 'MyPythonClass.f()'
...
&gt;&gt;&gt; import my_extension_module
&gt;&gt;&gt; class Derived(my_extension_module.MyExtensionClass, MyPythonClass):
... '''This is an extension class'''
... pass
...
&gt;&gt;&gt; x = Derived()
&gt;&gt;&gt; x.f()
'MyPythonClass.f()'
&gt;&gt;&gt; x.g()
'MyExtensionClass.g()'
</pre>
</blockquote>
<h2><a name="implicit_conversion">Reflecting C++ Inheritance Relationships</a></h2>
<p>
Py_cpp also allows us to represent C++ inheritance relationships so that
wrapped derived classes may be passed where values, pointers, or
references to a base class are expected as arguments. The
<code>declare_base</code> member function of
<code>ClassWrapper&lt;&gt;</code> is used to establish the relationship
between base and derived classes:
<blockquote>
<pre>
#include &lt;memory&gt; // for std::auto_ptr&lt;&gt;
struct Base {
virtual ~Base() {}
virtual const char* name() const { return "Base"; }
};
struct Derived : Base {
Derived() : x(-1) {}
virtual const char* name() const { return "Derived"; }
int x;
};
std::auto_ptr&lt;Base&gt; derived_as_base() {
return std::auto_ptr&lt;Base&gt;(new Derived);
}
const char* get_name(const Base& b) {
return b.name();
}
int get_derived_x(const Derived& d) {
return d.x;
}
<hr>
#include &lt;py_cpp/class_wrapper.h&gt;
extern "C"
#ifdef _WIN32
__declspec(dllexport)
#endif
void initmy_module()
{
    try
    {
       py::Module my_module("my_module");
       py::ClassWrapper&lt;Base&gt; base_class(my_module, "Base");
       base_class.def(py::Constructor&lt;void&gt;());
       py::ClassWrapper&lt;Derived&gt; derived_class(my_module, "Derived");
       derived_class.def(py::Constructor&lt;void&gt;());
<b>// Establish the inheritance relationship between Base and Derived
derived_class.declare_base(base_class);</b>
my_module.def(derived_as_base, "derived_as_base");
my_module.def(get_name, "get_name");
my_module.def(get_derived_x, "get_derived_x");
    }
    catch(...)
    {
       py::handle_exception();    // Deal with the exception for Python
    }
}
</pre>
</blockquote>
<p>
Then, in Python:
<blockquote>
<pre>
&gt;&gt;&gt; from my_module import *
&gt;&gt;&gt; base = Base()
&gt;&gt;&gt; derived = Derived()
&gt;&gt;&gt; get_name(base)
'Base'
</pre><i>objects of wrapped class Derived may be passed where Base is expected</i><pre>
&gt;&gt;&gt; get_name(derived)
'Derived'
</pre><i>objects of wrapped class Derived can be passed where Derived is
expected but where type information has been lost.</i><pre>
&gt;&gt;&gt; get_derived_x(derived_as_base())
-1
</pre>
</blockquote>
<h2>Inheritance Without Virtual Functions</h2>
<p>
If for some reason your base class has no virtual functions but you still want
to represent the inheritance relationship between base and derived classes,
pass the special symbol <code>py::without_downcast</code> as the 2nd parameter
to <code>declare_base</code>:
<blockquote>
<pre>
struct Base2 {};
struct Derived2 { int f(); };
<hr>
...
   py::ClassWrapper&lt;Base&gt; base2_class(my_module, "Base2");
   base2_class.def(py::Constructor&lt;void&gt;());
   py::ClassWrapper&lt;Derived2&gt; derived2_class(my_module, "Derived2");
   derived2_class.def(py::Constructor&lt;void&gt;());
derived_class.declare_base(base_class, <b>py::without_downcast</b>);
</pre>
</blockquote>
<p>This approach will allow <code>Derived2</code> objects to be passed where
<code>Base2</code> is expected, but does not attempt to implicitly convert (downcast)
smart-pointers to <code>Base2</code> into <code>Derived2</code> pointers,
references, or values.
<p>
Previous: <a href="overloading.html">Function Overloading</a>
Next: <a href="special.html">Special Method Names</a>
Up: <a href="py_cpp.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided "as is" without
express or implied warranty, and with no claim as to its suitability
for any purpose.
<p>
Updated: Oct 30, 2000
</div>

View File

@@ -1,36 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#include "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();
}
}

View File

@@ -1,288 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
//
// This file was generated for %d-argument constructors by gen_init_function.py
#ifndef INIT_FUNCTION_DWA052000_H_
# define INIT_FUNCTION_DWA052000_H_
# include "pyconfig.h"
# include "functions.h"
# include "signatures.h"
# include <typeinfo>
namespace py {
namespace detail {
// parameter_traits - so far, this is a way to pass a const T& when we can be
// sure T is not a reference type, and a raw T otherwise. This should be
// rolled into boost::call_traits. Ordinarily, parameter_traits would be
// written:
//
// template <class T> struct parameter_traits
// {
// typedef const T& const_reference;
// };
//
// template <class T> struct parameter_traits<T&>
// {
// typedef T& const_reference;
// };
//
// template <> struct parameter_traits<void>
// {
// typedef void const_reference;
// };
//
// ...but since we can't partially specialize on reference types, we need this
// long-winded but equivalent incantation.
// const_ref_selector -- an implementation detail of parameter_traits (below). This uses
// the usual "poor man's partial specialization" hack for MSVC.
template <bool is_ref>
struct const_ref_selector
{
template <class T>
struct const_ref
{
typedef const T& type;
};
};
template <>
struct const_ref_selector<true>
{
template <class T>
struct const_ref
{
typedef T type;
};
};
# ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4181)
# endif // BOOST_MSVC
template <class T>
struct parameter_traits
{
private:
typedef const_ref_selector<boost::is_reference<T>::value> selector;
public:
typedef typename selector::template const_ref<T>::type const_reference;
};
# ifdef BOOST_MSVC
# pragma warning(pop)
# endif // BOOST_MSVC
// Full spcialization for void
template <>
struct parameter_traits<void>
{
typedef void const_reference;
};
template <class T>
class reference_parameter
{
typedef typename parameter_traits<T>::const_reference const_reference;
public:
reference_parameter(const_reference value)
: value(value) {}
operator const_reference() { return value; }
private:
const_reference value;
};
}
class 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,
detail::parameter_traits<A1>::const_reference>;
}
template <class A1, class A2>
static Init* create(Signature2<A1, A2>) {
return new Init2<T,
detail::parameter_traits<A1>::const_reference,
detail::parameter_traits<A2>::const_reference>;
}
template <class A1, class A2, class A3>
static Init* create(Signature3<A1, A2, A3>) {
return new Init3<T,
detail::parameter_traits<A1>::const_reference,
detail::parameter_traits<A2>::const_reference,
detail::parameter_traits<A3>::const_reference>;
}
template <class A1, class A2, class A3, class A4>
static Init* create(Signature4<A1, A2, A3, A4>) {
return new Init4<T,
detail::parameter_traits<A1>::const_reference,
detail::parameter_traits<A2>::const_reference,
detail::parameter_traits<A3>::const_reference,
detail::parameter_traits<A4>::const_reference>;
}
template <class A1, class A2, class A3, class A4, class A5>
static Init* create(Signature5<A1, A2, A3, A4, A5>) {
return new Init5<T,
detail::parameter_traits<A1>::const_reference,
detail::parameter_traits<A2>::const_reference,
detail::parameter_traits<A3>::const_reference,
detail::parameter_traits<A4>::const_reference,
detail::parameter_traits<A5>::const_reference>;
}
};
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 (*)(T&)).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,
py::detail::reference_parameter<A1>(from_python(a1, Type<A1>()))
);
}
const char* description() const
{ return typeid(void (*)(T&, A1)).name(); }
};
template <class T, class A1, class A2>
struct Init2 : Init
{
virtual 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,
py::detail::reference_parameter<A1>(from_python(a1, Type<A1>())),
py::detail::reference_parameter<A2>(from_python(a2, Type<A2>()))
);
}
const char* description() const
{ return typeid(void (*)(T&, A1, A2)).name(); }
};
template <class T, class A1, class A2, class A3>
struct Init3 : Init
{
virtual 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,
py::detail::reference_parameter<A1>(from_python(a1, Type<A1>())),
py::detail::reference_parameter<A2>(from_python(a2, Type<A2>())),
py::detail::reference_parameter<A3>(from_python(a3, Type<A3>()))
);
}
const char* description() const
{ return typeid(void (*)(T&, A1, A2, A3)).name(); }
};
template <class T, class A1, class A2, class A3, class A4>
struct Init4 : Init
{
virtual 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,
py::detail::reference_parameter<A1>(from_python(a1, Type<A1>())),
py::detail::reference_parameter<A2>(from_python(a2, Type<A2>())),
py::detail::reference_parameter<A3>(from_python(a3, Type<A3>())),
py::detail::reference_parameter<A4>(from_python(a4, Type<A4>()))
);
}
const char* description() const
{ return typeid(void (*)(T&, A1, A2, A3, A4)).name(); }
};
template <class T, class A1, class A2, class A3, class A4, class A5>
struct Init5 : Init
{
virtual 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,
py::detail::reference_parameter<A1>(from_python(a1, Type<A1>())),
py::detail::reference_parameter<A2>(from_python(a2, Type<A2>())),
py::detail::reference_parameter<A3>(from_python(a3, Type<A3>())),
py::detail::reference_parameter<A4>(from_python(a4, Type<A4>())),
py::detail::reference_parameter<A5>(from_python(a5, Type<A5>()))
);
}
const char* description() const
{ return typeid(void (*)(T&, A1, A2, A3, A4, A5)).name(); }
};
}
#endif // INIT_FUNCTION_DWA052000_H_

View File

@@ -1,39 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#include "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 } };
}

View File

@@ -1,49 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef MODULE_DWA051000_H_
# define MODULE_DWA051000_H_
# include "pyconfig.h"
# include "pyptr.h"
# include "functions.h"
namespace py {
class Module
{
typedef PyObject * (*RawFunctionPtr)(py::Tuple const &, py::Dict const &);
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_raw(Fn fn, const char* name)
{
add(py::detail::new_raw_arguments_function(fn), 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

View File

@@ -1,2 +0,0 @@
#define DEBUG_PYTHON
#include "newtypes.cpp"

21
none.h
View File

@@ -1,21 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef NONE_DWA_052000_H_
# define NONE_DWA_052000_H_
# include "pyconfig.h"
# include "wrap_python.h"
namespace py {
inline PyObject* none() { Py_INCREF(Py_None); return Py_None; }
}
#endif // NONE_DWA_052000_H_

View File

@@ -1,485 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
// TODO: Move inline implementations from objects.cpp here
#include "objects.h"
#include "none.h"
namespace py {
template <class T>
T object_from_python(PyObject* p, Type<T>)
{
Ptr x(p, Ptr::new_ref);
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();
}
} // namespace py
PY_BEGIN_CONVERSION_NAMESPACE
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);
}
PY_END_CONVERSION_NAMESPACE
namespace py {
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));
if (!accepts(p))
{
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
throw ErrorAlreadySet();
}
}
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));
if (!accepts(p))
{
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
throw ErrorAlreadySet();
}
}
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));
}
String& String::operator*=(unsigned int repeat_count)
{
*this = String(Ptr(PySequence_Repeat(get(), repeat_count)));
return *this;
}
Dict::Dict(Ptr p)
: Object(p)
{
assert(accepts(p));
if (!accepts(p))
{
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
throw ErrorAlreadySet();
}
}
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
{
return get_item(key, Ptr());
}
Ptr Dict::get_item(const Ptr& key, const Ptr& default_) const
{
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::set_item(const Ptr& key, const Ptr& value)
{
if (PyDict_SetItem(get(), key.get(), value.get()) == -1)
throw ErrorAlreadySet();
}
void Dict::erase(Ptr key) {
if (PyDict_DelItem(get(), key.get()) == -1)
throw ErrorAlreadySet();
}
List Dict::items() const { return List(Ptr(PyDict_Items(get()))); }
List Dict::keys() const { return List(Ptr(PyDict_Keys(get()))); }
List Dict::values() const { return List(Ptr(PyDict_Values(get()))); }
std::size_t Dict::size() const { return static_cast<std::size_t>(PyDict_Size(get())); }
String operator+(String x, String y)
{
PyObject* io_string = x.reference().release();
PyString_Concat(&io_string, y.get());
return String(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));
if (!accepts(p))
{
PyErr_SetString(PyExc_TypeError, p->ob_type->tp_name);
throw ErrorAlreadySet();
}
}
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, const Ptr& item)
{
if (PyList_Insert(get(), index, item.get()) == -1)
throw ErrorAlreadySet();
}
void List::push_back(const Ptr& item)
{
if (PyList_Append(get(), item.get()) == -1)
throw ErrorAlreadySet();
}
void List::append(const 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)
{
m_list.set_item(m_index, rhs);
return rhs;
}
List::Proxy::operator Ptr() const
{
return Ptr(PyList_GetItem(m_list.get(), m_index), Ptr::borrowed);
}
Ptr List::get_item(std::size_t pos) const
{
return Ptr(PyList_GetItem(this->get(), pos), Ptr::borrowed);
}
void List::set_item(std::size_t pos, const Ptr& rhs)
{
int result = PyList_SetItem(this->get(), pos, rhs.get());
if (result == -1)
throw ErrorAlreadySet();
Py_INCREF(rhs.get());
}
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)
{
}
}

334
objects.h
View File

@@ -1,334 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef OBJECTS_DWA051100_H_
# define OBJECTS_DWA051100_H_
# include "wrap_python.h"
# include "pyconfig.h"
# include "pyptr.h"
# include "boost/operators.hpp"
# include <utility>
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:
explicit Tuple(std::size_t n = 0);
explicit Tuple(Ptr p);
template <class First, class Second>
Tuple(const std::pair<First,Second>& x)
: Object(Ptr(PyTuple_New(2)))
{
set_item(0, x.first);
set_item(1, x.second);
}
template <class First, class Second>
Tuple(const First& first, const Second& second)
: Object(Ptr(PyTuple_New(2)))
{
set_item(0, first);
set_item(1, second);
}
template <class First, class Second, class Third>
Tuple(const First& first, const Second& second, const Third& third)
: Object(Ptr(PyTuple_New(3)))
{
set_item(0, first);
set_item(1, second);
set_item(2, third);
}
template <class First, class Second, class Third, class Fourth>
Tuple(const First& first, const Second& second, const Third& third, const Fourth& fourth)
: Object(Ptr(PyTuple_New(4)))
{
set_item(0, first);
set_item(1, second);
set_item(2, third);
set_item(3, fourth);
}
static PyTypeObject* type_object();
static bool accepts(Ptr p);
std::size_t size() const;
Ptr operator[](std::size_t pos) const;
template <class T>
void set_item(std::size_t pos, const T& rhs)
{
this->set_item(pos, make_ptr(rhs));
}
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);
Ptr get_item(std::size_t pos) const;
template <class T>
void set_item(std::size_t pos, const T& x)
{ this->set_item(pos, make_ptr(x)); }
void set_item(std::size_t pos, const Ptr& );
// void set_item(std::size_t pos, const Object& );
template <class T>
void insert(std::size_t index, const T& x)
{ this->insert(index, make_ptr(x)); }
void insert(std::size_t index, const Ptr& item);
template <class T>
void push_back(const T& item)
{ this->push_back(make_ptr(item)); }
void push_back(const Ptr& item);
template <class T>
void append(const T& item)
{ this->append(make_ptr(item)); }
void append(const 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 boost::multipliable2<String, unsigned int>
{
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);
// 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*=(unsigned int repeat_count);
String& operator+=(const String& rhs);
friend String operator+(String x, String y);
String& operator+=(const char* rhs);
friend String operator+(String x, const char* y);
friend String operator+(const char* x, String y);
void intern();
friend String operator%(const String& format, const Tuple& args);
};
class Dict : public Object
{
private:
struct Proxy;
public:
explicit Dict(Ptr p);
Dict();
void clear();
static PyTypeObject* type_object();
static bool accepts(Ptr p);
public:
template <class Key>
Proxy operator[](const Key& key)
{ return this->operator[](make_ptr(key)); }
Proxy operator[](Ptr key);
template <class Key>
Ptr operator[](const Key& key) const
{ return this->operator[](make_ptr(key)); }
Ptr operator[](Ptr key) const;
template <class Key>
Ptr get_item(const Key& key) const
{ return this->get_item(make_ptr(key)); }
Ptr get_item(const Ptr& key) const;
template <class Key, class Default>
Ptr get_item(const Key& key, const Default& default_) const
{ return this->get_item(make_ptr(key), make_ptr(default_)); }
Ptr get_item(const Ptr& key, const Ptr& default_) const;
template <class Key, class Value>
void set_item(const Key& key, const Value& value)
{ this->set_item(make_ptr(key), make_ptr(value)); }
void set_item(const Ptr& key, const Ptr& value);
template <class Key>
void erase(const Key& key)
{ this->erase(make_ptr(key)); }
void erase(Ptr key);
// Proxy operator[](const Object& key);
// Ptr operator[](const Object& key) const;
// Ptr get_item(const Object& key, Ptr default_ = Ptr()) const;
// void set_item(const Object& key, const Ptr& value);
// void erase(const Object& key);
List items() const;
List keys() const;
List values() const;
std::size_t size() const;
// TODO: iterator support
};
struct Dict::Proxy
{
template <class T>
const Ptr& operator=(const T& rhs)
{ return (*this) = make_ptr(rhs); }
const Ptr& operator=(const Ptr& rhs);
operator Ptr() const;
private:
friend class Dict;
Proxy(const Ptr& dict, const Ptr& key);
// This is needed to work around the very strange MSVC error report that the
// return type of the built-in operator= differs from that of the ones
// defined above. Couldn't hurt to make these un-assignable anyway, though.
const Ptr& operator=(const Proxy&); // Not actually implemented
private:
Ptr m_dict;
Ptr m_key;
};
struct List::Proxy
{
template <class T>
const Ptr& operator=(const T& rhs)
{ return (*this) = make_ptr(rhs); }
const Ptr& operator=(const Ptr& rhs);
operator Ptr() const;
private:
friend class List;
Proxy(const Ptr& list, std::size_t index);
// This is needed to work around the very strange MSVC error report that the
// return type of the built-in operator= differs from that of the ones
// defined above. Couldn't hurt to make these un-assignable anyway, though.
const Ptr& operator=(const Proxy&); // Not actually implemented
private:
List 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;
};
} // namespace py
PY_BEGIN_CONVERSION_NAMESPACE
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>());
}
PY_END_CONVERSION_NAMESPACE
#endif // OBJECTS_DWA051100_H_

View File

@@ -1,436 +0,0 @@
#ifndef OPERATORS_UK112000_H_
#define OPERATORS_UK112000_H_
#include "functions.h"
#if !defined(__GNUC__) || defined(__SGI_STL_PORT)
# include <sstream>
#else
# include <strstream>
#endif
namespace py {
namespace detail {
template <long> struct define_operator;
// Base class which grants access to ExtensionClassBase::add_method() to its derived classes
struct add_operator_base
{
protected:
static inline void add_method(ExtensionClassBase* target, Function* method, const char* name)
{ target->add_method(method, name); }
};
//
// choose_op, choose_unary_op, and choose_rop
//
// These templates use "poor man's partial specialization" to generate the
// appropriate add_method() call (if any) for a given operator and argument set.
//
// Usage:
// choose_op<(which & op_add)>::template args<left_t,right_t>::add(ext_class);
//
// (see ExtensionClass<>::def_operators() for more examples).
//
template <long op_selector>
struct choose_op
{
template <class Left, class Right = Left>
struct args : add_operator_base
{
static inline void add(ExtensionClassBase* target)
{
typedef define_operator<op_selector> def_op;
add_method(target,
new typename def_op::template operator_function<Left, Right>(),
def_op::name());
}
};
};
// specialization for 0 has no effect
template <>
struct choose_op<0>
{
template <class Left, class Right = Left>
struct args
{
static inline void add(ExtensionClassBase*)
{
}
};
};
template <long op_selector>
struct choose_unary_op
{
template <class Operand>
struct args : add_operator_base
{
static inline void add(ExtensionClassBase* target)
{
typedef define_operator<op_selector> def_op;
add_method(target,
new typename def_op::template operator_function<Operand>(),
def_op::name());
}
};
};
// specialization for 0 has no effect
template <>
struct choose_unary_op<0>
{
template <class Operand>
struct args
{
static inline void add(ExtensionClassBase*)
{
}
};
};
template <long op_selector>
struct choose_rop
{
template <class Left, class Right = Left>
struct args : add_operator_base
{
static inline void add(ExtensionClassBase* target)
{
typedef define_operator<op_selector> def_op;
add_method(target,
new typename def_op::template roperator_function<Right, Left>(),
def_op::rname());
}
};
};
// specialization for 0 has no effect
template <>
struct choose_rop<0>
{
template <class Left, class Right = Left>
struct args
{
static inline void add(ExtensionClassBase*)
{
}
};
};
#define PY_DEFINE_BINARY_OPERATORS(id, oper) \
template <> \
struct define_operator<op_##id> \
{ \
template <class Left, class Right = Left> \
struct operator_function : Function \
{ \
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \
{ \
Tuple args(Ptr(arguments, Ptr::new_ref)); \
\
return PY_CONVERSION::to_python( \
PY_CONVERSION::from_python(args[0].get(), py::Type<Left>()) oper \
PY_CONVERSION::from_python(args[1].get(), py::Type<Right>())); \
} \
\
const char* description() const \
{ return "__" #id "__"; } \
}; \
\
template <class Right, class Left> \
struct roperator_function : Function \
{ \
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \
{ \
Tuple args(Ptr(arguments, Ptr::new_ref)); \
\
return PY_CONVERSION::to_python( \
PY_CONVERSION::from_python(args[1].get(), py::Type<Left>()) oper \
PY_CONVERSION::from_python(args[0].get(), py::Type<Right>())); \
} \
\
const char* description() const \
{ return "__r" #id "__"; } \
\
}; \
\
static const char * name() { return "__" #id "__"; } \
static const char * rname() { return "__r" #id "__"; } \
}
#define PY_DEFINE_UNARY_OPERATORS(id, oper) \
template <> \
struct define_operator<op_##id> \
{ \
template <class operand> \
struct operator_function : Function \
{ \
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \
{ \
Tuple args(Ptr(arguments, Ptr::new_ref)); \
\
return PY_CONVERSION::to_python( \
oper(PY_CONVERSION::from_python(args[0].get(), py::Type<operand>()))); \
} \
\
const char* description() const \
{ return "__" #id "__"; } \
}; \
\
static const char * name() { return "__" #id "__"; } \
}
#define PY_DEFINE_CONVERSION_OPERATORS(id, oper) \
template <> \
struct define_operator<op_##id> \
{ \
template <class operand> \
struct operator_function : Function \
{ \
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const \
{ \
Tuple args(Ptr(arguments, Ptr::new_ref)); \
\
return PY_CONVERSION::to_python( \
oper(PY_CONVERSION::from_python(args[0].get(), py::Type<operand>()))); \
} \
\
const char* description() const \
{ return "__" #id "_"; } \
}; \
\
static const char * name() { return "__" #id "_"; } \
}
PY_DEFINE_BINARY_OPERATORS(add, +);
PY_DEFINE_BINARY_OPERATORS(sub, -);
PY_DEFINE_BINARY_OPERATORS(mul, *);
PY_DEFINE_BINARY_OPERATORS(div, /);
PY_DEFINE_BINARY_OPERATORS(mod, %);
PY_DEFINE_BINARY_OPERATORS(lshift, <<);
PY_DEFINE_BINARY_OPERATORS(rshift, >>);
PY_DEFINE_BINARY_OPERATORS(and, &);
PY_DEFINE_BINARY_OPERATORS(xor, ^);
PY_DEFINE_BINARY_OPERATORS(or, |);
PY_DEFINE_UNARY_OPERATORS(neg, -);
PY_DEFINE_UNARY_OPERATORS(pos, +);
PY_DEFINE_UNARY_OPERATORS(abs, abs);
PY_DEFINE_UNARY_OPERATORS(invert, ~);
PY_DEFINE_CONVERSION_OPERATORS(int, int);
PY_DEFINE_CONVERSION_OPERATORS(long, long);
PY_DEFINE_CONVERSION_OPERATORS(float, double);
#undef PY_DEFINE_BINARY_OPERATORS
#undef PY_DEFINE_UNARY_OPERATORS
#undef PY_DEFINE_CONVERSION_OPERATORS
template <>
struct define_operator<op_pow>
{
template <class Left, class Right = Left>
struct operator_function : Function
{
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const
{
Tuple args(Ptr(arguments, Ptr::new_ref));
if (args.size() == 3 && args[2]->ob_type != Py_None->ob_type)
{
PyErr_SetString(PyExc_TypeError, "expected 2 arguments, got 3");
throw ArgumentError();
}
return PY_CONVERSION::to_python(
pow(PY_CONVERSION::from_python(args[0].get(), py::Type<Left>()),
PY_CONVERSION::from_python(args[1].get(), py::Type<Right>())));
}
const char* description() const
{ return "__pow__"; }
};
template <class Right, class Left>
struct roperator_function : Function
{
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const
{
Tuple args(Ptr(arguments, Ptr::new_ref));
if (args.size() == 3 && args[2]->ob_type != Py_None->ob_type)
{
PyErr_SetString(PyExc_TypeError, "expected 2 arguments, got 3");
throw ArgumentError();
}
return PY_CONVERSION::to_python(
pow(PY_CONVERSION::from_python(args[1].get(), py::Type<Left>()),
PY_CONVERSION::from_python(args[0].get(), py::Type<Right>())));
}
const char* description() const
{ return "__rpow__"; }
};
static const char * name() { return "__pow__"; }
static const char * rname() { return "__rpow__"; }
};
template <>
struct define_operator<op_divmod>
{
template <class Left, class Right = Left>
struct operator_function : Function
{
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const
{
Tuple args(Ptr(arguments, Ptr::new_ref));
PyObject * res = PyTuple_New(2);
PyTuple_SET_ITEM(res, 0,
PY_CONVERSION::to_python(
PY_CONVERSION::from_python(args[0].get(), py::Type<Left>()) /
PY_CONVERSION::from_python(args[1].get(), py::Type<Right>())));
PyTuple_SET_ITEM(res, 1,
PY_CONVERSION::to_python(
PY_CONVERSION::from_python(args[0].get(), py::Type<Left>()) %
PY_CONVERSION::from_python(args[1].get(), py::Type<Right>())));
return res;
}
const char* description() const
{ return "__divmod__"; }
};
template <class Right, class Left>
struct roperator_function : Function
{
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const
{
Tuple args(Ptr(arguments, Ptr::new_ref));
PyObject * res = PyTuple_New(2);
PyTuple_SET_ITEM(res, 0,
PY_CONVERSION::to_python(
PY_CONVERSION::from_python(args[1].get(), py::Type<Left>()) /
PY_CONVERSION::from_python(args[0].get(), py::Type<Right>())));
PyTuple_SET_ITEM(res, 1,
PY_CONVERSION::to_python(
PY_CONVERSION::from_python(args[1].get(), py::Type<Left>()) %
PY_CONVERSION::from_python(args[0].get(), py::Type<Right>())));
return res;
}
const char* description() const
{ return "__rdivmod__"; }
};
static const char * name() { return "__divmod__"; }
static const char * rname() { return "__rdivmod__"; }
};
template <>
struct define_operator<op_cmp>
{
template <class Left, class Right = Left>
struct operator_function : Function
{
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const
{
Tuple args(Ptr(arguments, Ptr::new_ref));
return PY_CONVERSION::to_python(
(PY_CONVERSION::from_python(args[0].get(), py::Type<Left>()) <
PY_CONVERSION::from_python(args[1].get(), py::Type<Right>())) ?
- 1 :
(PY_CONVERSION::from_python(args[1].get(), py::Type<Right>()) <
PY_CONVERSION::from_python(args[0].get(), py::Type<Left>())) ?
1 :
0) ;
}
const char* description() const
{ return "__cmp__"; }
};
template <class Right, class Left>
struct roperator_function : Function
{
PyObject* do_call(PyObject* arguments, PyObject* /* keywords */) const
{
Tuple args(Ptr(arguments, Ptr::new_ref));
return PY_CONVERSION::to_python(
(PY_CONVERSION::from_python(args[1].get(), py::Type<Left>()) <
PY_CONVERSION::from_python(args[0].get(), py::Type<Right>())) ?
- 1 :
(PY_CONVERSION::from_python(args[0].get(), py::Type<Right>()) <
PY_CONVERSION::from_python(args[1].get(), py::Type<Left>())) ?
1 :
0) ;
}
const char* description() const
{ return "__rcmp__"; }
};
static const char * name() { return "__cmp__"; }
static const char * rname() { return "__rcmp__"; }
};
template <>
struct define_operator<op_str>
{
template <class operand>
struct operator_function : Function
{
PyObject* do_call(PyObject* arguments, PyObject*) const
{
Tuple args(Ptr(arguments, Ptr::new_ref));
#if !defined(__GNUC__) || defined(__SGI_STL_PORT)
std::ostringstream s;
#else
std::strstream s;
#endif
s << PY_CONVERSION::from_python(args[0].get(), py::Type<operand>());
#if !defined(__GNUC__) || defined(__SGI_STL_PORT)
return PY_CONVERSION::to_python(s.str());
#else
return PY_CONVERSION::to_python(const_cast<char const *>(s.str()));
#endif
}
const char* description() const
{ return "__str__"; }
};
static const char * name() { return "__str__"; }
};
} // namespace detail
} // namespace py
#endif /* OPERATORS_UK112000_H_ */

View File

@@ -1,149 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>
Function Overloading
</title>
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" align="center"
src="c++boost.gif" alt= "c++boost.gif (8819 bytes)">Function Overloading
</h1>
<h2>An Example</h2>
<p>
To expose overloaded functions in Python, simply <code>def()</code> each
one with the same Python name:
<blockquote>
<pre>
inline int f1() { return 3; }
inline int f2(int x) { return x + 1; }
class X {
public:
X() : m_value(0) {}
X(int n) : m_value(n) {}
int value() const { return m_value; }
void value(int v) { m_value = v; }
private:
int m_value;
};
...
void initoverload_demo()
{
    try
    {
py::Module overload_demo("overload_demo");
// Overloaded functions at module scope
overload_demo.def(f1, "f");
overload_demo.def(f2, "f");
py::ClassWrapper&lt;X&gt; x_class(overload_demo, "X");
// Overloaded constructors
x_class.def(py::Constructor&lt;&gt;());
x_class.def(py::Constructor&lt;int&gt;());
// Overloaded member functions
x_class.def((int (X::*)() const)&amp;X::value, "value");
x_class.def((void (X::*)(int))&amp;X::value, "value");
...
</pre>
</blockquote>
<p>
Now in Python:
<blockquote>
<pre>
>>> from overload_demo import *
>>> x0 = X()
>>> x1 = X(1)
>>> x0.value()
0
>>> x1.value()
1
>>> x0.value(3)
>>> x0.value()
3
>>> X('hello')
TypeError: No overloaded functions match (X, string). Candidates are:
void (*)()
void (*)(int)
>>> f()
3
>>> f(4)
5
</pre>
</blockquote>
<h2>Discussion</h2>
<p>
Notice that overloading in the Python module was produced three ways:<ol>
<li>by combining the non-overloaded C++ functions <code>int f1()</code>
and <code>int f2(int)</code> and exposing them as <code>f</code> in Python.
<li>by exposing the overloaded constructors of <code>class X</code>
<li>by exposing the overloaded member functions <code>X::value</code>.
</ol>
<p>
Techniques 1. and 3. above are really alternatives. In case 3, you need
to form a pointer to each of the overloaded functions. The casting
syntax shown above is one way to do that in C++. Case 1 does not require
complicated-looking casts, but may not be viable if you can't change
your C++ interface. N.B. There's really nothing unsafe about casting an
overloaded (member) function address this way: the compiler won't let
you write it at all unless you get it right.
<h2>An Alternative to Casting</h2>
<p>
This approach is not neccessarily better, but may be preferable for some
people who have trouble writing out the types of (member) function
pointers or simply prefer to avoid all casts as a matter of principle:
<blockquote>
<pre>
// Forwarding functions for X::value
inline void set_x_value(X&amp; self, int v) { self.value(v); }
inline int get_x_value(X&amp; self) { return self.value(); }
...
// Overloaded member functions
x_class.def(set_x_value, "value");
x_class.def(get_x_value, "value");
</pre>
</blockquote>
<p>Here we are taking advantage of the ability to expose C++ functions at
namespace scope as Python member functions.
<h2>Overload Resolution</h2>
<p>
The function overload resolution mechanism in py_cpp works as
follows:
<ul>
<li>Attribute lookup for extension classes proceeds in <a
href="http://www.pythonlabs.com/pub/www.python.org/doc/current/tut/node11.html#SECTION0011510000000000000000">the
usual Python way</a> using a depth-first, left-to-right search. When a
class is found which has a matching attribute, only functions overloaded
in the context of that class are candidates for overload resolution. In
this sense, overload resolution mirrors the C++ mechanism, where a name
in a derived class "hides" all functions with the same name from a base
class.
<li>Within a name-space context (extension class or module), overloaded
functions are tried in the same order they were
<code>def()</code>ed. The first function whose signature can be made to
match each argument passed is the one which is ultimately called.
</ul>
<p>
Prev: <a href="overloading.html">Function Overloading</a>
Next: <a href="inheritance.html">Special Method Names</a>
Up: <a href="py_cpp.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided "as is" without
express or implied warranty, and with no claim as to its suitability
for any purpose.
<p>
Updated: Oct 30, 2000
</div>

View File

@@ -1,194 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Overridable Virtual Functions</title>
<img src="c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
width="277" height="86">
<h1>Overridable Virtual Functions</h1>
<p>
In the <a href="example1.html">previous example</a> we exposed a simple
C++ class in Python and showed that we could write a subclass. We even
redefined one of the functions in our derived class. Now we will learn
how to make the function <em>behave virtually</em>.
<h2><a name="overriding_example">Example</a></h2>
<p>In this example, it is assumed that <code>world::get()</code> is a virtual
member function:
<blockquote><pre>
class world
{
public:
   world(int);
    virtual ~world();
    <b>virtual</b> const char* get() const { return "hi, world"; }
};
</pre></blockquote>
<p>
We'll need a derived class<a href="#why_derived">*</a> to help us
dispatch the call to Python. In our derived class, we need the following
elements:
<ol>
<li><a name="derived_1">A</a> <code>PyObject*</code> data member that holds a reference to the
corresponding Python object.
<li><a name="derived_2">A</a> constructor for each exposed constructor of the base class which stores an
additional initial <code>PyObject*</code> argument in the data
member described above.
<li><a name="derived_3">An</a> implementation of each virtual function you may wish to override in
Python which uses
<code>py::Callback&lt<i>return-type</i>&gt;::call_method()</code> to call the
Python override.
<li><a name="derived_4">For</a> each non-pure virtual function meant to be overridable from Python, a
static member function (or a free function) taking a reference or pointer to the
base type as the first parameter and which forwards any additional parameters
neccessary to the <i>default</i> implementation of the virtual function. See also
<a href="#private">this note</a> if the base class virtual function is private.
</ol>
<blockquote><pre>
struct world_callback : world
{
world_callback(PyObject* self, int x) // <a href="#derived_2">2</a>
: world(x),
m_self(self) {}
const char* get() const // <a href="#derived_3">3</a>
{ return py::Callback&lt;const char*&gt;::call_method(m_self, "get"); }
static const char* <a name= "default_implementation">default_get</a>(const hello::world& self) const // <a href="#derived_4">4</a>
{ return self.world::get(); }
private:
PyObject* m_self; // <a href="#derived_1">1</a>
};
</pre></blockquote>
<p>
Finally, we add <code>world_callback</code> to the <code>
ClassWrapper&lt;&gt;</code> declaration in our module initialization
function, and when we define the function, we must tell py_cpp about the default
implementation:
<blockquote><pre>
// Create the <a name=
"world_class">Python type object</a> for our extension class
py::ClassWrapper&lt;hello::world<strong>,world_callback&gt;</strong> world_class(hello, "world");
// Add a virtual member function
world_class.def(&amp;world::get, "get", &amp;<b>world_callback::default_get</b>);
</pre></blockquote>
<p>
Now our subclass of <code>hello.world</code> behaves as expected:
<blockquote><pre>
&gt;&gt;&gt; class my_subclass(hello.world):
... def get(self):
... return 'hello, world'
...
&gt;&gt;&gt; hello.length(my_subclass())
12
</pre></blockquote>
<p>
<a name="why_derived">*</a>You may ask, "Why do we need this derived
class? This could have been designed so that everything gets done right
inside of <code>hello::world</code>." One of the goals of py_cpp is to be
minimally intrusive on an existing C++ design. In principle, it should be
possible to expose the interface for a 3rd party library without changing
it. To unintrusively hook into the virtual functions so that a Python
override may be called, we must use a derived class.
<h2>Pure Virtual Functions</h2>
<p>
A pure virtual function with no implementation is actually a lot easier
to deal with than a virtual function with a default implementation. First
of all, you obviously don't need to <a href="#default_implementation">
supply a default implementation</a>. Secondly, you don't need to call
<code>def()</code> on the <code>ExtensionClass&lt;&gt;</code> instance
for the virtual function. In fact, you wouldn't <em>want</em> to: if the
corresponding attribute on the Python class stays undefined, you'll get
an <code>AttributeError</code> in Python when you try to call the
function, indicating that it should have been implemented. For example:
<blockquote>
<pre>
struct baz {
<strong>virtual</strong> int pure(int) = 0;
};
struct baz_callback {
int pure(int x) { py::Callback&lt;int&gt;::call_method(m_self, "pure", x); }
};
extern "C"
#ifdef _WIN32
__declspec(dllexport)
#endif
initfoobar()
{
try
{
py::Module foobar("foobar");
py::ClassWrapper&lt;baz,baz_callback&gt; baz_class("baz");
baz_class.def(&amp;baz::pure, "pure");
}
catch(...)
{
py::handle_exception(); // Deal with the exception for Python
}
}
</pre>
</blockquote>
<p>
Now in Python:
<blockquote>
<pre>
&gt;&gt;&gt; from foobar import baz
&gt;&gt;&gt; x = baz()
&gt;&gt;&gt; x.pure(1)
Traceback (innermost last):
File "&lt;stdin&gt;", line 1, in ?
AttributeError: pure
&gt;&gt;&gt; class mumble(baz):
... def pure(self, x): return x + 1
...
&gt;&gt;&gt; y = mumble()
&gt;&gt;&gt; y.pure(99)
100
</pre></blockquote>
<a name="private"><h2>Private Non-Pure Virtual Functions</h2></a>
<p>This is one area where some minor intrusiveness on the wrapped library is
required. Once it has been overridden, the only way to call the base class
implementation of a private virtual function is to make the derived class a
friend of the base class. You didn't hear it from me, but most C++
implementations will allow you to change the declaration of the base class in
this limited way without breaking binary compatibility (though it will certainly
break the <a
href="http://cs.calvin.edu/c++/C++Standard-Nov97/basic.html#basic.def.odr">ODR</a>).
<p>
Prev: <a href="example1.html">A Simple Example Using py_cpp</a> Next: <a
href="overloading.html">Function Overloading</a> Up: <a href=
"py_cpp.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided "as is" without
express or implied warranty, and with no claim as to its suitability for
any purpose.
<p>
Updated: Oct 30, 2000

View File

@@ -1,143 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>
Pointers
</title>
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" align="center"
src="c++boost.gif" alt= "c++boost.gif (8819 bytes)">Pointers
</h1>
<h2>The Problem With Pointers</h2>
<p>
In general, raw pointers passed to or returned from functions are problematic
for py_cpp because pointers have too many potential meanings. Is it an iterator?
A pointer to a single element? An array? When used as a return value, is the
caller expected to manage (delete) the pointed-to object or is the pointer
really just a reference? If the latter, what happens to Python references to the
referent when some C++ code deletes it?
<p>
There are a few cases in which pointers are converted automatically:
<ul>
<li>Both const- and non-const pointers to wrapped class instances can be passed
<i>to</i> C++ functions.
<li>Values of type <code>const char*</code> are interpreted as
null-terminated 'C' strings and when passed to or returned from C++ functions are
converted from/to Python strings.
</ul>
<h3>Can you avoid the problem?</h3>
<p>My first piece of advice to anyone with a case not covered above is
&quot;find a way to avoid the problem.&quot; For example, if you have just one
or two functions returning a pointer to a single (not an array of) <code>const
T*</code> for some wrapped <code>T</code>, you may be able to write a &quot;thin
converting wrapper&quot; over those two functions as follows (Since py_cpp
converts <code>const T&</code> values <code>to_python</code> by copying the T
into a new extension instance, Foo must have a public copy constructor):
<blockquote><pre>
const Foo* f(); // original function
const Foo& f_wrapper() { return *f(); }
...
my_module.def(f_wrapper, "f");
</pre></blockquote>
<h2>Dealing with the problem</h2>
<p>The first step in handling the remaining cases is to figure out what the pointer
means. Several potential solutions are provided in the examples that follow:
<h3>Returning a pointer to a wrapped type</h3>
<h4>Returning a const pointer</h4>
<p>If you have lots of functions returning a <code>const T*</code> for some
wrapped <code>T</code>, you may want to provide an automatic
<code>to_python</code> conversion function so you don't have to write lots of
thin wrappers. You can do this simply as follows:
<blockquote><pre>
PY_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
PyObject* to_python(const Foo* p) {
return to_python(*p); // convert const Foo* in terms of const Foo&
}
PY_END_CONVERSION_NAMESPACE
</pre></blockquote>
<h4>If you can't (afford to) copy the referent, or the pointer is non-const</h4>
<p>If the wrapped type doesn't have a public copy constructor, if copying is
<i>extremely</i> costly (remember, we're dealing with Python here), or if the
pointer is non-const and you really need to be able to modify the referent from
Python, you can use the following dangerous trick. Why dangerous? Because python
can not control the lifetime of the referent, so it may be destroyed by your C++
code before the last Python reference to it disappears:
<blockquote><pre>
PY_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
PyObject* to_python(Foo* p)
{
return py::PyExtensionClassConverters<Foo>::ptr_to_python(p);
}
PyObject* to_python(const Foo* p)
{
return to_python(const_cast<Foo*>(p));
}
PY_END_CONVERSION_NAMESPACE
</pre></blockquote>
This will cause the Foo* to be treated as though it were an owning smart
pointer, even though it's not. Be sure you don't use the reference for anything
from Python once the pointer becomes invalid, though. Don't worry too much about
the <code>const_cast&lt;&gt;</code> above: Const-correctness is completely lost
to Python anyway!
<h3>[In/]Out Parameters and Immutable Types</h3>
<p>If you have an interface that uses non-const pointers (or references) as
in/out parameters to types which in Python are immutable (e.g. int, string),
there simply is <i>no way</i> to get the same interface in Python. You must
resort to transforming your interface with simple thin wrappers as shown below:
<blockquote><pre>
const void f(int* in_out_x); // original function
const int f_wrapper(int in_x) { f(in_x); return in_x; }
...
my_module.def(f_wrapper, "f");
</pre></blockquote>
<p>Of course, [in/]out parameters commonly occur only when there is already a
return value. You can handle this case by returning a Python tuple:
<blockquote><pre>
typedef unsigned ErrorCode;
const char* f(int* in_out_x); // original function
...
#include &lt;py_cpp/objects.h&gt;
const py::Tuple f_wrapper(int in_x) {
const char* s = f(in_x);
return py::Tuple(s, in_x);
}
...
my_module.def(f_wrapper, "f");
</pre></blockquote>
<p>Now, in Python:
<blockquote><pre>
&gt;&gt;&gt; str,out_x = f(3)
</pre></blockquote>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided "as is" without
express or implied warranty, and with no claim as to its suitability
for any purpose.
<p>
Updated: Nov 6, 2000
</div>

245
py.cpp
View File

@@ -1,245 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#include "py.h"
#include <typeinfo>
#ifndef BOOST_NO_LIMITS
# include <boost/cast.hpp>
#endif
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");
}
}
} // namespace py
PY_BEGIN_CONVERSION_NAMESPACE
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;
{
result = PyInt_AsLong(p);
if (PyErr_Occurred())
throw py::ArgumentError();
}
return result;
}
double from_python(PyObject* p, py::Type<double>)
{
double result;
{
result = PyFloat_AsDouble(p);
if (PyErr_Occurred())
throw py::ArgumentError();
}
return result;
}
template <class T>
T integer_from_python(PyObject* p, py::Type<T>)
{
const long long_result = from_python(p, py::Type<long>());
#ifndef BOOST_NO_LIMITS
try
{
return boost::numeric_cast<T>(long_result);
}
catch(const boost::bad_numeric_cast&)
#else
if (static_cast<T>(long_result) == long_result)
{
return static_cast<T>(long_result);
}
else
#endif
{
char buffer[256];
const char message[] = "%ld out of range for %s";
sprintf(buffer, message, long_result, typeid(T).name());
PyErr_SetString(PyExc_ValueError, buffer);
throw py::ArgumentError();
}
#if defined(__MWERKS__) && __MWERKS__ <= 0x2400
return 0; // Not smart enough to know that the catch clause always rethrows
#endif
}
template <class T>
PyObject* integer_to_python(T value)
{
long value_as_long;
#ifndef BOOST_NO_LIMITS
try
{
value_as_long = boost::numeric_cast<long>(value);
}
catch(const boost::bad_numeric_cast&)
#else
value_as_long = static_cast<long>(value);
if (value_as_long != value)
#endif
{
const char message[] = "value out of range for Python int";
PyErr_SetString(PyExc_ValueError, message);
throw 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 char i)
{
return integer_to_python(i);
}
unsigned char from_python(PyObject* p, py::Type<unsigned char> type)
{
return integer_from_python(p, type);
}
PyObject* to_python(signed char i)
{
return integer_to_python(i);
}
signed char from_python(PyObject* p, py::Type<signed char> type)
{
return integer_from_python(p, type);
}
PyObject* to_python(unsigned long x)
{
return integer_to_python(x);
}
unsigned long from_python(PyObject* p, 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_MSVC6_OR_EARLIER
// An optimizer bug prevents these from being inlined.
PyObject* to_python(double d)
{
return PyFloat_FromDouble(d);
}
PyObject* to_python(float f)
{
return PyFloat_FromDouble(f);
}
#endif // PY_MSVC6_OR_EARLIER
PY_END_CONVERSION_NAMESPACE

325
py.h
View File

@@ -1,325 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef METHOD_DWA122899_H_
# define METHOD_DWA122899_H_
# include "pyconfig.h"
# include "wrap_python.h"
# include "none.h"
# include "signatures.h"
# include <boost/smart_ptr.hpp>
# include "errors.h"
# include <string>
PY_BEGIN_CONVERSION_NAMESPACE // this is a gcc 2.95.2 bug workaround
// This can be instantiated on an enum to provide the to_python/from_python
// conversions, provided the values can fit in a long.
template <class EnumType>
class py_enum_as_int_converters
{
friend EnumType from_python(PyObject* x, py::Type<EnumType>)
{
return static_cast<EnumType>(
from_python(x, py::Type<long>()));
}
friend EnumType from_python(PyObject* x, py::Type<const EnumType&>)
{
return static_cast<EnumType>(
from_python(x, py::Type<long>()));
}
friend PyObject* to_python(EnumType x)
{
return to_python(static_cast<long>(x));
}
};
PY_END_CONVERSION_NAMESPACE
namespace py {
template <class EnumType> class enum_as_int_converters
: public PY_CONVERSION::py_enum_as_int_converters<EnumType> {};
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));
}
} // namespace py
PY_BEGIN_CONVERSION_NAMESPACE
//
// 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(signed char);
signed char from_python(PyObject*, py::Type<signed char>);
signed char from_python(PyObject*, py::Type<const signed char&>);
PyObject* to_python(unsigned char);
unsigned char from_python(PyObject*, py::Type<unsigned char>);
unsigned char from_python(PyObject*, py::Type<const unsigned char&>);
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
//
#ifndef PY_MSVC6_OR_EARLIER
inline PyObject* to_python(double d)
{
return PyFloat_FromDouble(d);
}
inline PyObject* to_python(float f)
{
return PyFloat_FromDouble(f);
}
#endif // PY_MSVC6_OR_EARLIER
inline PyObject* to_python(long l)
{
return PyInt_FromLong(l);
}
inline PyObject* to_python(int x)
{
return PyInt_FromLong(x);
}
inline PyObject* to_python(short x)
{
return PyInt_FromLong(x);
}
inline PyObject* to_python(bool b)
{
return PyInt_FromLong(b);
}
inline PyObject* to_python(void)
{
return py::none();
}
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 const char* from_python(PyObject* p, py::Type<const char* const&>)
{
return from_python(p, py::Type<const char*>());
}
inline double from_python(PyObject* p, py::Type<const double&>)
{
return from_python(p, py::Type<double>());
}
inline float from_python(PyObject* p, py::Type<const float&>)
{
return from_python(p, py::Type<float>());
}
inline int from_python(PyObject* p, py::Type<const int&>)
{
return from_python(p, py::Type<int>());
}
inline short from_python(PyObject* p, py::Type<const short&>)
{
return from_python(p, py::Type<short>());
}
inline long from_python(PyObject* p, py::Type<const long&>)
{
return from_python(p, py::Type<long>());
}
inline bool from_python(PyObject* p, py::Type<const bool&>)
{
return from_python(p, py::Type<bool>());
}
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 signed char from_python(PyObject* p, py::Type<const signed char&>)
{
return from_python(p, py::Type<signed char>());
}
inline unsigned char from_python(PyObject* p, py::Type<const unsigned char&>)
{
return from_python(p, py::Type<unsigned char>());
}
inline unsigned long from_python(PyObject* p, py::Type<const unsigned long&>)
{
return from_python(p, py::Type<unsigned long>());
}
PY_END_CONVERSION_NAMESPACE
#endif // METHOD_DWA122899_H_

View File

@@ -1,203 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>
py_cpp Python/C++ binding documentation
</title>
<h1>
<img src="c++boost.gif" alt="c++boost.gif (8819 bytes)" width="277"
align="center" height="86"> py_cpp<a href="#naming_contest">*</a>
</h1>
<p>
The source code for py_cpp, including a MSVC demo project is available <a
href="py_cpp_20001106.zip">here</a>.
<h2>Synopsis</h2>
<p>
py_cpp is a system for quickly and easily interfacing C++ code with <a
href="http:www.python.org">Python</a> such that the Python interface is
very similar to the C++ interface. It is designed to be minimally
intrusive on your C++ design. In most cases, you should not have to alter
your C++ classes in any way in order to use them with py_cpp. The system
<em>should</em> simply "reflect" your C++ classes and functions into
Python.
<h2>Supported Platforms</h2>
<p>py_cpp has been tested in the following configurations:
<ul>
<li>Against Python 1.5.2 using the following compiler/library:
<ul>
<li><a
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a>
<li><a
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a>/<a
href="http://www.stlport.org">STLport 4.0</a>
<li><a href="http://gcc.gnu.org/">GCC 2.95.2</a> [by <a href="mailto:koethe@informatik.uni-hamburg.de">Ullrich
Koethe</a>]
<li><a href="http://gcc.gnu.org/">GCC 2.95.2</a>/<a href="http://www.stlport.org">STLport 4.0</a>
<li>Compaq C++ V6.2-024 for Digital UNIX V5.0 Rev. 910 (an <a
href="http://www.edg.com/">EDG</a>-based compiler) with <a
href="http://www.stlport.org/beta.html">STLport-4.1b3</a> [by <a
href="mailto:rwgk@cci.lbl.gov">Ralf W. Grosse-Kunstleve</a>]
<li>An upcoming release of <a href="http://www.metrowerks.com/products/windows/">Metrowerks CodeWarrior
Pro6 for Windows</a> (the first release has a bug that's fatal to py_cpp)
</ul>
<br>
<li>Against Python 2.0 using the following compiler/library combinations:
<ul>
<li><a
href="http://msdn.microsoft.com/vstudio/sp/vs6sp4/dnldoverview.asp">MSVC++6sp4</a> [by
<a href="mailto:aleaxit@yahoo.com">Alex Martelli</a>]
</ul>
</ul>
<p>Py_cpp requires the <a href="http://www.boost.org">boost</a> libraries, and is
has been accepted for inclusion into the boost libraries pending &quot;boostification&quot;
(completion of the documentation, change in some naming conventions and
resolution of some namespace issues).
<h2>Credits</h2>
<p>
<ul>
<li><a href="mailto:abrahams@mediaone.net">David Abrahams</a> originated
and wrote py_cpp.
<li><a href="mailto:koethe@informatik.uni-hamburg.de">Ullrich Koethe</a>
had independently developed a similar system. When he discovered py_cpp,
he generously contributed countless hours of coding and much insight into
improving it. He is responsible for an early version of the support for <a
href="overloading.html">function overloading</a> and wrote the support for
<a href="inheritance.html#implicit_conversion">reflecting C++ inheritance
relationships</a>. He has helped to improve error-reporting from both
Python and C++, and is currently doing valuable research into <a
href="special.html#reasons">the best approach for numeric coercion</a>.
<li>The members of the boost mailing list and the Python community supplied
invaluable early feedback. In particular, Ron Clarke, Mark Evans, Anton
Gluck, Ralf W. Grosse-Kunstleve, Prabhu Ramachandran, and Barry Scott took
the brave step of trying to use py_cpp while it was still in early stages
of development.
<li>The development of py_cpp wouldn't have been
possible without the generous support of <a href="http://www.dragonsys.com/">Dragon Systems/Lernout and
Hauspie, Inc</a> who supported its development as an open-source project.
</ul>
<h2>Table of Contents</h2>
<ol>
<li><a href="extending.html">A Brief Introduction to writing Python
extension modules</a>
<li><a href="comparisons.html">Comparisons between py_cpp and other
systems for extending Python</a>
<li><a href="example1.html">A Simple Example Using py_cpp</a>
<li><a href="overriding.html">Overridable Virtual Functions</a>
<li><a href="overloading.html">Function Overloading</a>
<li><a href="inheritance.html">Inheritance</a>
<li><a href="special.html">Special Method Name Support</a>
<li><a href="under-the-hood.html">A Peek Under the Hood</a>
<li><a href="building.html">Building a Module with Py_cpp</a>
<li>Advanced Topics
<ol>
<li>ClassWrapper&lt;&gt;
<li><a href="enums.html">enums</a>
<li>References
<li><a href="pointers.html">Pointers and Smart Pointers</a>
<li>Built-in Python Types
<li>Other Extension Types
<li>Templates
</ol>
</ol>
<p>
More sophisticated examples are given in
<code>extclass_demo.cpp</code>, <code> extclass_demo.h</code>, and <code>
test_extclass.py</code> in the <a href="py_cpp.tgz">source code
archive</a>. There's much more here, and much more documentation to
come...
<p>
Questions should be directed to <a href=
"http://www.egroups.com/list/boost">the boost mailing list</a>.
<h2>Naming Contest</h2>
<p>
Yes, I know py_cpp is a lousy name. Problem is, the best names my puny
imagination can muster (IDLE and GRAIL) are taken, so I'm holding a
naming contest. First prize? You get to pick the name&lt;0.2wink&gt; and
you will be credited in the documentation. Names that have been suggested
so far include:
<ul>
<li>
Py++
<li>
Python++
<li>
Coil
<li>
SnakeSkin
<li>
CCCP - <b>C</b>onvert <b>C</b>++ <b>
C</b>lasses to <b>P</b>ython
<li>
C<sup>3</sup>PO - <b>C</b>onvert <b>C</b>++
<b>C</b>lasses to <b>P</b>ython <b>
O</b>bjects
<li>
PALIN - <b>P</b>ython <b>
A</b>ugmented-<b>L</b>anguage <b>
IN</b>tegration
<li>
CLEESE - <b>C</b>++ <b>L</b>anguage <b>E</b>xtension <b>E</b>nvironment
<b>S</b>upremely <b>E</b>asy
<li>
JONES - <b>J</b>ust <b>O</b>bscenely <b>N</b>eat <b>E</b>xtension
<b>S</b>ystem
<li>
C-thru
<li>
SeamlessC
<li>
BorderCrossing
<li>
Perseus (because he solved a hairy problem involving snakes by using
reflection and was invisible most of the time).
</ul>
Please <a href="http://www.egroups.com/list/boost">post</a> or send <a
href="http:mailto:abrahams@mediaone.net">me</a> your suggestions!<br>
<br>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided "as is" without
express or implied warranty, and with no claim as to its suitability for
any purpose.
<p>
Updated: Oct 18, 2000

View File

@@ -1,57 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef CONFIG_DWA052200_H_
# define CONFIG_DWA052200_H_
# include <boost/config.hpp>
# include <cstddef>
# ifdef BOOST_NO_OPERATORS_IN_NAMESPACE
// A gcc bug forces some symbols into the global namespace
# define PY_BEGIN_CONVERSION_NAMESPACE
# define PY_END_CONVERSION_NAMESPACE
# define PY_CONVERSION
# define PY_IMPORT_CONVERSION(x) using ::x
# else
# define PY_BEGIN_CONVERSION_NAMESPACE namespace py {
# define PY_END_CONVERSION_NAMESPACE }
# define PY_CONVERSION py
# define PY_IMPORT_CONVERSION(x) void never_defined() // so we can follow the macro with a ';'
# endif
# if defined(BOOST_MSVC)
# define PY_COMPILER_IS_MSVC 1
# if _MSC_VER <= 1200
# define PY_MSVC6_OR_EARLIER 1
# endif
# pragma warning (disable : 4786)
# endif
// Work around the broken library implementation/strict ansi checking on some
// EDG-based compilers (e.g. alpha), which incorrectly warn that the result of
// offsetof() is not an integer constant expression.
# if defined(__DECCXX_VER) && __DECCXX_VER <= 60290024
# define PY_OFFSETOF(s_name, s_member) \
((size_t)__INTADDR__(&(((s_name *)0)->s_member)))
# else
# define PY_OFFSETOF(s_name, s_member) \
offsetof(s_name, s_member)
# endif
// The STLport puts all of the standard 'C' library names in std (as far as the
// user is concerned), but without it you need a fix if you're using MSVC.
# if defined(PY_MSVC6_OR_EARLIER) && !defined(__STLPORT)
# define PY_CSTD_
# else
# define PY_CSTD_ std
# endif
#endif // CONFIG_DWA052200_H_

173
pyptr.h
View File

@@ -1,173 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef PYPTR_DWA050400_H_
# define PYPTR_DWA050400_H_
# include "pyconfig.h"
# include <boost/operators.hpp>
# include "wrap_python.h"
# include "cast.h"
# include <cassert>
# include "signatures.h"
# include "errors.h"
# include "py.h"
PY_BEGIN_CONVERSION_NAMESPACE
template <class T, class Value, class Base>
struct PyPtrConversions : Base
{
inline friend T from_python(PyObject* x, py::Type<const T&>)
{ return T(py::Downcast<Value>(x).get(), T::new_ref); }
inline friend T from_python(PyObject* x, py::Type<T>)
{ return T(py::Downcast<Value>(x).get(), T::new_ref); }
inline friend PyObject* to_python(T x)
{ return py::as_object(x.release()); }
};
PY_END_CONVERSION_NAMESPACE
namespace py {
PY_IMPORT_CONVERSION(PyPtrConversions);
template <class T>
class PyPtr
: public PyPtrConversions<PyPtr<T>, T,
boost::dereferenceable<PyPtr<T>, T*> > // supplies op->
{
public:
typedef T value_type;
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;
template <class T>
Ptr make_ptr(const T& x)
{
return Ptr(to_python(x));
}
}
#endif // PYPTR_DWA050400_H_

View File

@@ -1,174 +0,0 @@
2000-11-15 12:01
Fixed Ullrich's refcount bug
Moved operator_dispatcher into extclass.cpp
Gave it shared ownership of the objects it wraps
Introduced sequence points in extension_class_coerce for exception-safety
UPPER_CASE_MACRO_NAMES
MixedCase template type argument names
Changed internal error reporting to use Python exceptions so we don't force the
user to link in iostreams code
Changed error return value of call_cmp to -1
Moved unwrap_* functions out of operator_dispatcher. This was transitional: when
I realized they didn't need to be declared in extclass.h I moved them out, but
now that operator_dispatcher itself is in extclass.cpp they could go back in.
Numerous formatting tweaks
Updated the BoundFunction::create() optimization and enabled it so it could actually be used!
2000-11-15 00:26
Made Ullrich's operators support work with MSVC
Cleaned up operators.h such that invalid define_operator<0> is no longer needed.
2000-11-13 22:29
removed obsolete ExtensionClassFromPython for good.
removed unused class ExtensionType forward declaration
2000-11-12 13:08
Added enum_as_int_converters for easier enum wrapping
Introduced new conversion namespace macros:
PY_BEGIN_CONVERSION_NAMESPACE,
PY_END_CONVERSION_NAMESPACE,
PY_CONVERSION
callback.h, gen_callback.py:
Added call() function so that a regular python function (as opposed to
method or other function-as-attribute) can be called.
Added newlines for readability.
class_wrapper.h:
Fixed a bug in add(), which allows non-method class attributes
Ullrich has added def_raw for simple varargs and keyword support.
Fixed version number check for __MWERKS__
Added tests for enums and non-method class attributes
objects.h/objects.cpp:
Added py::String operator*= and operator* for repetition
Change Dict::items(), keys(), and values() to return a List
Added template versions of set_item, etc., methods so that users can optionally
use C++ types that have to_python() functions as parameters.
Changed various Ptr by-value parameters to const Ptr&
======= Release =======
2000-11-06 0:22
Lots of documentation updates
added 4-argument template constructor to py::Tuple
added "add" member function to ClassWrapper<> to allow arbitrary Python
objects to be added to an extension class.
gen_all.py now generates support for n argument member functions and n+1
argument member functions at the suggestion of "Ralf W. Grosse-Kunstleve"
<rwgk@cci.lbl.gov>
Added regression tests and re-ordered declare_base calls to verify that the
phantom base class issue is resolved.
2000-11-04 17:35
Integrated Ullrich Koethe's brilliant from_python_experiment for better
error-reporting in many cases.
extclass.h, gen_extclass.py:
removed special-case MSVC code
added much commentary
removed unused py_copy_to_new_value_holder
init_function.h, gen_init_function.py:
added missing 'template' keyword on type-dependent template member usage
removed special-case MSVC code
added much commentary
2000-11-04 0:36
Removed the need for the phantom base class that screwed up inheritance
hierarchies, introduced error-prone ordering dependencies, and complexified
logic in many places!
extclass.h: Added some explanatory comments, removed wasteful m_self member
of HeldInstance
extclass_demo.cpp: Added #pragmas which allow compilation in ansi strict
mode under Metrowerks
functions.h: Added virtual_function as part of phantom base class removal;
expanded commentary
pyptr.h: Added some missing 'typename's and a GCC workaround fix
subclass.cpp: Added missing string literal const_cast<>s.
2000-11-03 10:58
Fix friend function instantiation bug caught by Metrowerks (thanks
Metrowerks!)
Add proof-of-concept for one technique of wrapping function that return a
pointer
Worked around MSVC optimizer bug by writing to_python(double) and
to_python(float) out-of-line
2000-11-02 23:25
Add /Zm200 option to vc6_prj to deal with MSVC resource limitations
Remove conflicting /Ot option from vc6_prj release build
======= Release =======
2000-11-02 17:42
Added a fix for interactions between default virtual function
implementations and declare_base(). You still need to write your
declare_base() /after/ all member functions have been def()d for the two
classes concerned. Many, many thanks to Ullrich Koethe
<koethe@informatik.uni-hamburg.de> for all his work on this.
Added missing conversions:
to_python(float)
from_python(const char* const&)
from_python(const double&)
from_python(const float&)
Added a Regression test for a reference-counting bug thanks to Mark Evans
(<mark.evans@clarisay.com>)
const-ify ClassBase::getattr()
Add repr() function to Class<T>
Add to_python/from_python conversions for PyPtr<T>
Standardize set_item/get_item interfaces (instead of proxies) for Dict and List
Add Reprable<> template to newtypes.h
Fix a bug wherein the __module__ attribute would be lost for classes that have a
default virtual function implementation.
Remove extra ';' in module.cpp thanks to "Ralf W. Grosse-Kunstleve"
<rwgk@cci.lbl.gov>
Fix a bug in the code of example1.html

View File

@@ -1,165 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
//
// This file automatically generated by gen_signatures.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

View File

@@ -1,53 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef SINGLETON_DWA051900_H_
# define SINGLETON_DWA051900_H_
# include "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

View File

@@ -1,397 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<title>
Special Method Name Support
</title>
<div>
<h1>
<img width="277" height="86" id="_x0000_i1025" align="center" src=
"c++boost.gif" alt="c++boost.gif (8819 bytes)">Special Method Name
Support
</h1>
<h2>
Overview
</h2>
<p>
Py_cpp supports all of the standard <a href=
"http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/specialnames.html">
special method names</a> supported by real Python class instances <em>
except:</em>
<ul>
<li>the <code>__r<em>&lt;name&gt;</em>__</code> "reversed operand" <a href=
"http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/numeric-types.html">
numeric methods</a>, and
<li><code>__complex__</code>
</ul>
(more on the reasons <a href="#reasons">below</a>). So, for example, we can wrap a
<code>std::map&lt;std::size_t,std::string&gt;</code> as follows:
<h2>
Example
</h2>
<blockquote>
<pre>
typedef std::map&lt;std::size_t, std::string&gt; StringMap;
// A helper function for dealing with errors. Throw a Python exception
// if p == m.end().
void throw_key_error_if_end(
const StringMap&amp; 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();
}
}
// Define some simple wrapper functions which match the Python protocol
// for __getitem__, __setitem__, and __delitem__. Just as in Python, a
// free function with a "self" first parameter makes a fine class method.
const std::string&amp; get_item(const StringMap&amp; self, std::size_t key)
{
const StringMap::const_iterator p = self.find(key);
throw_key_error_if_end(self, p, key);
return p-&gt;second;
}
// Sets the item corresponding to key in the map.
void StringMapPythonClass::set_item(StringMap&amp; self, std::size_t key, const std::string&amp; value)
{
self[key] = value;
}
// Deletes the item corresponding to key from the map.
void StringMapPythonClass::del_item(StringMap&amp; self, std::size_t key)
{
const StringMap::iterator p = self.find(key);
throw_key_error_if_end(self, p, key);
self.erase(p);
}
ClassWrapper&lt;StringMap&gt; string_map(my_module, "StringMap");
string_map.def(py::Constructor&lt;&gt;());
string_map.def(&amp;StringMap::size, "__len__");
string_map.def(get_item, "__getitem__");
string_map.def(set_item, "__setitem__");
string_map.def(del_item, "__delitem__");
</pre>
</blockquote>
<p>
Then in Python:
<blockquote>
<pre>
&gt;&gt;&gt; m = StringMap()
&gt;&gt;&gt; m[1]
Traceback (innermost last):
File "&lt;stdin&gt;", line 1, in ?
KeyError: 1
&gt;&gt;&gt; m[1] = 'hello'
&gt;&gt;&gt; m[1]
'hello'
&gt;&gt;&gt; del m[1]
&gt;&gt;&gt; m[1] # prove that it's gone
Traceback (innermost last):
File "&lt;stdin&gt;", line 1, in ?
KeyError: 1
&gt;&gt;&gt; del m[2]
Traceback (innermost last):
File "&lt;stdin&gt;", line 1, in ?
KeyError: 2
&gt;&gt;&gt; len(m)
0
&gt;&gt;&gt; m[3] = 'farther'
&gt;&gt;&gt; len(m)
1
</pre>
</blockquote>
<h2>
<a name="getter_setter">Getters and Setters</a>
</h2>
<p>
Py_cpp extension classes support some additional "special method"
protocols not supported by built-in Python classes. Because writing
<code>__getattr__</code>, <code> __setattr__</code>, and
<code>__delattr__</code> functions can be tedious in the common case
where the attributes being accessed are known statically, py_cpp checks
the special names
<ul>
<li>
<code>__getattr__<em>&lt;name&gt;</em>__</code>
<li>
<code>__setattr__<em>&lt;name&gt;</em>__</code>
<li>
<code>__delattr__<em>&lt;name&gt;</em>__</code>
</ul>
to provide functional access to the attribute <em>&lt;name&gt;</em>. This
facility can be used from C++ or entirely from Python. For example, the
following shows how we can implement a "computed attribute" in Python:
<blockquote>
<pre>
&gt;&gt;&gt; class Range(AnyPy_cppExtensionClass):
... def __init__(self, start, end):
... self.start = start
... self.end = end
... def __getattr__length__(self):
... return self.end - self.start
...
&gt;&gt;&gt; x = Range(3, 9)
&gt;&gt;&gt; x.length
6
</pre>
</blockquote>
<h2>
Direct Access to Data Members
</h2>
<p>
Py_cpp uses the special <code>
__xxxattr__<em>&lt;name&gt;</em>__</code> functionality described above
to allow direct access to data members through the following special
functions on <code>ClassWrapper&lt;&gt;</code> and <code>
ExtensionClass&lt;&gt;</code>:
<ul>
<li>
<code>def_getter(<em>pointer-to-member</em>, <em>name</em>)</code> //
read access to the member via attribute <em>name</em>
<li>
<code>def_setter(<em>pointer-to-member</em>, <em>name</em>)</code> //
write access to the member via attribute <em>name</em>
<li>
<code>def_readonly(<em>pointer-to-member</em>, <em>name</em>)</code>
// read-only access to the member via attribute <em>name</em>
<li>
<code>def_read_write(<em>pointer-to-member</em>, <em>
name</em>)</code> // read/write access to the member via attribute
<em>name</em>
</ul>
<p>
Note that the first two functions, used alone, may produce surprising
behavior. For example, when <code>def_getter()</code> is used, the
default functionality for <code>setattr()</code> and <code>
delattr()</code> remains in effect, operating on items in the extension
instance's name-space (i.e., its <code>__dict__</code>). For that
reason, you'll usually want to stick with <code>def_readonly</code> and
<code>def_read_write</code>.
<p>
For example, to expose a <code>std::pair&lt;int,long&gt;</code> we
might write:
<blockquote>
<pre>
typedef std::pair&lt;int,long&gt; Pil;
int first(const Pil&amp; x) { return x.first; }
long second(const Pil&amp; x) { return x.second; }
...
my_module.def(first, "first");
my_module.def(second, "second");
ClassWrapper&lt;Pil&gt; pair_int_long(my_module, "Pair");
pair_int_long.def(py::Constructor&lt;&gt;());
pair_int_long.def(py::Constructor&lt;int,long&gt;());
pair_int_long.def_read_write(&amp;Pil::first, "first");
pair_int_long.def_read_write(&amp;Pil::second, "second");
</pre>
</blockquote>
<p>
Now your Python class has attributes <code>first</code> and <code>
second</code> which, when accessed, actually modify or reflect the
values of corresponding data members of the underlying C++ object. Now
in Python:
<blockquote>
<pre>
&gt;&gt;&gt; x = Pair(3,5)
&gt;&gt;&gt; x.first
3
&gt;&gt;&gt; x.second
5
&gt;&gt;&gt; x.second = 8
&gt;&gt;&gt; x.second
8
&gt;&gt;&gt; second(x) # Prove that we're not just changing the instance __dict__
8
</pre>
</blockquote>
<h2>
<a name="numerics">Numeric Method Support</a>
</h2>
<p>
Py_cpp supports the following <a href=
"http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/numeric-types.html">
Python special numeric method names</a>:
<p>
<table summary="special numeric methods" cellpadding="5" border="1">
<thead>
<tr>
<td>
Name
<td>
Notes
<tr>
<td>
<code>__add__(self,&nbsp;other)</code>
<td>
<code>operator+(const T&amp;,&nbsp;const T&amp;)</code>
<tr>
<td>
<code>__sub__(self,&nbsp;other)</code>
<td>
<code>operator-(const T&amp;,&nbsp;const T&amp;)</code>
<tr>
<td>
<code>__mul__(self,&nbsp;other)</code>
<td>
<code>operator*(const T&amp;,&nbsp;const T&amp;)</code>
<tr>
<td>
<code>__div__(self,&nbsp;other)</code>
<td>
<code>operator/(const T&amp;,&nbsp;const T&amp;)</code>
<tr>
<td>
<code>__mod__(self,&nbsp;other)</code>
<td>
<code>operator%(const T&amp;,&nbsp;const T&amp;)</code>
<tr>
<td>
<code>__divmod__(self,&nbsp;other)</code>
<td>
return a <code> py::Tuple</code> initialized with <code>
(</code><em>quotient</em><code>,</code> <em>
remainder</em><code>)</code>.
<tr>
<td>
<code>__pow__(self,&nbsp;other&nbsp;[,&nbsp;modulo])</code>
<td>
use <a href="overloading.html">overloading</a> to support both
forms of __pow__
<tr>
<td>
<code>__lshift__(self,&nbsp;other)</code>
<td>
<code>operator&lt;&lt;(const T&amp;,&nbsp;const T&amp;)</code>
<tr>
<td>
<code>__rshift__(self,&nbsp;other)</code>
<td>
<code>operator&gt;&gt;(const T&amp;,&nbsp;const T&amp;)</code>
<tr>
<td>
<code>__and__(self,&nbsp;other)</code>
<td>
<code>operator&amp;(const T&amp;,&nbsp;const T&amp;)</code>
<tr>
<td>
<code>__xor__(self,&nbsp;other)</code>
<td>
<code>operator^(const T&amp;,&nbsp;const T&amp;)</code>
<tr>
<td>
<code>__or__(self,&nbsp;other)</code>
<td>
<code>operator|(const T&amp;,&nbsp;const T&amp;)</code>
<tr>
<td>
<code>__neg__(self)</code>
<td>
<code>operator-(const T&amp;)</code> (unary negation)
<tr>
<td>
<code>__pos__(self)</code>
<td>
<code>operator+(const T&amp;)</code> (identity)
<tr>
<td>
<code>__abs__(self)</code>
<td>
Called to implement the built-in function abs()
<tr>
<td>
<code>__invert__(self)</code>
<td>
<code>operator~(const T&amp;)</code>
<tr>
<td>
<code>__int__(self)</code>
<td>
<code>operator long() const</code>
<tr>
<td>
<code>__long__(self)</code>
<td>
Should return a Python <code>long</code> object. Can be
implemented with <code>PyLong_FromLong(<em>value</em>)</code>,
for example.
<tr>
<td>
<code>__float__(self)</code>
<td>
<code>operator double() const</code>
<tr>
<td>
<code>__oct__(self)</code>
<td>
Called to implement the built-in function oct(). Should return a
string value.
<tr>
<td>
<code>__hex__(self)</code>
<td>
Called to implement the built-in function hex(). Should return a
string value.
<tr>
<td>
<code>__coerce__(self,&nbsp;other)</code>
<td>
Should return a Python 2-<em>tuple</em> (C++ code may return a
<code>py::Tuple</code>) where the elements represent the values
of <code> self</code> and <code>other</code> converted to the
same type.
</table>
<h2><a name="reasons">Where are the <code>__r</code><i>&lt;name&gt;</i><code>__</code>
functions?</a></h2>
<p>
At first we thought that supporting <code>__radd__</code> and its ilk would be
impossible, since Python doesn't supply any direct support and in fact
implements a special case for its built-in class instances. <a
href="http://starship.python.net/crew/arcege/extwriting/pyextnum.html">This
article</a> gives a pretty good overview of the direct support for numerics
that Python supplies for extension types. We've since discovered that it can
be done, but there are some pretty convincing <a
href="http://starship.python.net/crew/lemburg/CoercionProposal.html">arguments</a>
out there that this arrangement is less-than-ideal. Instead of supplying a
sub-optimal solution for the sake of compatibility with built-in Python
classes, we're doing the neccessary research so we can "do it right". This
will also give us a little time to hear from users about what they want. The
direction we're headed in is based on the idea of <a
href="http://www.sff.net/people/neelk/open-source/Multimethod.py">multimethods</a>
rather than on trying to find a coercion function bound to one of the
arguments.
<h3>And what about <code>__complex__</code>?</h3>
<p>That, dear reader, is one problem we don't know how to solve. The Python
source contains the following fragment, indicating the special-case code really
is hardwired:
<blockquote>
<pre>
/* XXX Hack to support classes with __complex__ method */
if (PyInstance_Check(r)) { ...
</pre>
</blockquote>
<p>
Previous: <a href="inheritance.html">Inheritance</a> Next: <a
href="under-the-hood.html">A Peek Under the Hood</a> Up: <a href=
"py_cpp.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided "as is" without
express or implied warranty, and with no claim as to its suitability
for any purpose.
<p>
Updated: Oct 19, 2000
</div>

View File

@@ -1,520 +0,0 @@
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
#ifndef SUBCLASS_DWA051500_H_
# define SUBCLASS_DWA051500_H_
# include "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.
class Instance : public PythonObject
{
public:
Instance(PyTypeObject* class_);
~Instance();
// Standard Python functions.
PyObject* repr();
int compare(PyObject*);
PyObject* str();
long hash();
PyObject* call(PyObject* args, PyObject* keywords);
PyObject* getattr(const char* name, bool use_special_function = true);
int setattr(const char* name, PyObject* value);
// Mapping methods
int length();
PyObject* get_subscript(PyObject* key);
void set_subscript(PyObject* key, PyObject* value);
// Sequence methods
PyObject* get_slice(int start, int finish);
void set_slice(int start, int finish, PyObject* value);
// Number methods
PyObject* add(PyObject* other);
PyObject* subtract(PyObject* other);
PyObject* multiply(PyObject* other);
PyObject* divide(PyObject* other);
PyObject* remainder(PyObject* other);
PyObject* divmod(PyObject* other);
PyObject* power(PyObject*, PyObject*);
PyObject* negative();
PyObject* positive();
PyObject* absolute();
int nonzero();
PyObject* invert();
PyObject* lshift(PyObject* other);
PyObject* rshift(PyObject* other);
PyObject* do_and(PyObject* other);
PyObject* do_xor(PyObject* other);
PyObject* do_or(PyObject* other);
int coerce(PyObject**, PyObject**);
PyObject* as_int();
PyObject* as_long();
PyObject* as_float();
PyObject* oct();
PyObject* hex();
private: // noncopyable, without the size bloat
Instance(const Instance&);
void operator=(const Instance&);
private: // helper functions
int setattr_dict(PyObject* value);
private:
Dict m_name_space;
};
template <class T> class MetaClass;
namespace detail {
class ClassBase : public py::TypeObjectBase
{
public:
ClassBase(PyTypeObject* 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) const;
int setattr(const char* name, PyObject* value);
PyObject* repr() const;
void add_base(Ptr base);
protected:
bool initialize_instance(Instance* instance, PyObject* args, PyObject* keywords);
private: // virtual functions
// Subclasses should override this to delete the particular instance type
virtual void delete_instance(PyObject*) const = 0;
private: // py::TypeObjectBase required interface implementation
void instance_dealloc(PyObject*) const; // subclasses should not override this
private:
String m_name;
Tuple m_bases;
Dict m_name_space;
};
void enable_named_method(ClassBase* type_object, const char* name);
}
// 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 py::detail::ClassBase
{
public:
Class(MetaClass<T>* meta_class, String name, Tuple bases, const Dict& name_space);
// Standard Python functions.
PyObject* call(PyObject* args, PyObject* keywords);
private: // Implement mapping methods on instances
PyObject* instance_repr(PyObject*) const;
int instance_compare(PyObject*, PyObject* other) const;
PyObject* instance_str(PyObject*) const;
long instance_hash(PyObject*) const;
int instance_mapping_length(PyObject*) const;
PyObject* instance_mapping_subscript(PyObject*, PyObject*) const;
int instance_mapping_ass_subscript(PyObject*, PyObject*, PyObject*) const;
private: // Implement sequence methods on instances
int instance_sequence_length(PyObject*) const;
PyObject* instance_sequence_item(PyObject* 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: // Implement number methods on instances
PyObject* instance_number_add(PyObject*, PyObject*) const;
PyObject* instance_number_subtract(PyObject*, PyObject*) const;
PyObject* instance_number_multiply(PyObject*, PyObject*) const;
PyObject* instance_number_divide(PyObject*, PyObject*) const;
PyObject* instance_number_remainder(PyObject*, PyObject*) const;
PyObject* instance_number_divmod(PyObject*, PyObject*) const;
PyObject* instance_number_power(PyObject*, PyObject*, PyObject*) const;
PyObject* instance_number_negative(PyObject*) const;
PyObject* instance_number_positive(PyObject*) const;
PyObject* instance_number_absolute(PyObject*) const;
int instance_number_nonzero(PyObject*) const;
PyObject* instance_number_invert(PyObject*) const;
PyObject* instance_number_lshift(PyObject*, PyObject*) const;
PyObject* instance_number_rshift(PyObject*, PyObject*) const;
PyObject* instance_number_and(PyObject*, PyObject*) const;
PyObject* instance_number_xor(PyObject*, PyObject*) const;
PyObject* instance_number_or(PyObject*, PyObject*) const;
int instance_number_coerce(PyObject*, PyObject**, PyObject**) const;
PyObject* instance_number_int(PyObject*) const;
PyObject* instance_number_long(PyObject*) const;
PyObject* instance_number_float(PyObject*) const;
PyObject* instance_number_oct(PyObject*) const;
PyObject* instance_number_hex(PyObject*) const;
private: // Miscellaneous "special" methods
PyObject* instance_call(PyObject* instance, PyObject* args, PyObject* keywords) const;
PyObject* instance_getattr(PyObject* instance, const char* name) const;
int instance_setattr(PyObject* instance, const char* name, PyObject* value) const;
private: // Implementation of py::detail::ClassBase required interface
void delete_instance(PyObject*) const;
private: // noncopyable, without the size bloat
Class(const Class<T>&);
void operator=(const Class&);
};
// The type of a Class<T> object.
template <class T>
class MetaClass
: public Reprable<Callable<Getattrable<Setattrable<TypeObject<Class<T> > > > > >,
boost::noncopyable
{
public:
MetaClass();
// Standard Python functions.
PyObject* call(PyObject* args, PyObject* keywords);
struct TypeObject
: Singleton<TypeObject, Callable<py::TypeObject<MetaClass> > >
{
TypeObject() : SingletonBase(&PyType_Type) {}
};
};
//
// 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)
: py::detail::ClassBase(meta_class, name, bases, name_space)
{
}
template <class T>
void Class<T>::delete_instance(PyObject* instance) const
{
delete Downcast<T>(instance);
}
template <class T>
PyObject* Class<T>::call(PyObject* args, PyObject* keywords)
{
PyPtr<T> result(new T(this));
if (!this->initialize_instance(result.get(), args, keywords))
return 0;
else
return result.release();
}
template <class T>
PyObject* Class<T>::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>
PyObject* Class<T>::instance_getattr(PyObject* instance, const char* name) const
{
return Downcast<T>(instance)->getattr(name);
}
template <class T>
int Class<T>::instance_setattr(PyObject* instance, const char* name, PyObject* value) const
{
return Downcast<T>(instance)->setattr(name, value);
}
template <class T>
PyObject* Class<T>::instance_number_add(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->add(other);
}
template <class T>
PyObject* Class<T>::instance_number_subtract(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->subtract(other);
}
template <class T>
PyObject* Class<T>::instance_number_multiply(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->multiply(other);
}
template <class T>
PyObject* Class<T>::instance_number_divide(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->divide(other);
}
template <class T>
PyObject* Class<T>::instance_number_remainder(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->remainder(other);
}
template <class T>
PyObject* Class<T>::instance_number_divmod(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->divmod(other);
}
template <class T>
PyObject* Class<T>::instance_number_power(PyObject* instance, PyObject* exponent, PyObject* modulus) const
{
return Downcast<T>(instance)->power(exponent, modulus);
}
template <class T>
PyObject* Class<T>::instance_number_negative(PyObject* instance) const
{
return Downcast<T>(instance)->negative();
}
template <class T>
PyObject* Class<T>::instance_number_positive(PyObject* instance) const
{
return Downcast<T>(instance)->positive();
}
template <class T>
PyObject* Class<T>::instance_number_absolute(PyObject* instance) const
{
return Downcast<T>(instance)->absolute();
}
template <class T>
int Class<T>::instance_number_nonzero(PyObject* instance) const
{
return Downcast<T>(instance)->nonzero();
}
template <class T>
PyObject* Class<T>::instance_number_invert(PyObject* instance) const
{
return Downcast<T>(instance)->invert();
}
template <class T>
PyObject* Class<T>::instance_number_lshift(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->lshift(other);
}
template <class T>
PyObject* Class<T>::instance_number_rshift(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->rshift(other);
}
template <class T>
PyObject* Class<T>::instance_number_and(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->do_and(other);
}
template <class T>
PyObject* Class<T>::instance_number_xor(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->do_xor(other);
}
template <class T>
PyObject* Class<T>::instance_number_or(PyObject* instance, PyObject* other) const
{
return Downcast<T>(instance)->do_or(other);
}
template <class T>
int Class<T>::instance_number_coerce(PyObject* instance, PyObject** x, PyObject** y) const
{
return Downcast<T>(instance)->coerce(x, y);
}
template <class T>
PyObject* Class<T>::instance_number_int(PyObject* instance) const
{
return Downcast<T>(instance)->as_int();
}
template <class T>
PyObject* Class<T>::instance_number_long(PyObject* instance) const
{
return Downcast<T>(instance)->as_long();
}
template <class T>
PyObject* Class<T>::instance_number_float(PyObject* instance) const
{
return Downcast<T>(instance)->as_float();
}
template <class T>
PyObject* Class<T>::instance_number_oct(PyObject* instance) const
{
return Downcast<T>(instance)->oct();
}
template <class T>
PyObject* Class<T>::instance_number_hex(PyObject* instance) const
{
return Downcast<T>(instance)->hex();
}
namespace detail {
inline Dict& ClassBase::dict()
{
return m_name_space;
}
inline Tuple ClassBase::bases() const
{
return m_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();
inline String ClassBase::name() const
{
return m_name;
}
}
} // namespace py
#endif

View File

@@ -1,50 +0,0 @@
r'''
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
That's it! If we build this shared library and put it on our PYTHONPATH we can
now access our C++ class and function from Python.
>>> import hello
>>> hi_world = hello.world(3)
>>> hi_world.get()
'hi, world'
>>> hello.length(hi_world)
9
We can even make a subclass of hello.world:
>>> class my_subclass(hello.world):
... def get(self):
... return 'hello, world'
...
>>> y = my_subclass(2)
>>> y.get()
'hello, world'
Pretty cool! You can't do that with an ordinary Python extension type!
>>> hello.length(y)
9
Of course, you may now have a slightly empty feeling in the pit of your little
pythonic stomach. Perhaps you feel your subclass deserves to have a length() of
12? If so, read on...
'''
from hello import *
def run(args = None):
if args is not None:
import sys
sys.argv = args
import doctest, test_example1
doctest.testmod(test_example1)
if __name__ == '__main__':
run()

File diff suppressed because it is too large Load Diff

425
todo.txt
View File

@@ -1,425 +0,0 @@
Check for const reference parameters in all from_python functions in py.h, including implementations.
Better python and C++ exception handling/error reporting.
long long support
use Python generic numeric coercion in from_python() for C++ numeric types
Rename PyPtr to Reference.
Report Cygwin linker memory issues
pickling support
__init__ stuff
Make abstract classes non-instantiable (?)
Call default __init__ functions automatically where applicable (?)
Support for Python LONG types in Objects.h
Throw TypeError after asserting when objects from objects.cpp detect a type mismatch.
Add callback-through-function ability to callback.h
Figure out how to package everything as a shared library.
Unicode string support
Add read-only wrapper for __dict__ attribute
More template member functions for the elements of objects.h
Testing
Python 2.0
object revival in __del__
More thorough tests of objects.h/cpp classes
Optimizations
Reference-counting for UniquePodSet?
Remove one level of indirection on type objects (no vtbl?).
Specializations of Caller<> for commmon combinations of argument types (?)
Collect common code into a nice shared library.
Documentation:
differences between Python classes and ExtensionClasses
additional capabilities of ExtensionClasses
slice adjustment
Why special attributes other than __doc__ and __name__ are immutable.
An example of the problems with the built-in Python classes.
>>> class A:
... def __getattr__(self, name):
... return 'A.__getattr__'
...
>>> class B(A): pass
...
>>> class C(B): pass
...
>>> C().x
'A.__getattr__'
>>> B.__bases__ = ()
>>> C().x
'A.__getattr__'
Smart pointers
#ifndef PY_NO_INLINE_FRIENDS_IN_NAMESPACE
namespace py {
#endif
template <class T>
struct VtkConverters
{
typedef py::PyExtensionClassConverters<T> Converters;
friend vtk_ptr<T>& from_python(PyObject* p, py::Type<vtk_ptr<T>&>)
{ return Converters::ptr_from_python(p, py::Type<vtk_ptr<T> >()); }
friend vtk_ptr<T>& from_python(PyObject* p, py::Type<vtk_ptr<T> >)
{ return Converters::ptr_from_python(p, py::Type<vtk_ptr<T> >()); }
friend const vtk_ptr<T>& from_python(PyObject* p, py::Type<const vtk_ptr<T>&>)
{ return Converters::ptr_from_python(p, py::Type<vtk_ptr<T> >()); }
friend PyObject* to_python(vtk_ptr<T> x)
{ return Converters::ptr_to_python(x); }
};
#ifndef PY_NO_INLINE_FRIENDS_IN_NAMESPACE
}
#endif
template <class T>
struct VtkWrapper : py::ClassWrapper<T>, py::VtkConverters<T>
{
typedef py::ClassWrapper<T> Base;
VtkWrapper(Module& module, const char* name)
: Base(module, name) {}
};
exception handling
Advanced Topics:
Advanced Type Conversion
adding conversions for fundamental types
generic conversions for template types (with partial spec).
Interacting with built-in Python objects and types from C++
dealing with non-const reference/pointer parameters
extending multiple-argument support using gen_all.py
Fancy wrapping tricks
templates
Yes. If you look at the examples in extclass_demo.cpp you'll see that I have
exposed several template instantiations (e.g. std::pair<int,int>) in Python.
Keep in mind, however, that you can only expose a template instantiation,
not a template. In other words, MyTemplate<Foo> can be exposed. MyTemplate
itself cannot.
Well, that's not strictly true. Wow, this is more complicated to explain
than I thought.
You can't make an ExtensionClass<MyTemplate>, since after all MyTemplate is
not a type. You can only expose a concrete type to Python.
What you *can* do (if your compiler supports partial ordering of function
templates - MSVC is broken and does not) is to write appropriate
from_python() and to_python() functions for converting a whole class of
template instantiations to/from Python. That won't let you create an
instance of MyTemplate<SomePythonType> from Python, but it will let you
pass/return arbitrary MyTemplate<SomeCplusplusType> instances to/from your
wrapped C++ functions.
template <class T>
MyTemplate<T> from_python(PyObject* x, py::Type<MyTemplate<T> >)
{
// code to convert x into a MyTemplate<T>... that part is up to you
}
template <class T>
PyObject* from_python(const MyTemplate<T>&)
{
// code to convert MyTemplate<T> into a PyObject*... that part is up to
you
}
For example, you could use this to convert Python lists to/from
std::vector<T> automatically.
Pointer return values
Case 1:
> I am now also able to wrap the problematic TextRecordIterator for Python.
> However, one of its function compiles with this warning:
>
> d:\py_cpp/caller.h(33) : warning C4800: 'const class Record *const '
> : forcing value to bool 'true' or 'false' (performance warning)
> d:\py_cpp/functions.h(54) : see reference to function template
> instantiation 'struct _object *__cdecl py::Caller::call(const class Record
> *const (__thiscall TextRecordIterator::*)(void),struct _object *,struct
> _object *)' being compiled
>
> If you look at the offending code, you'll see that we really do need to
> get back that pointer:
>
> const Record* const TextRecordIterator::Next() {
> if (fStatus != RecordIterator::SUCCESS) {
> return 0;
> } else {
> return &fData;
> }
> }
>
> The point of the TextRecordIterator is to hand over one reord after
> another. A bool wouldn't do us much good here :-)
>
> Do you have any suggestions for fixing this?
In general, py_cpp doesn't automatically convert pointer return values
to_python because pointers have too many potential meanings. Is it an
iterator? A pointer to a single element? An array? Is ownership being passed
to Python or is the pointer really just a reference? If the latter, what
happens when some C++ code deletes the referent. The only exception to this
rule is const char*, since it has a generally accepted interpretation (could
be trouble with some generic code, though!)
If you have wrapped the Record class, you could add this to namespace py:
PyObject* to_python(const Record* p) {
return to_python(*p);
}
Of course, this will cause the Record class to be copied. If you can't live
with that (Record would have to be /really/ heavyweight to make this
worthwhile), you can follow one of these dangerous approaches:
1. Use the technique I described with dangerous_array in
http://www.egroups.com/message/boost/6196. You do not have to expose Record
explicitly in this case. Instead the class you expose will be more of a
Record_proxy
2. Wrap Record in the usual way, then add the following to namespace py:
PyObject* to_python(const Record* p)
{
return ExtensionClass<Record>::ptr_to_python(const_cast<Record*>(p));
}
This will cause the Record* to be treated as though it were an owning smart
pointer, even though it's not. Be sure you don't use the reference for
anything from Python once the pointer becomes invalid, though. Don't worry
too much about the const-correctness issue: Const-correctness is completely
lost to Python anyway!
3. As above, but instead wrap const Record rather than plain Record. Then
you can avoid the const_cast, but you obviously can't def() any non-const
member functions of Record.
Case 2:
> I have yet another question. This is more a general wrapper question.
> Let me say that there is a function that returns a float* which most
> probably is an array. Similarly if I have a function that takes a
> float* as an argument, what is the best way of wrapping this?
I think you have correctly perceived that it doesn't make sense for me to
automatically convert all pointers, since the ownership semantics are so
blurry.
> 1) If the array is small it makes sense to convert it to either a
> tuple or list. What is the easiest way to do this?? I am looking
> for a way that makes one write the least code. :)
How can you tell the length of the array from a single pointer?
Once you've answered that question, you can expose a wrapper function which
returns an instance of the py::Tuple or py::List class from objects.h. If
you are using a List, for example, you could write something like this:
py::List wrap_f()
{
T* start = f();
py::List x;
for (T* p = start; p != start + length_constant; ++p)
x.push_back(py::to_python(*p));
return x;
}
> 2) If the array is large it may not make sense to use a list/tuple
> esp. if the values are used for computationally intense programs.
In this case you can do one of several somewhat dangerous things. Why
dangerous? Because python can not control the lifetime of the data, so the
data in the array may be destroyed or become invalid before the last
reference to it disappears. The basic approach is to make a small C++ class
which contains the pointer, and expose that:
// UNTESTED
template <class T>
struct dangerous_array
{
dangerous_array(T* start, T* end)
: m_start(start), m_end(end) {}
// exposed as "__len__"
std::size_t length() {
return m_end - m_start;
}
// exposed as "__getitem__"
T get_item(std::size_t n) {
check_range(n);
return start[n];
}
// exposed as "__setitem__" if the array is mutable
void set_item(std::size_t n, const T& x) {
check_range(n);
start[n] = x;
}
private:
void check_range(std::size_t n) {
if (n >= m_end - m_start) {
PyErr_SetString(PyExc_IndexError, "array index out of range");
throw py::ErrorAlreadySet;
}
}
T* m_start;
T* m_end;
};
A reasonably safe approach would be to make a wrapper function for each
function that returns a T*, and expose that instead. If you're too lazy and
you really like to live on the edge, though, you can write to_python(T*) in
terms of to_python(const dangerous_array<T>&), and you'll automatically
convert all T* return values to a wrapped dangerous_array.
> 3) For an arbitrary class "class_A", say, can py_cpp handle
> references to class_A &instance, or class_A *instance?? i.e. will it
> wrap function calls to such objects? This question is obviously
> related to the earlier questions.
Yes, iff class_A has been exposed to python with a ClassWrapper<class_A>.
See http://people.ne.mediaone.net/abrahams/downloads/under-the-hood.html for
a few details.
raw C++ arrays
You could expose a function like this one to get the desired effect:
#include <py_cpp/objects.h>
void set_len(UnitCell& x, py::Tuple tuple)
{
double len[3];
for (std::size_t i =0; i < 3; ++i)
len[i] = py::from_python(tuple[i].get(), py::Type<double>());
x.set_len(len);
}
Types that are already wrapped by other libraries
It's not documented yet, but you should be able to use a raw PyObject* or a
py::Ptr as one parameter to your C++ function. Then you can manipulate it as
any other generic Python object.
Alternatively, If the NTL gives you a C/C++ interface, you can also write
your own converter function:
some_ntl_type& from_python(PyObject* p, py::Type<some_NTL_type&>)
{
// an Example implementation. Basically, you need
// to extract the NTL type from the PyObject*.
if (p->ob_type != NTL_long_type) {
PyErr_SetString(PyExc_TypeErr, "NTL long required");
throw py::ArgumentError();
}
return *static_cast<some_NTL_type*>(p);
}
then the C++ functions you're wrapping can take a some_NTL_type& parameter
directly.
"Thin converting wrappers" for constructors
hijack some of the functionality
described in the section on Overridable Virtual Functions (even though you
don't have any virtual functions). I suggest this workaround:
struct UnitCellWrapper : UnitCell
{
UnitCellWrapper(PyObject* self, py::Tuple x, py::Tuple y)
: UnitCell(from_python(x[1], py::Type<double>()),
from_python(x[2], py::Type<double>()),
from_python(x[3], py::Type<double>()),
from_python(y[1], py::Type<double>()),
from_python(y[2], py::Type<double>()),
from_python(y[3], py::Type<double>()))
{}
}
py::ClassWrapper<UnitCell, UnitCellWrapper> unit_cell_class;
unit_cell_class.def(py::Constructor<py::Tuple, py::Tuple>());
...
returning references to wrapped objects
the importance of declaration order of ClassWrappers/ExtensionInstances
out parameters and non-const pointers
Calling back into Python:
// caveat: UNTESTED!
#include <py_cpp/pyptr.h>
#include <py_cpp/callback.h>
#include <py_cpp/py.h>
#include <Python.h>
int main()
{
try {
py::Ptr module(PyImport_ImportModule("weapons"));
const int strength = 10;
const char* manufacturer = "Vordon Empire";
py::Ptr a_blaster(py::Callback<py::Ptr>::call_method(
module.get(), "Blaster", strength, manufacturer));
py::Callback<void>::call_method(a_blaster.get(), "Fire");
int old_strength = py::Callback<int>::call_method(a_blaster.get(), "get_strength");
py::Callback<void>::call_method(a_blaster.get(), "set_strength", 5);
}
catch(...)
{
}
}
Miscellaneous
About the vc6 project and the debug build
About doctest.py
Boost remarks:
> > One of us is completely nuts ;->. How can I move the test
> > (is_prefix(enablers[i].name + 2, name + 2)) outside the loop if it
depends
> > on the loop index, i?
> >
> name += 2;
> for()
> {
> if (is_prefix(enablers[i].name + 2, name))
> }
I see now. I guess I should stop pussyfooting and either go for optimization
or clarity here, eh?
------
> Re: Dict
> Why abbreviate this? Code is read 5 or 6 times for every time its
> written. The few extra characters don't affect compile time or program
> speed. It's part of my personal goal of write what you mean, name them
what
> they are.
I completely agree. Abbrevs rub me the wrong way, 2 ;->
-------
Later:
keyword and varargs?
Put explicit Type<> arguments at the beginnings of overloads, to make them look more like template instance specifications.
Known bugs
can't handle 'const void' return values
Who returns 'const void'? I did it once, by mistake ;)

View File

@@ -1,51 +0,0 @@
#
# Tested with:
# Compaq C++ V6.2-024 for Digital UNIX V5.0 (Rev. 910)
#
# Python 1.5.2 was installed without any customizations.
# boost_all.zip vers. 1.18.1 was unpacked using unzip -aa and not modified.
# STLport-4.1b3 was unpacked using unzip -aa and not modified.
#
# Initial version 2000-10-20: Ralf W. Grosse-Kunstleve, rwgk@cci.lbl.gov
#
PYINC= /usr/local/include/python1.5
BOOSTINC= /usr/local/boost_1_18_1
STLPORTINC= /usr/local/STLport-4.1b3/stlport
STLPORTOPTS= \
-D__USE_STD_IOSTREAM \
-D__STL_NO_SGI_IOSTREAMS \
-D__STL_NO_NEW_C_HEADERS \
-D_RWSTD_COMPILE_INSTANTIATE=1
STDOPTS= -std strict_ansi
WARNOPTS= -msg_disable 186,450,1115
# use -msg_display_number to obtain integer tags for -msg_disable
CPP= cxx
CPPOPTS= -I$(STLPORTINC) $(STLPORTOPTS) -I$(BOOSTINC) -I$(PYINC) \
$(STDOPTS) $(WARNOPTS)
LD= cxx
LDOPTS= -shared -expect_unresolved '*'
OBJ = extclass.o functions.o init_function.o module.o newtypes.o \
objects.o py.o subclass.o
.SUFFIXES: .o .cpp
all: demo.so hello.so
demo.so: $(OBJ) extclass_demo.o
$(LD) $(LDOPTS) $(OBJ) extclass_demo.o -o demo.so
hello.so: $(OBJ) example1.o
$(LD) $(LDOPTS) $(OBJ) example1.o -o hello.so
.cpp.o:
-$(CPP) $(CPPOPTS) $(INC) -c $*.cpp
clean:
rm -f $(OBJ) extclass_demo.o example1.o demo.so hello.so so_locations
rm -rf cxx_repository
rm -f *.pyc

View File

@@ -1,59 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>
A Peek Under the Hood
</title>
<h1>
<img src="c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center"
width="277" height="86">
</h1>
<h1>
A Peek Under the Hood
</h1>
<p>
<code> ExtensionClass&lt;T&gt;</code> is a subclass of <code>
PyTypeObject</code>, the <code> struct</code> which Python's 'C' API uses
to describe a type. <a href="example1.html#world_class">An instance of
the <code>ExtensionClass&lt;&gt;</code></a> becomes the Python type
object corresponding to <code>hello::world</code>. When we <a href=
"example1.html#add_world_class">add it to the module</a> it goes into the
module's dictionary to be looked up under the name "world".
<p>
Py_cpp uses C++'s template argument deduction mechanism to determine the
types of arguments to functions (except constructors, for which we must
<a href="example1.html#Constructor_example">provide an argument list</a>
because they can't be named in C++). Then, it calls the appropriate
overloaded functions <code>PyObject*
to_python(</code><em>S</em><code>)</code> and <em>
S'</em><code>from_python(PyObject*,
Type&lt;</code><em>S</em><code>&gt;)</code> which convert between any C++
type <em>S</em> and a <code>PyObject*</code>, the type which represents a
reference to any Python object in its 'C' API. The <a href=
"example1.html#world_class"><code>ExtensionClass&lt;T&gt;</code></a>
template defines a whole raft of these conversions (for <code>T, T*,
T&amp;, std::auto_ptr&lt;T&gt;</code>, etc.), using the same inline
friend function technique employed by <a href=
"http://www.boost.org/libs/utility/operators.htm">the boost operators
library</a>.
<p>
Because the <code>to_python</code> and <code>from_python</code> functions
for a user-defined class are defined by <code>
ExtensionClass&lt;T&gt;</code>, it is important that an instantiation of
<code> ExtensionClass&lt;T&gt;</code> is visible to any code which wraps
a C++ function with a <code>T, T*, const T&amp;</code>, etc. parameter or
return value. In particular, you may want to create all of the classes at
the top of your module's init function, then <code>def</code> the member
functions later to avoid problems with inter-class dependencies.
<p>
Previous: <a href="overriding.html">Function Overloading</a>
Next: <a href="building.html">Building a Module with Py_cpp</a>
Up: <a href="py_cpp.html">Top</a>
<p>
&copy; Copyright David Abrahams 2000. Permission to copy, use, modify,
sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided "as is" without
express or implied warranty, and with no claim as to its suitability for
any purpose.
<p>
Updated: Sept 30, 2000

View File

@@ -1,6 +0,0 @@
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'])

View File

@@ -1,6 +0,0 @@
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"])

View File

@@ -1,158 +0,0 @@
# 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 /MD /W3 /GR /GX /Ox /Og /Oi /Os /Op- /Oy /Gy /I "c:\boost" /I "c:\tools\python\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "VC6_PRJ_EXPORTS" /FD /Zm200 /c
# SUBTRACT CPP /Ot
# 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 /MDd /Gm /GR /GX /ZI /Od /Oy- /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 /Zm200 /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /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

View File

@@ -1,29 +0,0 @@
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>
{{{
}}}
###############################################################################

Binary file not shown.

View File

@@ -1,61 +0,0 @@
#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