2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-19 16:32:16 +00:00

initial development of NumericDispatcher

[SVN r8022]
This commit is contained in:
Ullrich Köthe
2000-10-20 08:48:01 +00:00
parent 6b0144ef31
commit 90fca10190
6 changed files with 407 additions and 1 deletions

View File

@@ -9,7 +9,7 @@ LIBSRC = \
objects.cpp
LIBOBJ = $(LIBSRC:.cpp=.o)
OBJ = $(LIBOBJ) extclass_demo.o
OBJ = $(LIBOBJ) extclass_demo.o num_demo.o numeric.o
ifeq "$(OS)" "Windows_NT"
@@ -34,6 +34,10 @@ demo: extclass_demo.o libpycpp.a
g++ -shared -o demomodule.$(MODULE_EXTENSION) $(PYTHON_LIB) extclass_demo.o -L. -lpycpp
python test_extclass.py
num: num_demo.o numeric.o libpycpp.a
g++ -shared -o nummodule.$(MODULE_EXTENSION) $(PYTHON_LIB) num_demo.o numeric.o -L. -lpycpp
python test_num.py
clean:
rm -rf *.o *.$(MODULE_EXTENSION) *.a *.d *.pyc *.bak a.out

View File

@@ -12,6 +12,7 @@
# include "pyconfig.h"
# include "pyptr.h"
# include "functions.h"
# include "numeric.h"
namespace py {
@@ -33,6 +34,81 @@ public:
{
add(new_wrapped_function(fn), name);
}
template <class T1, class U1, class T2, class U2>
void
def_numeric(ExtensionClass<T1,U1> * l, ExtensionClass<T2,U2> * r,
char const * name)
{
PyTypeObject * tl = l;
PyTypeObject * tr = r;
l->def(coerce_wrapped, "__coerce__");
r->def(coerce_wrapped, "__coerce__");
if(strcmp(name,"__add__") == 0)
{
NumericDispatcher::add_functions[std::make_pair(tl,tr)] =
NumericOperators<T1, T2>::add;
l->def(py::NumericDispatcher::add, "__add__");
r->def(py::NumericDispatcher::add, "__add__");
}
else if(strcmp(name,"__sub__") == 0)
{
NumericDispatcher::sub_functions[std::make_pair(tl,tr)] =
NumericOperators<T1, T2>::subtract;
l->def(py::NumericDispatcher::sub, "__sub__");
r->def(py::NumericDispatcher::sub, "__sub__");
}
}
template <class T1, class U1>
void
def_numeric(ExtensionClass<T1,U1> * l, PyTypeObject * r,
char const * name)
{
PyTypeObject * tl = l;
PyTypeObject * tr = r;
l->def(coerce_wrapped, "__coerce__");
if(strcmp(name,"__add__") == 0)
{
NumericDispatcher::add_functions[std::make_pair(tl,tr)] =
NumericOperators<T1, int>::add;
l->def(py::NumericDispatcher::add, "__add__");
}
else if(strcmp(name,"__sub__") == 0)
{
NumericDispatcher::sub_functions[std::make_pair(tl,tr)] =
NumericOperators<T1, int>::subtract;
l->def(py::NumericDispatcher::sub, "__sub__");
}
}
template <class T2, class U2>
void
def_numeric(PyTypeObject * l, ExtensionClass<T2,U2> * r,
char const * name)
{
PyTypeObject * tl = l;
PyTypeObject * tr = r;
r->def(coerce_wrapped, "__coerce__");
if(strcmp(name,"__add__") == 0)
{
NumericDispatcher::add_functions[std::make_pair(tl,tr)] =
NumericOperators<int, T2>::add;
r->def(py::NumericDispatcher::add, "__add__");
}
else if(strcmp(name,"__sub__") == 0)
{
NumericDispatcher::sub_functions[std::make_pair(tl,tr)] =
NumericOperators<int, T2>::subtract;
r->def(py::NumericDispatcher::sub, "__sub__");
}
}
private:
PyObject* m_module;
static PyMethodDef initial_methods[1];

52
num_demo.cpp Normal file
View File

@@ -0,0 +1,52 @@
#include "numeric.h"
#include "class_wrapper.h"
struct Int
{
Int(int i) : i_(i) {}
Int operator+(int const & r) const { return Int(i_ + r); }
Int operator-(int const & r) const { return Int(i_ - r); }
Int operator+(Int const & r) const { return Int(i_ + r.i_); }
Int operator-(Int const & r) const { return Int(i_ - r.i_); }
int i() const { return i_; }
int i_;
};
Int operator+(int const & i, Int const & j) { return Int(i+j.i()); }
Int operator-(int const & i, Int const & j) { return Int(i-j.i()); }
ostream & operator<<(ostream & o, Int const & i)
{
o << i.i();
return o;
}
extern "C"
void initnum()
{
try
{
py::Module num("num");
py::ClassWrapper<Int> int_class(num, "Int");
int_class.def(py::Constructor<int>());
int_class.def(py::Constructor<Int>());
int_class.def(py::coerce_wrapped, "__coerce__");
int_class.def(&Int::i, "i");
num.def_numeric(int_class.get_extension_class(),
int_class.get_extension_class(), "__add__");
num.def_numeric(int_class.get_extension_class(),
int_class.get_extension_class(), "__sub__");
num.def_numeric(int_class.get_extension_class(), &PyInt_Type, "__add__");
num.def_numeric(&PyInt_Type, int_class.get_extension_class(), "__add__");
}
catch(...)
{
py::handle_exception();
} // Need a way to report other errors here
}

171
numeric.cpp Normal file
View File

@@ -0,0 +1,171 @@
#include "numeric.h"
#include "py.h"
#include <stdexcept>
namespace py {
NumericDispatcher::FunctionRepository NumericDispatcher::add_functions;
NumericDispatcher::FunctionRepository NumericDispatcher::sub_functions;
PyTypeObject NumericDispatcher::type_object =
{
PyObject_HEAD_INIT(&PyType_Type)
0,
"NumericDispatcher",
sizeof(NumericDispatcher),
0,
(destructor)&NumericDispatcher::dealloc,
0,
0,
0,
0,
0,
&NumericDispatcher::number_methods,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
};
PyNumberMethods NumericDispatcher::number_methods =
{
&NumericDispatcher::add,
&NumericDispatcher::sub,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
};
NumericDispatcher::NumericDispatcher(PyObject * o)
: object(o)
{
ob_refcnt = 1;
ob_type = &type_object;
}
void NumericDispatcher::dealloc(PyObject *self)
{
delete static_cast<NumericDispatcher *>(self);
}
PyObject * NumericDispatcher::add(PyObject * l, PyObject * r)
{
coerce(l,r);
PyTypeObject * lt = l->ob_type;
PyTypeObject * rt = r->ob_type;
FunctionRepository::iterator f = add_functions.find(make_pair(lt, rt));
if(f != add_functions.end())
{
PyObject * result = (*(*f).second)(l, r);
Py_DECREF(l);
Py_DECREF(r);
return result;
}
else
{
Py_DECREF(l);
Py_DECREF(r);
PyErr_SetString(PyExc_TypeError, "incompatible arguments for +");
return 0;
}
}
PyObject * NumericDispatcher::sub(PyObject * l, PyObject * r)
{
coerce(l,r);
PyTypeObject * lt = l->ob_type;
PyTypeObject * rt = r->ob_type;
FunctionRepository::iterator f = sub_functions.find(make_pair(lt, rt));
if(f != sub_functions.end())
{
PyObject * result = (*(*f).second)(l, r);
Py_DECREF(l);
Py_DECREF(r);
return result;
}
else
{
Py_DECREF(l);
Py_DECREF(r);
PyErr_SetString(PyExc_TypeError, "incompatible arguments for -");
return 0;
}
}
// add appropriate ref counting here !!!
void NumericDispatcher::coerce(PyObject * & l, PyObject * & r)
{
if(l->ob_type == &type_object)
{
if(r->ob_type != &type_object)
{
throw std::runtime_error("internal error");
}
NumericDispatcher * lwrapper = static_cast<NumericDispatcher *>(l);
NumericDispatcher * rwrapper = static_cast<NumericDispatcher *>(r);
l = lwrapper->object;
r = rwrapper->object;
}
Py_INCREF(l);
Py_INCREF(r);
return;
}
void NumericDispatcher::init_type_object()
{
}
void NumericDispatcher::free_type_object()
{
}
py::Tuple coerce_wrapped(PyObject * l, PyObject * r)
{
return py::Tuple(new NumericDispatcher(l),
new NumericDispatcher(r));
}
bool operator<(TypePair const & l, TypePair const & r)
{
return (l.first < r.first) ?
1 :
(r.first < l.first) ?
0 :
l.second < r.second;
}
}

67
numeric.h Normal file
View File

@@ -0,0 +1,67 @@
#ifndef PYCPP_NUMERIC_H
#define PYCPP_NUMERIC_H
#include <map>
#include <utility>
#include "py.h"
#include "extclass.h"
namespace py {
template <class T, class U>
struct NumericOperators
{
static PyObject * add(PyObject * l, PyObject * r)
{
return to_python(from_python(l, py::Type<T const &>()) +
from_python(r, py::Type<U const &>()));
}
static PyObject * subtract(PyObject * l, PyObject * r)
{
return to_python(from_python(l, py::Type<T const &>()) -
from_python(r, py::Type<U const &>()));
}
};
typedef std::pair<PyTypeObject *, PyTypeObject *> TypePair;
bool operator<(TypePair const & l, TypePair const & r);
struct NumericDispatcher
: public PyObject
{
typedef PyObject * (*NumericFunction)(PyObject *, PyObject *);
typedef std::map<TypePair, NumericFunction> FunctionRepository;
static FunctionRepository add_functions;
static FunctionRepository sub_functions;
static PyTypeObject type_object;
static PyNumberMethods number_methods;
friend class Module;
// store this function in NumericDispatcher's 'nb_add' slot
static PyObject * add(PyObject * l, PyObject * r);
static PyObject * sub(PyObject * l, PyObject * r);
static void coerce(PyObject * & l, PyObject * & r);
static void init_type_object();
static void free_type_object();
NumericDispatcher(PyObject * o);
static void dealloc(PyObject *self);
PyObject * object;
};
py::Tuple coerce_wrapped(PyObject * l, PyObject * r);
}
inline PyObject * to_python(py::NumericDispatcher * n) { return n; }
#endif /* PYCPP_NUMERIC_H */

36
test_num.py Normal file
View File

@@ -0,0 +1,36 @@
r'''
>>> i1 = Int(1)
>>> i2 = Int(2)
>>> i = i1 + i2
>>> i.i()
3
>>> i = i1 - i2
>>> i.i()
-1
>>> i = i1 + 5
>>> i.i()
6
>>> i = 3 + i2
>>> i.i()
5
>>> i = i1 - 3
Traceback (innermost last):
TypeError: incompatible arguments for -
>>> i = 3 - i1
Traceback (innermost last):
TypeError: incompatible arguments for -
'''
from num import *
import string
import re
import sys
def run(args = None):
if args is not None:
sys.argv = args
import doctest, test_num
doctest.testmod(test_num)
if __name__ == '__main__':
run()