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:
6
gcc.mak
6
gcc.mak
@@ -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
|
||||
|
||||
|
||||
76
module.h
76
module.h
@@ -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
52
num_demo.cpp
Normal 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
171
numeric.cpp
Normal 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
67
numeric.h
Normal 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
36
test_num.py
Normal 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()
|
||||
Reference in New Issue
Block a user