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:
@@ -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_
|
||||
@@ -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>
|
||||
© 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>
|
||||
|
||||
339
callback.h
339
callback.h
@@ -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
507
caller.h
@@ -1,507 +0,0 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
//
|
||||
// This file 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
79
cast.h
@@ -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_
|
||||
149
class_wrapper.h
149
class_wrapper.h
@@ -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_
|
||||
216
comparisons.html
216
comparisons.html
@@ -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>
|
||||
© 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>
|
||||
|
||||
@@ -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
1112
doctest.py
File diff suppressed because it is too large
Load Diff
708
doxyfile
708
doxyfile
@@ -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 =
|
||||
94
enums.html
94
enums.html
@@ -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<EnumType></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<MyEnumType>)
|
||||
{
|
||||
return static_cast<MyEnum>(
|
||||
from_python(x, py::Type<long>()));
|
||||
}
|
||||
|
||||
MyEnumType from_python(PyObject* x, py::Type<const MyEnumType&>)
|
||||
{
|
||||
return static_cast<MyEnum>(
|
||||
from_python(x, py::Type<long>()));
|
||||
}
|
||||
|
||||
PyObject* to_python(MyEnumType x)
|
||||
{
|
||||
return to_python(static_cast<long>(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>
|
||||
© 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>
|
||||
|
||||
30
errors.h
30
errors.h
@@ -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_
|
||||
54
example1.cpp
54
example1.cpp
@@ -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
|
||||
127
example1.html
127
example1.html
@@ -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& 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 <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
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
That's it! If we build this shared library and put it on our <code>
|
||||
PYTHONPATH</code> we can now access our C++ class and function from
|
||||
Python.
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> import hello
|
||||
>>> hi_world = hello.world(3)
|
||||
>>> hi_world.get()
|
||||
'hi, world'
|
||||
>>> hello.length(hi_world)
|
||||
9
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
We can even make a subclass of <code>hello.world</code>:
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> class my_subclass(hello.world):
|
||||
... def get(self):
|
||||
... return 'hello, world'
|
||||
...
|
||||
>>> y = my_subclass(4)
|
||||
>>> y.get()
|
||||
'hello, world'
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
Pretty cool! You can't do that with an ordinary Python extension type!
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> hello.length(y)
|
||||
9
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
Of course, you may now have a slightly empty feeling in the pit of
|
||||
your little pythonic stomach. Perhaps you feel your subclass deserves
|
||||
to have a <code>length()</code> of <code>12</code>? If so, <a href=
|
||||
"overriding.html">read on</a>...
|
||||
<p>
|
||||
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>
|
||||
© 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>
|
||||
|
||||
661
extclass.cpp
661
extclass.cpp
@@ -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
|
||||
886
extclass.h
886
extclass.h
@@ -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_
|
||||
|
||||
1074
extclass_demo.cpp
1074
extclass_demo.cpp
File diff suppressed because it is too large
Load Diff
231
extclass_demo.h
231
extclass_demo.h
@@ -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_
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
© 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>
|
||||
|
||||
167
functions.cpp
167
functions.cpp
@@ -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;
|
||||
|
||||
}
|
||||
309
functions.h
309
functions.h
@@ -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
48
gcc.mak
@@ -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
|
||||
26
gen_all.py
26
gen_all.py
@@ -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)
|
||||
|
||||
|
||||
103
gen_callback.py
103
gen_callback.py
@@ -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)
|
||||
138
gen_caller.py
138
gen_caller.py
@@ -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)
|
||||
|
||||
|
||||
883
gen_extclass.py
883
gen_extclass.py
@@ -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)
|
||||
184
gen_function.py
184
gen_function.py
@@ -1,184 +0,0 @@
|
||||
import string
|
||||
|
||||
def _find(s, sub, start=0, end=None):
|
||||
"""Just like string.find, except it returns end or len(s) when not found.
|
||||
"""
|
||||
if end == None:
|
||||
end = len(s)
|
||||
|
||||
pos = string.find(s, sub, start, end)
|
||||
if pos < 0:
|
||||
return end
|
||||
else:
|
||||
return pos
|
||||
|
||||
def _gen_common_key(key, n, args):
|
||||
if len(key) > 0 and key in '123456789':
|
||||
return str(args[int(key) - 1])
|
||||
elif key == 'x':
|
||||
return str(n)
|
||||
else:
|
||||
return key
|
||||
|
||||
def _gen_arg(template, n, args, delimiter = '%'):
|
||||
result = ''
|
||||
i = 0
|
||||
while i < len(template): # until the template is consumed
|
||||
# consume everything up to the first delimiter
|
||||
delimiter_pos = _find(template, delimiter, i)
|
||||
result = result + template[i:delimiter_pos]
|
||||
|
||||
# The start position of whatever comes after the delimiter+key
|
||||
start = delimiter_pos + 2
|
||||
key = template[start - 1 : start] # the key character. If there were no
|
||||
# delimiters left, key will be empty
|
||||
|
||||
if key == 'n':
|
||||
result = result + `n`
|
||||
else:
|
||||
result = result + _gen_common_key(key, n, args)
|
||||
|
||||
i = start
|
||||
|
||||
return result
|
||||
|
||||
def gen_function(template, n, *args, **keywords):
|
||||
r"""gen_function(template, n, [args...] ) -> string
|
||||
|
||||
Generate a function declaration based on the given template.
|
||||
|
||||
Sections of the template between '%(', '%)' pairs are repeated n times. If '%:'
|
||||
appears in the middle, it denotes the beginning of a delimiter.
|
||||
|
||||
Sections of the template between '%{', '%}' pairs are ommitted if n == 0.
|
||||
|
||||
%n is transformed into the string representation of 1..n for each repetition
|
||||
of n.
|
||||
|
||||
%x, where x is a digit, is transformed into the corresponding additional
|
||||
argument.
|
||||
|
||||
for example,
|
||||
|
||||
>>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 2, 'void')
|
||||
'void abc(int a1, int a2); // all args are ints'
|
||||
>>> gen_function('%1 abc(%(int a%n%:, %));%{ // all args are ints%}', 0, 'x')
|
||||
'x abc();'
|
||||
|
||||
|
||||
>>> template = ''' template <class T%(, class A%n%)>
|
||||
... static PyObject* call( %1(T::*pmf)(%(A%n%:, %))%2, PyObject* args, PyObject* /* keywords */ ) {
|
||||
... PyObject* self;
|
||||
... %( PyObject* a%n;
|
||||
... %) if (!PyArg_ParseTuple(args, const_cast<char*>("O%(O%)"), &self%(, &a%n%)))
|
||||
... return 0;
|
||||
... T& target = from_python(self, Type<T&>());
|
||||
... %3to_python((target.*pmf)(%(
|
||||
... from_python(a%n, Type<A%n>())%:,%)
|
||||
... ));%4
|
||||
... }'''
|
||||
|
||||
>>> print gen_function(template, 0, 'R ', '', 'return ', '')
|
||||
template <class T>
|
||||
static PyObject* call( R (T::*pmf)(), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("O"), &self))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
return to_python((target.*pmf)(
|
||||
));
|
||||
}
|
||||
|
||||
>>> print gen_function(template, 2, 'R ', '', 'return ', '')
|
||||
template <class T, class A1, class A2>
|
||||
static PyObject* call( R (T::*pmf)(A1, A2), PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOO"), &self, &a1, &a2))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
return to_python((target.*pmf)(
|
||||
from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>())
|
||||
));
|
||||
}
|
||||
|
||||
>>> print gen_function(template, 3, 'void ', ' const', '', '\n'+8*' ' + 'return none();')
|
||||
template <class T, class A1, class A2, class A3>
|
||||
static PyObject* call( void (T::*pmf)(A1, A2, A3) const, PyObject* args, PyObject* /* keywords */ ) {
|
||||
PyObject* self;
|
||||
PyObject* a1;
|
||||
PyObject* a2;
|
||||
PyObject* a3;
|
||||
if (!PyArg_ParseTuple(args, const_cast<char*>("OOOO"), &self, &a1, &a2, &a3))
|
||||
return 0;
|
||||
T& target = from_python(self, Type<T&>());
|
||||
to_python((target.*pmf)(
|
||||
from_python(a1, Type<A1>()),
|
||||
from_python(a2, Type<A2>()),
|
||||
from_python(a3, Type<A3>())
|
||||
));
|
||||
return none();
|
||||
}
|
||||
"""
|
||||
delimiter = keywords.get('delimiter', '%')
|
||||
result = ''
|
||||
i = 0
|
||||
while i < len(template): # until the template is consumed
|
||||
# consume everything up to the first delimiter
|
||||
delimiter_pos = _find(template, delimiter, i)
|
||||
result = result + template[i:delimiter_pos]
|
||||
|
||||
# The start position of whatever comes after the delimiter+key
|
||||
start = delimiter_pos + 2
|
||||
key = template[start - 1 : start] # the key character. If there were no
|
||||
# delimiters left, key will be empty
|
||||
|
||||
pairs = { '(':')', '{':'}' }
|
||||
|
||||
if key in pairs.keys():
|
||||
end = string.find(template, delimiter + pairs[key], start)
|
||||
assert end >= 0, "Matching '" + delimiter + pairs[key] +"' not found!"
|
||||
delimiter_pos = end
|
||||
|
||||
if key == '{':
|
||||
if n > 0:
|
||||
result = result + gen_function(template[start:end], n, args, delimiter)
|
||||
else:
|
||||
separator_pos = _find(template, delimiter + ':', start, end)
|
||||
separator = template[separator_pos+2 : end]
|
||||
|
||||
for x in range(1, n + 1):
|
||||
result = result + _gen_arg(template[start:separator_pos], x, args,
|
||||
delimiter)
|
||||
if x != n:
|
||||
result = result + separator
|
||||
|
||||
else:
|
||||
result = result + _gen_common_key(key, n, args)
|
||||
|
||||
i = delimiter_pos + 2
|
||||
|
||||
return result
|
||||
|
||||
def gen_functions(template, n, *args):
|
||||
r"""gen_functions(template, n, [args...]) -> string
|
||||
|
||||
Call gen_function repeatedly with from 0..n and the given optional
|
||||
arguments.
|
||||
|
||||
>>> print gen_functions('%1 abc(%(int a%n%:, %));%{ // all args are ints%}\n', 2, 'void'),
|
||||
void abc();
|
||||
void abc(int a1); // all args are ints
|
||||
void abc(int a1, int a2); // all args are ints
|
||||
|
||||
"""
|
||||
result = ''
|
||||
for x in range(n + 1):
|
||||
result = result + apply(gen_function, (template, x) + args)
|
||||
return result
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
@@ -1,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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
165
inheritance.html
165
inheritance.html
@@ -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>
|
||||
>>> class MyPythonClass:
|
||||
... def f(): return 'MyPythonClass.f()'
|
||||
...
|
||||
>>> import my_extension_module
|
||||
>>> class Derived(my_extension_module.MyExtensionClass, MyPythonClass):
|
||||
... '''This is an extension class'''
|
||||
... pass
|
||||
...
|
||||
>>> x = Derived()
|
||||
>>> x.f()
|
||||
'MyPythonClass.f()'
|
||||
>>> x.g()
|
||||
'MyExtensionClass.g()'
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h2><a name="implicit_conversion">Reflecting C++ Inheritance Relationships</a></h2>
|
||||
<p>
|
||||
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<></code> is used to establish the relationship
|
||||
between base and derived classes:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
#include <memory> // for std::auto_ptr<>
|
||||
|
||||
struct Base {
|
||||
virtual ~Base() {}
|
||||
virtual const char* name() const { return "Base"; }
|
||||
};
|
||||
|
||||
struct Derived : Base {
|
||||
Derived() : x(-1) {}
|
||||
virtual const char* name() const { return "Derived"; }
|
||||
int x;
|
||||
};
|
||||
|
||||
std::auto_ptr<Base> derived_as_base() {
|
||||
return std::auto_ptr<Base>(new Derived);
|
||||
}
|
||||
|
||||
const char* get_name(const Base& b) {
|
||||
return b.name();
|
||||
}
|
||||
|
||||
int get_derived_x(const Derived& d) {
|
||||
return d.x;
|
||||
}
|
||||
<hr>
|
||||
#include <py_cpp/class_wrapper.h>
|
||||
extern "C"
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
void initmy_module()
|
||||
{
|
||||
try
|
||||
{
|
||||
py::Module my_module("my_module");
|
||||
|
||||
py::ClassWrapper<Base> base_class(my_module, "Base");
|
||||
base_class.def(py::Constructor<void>());
|
||||
|
||||
py::ClassWrapper<Derived> derived_class(my_module, "Derived");
|
||||
derived_class.def(py::Constructor<void>());
|
||||
<b>// Establish the inheritance relationship between Base and Derived
|
||||
derived_class.declare_base(base_class);</b>
|
||||
|
||||
my_module.def(derived_as_base, "derived_as_base");
|
||||
my_module.def(get_name, "get_name");
|
||||
my_module.def(get_derived_x, "get_derived_x");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
py::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
Then, in Python:
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> from my_module import *
|
||||
>>> base = Base()
|
||||
>>> derived = Derived()
|
||||
>>> get_name(base)
|
||||
'Base'
|
||||
</pre><i>objects of wrapped class Derived may be passed where Base is expected</i><pre>
|
||||
>>> get_name(derived)
|
||||
'Derived'
|
||||
</pre><i>objects of wrapped class Derived can be passed where Derived is
|
||||
expected but where type information has been lost.</i><pre>
|
||||
>>> get_derived_x(derived_as_base())
|
||||
-1
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h2>Inheritance Without Virtual Functions</h2>
|
||||
|
||||
<p>
|
||||
If for some reason your base class has no virtual functions but you still want
|
||||
to represent the inheritance relationship between base and derived classes,
|
||||
pass the special symbol <code>py::without_downcast</code> as the 2nd parameter
|
||||
to <code>declare_base</code>:
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
struct Base2 {};
|
||||
struct Derived2 { int f(); };
|
||||
<hr>
|
||||
...
|
||||
py::ClassWrapper<Base> base2_class(my_module, "Base2");
|
||||
base2_class.def(py::Constructor<void>());
|
||||
|
||||
py::ClassWrapper<Derived2> derived2_class(my_module, "Derived2");
|
||||
derived2_class.def(py::Constructor<void>());
|
||||
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>
|
||||
© 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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
288
init_function.h
288
init_function.h
@@ -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_
|
||||
39
module.cpp
39
module.cpp
@@ -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 } };
|
||||
|
||||
}
|
||||
49
module.h
49
module.h
@@ -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
|
||||
@@ -1,2 +0,0 @@
|
||||
#define DEBUG_PYTHON
|
||||
#include "newtypes.cpp"
|
||||
21
none.h
21
none.h
@@ -1,21 +0,0 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#ifndef NONE_DWA_052000_H_
|
||||
# define NONE_DWA_052000_H_
|
||||
|
||||
# include "pyconfig.h"
|
||||
# include "wrap_python.h"
|
||||
|
||||
namespace py {
|
||||
|
||||
inline PyObject* none() { Py_INCREF(Py_None); return Py_None; }
|
||||
|
||||
}
|
||||
|
||||
#endif // NONE_DWA_052000_H_
|
||||
485
objects.cpp
485
objects.cpp
@@ -1,485 +0,0 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
// TODO: Move inline implementations from objects.cpp here
|
||||
|
||||
#include "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
334
objects.h
@@ -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_
|
||||
436
operators.h
436
operators.h
@@ -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_ */
|
||||
149
overloading.html
149
overloading.html
@@ -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<X> x_class(overload_demo, "X");
|
||||
// Overloaded constructors
|
||||
x_class.def(py::Constructor<>());
|
||||
x_class.def(py::Constructor<int>());
|
||||
|
||||
// Overloaded member functions
|
||||
x_class.def((int (X::*)() const)&X::value, "value");
|
||||
x_class.def((void (X::*)(int))&X::value, "value");
|
||||
...
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
Now in Python:
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> from overload_demo import *
|
||||
>>> x0 = X()
|
||||
>>> x1 = X(1)
|
||||
>>> x0.value()
|
||||
0
|
||||
>>> x1.value()
|
||||
1
|
||||
>>> x0.value(3)
|
||||
>>> x0.value()
|
||||
3
|
||||
>>> X('hello')
|
||||
TypeError: No overloaded functions match (X, string). Candidates are:
|
||||
void (*)()
|
||||
void (*)(int)
|
||||
>>> f()
|
||||
3
|
||||
>>> f(4)
|
||||
5
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<h2>Discussion</h2>
|
||||
<p>
|
||||
Notice that overloading in the Python module was produced three ways:<ol>
|
||||
<li>by combining the non-overloaded C++ functions <code>int f1()</code>
|
||||
and <code>int f2(int)</code> and exposing them as <code>f</code> in Python.
|
||||
<li>by exposing the overloaded constructors of <code>class X</code>
|
||||
<li>by exposing the overloaded member functions <code>X::value</code>.
|
||||
</ol>
|
||||
<p>
|
||||
Techniques 1. and 3. above are really alternatives. In case 3, you need
|
||||
to form a pointer to each of the overloaded functions. The casting
|
||||
syntax shown above is one way to do that in C++. Case 1 does not require
|
||||
complicated-looking casts, but may not be viable if you can't change
|
||||
your C++ interface. N.B. There's really nothing unsafe about casting an
|
||||
overloaded (member) function address this way: the compiler won't let
|
||||
you write it at all unless you get it right.
|
||||
|
||||
<h2>An Alternative to Casting</h2>
|
||||
<p>
|
||||
This approach is not neccessarily better, but may be preferable for some
|
||||
people who have trouble writing out the types of (member) function
|
||||
pointers or simply prefer to avoid all casts as a matter of principle:
|
||||
<blockquote>
|
||||
<pre>
|
||||
// Forwarding functions for X::value
|
||||
inline void set_x_value(X& self, int v) { self.value(v); }
|
||||
inline int get_x_value(X& self) { return self.value(); }
|
||||
...
|
||||
// Overloaded member functions
|
||||
x_class.def(set_x_value, "value");
|
||||
x_class.def(get_x_value, "value");
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>Here we are taking advantage of the ability to expose C++ functions at
|
||||
namespace scope as Python member functions.
|
||||
|
||||
<h2>Overload Resolution</h2>
|
||||
<p>
|
||||
The function overload resolution mechanism 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>
|
||||
© 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>
|
||||
|
||||
194
overriding.html
194
overriding.html
@@ -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<<i>return-type</i>>::call_method()</code> to call the
|
||||
Python override.
|
||||
|
||||
<li><a name="derived_4">For</a> each non-pure virtual function meant to be overridable from Python, a
|
||||
static member function (or a free function) taking a reference or pointer to the
|
||||
base type as the first parameter and which forwards any additional parameters
|
||||
neccessary to the <i>default</i> implementation of the virtual function. See also
|
||||
<a href="#private">this note</a> if the base class virtual function is private.
|
||||
|
||||
</ol>
|
||||
|
||||
<blockquote><pre>
|
||||
struct world_callback : world
|
||||
{
|
||||
world_callback(PyObject* self, int x) // <a href="#derived_2">2</a>
|
||||
: world(x),
|
||||
m_self(self) {}
|
||||
|
||||
const char* get() const // <a href="#derived_3">3</a>
|
||||
{ return py::Callback<const char*>::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<></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<hello::world<strong>,world_callback></strong> world_class(hello, "world");
|
||||
// Add a virtual member function
|
||||
world_class.def(&world::get, "get", &<b>world_callback::default_get</b>);
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
Now our subclass of <code>hello.world</code> behaves as expected:
|
||||
|
||||
<blockquote><pre>
|
||||
>>> class my_subclass(hello.world):
|
||||
... def get(self):
|
||||
... return 'hello, world'
|
||||
...
|
||||
>>> hello.length(my_subclass())
|
||||
12
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
<a name="why_derived">*</a>You may ask, "Why do we need this derived
|
||||
class? This could have been designed so that everything gets done right
|
||||
inside of <code>hello::world</code>." One of the goals of py_cpp is to be
|
||||
minimally intrusive on an existing C++ design. In principle, it should be
|
||||
possible to expose the interface for a 3rd party library without changing
|
||||
it. To unintrusively hook into the virtual functions so that a Python
|
||||
override may be called, we must use a derived class.
|
||||
|
||||
<h2>Pure Virtual Functions</h2>
|
||||
|
||||
<p>
|
||||
A pure virtual function with no implementation is actually a lot easier
|
||||
to deal with than a virtual function with a default implementation. First
|
||||
of all, you obviously don't need to <a href="#default_implementation">
|
||||
supply a default implementation</a>. Secondly, you don't need to call
|
||||
<code>def()</code> on the <code>ExtensionClass<></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<int>::call_method(m_self, "pure", x); }
|
||||
};
|
||||
|
||||
extern "C"
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
initfoobar()
|
||||
{
|
||||
try
|
||||
{
|
||||
py::Module foobar("foobar");
|
||||
py::ClassWrapper<baz,baz_callback> baz_class("baz");
|
||||
baz_class.def(&baz::pure, "pure");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
py::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
Now in Python:
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> from foobar import baz
|
||||
>>> x = baz()
|
||||
>>> x.pure(1)
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
AttributeError: pure
|
||||
>>> class mumble(baz):
|
||||
... def pure(self, x): return x + 1
|
||||
...
|
||||
>>> y = mumble()
|
||||
>>> y.pure(99)
|
||||
100
|
||||
</pre></blockquote>
|
||||
|
||||
<a name="private"><h2>Private Non-Pure Virtual Functions</h2></a>
|
||||
|
||||
<p>This is one area where some minor intrusiveness on the wrapped library is
|
||||
required. Once it has been overridden, the only way to call the base class
|
||||
implementation of a private virtual function is to make the derived class a
|
||||
friend of the base class. You didn't hear it from me, but most C++
|
||||
implementations will allow you to change the declaration of the base class in
|
||||
this limited way without breaking binary compatibility (though it will certainly
|
||||
break the <a
|
||||
href="http://cs.calvin.edu/c++/C++Standard-Nov97/basic.html#basic.def.odr">ODR</a>).
|
||||
|
||||
<p>
|
||||
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>
|
||||
© 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
|
||||
|
||||
143
pointers.html
143
pointers.html
@@ -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
|
||||
"find a way to avoid the problem." For example, if you have just one
|
||||
or two functions returning a pointer to a single (not an array of) <code>const
|
||||
T*</code> for some wrapped <code>T</code>, you may be able to write a "thin
|
||||
converting wrapper" 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<></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 <py_cpp/objects.h>
|
||||
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>
|
||||
>>> str,out_x = f(3)
|
||||
</pre></blockquote>
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
© Copyright David Abrahams 2000. Permission to copy, use, modify,
|
||||
sell and distribute this document is granted provided this copyright
|
||||
notice appears in all copies. This document is provided "as is" without
|
||||
express or implied warranty, and with no claim as to its suitability
|
||||
for any purpose.
|
||||
<p>
|
||||
Updated: Nov 6, 2000
|
||||
</div>
|
||||
|
||||
245
py.cpp
245
py.cpp
@@ -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
325
py.h
@@ -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_
|
||||
203
py_cpp.html
203
py_cpp.html
@@ -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 "boostification"
|
||||
(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<>
|
||||
|
||||
<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<0.2wink> 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>
|
||||
© 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
|
||||
|
||||
57
pyconfig.h
57
pyconfig.h
@@ -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
173
pyptr.h
@@ -1,173 +0,0 @@
|
||||
// (C) Copyright David Abrahams 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
|
||||
#ifndef PYPTR_DWA050400_H_
|
||||
# define PYPTR_DWA050400_H_
|
||||
|
||||
# include "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_
|
||||
@@ -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
|
||||
165
signatures.h
165
signatures.h
@@ -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
|
||||
53
singleton.h
53
singleton.h
@@ -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
|
||||
397
special.html
397
special.html
@@ -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><name></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<std::size_t,std::string></code> as follows:
|
||||
<h2>
|
||||
Example
|
||||
</h2>
|
||||
<blockquote>
|
||||
<pre>
|
||||
typedef std::map<std::size_t, std::string> StringMap;
|
||||
|
||||
// A helper function for dealing with errors. Throw a Python exception
|
||||
// if p == m.end().
|
||||
void throw_key_error_if_end(
|
||||
const StringMap& m,
|
||||
StringMap::const_iterator p,
|
||||
std::size_t key)
|
||||
{
|
||||
if (p == m.end())
|
||||
{
|
||||
PyErr_SetObject(PyExc_KeyError, 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& get_item(const StringMap& self, std::size_t key)
|
||||
{
|
||||
const StringMap::const_iterator p = self.find(key);
|
||||
throw_key_error_if_end(self, p, key);
|
||||
return p->second;
|
||||
}
|
||||
|
||||
// Sets the item corresponding to key in the map.
|
||||
void StringMapPythonClass::set_item(StringMap& self, std::size_t key, const std::string& value)
|
||||
{
|
||||
self[key] = value;
|
||||
}
|
||||
|
||||
// Deletes the item corresponding to key from the map.
|
||||
void StringMapPythonClass::del_item(StringMap& self, std::size_t key)
|
||||
{
|
||||
const StringMap::iterator p = self.find(key);
|
||||
throw_key_error_if_end(self, p, key);
|
||||
self.erase(p);
|
||||
}
|
||||
|
||||
ClassWrapper<StringMap> string_map(my_module, "StringMap");
|
||||
string_map.def(py::Constructor<>());
|
||||
string_map.def(&StringMap::size, "__len__");
|
||||
string_map.def(get_item, "__getitem__");
|
||||
string_map.def(set_item, "__setitem__");
|
||||
string_map.def(del_item, "__delitem__");
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
Then in Python:
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> m = StringMap()
|
||||
>>> m[1]
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
KeyError: 1
|
||||
>>> m[1] = 'hello'
|
||||
>>> m[1]
|
||||
'hello'
|
||||
>>> del m[1]
|
||||
>>> m[1] # prove that it's gone
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
KeyError: 1
|
||||
>>> del m[2]
|
||||
Traceback (innermost last):
|
||||
File "<stdin>", line 1, in ?
|
||||
KeyError: 2
|
||||
>>> len(m)
|
||||
0
|
||||
>>> m[3] = 'farther'
|
||||
>>> 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><name></em>__</code>
|
||||
<li>
|
||||
<code>__setattr__<em><name></em>__</code>
|
||||
<li>
|
||||
<code>__delattr__<em><name></em>__</code>
|
||||
</ul>
|
||||
to provide functional access to the attribute <em><name></em>. This
|
||||
facility can be used from C++ or entirely from Python. For example, the
|
||||
following shows how we can implement a "computed attribute" in Python:
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> class Range(AnyPy_cppExtensionClass):
|
||||
... def __init__(self, start, end):
|
||||
... self.start = start
|
||||
... self.end = end
|
||||
... def __getattr__length__(self):
|
||||
... return self.end - self.start
|
||||
...
|
||||
>>> x = Range(3, 9)
|
||||
>>> x.length
|
||||
6
|
||||
</pre>
|
||||
</blockquote>
|
||||
<h2>
|
||||
Direct Access to Data Members
|
||||
</h2>
|
||||
<p>
|
||||
Py_cpp uses the special <code>
|
||||
__xxxattr__<em><name></em>__</code> functionality described above
|
||||
to allow direct access to data members through the following special
|
||||
functions on <code>ClassWrapper<></code> and <code>
|
||||
ExtensionClass<></code>:
|
||||
<ul>
|
||||
<li>
|
||||
<code>def_getter(<em>pointer-to-member</em>, <em>name</em>)</code> //
|
||||
read access to the member via attribute <em>name</em>
|
||||
<li>
|
||||
<code>def_setter(<em>pointer-to-member</em>, <em>name</em>)</code> //
|
||||
write access to the member via attribute <em>name</em>
|
||||
<li>
|
||||
<code>def_readonly(<em>pointer-to-member</em>, <em>name</em>)</code>
|
||||
// read-only access to the member via attribute <em>name</em>
|
||||
<li>
|
||||
<code>def_read_write(<em>pointer-to-member</em>, <em>
|
||||
name</em>)</code> // read/write access to the member via attribute
|
||||
<em>name</em>
|
||||
</ul>
|
||||
<p>
|
||||
Note that the first two functions, used alone, may produce surprising
|
||||
behavior. For example, when <code>def_getter()</code> is used, the
|
||||
default functionality for <code>setattr()</code> and <code>
|
||||
delattr()</code> remains in effect, operating on items in the extension
|
||||
instance's name-space (i.e., its <code>__dict__</code>). For that
|
||||
reason, you'll usually want to stick with <code>def_readonly</code> and
|
||||
<code>def_read_write</code>.
|
||||
<p>
|
||||
For example, to expose a <code>std::pair<int,long></code> we
|
||||
might write:
|
||||
<blockquote>
|
||||
<pre>
|
||||
typedef std::pair<int,long> Pil;
|
||||
int first(const Pil& x) { return x.first; }
|
||||
long second(const Pil& x) { return x.second; }
|
||||
...
|
||||
my_module.def(first, "first");
|
||||
my_module.def(second, "second");
|
||||
|
||||
ClassWrapper<Pil> pair_int_long(my_module, "Pair");
|
||||
pair_int_long.def(py::Constructor<>());
|
||||
pair_int_long.def(py::Constructor<int,long>());
|
||||
pair_int_long.def_read_write(&Pil::first, "first");
|
||||
pair_int_long.def_read_write(&Pil::second, "second");
|
||||
</pre>
|
||||
</blockquote>
|
||||
<p>
|
||||
Now your Python class has attributes <code>first</code> and <code>
|
||||
second</code> which, when accessed, actually modify or reflect the
|
||||
values of corresponding data members of the underlying C++ object. Now
|
||||
in Python:
|
||||
<blockquote>
|
||||
<pre>
|
||||
>>> x = Pair(3,5)
|
||||
>>> x.first
|
||||
3
|
||||
>>> x.second
|
||||
5
|
||||
>>> x.second = 8
|
||||
>>> x.second
|
||||
8
|
||||
>>> second(x) # Prove that we're not just changing the instance __dict__
|
||||
8
|
||||
</pre>
|
||||
</blockquote>
|
||||
<h2>
|
||||
<a name="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, other)</code>
|
||||
<td>
|
||||
<code>operator+(const T&, const T&)</code>
|
||||
<tr>
|
||||
<td>
|
||||
<code>__sub__(self, other)</code>
|
||||
<td>
|
||||
<code>operator-(const T&, const T&)</code>
|
||||
<tr>
|
||||
<td>
|
||||
<code>__mul__(self, other)</code>
|
||||
<td>
|
||||
<code>operator*(const T&, const T&)</code>
|
||||
<tr>
|
||||
<td>
|
||||
<code>__div__(self, other)</code>
|
||||
<td>
|
||||
<code>operator/(const T&, const T&)</code>
|
||||
<tr>
|
||||
<td>
|
||||
<code>__mod__(self, other)</code>
|
||||
<td>
|
||||
<code>operator%(const T&, const T&)</code>
|
||||
<tr>
|
||||
<td>
|
||||
<code>__divmod__(self, 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, other [, modulo])</code>
|
||||
<td>
|
||||
use <a href="overloading.html">overloading</a> to support both
|
||||
forms of __pow__
|
||||
<tr>
|
||||
<td>
|
||||
<code>__lshift__(self, other)</code>
|
||||
<td>
|
||||
<code>operator<<(const T&, const T&)</code>
|
||||
<tr>
|
||||
<td>
|
||||
<code>__rshift__(self, other)</code>
|
||||
<td>
|
||||
<code>operator>>(const T&, const T&)</code>
|
||||
<tr>
|
||||
<td>
|
||||
<code>__and__(self, other)</code>
|
||||
<td>
|
||||
<code>operator&(const T&, const T&)</code>
|
||||
<tr>
|
||||
<td>
|
||||
<code>__xor__(self, other)</code>
|
||||
<td>
|
||||
<code>operator^(const T&, const T&)</code>
|
||||
<tr>
|
||||
<td>
|
||||
<code>__or__(self, other)</code>
|
||||
<td>
|
||||
<code>operator|(const T&, const T&)</code>
|
||||
<tr>
|
||||
<td>
|
||||
<code>__neg__(self)</code>
|
||||
<td>
|
||||
<code>operator-(const T&)</code> (unary negation)
|
||||
<tr>
|
||||
<td>
|
||||
<code>__pos__(self)</code>
|
||||
<td>
|
||||
<code>operator+(const T&)</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&)</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, 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><name></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>
|
||||
© 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>
|
||||
|
||||
520
subclass.h
520
subclass.h
@@ -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
|
||||
@@ -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()
|
||||
1048
test_extclass.py
1048
test_extclass.py
File diff suppressed because it is too large
Load Diff
425
todo.txt
425
todo.txt
@@ -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 ;)
|
||||
51
tru64.mak
51
tru64.mak
@@ -1,51 +0,0 @@
|
||||
#
|
||||
# Tested with:
|
||||
# Compaq C++ V6.2-024 for Digital UNIX V5.0 (Rev. 910)
|
||||
#
|
||||
# Python 1.5.2 was installed without any customizations.
|
||||
# boost_all.zip vers. 1.18.1 was unpacked using unzip -aa and not modified.
|
||||
# STLport-4.1b3 was unpacked using unzip -aa and not modified.
|
||||
#
|
||||
# Initial version 2000-10-20: Ralf W. Grosse-Kunstleve, rwgk@cci.lbl.gov
|
||||
#
|
||||
|
||||
PYINC= /usr/local/include/python1.5
|
||||
BOOSTINC= /usr/local/boost_1_18_1
|
||||
STLPORTINC= /usr/local/STLport-4.1b3/stlport
|
||||
STLPORTOPTS= \
|
||||
-D__USE_STD_IOSTREAM \
|
||||
-D__STL_NO_SGI_IOSTREAMS \
|
||||
-D__STL_NO_NEW_C_HEADERS \
|
||||
-D_RWSTD_COMPILE_INSTANTIATE=1
|
||||
|
||||
STDOPTS= -std strict_ansi
|
||||
WARNOPTS= -msg_disable 186,450,1115
|
||||
# use -msg_display_number to obtain integer tags for -msg_disable
|
||||
|
||||
CPP= cxx
|
||||
CPPOPTS= -I$(STLPORTINC) $(STLPORTOPTS) -I$(BOOSTINC) -I$(PYINC) \
|
||||
$(STDOPTS) $(WARNOPTS)
|
||||
|
||||
LD= cxx
|
||||
LDOPTS= -shared -expect_unresolved '*'
|
||||
|
||||
OBJ = extclass.o functions.o init_function.o module.o newtypes.o \
|
||||
objects.o py.o subclass.o
|
||||
|
||||
.SUFFIXES: .o .cpp
|
||||
|
||||
all: demo.so hello.so
|
||||
|
||||
demo.so: $(OBJ) extclass_demo.o
|
||||
$(LD) $(LDOPTS) $(OBJ) extclass_demo.o -o demo.so
|
||||
|
||||
hello.so: $(OBJ) example1.o
|
||||
$(LD) $(LDOPTS) $(OBJ) example1.o -o hello.so
|
||||
|
||||
.cpp.o:
|
||||
-$(CPP) $(CPPOPTS) $(INC) -c $*.cpp
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) extclass_demo.o example1.o demo.so hello.so so_locations
|
||||
rm -rf cxx_repository
|
||||
rm -f *.pyc
|
||||
@@ -1,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<T></code> is a subclass of <code>
|
||||
PyTypeObject</code>, the <code> struct</code> which Python's 'C' API uses
|
||||
to describe a type. <a href="example1.html#world_class">An instance of
|
||||
the <code>ExtensionClass<></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<</code><em>S</em><code>>)</code> which convert between any C++
|
||||
type <em>S</em> and a <code>PyObject*</code>, the type which represents a
|
||||
reference to any Python object in its 'C' API. The <a href=
|
||||
"example1.html#world_class"><code>ExtensionClass<T></code></a>
|
||||
template defines a whole raft of these conversions (for <code>T, T*,
|
||||
T&, std::auto_ptr<T></code>, etc.), using the same inline
|
||||
friend function technique employed by <a href=
|
||||
"http://www.boost.org/libs/utility/operators.htm">the boost operators
|
||||
library</a>.
|
||||
<p>
|
||||
Because the <code>to_python</code> and <code>from_python</code> functions
|
||||
for a user-defined class are defined by <code>
|
||||
ExtensionClass<T></code>, it is important that an instantiation of
|
||||
<code> ExtensionClass<T></code> is visible to any code which wraps
|
||||
a C++ function with a <code>T, T*, const T&</code>, etc. parameter or
|
||||
return value. In particular, you may want to create all of the classes at
|
||||
the top of your module's init function, then <code>def</code> the member
|
||||
functions later to avoid problems with inter-class dependencies.
|
||||
<p>
|
||||
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>
|
||||
© 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
|
||||
|
||||
@@ -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'])
|
||||
|
||||
@@ -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"])
|
||||
|
||||
@@ -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
|
||||
@@ -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.
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user