[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