[pypy-svn] r75895 - in pypy/branch/reflex-support/pypy/module/cppyy: . include src test
cfbolz at codespeak.net
cfbolz at codespeak.net
Tue Jul 6 12:37:25 CEST 2010
Author: cfbolz
Date: Tue Jul 6 12:37:23 2010
New Revision: 75895
Added:
pypy/branch/reflex-support/pypy/module/cppyy/converter.py (contents, props changed)
Modified:
pypy/branch/reflex-support/pypy/module/cppyy/include/reflexcwrapper.h
pypy/branch/reflex-support/pypy/module/cppyy/interp_cppyy.py
pypy/branch/reflex-support/pypy/module/cppyy/src/reflexcwrapper.cxx
pypy/branch/reflex-support/pypy/module/cppyy/test/example01.cxx
pypy/branch/reflex-support/pypy/module/cppyy/test/test_cppyy.py
Log:
(antocuni, cfbolz, wlav, arigo around): start going in the direction of
supporting overloading. support returning doubles from static methods.
Added: pypy/branch/reflex-support/pypy/module/cppyy/converter.py
==============================================================================
--- (empty file)
+++ pypy/branch/reflex-support/pypy/module/cppyy/converter.py Tue Jul 6 12:37:23 2010
@@ -0,0 +1,27 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+
+class TypeConverter(object):
+ def convert_argument(self, space, w_obj):
+ raise NotImplementedError("abstract base class")
+
+
+class IntConverter(TypeConverter):
+ def convert_argument(self, space, w_obj):
+ arg = space.int_w(w_obj)
+ x = lltype.malloc(rffi.LONGP.TO, 1, flavor='raw')
+ x[0] = arg
+ return rffi.cast(rffi.VOIDP, x)
+
+class DoubleConverter(TypeConverter):
+ def convert_argument(self, space, w_obj):
+ arg = space.float_w(w_obj)
+ x = lltype.malloc(rffi.DOUBLEP.TO, 1, flavor='raw')
+ x[0] = arg
+ return rffi.cast(rffi.VOIDP, x)
+
+def get_converter(name):
+ if name == "int":
+ return IntConverter()
+ if name == "double":
+ return DoubleConverter()
+ raise TypeError("no clue what %s is" % name)
Modified: pypy/branch/reflex-support/pypy/module/cppyy/include/reflexcwrapper.h
==============================================================================
--- pypy/branch/reflex-support/pypy/module/cppyy/include/reflexcwrapper.h (original)
+++ pypy/branch/reflex-support/pypy/module/cppyy/include/reflexcwrapper.h Tue Jul 6 12:37:23 2010
@@ -3,10 +3,21 @@
#define CPPYY_REFLEXCWRAPPER
extern "C" {
- long callstatic_l(const char* class_name, const char* method_name, int numargs, void* args[]);
- long callmethod_l(const char* class_name, const char* method_name, void* self, int numargs, void* args[]);
+ long callstatic_l(const char* class_name, int method_index, int numargs, void* args[]);
+ double callstatic_d(const char* class_name, int method_index, int numargs, void* args[]);
+ long callmethod_l(const char* class_name, int method_index, void* self, int numargs, void* args[]);
void* construct(const char* class_name, int numargs, void* args[]);
void destruct(const char* class_name, void* self);
+
+ int num_methods(const char* class_name);
+ char* method_name(const char* class_name, int method_index);
+ char* result_type_method(const char* class_name, int method_index);
+ int num_args_method(const char* class_name, int method_index);
+ char* arg_type_method(const char* class_name, int method_index, int index);
+ int is_constructor(const char* class_name, int method_index);
+ int is_static(const char* class_name, int method_index);
+
+ void myfree(void* ptr);
}
#endif // ifndef CPPYY_REFLEXCWRAPPER
Modified: pypy/branch/reflex-support/pypy/module/cppyy/interp_cppyy.py
==============================================================================
--- pypy/branch/reflex-support/pypy/module/cppyy/interp_cppyy.py (original)
+++ pypy/branch/reflex-support/pypy/module/cppyy/interp_cppyy.py Tue Jul 6 12:37:23 2010
@@ -10,6 +10,8 @@
from pypy.rlib.libffi import CDLL
+from pypy.module.cppyy import converter
+
srcpath = py.path.local(__file__).dirpath().join("src")
incpath = py.path.local(__file__).dirpath().join("include")
@@ -26,7 +28,11 @@
callstatic_l = rffi.llexternal(
"callstatic_l",
- [rffi.CCHARP, rffi.CCHARP, rffi.INT, rffi.VOIDPP], rffi.LONG,
+ [rffi.CCHARP, rffi.INT, rffi.INT, rffi.VOIDPP], rffi.LONG,
+ compilation_info=eci)
+callstatic_d = rffi.llexternal(
+ "callstatic_d",
+ [rffi.CCHARP, rffi.INT, rffi.INT, rffi.VOIDPP], rffi.DOUBLE,
compilation_info=eci)
construct = rffi.llexternal(
"construct",
@@ -34,7 +40,7 @@
compilation_info=eci)
callmethod_l = rffi.llexternal(
"callmethod_l",
- [rffi.CCHARP, rffi.CCHARP, rffi.VOIDP, rffi.INT, rffi.VOIDPP], rffi.LONG,
+ [rffi.CCHARP, rffi.INT, rffi.VOIDP, rffi.INT, rffi.VOIDPP], rffi.LONG,
compilation_info=eci)
destruct = rffi.llexternal(
"destruct",
@@ -42,19 +48,54 @@
compilation_info=eci)
+num_methods = rffi.llexternal(
+ "num_methods",
+ [rffi.CCHARP], rffi.INT,
+ compilation_info=eci)
+method_name = rffi.llexternal(
+ "method_name",
+ [rffi.CCHARP, rffi.INT], rffi.CCHARP,
+ compilation_info=eci)
+result_type_method = rffi.llexternal(
+ "result_type_method",
+ [rffi.CCHARP, rffi.INT], rffi.CCHARP,
+ compilation_info=eci)
+num_args_method = rffi.llexternal(
+ "num_args_method",
+ [rffi.CCHARP, rffi.INT], rffi.INT,
+ compilation_info=eci)
+arg_type_method = rffi.llexternal(
+ "arg_type_method",
+ [rffi.CCHARP, rffi.INT, rffi.INT], rffi.CCHARP,
+ compilation_info=eci)
+is_constructor = rffi.llexternal(
+ "is_constructor",
+ [rffi.CCHARP, rffi.INT], rffi.INT,
+ compilation_info=eci)
+is_static = rffi.llexternal(
+ "is_static",
+ [rffi.CCHARP, rffi.INT], rffi.INT,
+ compilation_info=eci)
+myfree = rffi.llexternal(
+ "myfree",
+ [rffi.VOIDP], lltype.Void,
+ compilation_info=eci)
+
def load_lib(space, name):
cdll = CDLL(name)
return W_CPPLibrary(space, cdll)
load_lib.unwrap_spec = [ObjSpace, str]
-def prepare_arguments(space, args_w):
+def prepare_arguments(space, args_w, argtypes):
+ if len(args_w) != len(argtypes):
+ raise OperationError(space.w_TypeError, space.wrap("wrong number of args"))
args = lltype.malloc(rffi.CArray(rffi.VOIDP), len(args_w), flavor='raw')
for i in range(len(args_w)):
- arg = space.int_w(args_w[i])
- x = lltype.malloc(rffi.LONGP.TO, 1, flavor='raw')
- x[0] = arg
- args[i] = rffi.cast(rffi.VOIDP, x)
+ argtype = argtypes[i]
+ conv = converter.get_converter(argtype)
+ # XXX this can leak so far
+ args[i] = conv.convert_argument(space, args_w[i])
return args
def free_arguments(args, numargs):
@@ -75,24 +116,120 @@
type_byname = interp2app(W_CPPLibrary.type_byname, unwrap_spec=['self', str]),
)
+class CPPMethod(object):
+ """ A concrete function after overloading has been resolved """
+
+ def __init__(self, cpptype, method_index, result_type, arg_types):
+ self.cpptype = cpptype
+ self.space = cpptype.space
+ self.method_index = method_index
+ self.result_type = result_type
+ self.arg_types = arg_types
+
+ def call(self, cppthis, args_w):
+ args = prepare_arguments(self.space, args_w, self.arg_types)
+ result = callmethod_l(self.cpptype.name, self.method_index,
+ cppthis, len(args_w), args)
+ free_arguments(args, len(args_w))
+ return result
+
+ def __repr__(self):
+ return "CPPFunction(%s, %s, %s, %s)" % (
+ self.cpptype, self.method_index, self.result_type, self.arg_types)
+
+class CPPFunction(CPPMethod):
+ def call(self, cppthis, args_w):
+ assert cppthis is None
+ args = prepare_arguments(self.space, args_w, self.arg_types)
+ if self.result_type == "int":
+ result = callstatic_l(self.cpptype.name, self.method_index, len(args_w), args)
+ return self.space.wrap(result)
+ if self.result_type == "double":
+ result = callstatic_d(self.cpptype.name, self.method_index, len(args_w), args)
+ return self.space.wrap(result)
+ else:
+ raise NotImplementedError
+ free_arguments(args, len(args_w))
+
+
+class CPPConstructor(CPPFunction):
+ def call(self, cppthis, args_w):
+ assert cppthis is None
+ args = prepare_arguments(self.space, args_w, self.arg_types)
+ result = construct(self.cpptype.name, len(args_w), args)
+ free_arguments(args, len(args_w))
+ return result
+
+
+class CPPOverload(object):
+ def __init__(self, space, func_name):
+ self.space = space
+ self.func_name = func_name
+ self.functions = []
+
+ def add_function(self, cppfunc):
+ self.functions.append(cppfunc)
+
+ def call(self, cppthis, args_w):
+ space = self.space
+ for cppyyfunc in self.functions:
+ try:
+ return cppyyfunc.call(cppthis, args_w)
+ except OperationError, e:
+ if not e.match(space, space.w_TypeError):
+ raise
+ # XXX better error reporting
+ raise OperationError(space.w_TypeError, space.wrap("none of the overloads matched"))
+
+ def __repr__(self):
+ return "CPPOverload(%s, %s)" % (self.func_name, self.functions)
+
+def charp2str(charp):
+ string = rffi.charp2str(charp)
+ myfree(charp)
+ return string
class W_CPPType(Wrappable):
def __init__(self, cpplib, name):
self.space = cpplib.space
self.cpplib = cpplib
self.name = name
+ self.function_members = {}
+ self._find_func_members()
+
+ def _find_func_members(self):
+ num_func_members = num_methods(self.name)
+ for i in range(num_func_members):
+ func_member_name = charp2str(method_name(self.name, i))
+ cppfunction = self._make_cppfunction(i)
+ overload = self.function_members.get(func_member_name, None)
+ if overload is None:
+ overload = CPPOverload(self.space, func_member_name)
+ self.function_members[func_member_name] = overload
+ overload.add_function(cppfunction)
+
+ def _make_cppfunction(self, method_index):
+ result_type = charp2str(result_type_method(self.name, method_index))
+ num_args = num_args_method(self.name, method_index)
+ argtypes = []
+ for i in range(num_args):
+ argtype = charp2str(arg_type_method(self.name, method_index, i))
+ argtypes.append(argtype)
+ if is_constructor(self.name, method_index):
+ cls = CPPConstructor
+ elif is_static(self.name, method_index):
+ cls = CPPFunction
+ else:
+ cls = CPPMethod
+ return cls(self, method_index, result_type, argtypes)
def invoke(self, name, args_w):
- args = prepare_arguments(self.space, args_w)
- result = callstatic_l(self.name, name, len(args_w), args)
- free_arguments(args, len(args_w))
- return self.space.wrap(result)
+ overload = self.function_members[name]
+ return overload.call(None, args_w)
def construct(self, args_w):
- args = prepare_arguments(self.space, args_w)
- result = construct(self.name, len(args_w), args)
- free_arguments(args, len(args_w))
- return W_CPPObject(self, result)
+ overload = self.function_members[self.name]
+ return W_CPPObject(self, overload.call(None, args_w))
W_CPPType.typedef = TypeDef(
'CPPType',
@@ -109,10 +246,8 @@
self.rawobject = rawobject
def invoke(self, method_name, args_w):
- args = prepare_arguments(self.space, args_w)
- result = callmethod_l(self.cppclass.name, method_name,
- self.rawobject, len(args_w), args)
- free_arguments(args, len(args_w))
+ overload = self.cppclass.function_members[method_name]
+ result = overload.call(self.rawobject, args_w)
return self.space.wrap(result)
def destruct(self):
Modified: pypy/branch/reflex-support/pypy/module/cppyy/src/reflexcwrapper.cxx
==============================================================================
--- pypy/branch/reflex-support/pypy/module/cppyy/src/reflexcwrapper.cxx (original)
+++ pypy/branch/reflex-support/pypy/module/cppyy/src/reflexcwrapper.cxx Tue Jul 6 12:37:23 2010
@@ -3,22 +3,31 @@
#include <vector>
#include <iostream>
-long callstatic_l(const char* class_name, const char* method_name, int numargs, void* args[]) {
+long callstatic_l(const char* class_name, int method_index, int numargs, void* args[]) {
long result;
std::vector<void*> arguments(args, args+numargs);
Reflex::Type t = Reflex::Type::ByName(class_name);
- Reflex::Member m = t.FunctionMemberByName(method_name);
+ Reflex::Member m = t.FunctionMemberAt(method_index);
+ m.Invoke(result, arguments);
+ return result;
+}
+double callstatic_d(const char* class_name, int method_index, int numargs, void* args[]) {
+ double result;
+ std::vector<void*> arguments(args, args+numargs);
+ Reflex::Type t = Reflex::Type::ByName(class_name);
+ Reflex::Member m = t.FunctionMemberAt(method_index);
m.Invoke(result, arguments);
return result;
}
-long callmethod_l(const char* class_name, const char* method_name,
+long callmethod_l(const char* class_name, int method_index,
void* self, int numargs, void* args[]) {
long result;
std::vector<void*> arguments(args, args+numargs);
Reflex::Type t = Reflex::Type::ByName(class_name);
Reflex::Object o(t, self);
- o.Invoke(method_name, result, arguments);
+ Reflex::Member m = t.FunctionMemberAt(method_index);
+ m.Invoke(o, result, arguments);
return result;
}
@@ -39,3 +48,69 @@
Reflex::Type t = Reflex::Type::ByName(class_name);
t.Destruct(self, true);
}
+
+
+int num_methods(const char* class_name) {
+ Reflex::Type t = Reflex::Type::ByName(class_name);
+ for (int i = 0; i < t.FunctionMemberSize(); i++) {
+ Reflex::Member m = t.FunctionMemberAt(i);
+ std::cout << i << " " << m.Name() << std::endl;
+ for (int j = 0; j < m.FunctionParameterSize(); j++) {
+ Reflex::Type at = m.TypeOf().FunctionParameterAt(j);
+ std::cout << " " << j << " " << at.Name() << std::endl;
+ }
+ }
+ return t.FunctionMemberSize();
+}
+
+char* method_name(const char* class_name, int method_index) {
+ Reflex::Type t = Reflex::Type::ByName(class_name);
+ Reflex::Member m = t.FunctionMemberAt(method_index);
+ std::string name = m.Name();
+ char* name_char = (char*)malloc(name.size() + 1);
+ strcpy(name_char, name.c_str());
+ return name_char;
+}
+
+char* result_type_method(const char* class_name, int method_index) {
+ Reflex::Type t = Reflex::Type::ByName(class_name);
+ Reflex::Member m = t.FunctionMemberAt(method_index);
+ Reflex::Type rt = m.TypeOf().ReturnType();
+ std::string name = rt.Name(Reflex::FINAL);
+ char* name_char = (char*)malloc(name.size() + 1);
+ strcpy(name_char, name.c_str());
+ return name_char;
+}
+
+int num_args_method(const char* class_name, int method_index) {
+ Reflex::Type t = Reflex::Type::ByName(class_name);
+ Reflex::Member m = t.FunctionMemberAt(method_index);
+ return m.FunctionParameterSize();
+}
+
+char* arg_type_method(const char* class_name, int method_index, int arg_index) {
+
+ Reflex::Type t = Reflex::Type::ByName(class_name);
+ Reflex::Member m = t.FunctionMemberAt(method_index);
+ Reflex::Type at = m.TypeOf().FunctionParameterAt(arg_index);
+ std::string name = at.Name(Reflex::FINAL);
+ char* name_char = (char*)malloc(name.size() + 1);
+ strcpy(name_char, name.c_str());
+ return name_char;
+}
+
+int is_constructor(const char* class_name, int method_index) {
+ Reflex::Type t = Reflex::Type::ByName(class_name);
+ Reflex::Member m = t.FunctionMemberAt(method_index);
+ return m.IsConstructor();
+}
+
+int is_static(const char* class_name, int method_index) {
+ Reflex::Type t = Reflex::Type::ByName(class_name);
+ Reflex::Member m = t.FunctionMemberAt(method_index);
+ return m.IsStatic();
+}
+
+void myfree(void* ptr) {
+ free(ptr);
+}
Modified: pypy/branch/reflex-support/pypy/module/cppyy/test/example01.cxx
==============================================================================
--- pypy/branch/reflex-support/pypy/module/cppyy/test/example01.cxx (original)
+++ pypy/branch/reflex-support/pypy/module/cppyy/test/example01.cxx Tue Jul 6 12:37:23 2010
@@ -29,6 +29,9 @@
static int add1(int a) {
return a + 1;
}
+ static double adddouble(double a) {
+ return a + 0.01;
+ }
static int getcount() {
std::cout << "getcount called" << std::endl;
return count;
Modified: pypy/branch/reflex-support/pypy/module/cppyy/test/test_cppyy.py
==============================================================================
--- pypy/branch/reflex-support/pypy/module/cppyy/test/test_cppyy.py (original)
+++ pypy/branch/reflex-support/pypy/module/cppyy/test/test_cppyy.py Tue Jul 6 12:37:23 2010
@@ -1,22 +1,41 @@
import py
import os
from pypy.conftest import gettestobjspace
+from pypy.module.cppyy import interp_cppyy
currpath = py.path.local(__file__).dirpath()
+shared_lib = str(currpath.join("example01Dict.so"))
+
+space = gettestobjspace(usemodules=['cppyy'])
+
+class TestCPPYYImplementation:
+ def test_class_query(self):
+ lib = interp_cppyy.load_lib(space, shared_lib)
+ w_cppyyclass = lib.type_byname("example01")
+ adddouble = w_cppyyclass.function_members["adddouble"]
+ func, = adddouble.functions
+ assert func.result_type == "double"
+ assert func.arg_types == ["double"]
+
class AppTestCPPYY:
def setup_class(cls):
- cls.space = gettestobjspace(usemodules=['cppyy'])
+ cls.space = space
env = os.environ
cls.w_example01 = cls.space.appexec([], """():
import cppyy
- return cppyy.load_lib(%r)""" % (str(currpath.join("example01Dict.so")), ))
+ return cppyy.load_lib(%r)""" % (shared_lib, ))
def test_example01static(self):
t = self.example01.type_byname("example01")
res = t.invoke("add1", 1)
assert res == 2
+ def test_example01static_double(self):
+ t = self.example01.type_byname("example01")
+ res = t.invoke("adddouble", 0.09)
+ assert res == 0.09 + 0.01
+
def test_example01method(self):
t = self.example01.type_byname("example01")
count = t.invoke("getcount")
More information about the Pypy-commit
mailing list