Author: Wim Lavrijsen <[email protected]>
Branch: cppyy-packaging
Changeset: r94889:6f18d2274d2f
Date: 2018-07-25 23:32 -0700
http://bitbucket.org/pypy/pypy/changeset/6f18d2274d2f/
Log: support for multi-dimensional arrays of instances and further
refined template support
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
@@ -788,6 +788,7 @@
class TemplateOverloadMixin(object):
"""Mixin to instantiate templated methods/functions."""
+ _attrs_ = ['tmpl_args_w']
_mixin_ = True
def construct_template_args(self, w_tpArgs, args_w = None):
@@ -840,23 +841,37 @@
return cppol
def instantiate_and_call(self, name, args_w):
- # try to match with run-time instantiations
- for cppol in self.master.overloads.values():
- try:
- if not self.space.is_w(self.w_this, self.space.w_None):
- return self.space.call_obj_args(cppol, self.w_this,
Arguments(self.space, args_w))
- return self.space.call_args(cppol, Arguments(self.space,
args_w))
- except Exception:
- pass # completely ignore for now; have to see whether
errors become confusing
+ # existing cached instantiations
+ method = None
+ try:
+ if name[-1] == '>': # full templated name, so ensure explicit
+ method = self.master.overloads[name]
+ else:
+ # try to match with run-time instantiations
+ # TODO: logically, this could be used, but in practice, it's
proving to
+ # greedy ... maybe as a last resort?
+ #for cppol in self.master.overloads.values():
+ # try:
+ # if not self.space.is_w(self.w_this,
self.space.w_None):
+ # return self.space.call_obj_args(cppol,
self.w_this, Arguments(self.space, args_w))
+ # return self.space.call_args(cppol,
Arguments(self.space, args_w))
+ # except Exception:
+ # pass # completely ignore for now; have to see
whether errors become confusing
+ raise TypeError("pre-existing overloads failed")
+ except (KeyError, TypeError):
+ # if not known, try to deduce from argument types
+ w_types = self.space.newtuple([self.space.type(obj_w) for obj_w in
args_w])
+ proto = self.construct_template_args(w_types, args_w)
+ method = self.find_method_template(name, proto)
- # if all failed, then try to deduce from argument types
- w_types = self.space.newtuple([self.space.type(obj_w) for obj_w in
args_w])
- proto = self.construct_template_args(w_types, args_w)
- method = self.find_method_template(name, proto)
-
- # only cache result if the name retains the full template
- fullname = capi.c_method_full_name(self.space,
method.functions[0].cppmethod)
- if 0 <= fullname.rfind('>'):
+ # only cache result if the name retains the full template
+ # TODO: the problem is in part that c_method_full_name returns
incorrect names,
+ # e.g. when default template arguments are involved, so for now
use 'name' if it
+ # has the full templated name
+ if name[-1] == '>':
+ fullname = name
+ else:
+ fullname = capi.c_method_full_name(self.space,
method.functions[0].cppmethod)
try:
existing = self.master.overloads[fullname]
allf = existing.functions + method.functions
@@ -868,9 +883,10 @@
except KeyError:
self.master.overloads[fullname] = method
- if not self.space.is_w(self.w_this, self.space.w_None):
- return self.space.call_obj_args(method, self.w_this,
Arguments(self.space, args_w))
- return self.space.call_args(method, Arguments(self.space, args_w))
+ if method is not None:
+ if not self.space.is_w(self.w_this, self.space.w_None):
+ return self.space.call_obj_args(method, self.w_this,
Arguments(self.space, args_w))
+ return self.space.call_args(method, Arguments(self.space, args_w))
def getitem_impl(self, name, args_w):
space = self.space
@@ -884,14 +900,9 @@
fullname = name+'<'+tmpl_args+'>'
try:
method = self.master.overloads[fullname]
- except KeyError:
- method = self.find_method_template(fullname)
- # cache result (name is always full templated name)
- self.master.overloads[fullname] = method
- # also cache on "official" name (may include default template
arguments)
- c_fullname = capi.c_method_full_name(self.space,
method.functions[0].cppmethod)
- if c_fullname != fullname:
- self.master.overloads[c_fullname] = method
+ except KeyError as e:
+ # defer instantiation until arguments are known
+ return self.clone(tmpl_args)
return method.descr_get(self.w_this, None)
@@ -900,21 +911,29 @@
"""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', 'w_this']
- _immutable_fields_ = ['name']
+ _attrs_ = ['name', 'tmpl_args', 'overloads', 'master', 'w_this']
+ _immutable_fields_ = ['name', 'tmpl_args']
- def __init__(self, space, name, decl_scope, functions, flags =
OVERLOAD_FLAGS_USE_FFI):
+ def __init__(self, space, name, tmpl_args, decl_scope, functions, flags =
OVERLOAD_FLAGS_USE_FFI):
W_CPPOverload.__init__(self, space, decl_scope, functions, flags)
self.name = name
+ self.tmpl_args = tmpl_args
self.overloads = {}
self.master = self
self.w_this = space.w_None
+ def clone(self, tmpl_args):
+ other = W_CPPTemplateOverload(self.space, self.name, tmpl_args,
self.scope, self.functions, self.flags)
+ other.overloads = self.overloads
+ other.master = self.master
+ other.w_this = self.w_this
+ return other
+
def descr_get(self, w_cppinstance, w_cls=None):
# TODO: don't return copy, but bind in an external object (like
W_CPPOverload)
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_CPPTemplateOverload(self.space, self.name, self.tmpl_args,
self.scope, self.functions, self.flags)
cppol.w_this = w_cppinstance
cppol.master = self.master
return cppol # bound
@@ -924,13 +943,18 @@
# 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
+ # do explicit lookup with tmpl_args if given
try:
- return W_CPPOverload.call_args(self, [self.w_this]+args_w)
+ fullname = self.name
+ if self.tmpl_args is not None:
+ fullname = fullname+'<'+self.tmpl_args+'>'
+ return self.instantiate_and_call(fullname, args_w)
except Exception:
pass
- return self.instantiate_and_call(self.name, args_w)
+ # otherwise, try existing overloads or compile-time instantiations
+ # TODO: consolidate errors
+ return W_CPPOverload.call_args(self, [self.w_this]+args_w)
@unwrap_spec(args_w='args_w')
def getitem(self, args_w):
@@ -958,22 +982,30 @@
"""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', 'w_this']
- _immutable_fields_ = ['name']
+ _attrs_ = ['name', 'tmpl_args', 'overloads', 'master', 'w_this']
+ _immutable_fields_ = ['name', 'tmpl_args']
- def __init__(self, space, name, decl_scope, funcs, flags =
OVERLOAD_FLAGS_USE_FFI):
+ def __init__(self, space, name, tmpl_args, decl_scope, funcs, flags =
OVERLOAD_FLAGS_USE_FFI):
W_CPPStaticOverload.__init__(self, space, decl_scope, funcs, flags)
self.name = name
+ self.tmpl_args = tmpl_args
self.overloads = {}
self.master = self
self.w_this = space.w_None
+ def clone(self, tmpl_args):
+ other = W_CPPTemplateOverload(self.space, self.name, tmpl_args,
self.scope, self.functions, self.flags)
+ other.overloads = self.overloads
+ other.master = self.master
+ other.w_this = self.w_this
+ return other
+
def descr_get(self, w_cppinstance, w_cls=None):
# TODO: don't return copy, but bind in an external object (like
W_CPPOverload)
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_CPPTemplateStaticOverload(self.space, self.name,
self.tmpl_args, self.scope, self.functions, self.flags)
cppol.w_this = w_cppinstance
cppol.master = self.master
return cppol # bound
@@ -983,15 +1015,20 @@
def call_args(self, args_w):
# direct call: either pick non-templated overload or attempt to deduce
# the template instantiation from the argument types
+ # TODO: refactor with W_CPPTemplateOverload
- # try existing overloads or compile-time instantiations
+ # do explicit lookup with tmpl_args if given
try:
- return W_CPPStaticOverload.call_args(self, args_w)
+ fullname = self.name
+ if self.tmpl_args is not None:
+ fullname = fullname+'<'+self.tmpl_args+'>'
+ return self.instantiate_and_call(fullname, args_w)
except Exception:
pass
- # try new instantiation
- return self.instantiate_and_call(self.name, args_w)
+ # otherwise, try existing overloads or compile-time instantiations
+ # TODO: consolidate errors
+ return W_CPPStaticOverload.call_args(self, args_w)
@unwrap_spec(args_w='args_w')
def getitem(self, args_w):
@@ -1036,10 +1073,10 @@
_attrs_ = ['space', 'scope', 'converter', 'offset']
_immutable_fields = ['scope', 'converter', 'offset']
- def __init__(self, space, decl_scope, type_name, offset):
+ def __init__(self, space, decl_scope, type_name, dimensions, offset):
self.space = space
self.scope = decl_scope
- self.converter = converter.get_converter(self.space, type_name, '')
+ self.converter = converter.get_converter(self.space, type_name,
dimensions)
self.offset = rffi.cast(rffi.LONG, offset)
def _get_offset(self, cppinstance):
@@ -1184,6 +1221,15 @@
self.datamembers[name] = new_dm
return new_dm
+ def _encode_dm_dimensions(self, idata):
+ # encode dimensions (TODO: this is ugly, but here's where the info is)
+ dims = []
+ sz = capi.c_get_dimension_size(self.space, self, idata, len(dims))
+ while 0 < sz:
+ dims.append(str(sz))
+ sz = capi.c_get_dimension_size(self.space, self, idata, len(dims))
+ return ':'.join(dims)
+
@unwrap_spec(name='text', signature='text')
def scope__dispatch__(self, name, signature):
overload = self.get_overload(name)
@@ -1226,10 +1272,11 @@
offset = capi.c_datamember_offset(self.space, self, dm_idx)
if offset == -1:
raise self.missing_attribute_error(dm_name)
+ dims = self._encode_dm_dimensions(dm_idx)
if capi.c_is_const_data(self.space, self, dm_idx):
- datamember = W_CPPConstStaticData(self.space, self, type_name,
offset)
+ datamember = W_CPPConstStaticData(self.space, self, type_name,
dims, offset)
else:
- datamember = W_CPPStaticData(self.space, self, type_name, offset)
+ datamember = W_CPPStaticData(self.space, self, type_name, dims,
offset)
self.datamembers[dm_name] = datamember
return datamember
@@ -1244,10 +1291,10 @@
if capi.c_method_is_template(self.space, self, idx):
templated = True
if templated:
- return W_CPPTemplateStaticOverload(self.space, meth_name,
self, cppfunctions[:])
+ return W_CPPTemplateStaticOverload(self.space, meth_name,
None, self, cppfunctions[:])
return W_CPPStaticOverload(self.space, self, cppfunctions[:])
elif capi.c_exists_method_template(self.space, self, meth_name):
- return W_CPPTemplateStaticOverload(self.space, meth_name, self, [])
+ return W_CPPTemplateStaticOverload(self.space, meth_name, None,
self, [])
raise self.missing_attribute_error(meth_name)
def find_datamember(self, dm_name):
@@ -1339,12 +1386,12 @@
elif ftype & FUNCTION_IS_STATIC:
if ftype & FUNCTION_IS_TEMPLATE:
cppname = capi.c_method_name(self.space,
methods[0].cppmethod)
- overload = W_CPPTemplateStaticOverload(self.space,
cppname, self, methods[:])
+ overload = W_CPPTemplateStaticOverload(self.space,
cppname, None, self, methods[:])
else:
overload = W_CPPStaticOverload(self.space, self,
methods[:])
elif ftype & FUNCTION_IS_TEMPLATE:
cppname = capi.c_method_name(self.space, methods[0].cppmethod)
- overload = W_CPPTemplateOverload(self.space, cppname, self,
methods[:])
+ overload = W_CPPTemplateOverload(self.space, cppname, None,
self, methods[:])
else:
overload = W_CPPOverload(self.space, self, methods[:])
self.overloads[pyname] = overload
@@ -1384,14 +1431,15 @@
continue # dictionary problem; raises AttributeError on
use
is_static = bool(capi.c_is_staticdata(self.space, self, i))
is_const = bool(capi.c_is_const_data(self.space, self, i))
+ dims = self._encode_dm_dimensions(i)
if is_static and is_const:
- datamember = W_CPPConstStaticData(self.space, self, type_name,
offset)
+ datamember = W_CPPConstStaticData(self.space, self, type_name,
dims, offset)
elif is_static:
- datamember = W_CPPStaticData(self.space, self, type_name,
offset)
+ datamember = W_CPPStaticData(self.space, self, type_name,
dims, offset)
elif is_const:
- datamember = W_CPPConstDataMember(self.space, self, type_name,
offset)
+ datamember = W_CPPConstDataMember(self.space, self, type_name,
dims, offset)
else:
- datamember = W_CPPDataMember(self.space, self, type_name,
offset)
+ datamember = W_CPPDataMember(self.space, self, type_name,
dims, offset)
self.datamembers[datamember_name] = datamember
def find_overload(self, meth_name):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit