[pypy-commit] pypy cppyy-packaging: further template function use cases

wlav pypy.commits at gmail.com
Sat Jun 9 20:01:39 EDT 2018


Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: cppyy-packaging
Changeset: r94746:6e179cce7824
Date: 2018-06-09 16:42 -0700
http://bitbucket.org/pypy/pypy/changeset/6e179cce7824/

Log:	further template function use cases

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
@@ -162,10 +162,11 @@
 #   - overloads: user-facing collections of overloaded functions
 #   - wrappers: internal holders of the individual C++ methods
 #
-#  W_CPPOverload:             instance methods (base class)
-#  W_CPPConstructorOverload:  constructors
-#  W_CPPStaticOverload:       free and static functions
-#  W_CPPTemplateOverload:     templated methods/functions
+#  W_CPPOverload:                 instance methods (base class)
+#  W_CPPConstructorOverload:      constructors
+#  W_CPPStaticOverload:           free and static functions
+#  W_CPPTemplateOverload:         templated methods
+#  W_CPPTemplateStaticOveload:    templated free and static functions
 #
 #  CPPMethod:         a single function or method (base class)
 #  CPPSetItem:        specialization for Python's __setitem__
@@ -666,18 +667,10 @@
 )
 
 
-class W_CPPTemplateOverload(W_CPPOverload):
-    """App-level dispatcher to allow both lookup/instantiation of templated methods and
-    dispatch among overloads between templated and non-templated overloads."""
+class TemplateOverloadMixin(object):
+    """Mixin to instantiate templated methods/functions."""
 
-    _attrs_ = ['name', 'overloads', 'master']
-    _immutable_fields_ = ['name']
-
-    def __init__(self, space, name, declaring_scope, functions, flags = OVERLOAD_FLAGS_USE_FFI):
-         W_CPPOverload.__init__(self, space, declaring_scope, functions, flags)
-         self.name = name
-         self.overloads = {}
-         self.master = self
+    _mixin_ = True
 
     def construct_template_args(self, w_args):
         space = self.space
@@ -719,19 +712,8 @@
             cppol = W_CPPOverload(space, self.scope, funcs[:], self.flags)
         return cppol
 
-    @unwrap_spec(args_w='args_w')
-    def descr_get(self, w_cppinstance, args_w):
-        if self.space.is_w(w_cppinstance, self.space.w_None):
-            return self  # unbound
-        cppol = W_CPPTemplateOverload(self.space, self.name, self.scope, self.functions, self.flags)
-        cppol.w_this = w_cppinstance
-        cppol.master = self.master
-        return cppol     # bound
-
-    @unwrap_spec(args_w='args_w')
-    def call(self, args_w):
-        # direct call means attempt to deduce types ourselves
-        # first, try to match with existing methods
+    def instantiation_from_args(self, args_w):
+        # try to match with run-time instantiations
         for cppol in self.master.overloads.values():
             try:
                 cppol.descr_get(self.w_this, []).call(args_w)
@@ -772,6 +754,42 @@
 
         return method.descr_get(self.w_this, [])
 
+
+class W_CPPTemplateOverload(W_CPPOverload, TemplateOverloadMixin):
+    """App-level dispatcher to allow both lookup/instantiation of templated methods and
+    dispatch among overloads between templated and non-templated method."""
+
+    _attrs_ = ['name', 'overloads', 'master']
+    _immutable_fields_ = ['name']
+
+    def __init__(self, space, name, declaring_scope, functions, flags = OVERLOAD_FLAGS_USE_FFI):
+         W_CPPOverload.__init__(self, space, declaring_scope, functions, flags)
+         self.name = name
+         self.overloads = {}
+         self.master = self
+
+    @unwrap_spec(args_w='args_w')
+    def descr_get(self, w_cppinstance, args_w):
+        # like W_CPPOverload, but returns W_CPPTemplateOverload
+        if self.space.is_w(w_cppinstance, self.space.w_None):
+            return self  # unbound, so no new instance needed
+        cppol = W_CPPTemplateOverload(self.space, self.name, self.scope, self.functions, self.flags)
+        cppol.w_this = w_cppinstance
+        return cppol     # bound
+
+    @unwrap_spec(args_w='args_w')
+    def call(self, args_w):
+        # direct call: either pick non-templated overload or attempt to deduce
+        # the template instantiation from the argument types
+
+        # try existing overloads or compile-time instantiations
+        try:
+            return W_CPPOverload.call(self, args_w)
+        except Exception:
+            pass
+
+        return self.instantiation_from_args(args_w)
+
     def __repr__(self):
         return "W_CPPTemplateOverload(%s)" % [f.prototype() for f in self.functions]
 
@@ -784,6 +802,57 @@
     __doc__     = GetSetProperty(W_CPPTemplateOverload.fget_doc)
 )
 
+class W_CPPTemplateStaticOverload(W_CPPStaticOverload, TemplateOverloadMixin):
+    """App-level dispatcher to allow both lookup/instantiation of templated methods and
+    dispatch among overloads between templated and non-templated method."""
+
+    _attrs_ = ['name', 'overloads', 'master']
+    _immutable_fields_ = ['name']
+
+    def __init__(self, space, name, declaring_scope, functions, flags = OVERLOAD_FLAGS_USE_FFI):
+         W_CPPStaticOverload.__init__(self, space, declaring_scope, functions, flags)
+         self.name = name
+         self.overloads = {}
+         self.master = self
+
+    @unwrap_spec(args_w='args_w')
+    def descr_get(self, w_cppinstance, args_w):
+        # like W_CPPStaticOverload, but returns W_CPPTemplateStaticOverload
+        if isinstance(w_cppinstance, W_CPPInstance):
+            cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance)
+            if cppinstance.clsdecl.handle != self.scope.handle:
+                cppol = W_CPPTemplateStaticOverload(self.space, self.name, self.scope, self.functions, self.flags)
+                cppol.w_this = w_cppinstance
+                cppol.master = self.master
+                return cppol       # bound
+        return self      # unbound
+
+    @unwrap_spec(args_w='args_w')
+    def call(self, args_w):
+        # direct call: either pick non-templated overload or attempt to deduce
+        # the template instantiation from the argument types
+
+        # try existing overloads or compile-time instantiations
+        try:
+            return W_CPPStaticOverload.call(self, args_w)
+        except Exception:
+            pass
+
+        # try new instantiation
+        return self.instantiation_from_args(args_w)
+
+    def __repr__(self):
+        return "W_CPPTemplateStaticOverload(%s)" % [f.prototype() for f in self.functions]
+
+W_CPPTemplateStaticOverload.typedef = TypeDef(
+    'CPPTemplateStaticOverload',
+    __get__     = interp2app(W_CPPTemplateStaticOverload.descr_get),
+    __getitem__ = interp2app(W_CPPTemplateStaticOverload.getitem),
+    __call__    = interp2app(W_CPPTemplateStaticOverload.call),
+    __useffi__  = GetSetProperty(W_CPPTemplateStaticOverload.fget_useffi, W_CPPTemplateStaticOverload.fset_useffi),
+    __doc__     = GetSetProperty(W_CPPTemplateStaticOverload.fget_doc)
+)
+
 
 #-----
 # Classes for data members:
@@ -1006,10 +1075,10 @@
                 if capi.c_method_is_template(self.space, self, idx):
                     templated = True
             if templated:
-                return W_CPPTemplateOverload(self.space, meth_name, self, cppfunctions[:])
+                return W_CPPTemplateStaticOverload(self.space, meth_name, self, cppfunctions[:])
             return W_CPPStaticOverload(self.space, self, cppfunctions[:])
         elif capi.c_exists_method_template(self.space, self, meth_name):
-            return W_CPPTemplateOverload(self.space, meth_name, self, [])
+            return W_CPPTemplateStaticOverload(self.space, meth_name, self, [])
         raise self.missing_attribute_error(meth_name)
 
     def find_datamember(self, dm_name):
@@ -1092,9 +1161,14 @@
             if ftype & FUNCTION_IS_CONSTRUCTOR:
                 overload = W_CPPConstructorOverload(self.space, self, methods[:])
             elif ftype & FUNCTION_IS_STATIC:
-                overload = W_CPPStaticOverload(self.space, self, methods[:])
+                if ftype & FUNCTION_IS_TEMPLATE:
+                    cppname = capi.c_method_name(self.space, methods[0].cppmethod)
+                    overload = W_CPPTemplateStaticOverload(self.space, cppname, self, methods[:])
+                else:
+                    overload = W_CPPStaticOverload(self.space, self, methods[:])
             elif ftype & FUNCTION_IS_TEMPLATE:
-                overload = W_CPPTemplateOverload(self.space, pyname, self, methods[:])
+                cppname = capi.c_method_name(self.space, methods[0].cppmethod)
+                overload = W_CPPTemplateOverload(self.space, cppname, self, methods[:])
             else:
                 overload = W_CPPOverload(self.space, self, methods[:])
             self.overloads[pyname] = overload
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
@@ -8,9 +8,9 @@
 # the interp-level does not support metaclasses, they are created at app-level.
 # These are the metaclass base classes:
 class CPPScope(type):
-    def __getattr__(self, name, type_only=False):
+    def __getattr__(self, name):
         try:
-            return get_scoped_pycppitem(self, name, type_only)  # will cache on self
+            return get_scoped_pycppitem(self, name)  # will cache on self
         except Exception as e:
             raise AttributeError("%s object has no attribute '%s' (details: %s)" %
                                  (self, name, str(e)))
@@ -53,10 +53,13 @@
             [self._name, '<', ','.join(map(self._arg_to_str, args))])
         fullname += '>'
         try:
-            return getattr(self._scope, fullname, True)
-        except AttributeError:
+            return self._scope.__dict__[fullname]
+        except KeyError:
             pass
-        raise TypeError("%s does not exist" % fullname)
+        result = get_scoped_pycppitem(self._scope, fullname, True)
+        if not result:
+            raise TypeError("%s does not exist" % fullname)
+        return result
 
     def __getitem__(self, *args):
         if args and type(args[0]) == tuple:


More information about the pypy-commit mailing list