[pypy-commit] pypy reflex-support: nicer template support

wlav noreply at buildbot.pypy.org
Wed Jun 8 01:41:12 CEST 2011


Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r44823:cd3befebf2f2
Date: 2011-06-07 12:02 -0700
http://bitbucket.org/pypy/pypy/changeset/cd3befebf2f2/

Log:	nicer template support

diff --git a/pypy/module/cppyy/__init__.py b/pypy/module/cppyy/__init__.py
--- a/pypy/module/cppyy/__init__.py
+++ b/pypy/module/cppyy/__init__.py
@@ -6,6 +6,7 @@
     interpleveldefs = {
         '_load_lib'              : 'interp_cppyy.load_lib',
         '_type_byname'           : 'interp_cppyy.type_byname',
+        '_template_byname'       : 'interp_cppyy.template_byname',
     }
 
     appleveldefs = {
diff --git a/pypy/module/cppyy/capi.py b/pypy/module/cppyy/capi.py
--- a/pypy/module/cppyy/capi.py
+++ b/pypy/module/cppyy/capi.py
@@ -33,6 +33,11 @@
     [rffi.CCHARP], C_TYPEHANDLE,
     compilation_info=eci)
 
+c_get_templatehandle = rffi.llexternal(
+    "cppyy_get_templatehandle",
+    [rffi.CCHARP], C_TYPEHANDLE,
+    compilation_info=eci)
+
 c_allocate = rffi.llexternal(
     "cppyy_allocate",
     [C_TYPEHANDLE], rffi.VOIDP,
diff --git a/pypy/module/cppyy/include/cppyy.h b/pypy/module/cppyy/include/cppyy.h
--- a/pypy/module/cppyy/include/cppyy.h
+++ b/pypy/module/cppyy/include/cppyy.h
@@ -7,5 +7,6 @@
 #include "Reflex/Object.h"
 #include "Reflex/Builder/TypeBuilder.h"
 #include "Reflex/PropertyList.h"
+#include "Reflex/TypeTemplate.h"
 
 #endif // CPPYY_CPPYY
diff --git a/pypy/module/cppyy/include/reflexcwrapper.h b/pypy/module/cppyy/include/reflexcwrapper.h
--- a/pypy/module/cppyy/include/reflexcwrapper.h
+++ b/pypy/module/cppyy/include/reflexcwrapper.h
@@ -1,4 +1,3 @@
-
 #ifndef CPPYY_REFLEXCWRAPPER
 #define CPPYY_REFLEXCWRAPPER
 
@@ -11,6 +10,7 @@
 
     /* name to handle */
     cppyy_typehandle_t cppyy_get_typehandle(const char* class_name);
+    cppyy_typehandle_t cppyy_get_templatehandle(const char* template_name);
 
     /* memory management */
     void* cppyy_allocate(cppyy_typehandle_t handle);
diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py
--- a/pypy/module/cppyy/interp_cppyy.py
+++ b/pypy/module/cppyy/interp_cppyy.py
@@ -48,6 +48,22 @@
     raise OperationError(space.w_TypeError, space.wrap(str("no such C++ class %s" % name)))
 type_byname.unwrap_spec = [ObjSpace, str]
 
+def template_byname(space, name):
+    state = space.fromcache(State)
+    try:
+        return state.cpptype_cache[name]
+    except KeyError:
+        pass
+
+    handle = capi.c_get_templatehandle(name)
+    if handle:
+        template = W_CPPTemplateType(space, name, handle)
+        state.cpptype_cache[name] = template
+        return template
+
+    raise OperationError(space.w_TypeError, space.wrap(str("no such C++ template %s" % name)))
+template_byname.unwrap_spec = [ObjSpace, str]
+
 
 class W_CPPLibrary(Wrappable):
     _immutable_ = True
@@ -459,6 +475,24 @@
 )
 
 
+class W_CPPTemplateType(Wrappable):
+    _immutable_fields_ = ["name", "handle"]
+
+    def __init__(self, space, name, handle):
+        self.space = space
+        self.name = name
+        self.handle = handle
+
+    def __call__(self, args_w):
+        fullname = "".join([self.name, '<', self.space.str_w(args_w[0]), '>'])
+        return type_byname(self.space, fullname)
+
+W_CPPTemplateType.typedef = TypeDef(
+    'CPPTemplateType',
+    __call__ = interp2app(W_CPPTemplateType.__call__, unwrap_spec=['self', 'args_w']),
+)
+
+
 class W_CPPInstance(Wrappable):
     _immutable_fields_ = ["cppclass"]
 
diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py
--- a/pypy/module/cppyy/pythonify.py
+++ b/pypy/module/cppyy/pythonify.py
@@ -12,6 +12,16 @@
 class CppyyClass(type):
     pass
 
+
+class CppyyTemplateType(object):
+    def __init__(self, scope, name):
+        self._scope = scope
+        self._name = name
+
+    def __call__(self, *args):
+        fullname = "".join([self._name, '<', str(args[0]), '>'])
+        return getattr(self._scope, fullname)
+
 class CppyyObject(object):
     __metaclass__ = CppyyClass
 
@@ -56,14 +66,14 @@
 
 def __innercpp_getattr__(self, attr):
     try:
-        cppclass = get_cppitem(attr, self.__name__)
+        cppclass = get_cppitem(attr, self)
         self.__dict__[attr] = cppclass
         return cppclass
     except TypeError:
         raise AttributeError("%s object has no attribute '%s'" % (self,attr))
 
 
-def make_cppnamespace(name, cppns):
+def make_cppnamespace(namespace_name, cppns):
     d = {}
 
     # insert static methods into the "namespace" dictionary
@@ -72,7 +82,7 @@
         d[func_name] = make_static_function(cppns, func_name, cppol)
 
     # create a meta class to allow properties (for static data write access)
-    metans = type(CppyyNamespace)(name+'_meta', (type(type),),
+    metans = type(CppyyNamespace)(namespace_name+'_meta', (type(type),),
                                   {"__getattr__" : __innercpp_getattr__})
 
     # add all data members to the dictionary of the class to be created, and
@@ -83,10 +93,10 @@
         setattr(metans, dm, cppdm)
 
     # create the python-side C++ namespace representation
-    pycppns = metans(name, (type,), d)
+    pycppns = metans(namespace_name, (type,), d)
 
     # cache result and return
-    _existing_cppitems[name] = pycppns
+    _existing_cppitems[namespace_name] = pycppns
     return pycppns
 
 def make_cppclass(class_name, cpptype):
@@ -127,11 +137,14 @@
 
     return pycpptype
 
+def make_cpptemplatetype(template_name, scope):
+    return  CppyyTemplateType(scope, template_name)
+
 
 _existing_cppitems = {}               # to merge with gbl.__dict__ (?)
-def get_cppitem(name, scope=""):
+def get_cppitem(name, scope=None):
     if scope:
-        fullname = scope+"::"+name
+        fullname = scope.__name__+"::"+name
     else:
         fullname = name
 
@@ -142,11 +155,24 @@
         pass
 
     # ... if lookup failed, create
-    cppitem = cppyy._type_byname(fullname)
-    if cppitem.is_namespace():
-        return make_cppnamespace(fullname, cppitem)
-    else:
-        return make_cppclass(fullname, cppitem)
+    pycppitem = None
+    try:
+        cppitem = cppyy._type_byname(fullname)
+        if cppitem.is_namespace():
+            pycppitem = make_cppnamespace(fullname, cppitem)
+        else:
+            pycppitem = make_cppclass(fullname, cppitem)
+    except TypeError:
+        cppitem = cppyy._template_byname(fullname)
+        pycppitem = make_cpptemplatetype(name, scope)
+
+    if pycppitem:
+        _existing_cppitems[fullname] = pycppitem
+        return pycppitem
+
+    raise AttributeError("'%s' has no attribute '%s'", (str(scope), name))
+
+
 get_cppclass = get_cppitem         # TODO: restrict to classes only (?)
 
 
diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx
--- a/pypy/module/cppyy/src/reflexcwrapper.cxx
+++ b/pypy/module/cppyy/src/reflexcwrapper.cxx
@@ -24,7 +24,12 @@
 /* name to handle --------------------------------------------------------- */
 cppyy_typehandle_t cppyy_get_typehandle(const char* class_name) {
     Reflex::Scope s = Reflex::Scope::ByName(class_name);
-    return Reflex::Scope::ByName(class_name).Id();
+    return s.Id();
+}
+
+cppyy_typehandle_t cppyy_get_templatehandle(const char* template_name) {
+   Reflex::TypeTemplate tt = Reflex::TypeTemplate::ByName(template_name);
+   return tt.Id();
 }
 
 
diff --git a/pypy/module/cppyy/test/test_stltypes.py b/pypy/module/cppyy/test/test_stltypes.py
--- a/pypy/module/cppyy/test/test_stltypes.py
+++ b/pypy/module/cppyy/test/test_stltypes.py
@@ -30,15 +30,21 @@
         import cppyy
 
         assert cppyy.gbl.std        is cppyy.gbl.std
-#        assert cppyy.gbl.std.vector is cppyy.gbl.std.vector
+        assert cppyy.gbl.std.vector is cppyy.gbl.std.vector
 
-        tv = getattr(cppyy.gbl.std,'vector<int>')
+        assert callable(cppyy.gbl.std.vector)
 
-        v = tv()
+        tv1 = getattr(cppyy.gbl.std,'vector<int>')
+        tv2 = cppyy.gbl.std.vector('int')
+
+        assert tv1 is tv2
+
+        v = tv1()
         for i in range(self.N):
             v.push_back(i)
             assert v.size() == i+1
 #           assert v[i] == i
 
-#        assert len(v) == self.N
+        assert v.size() == self.N
+#       assert len(v) == self.N
         v.destruct()


More information about the pypy-commit mailing list