Author: Wim Lavrijsen <[email protected]>
Branch: cppyy-packaging
Changeset: r94737:264a0794b659
Date: 2018-06-07 08:40 -0700
http://bitbucket.org/pypy/pypy/changeset/264a0794b659/
Log: reduce layers in method dispatch for simplicity, performance, and
support of templated methods (this requires backend 1.1.0)
diff --git a/pypy/module/_cppyy/capi/loadable_capi.py
b/pypy/module/_cppyy/capi/loadable_capi.py
--- a/pypy/module/_cppyy/capi/loadable_capi.py
+++ b/pypy/module/_cppyy/capi/loadable_capi.py
@@ -88,7 +88,7 @@
assert obj._voidp != rffi.cast(rffi.VOIDP, 0)
data = rffi.cast(rffi.VOIDPP, data)
data[0] = obj._voidp
- else: # only other use is sring
+ else: # only other use is string
assert obj.tc == 's'
n = len(obj._string)
assert raw_string == rffi.cast(rffi.CCHARP, 0)
@@ -183,8 +183,7 @@
'constructor' : ([c_method, c_object, c_int, c_voidp],
c_object),
'call_o' : ([c_method, c_object, c_int, c_voidp, c_type],
c_object),
- 'function_address_from_index' : ([c_scope, c_index],
c_voidp), # TODO: verify
- 'function_address_from_method' : ([c_method],
c_voidp), # id.
+ 'function_address' : ([c_method],
c_voidp), # TODO: verify
# handling of function argument buffer
'allocate_function_args' : ([c_int], c_voidp),
@@ -216,30 +215,30 @@
'num_methods' : ([c_scope], c_int),
'method_indices_from_name' : ([c_scope, c_ccharp],
c_index_array),
- 'method_name' : ([c_scope, c_index],
c_ccharp),
- 'method_mangled_name' : ([c_scope, c_index],
c_ccharp),
- 'method_result_type' : ([c_scope, c_index],
c_ccharp),
- 'method_num_args' : ([c_scope, c_index], c_int),
- 'method_req_args' : ([c_scope, c_index], c_int),
- 'method_arg_type' : ([c_scope, c_index, c_int],
c_ccharp),
- 'method_arg_default' : ([c_scope, c_index, c_int],
c_ccharp),
- 'method_signature' : ([c_scope, c_index, c_int],
c_ccharp),
- 'method_prototype' : ([c_scope, c_index, c_int],
c_ccharp),
+ 'get_method' : ([c_scope, c_index],
c_method),
+
+ 'method_name' : ([c_method],
c_ccharp),
+ 'method_mangled_name' : ([c_method],
c_ccharp),
+ 'method_result_type' : ([c_method],
c_ccharp),
+ 'method_num_args' : ([c_method], c_int),
+ 'method_req_args' : ([c_method], c_int),
+ 'method_arg_type' : ([c_method, c_int],
c_ccharp),
+ 'method_arg_default' : ([c_method, c_int],
c_ccharp),
+ 'method_signature' : ([c_method, c_int],
c_ccharp),
+ 'method_prototype' : ([c_scope, c_method, c_int],
c_ccharp),
'is_const_method' : ([c_method], c_int),
'exists_method_template' : ([c_scope, c_ccharp], c_int),
'method_is_template' : ([c_scope, c_index], c_int),
- 'method_num_template_args' : ([c_scope, c_index], c_int),
- 'method_template_arg_name' : ([c_scope, c_index, c_index],
c_ccharp),
+ 'get_method_template' : ([c_scope, c_ccharp, c_ccharp],
c_method),
- 'get_method' : ([c_scope, c_index],
c_method),
'get_global_operator' : ([c_scope, c_scope, c_scope,
c_ccharp], c_index),
# method properties
- 'is_public_method' : ([c_type, c_index], c_int),
- 'is_constructor' : ([c_type, c_index], c_int),
- 'is_destructor' : ([c_type, c_index], c_int),
- 'is_staticmethod' : ([c_type, c_index], c_int),
+ 'is_public_method' : ([c_method], c_int),
+ 'is_constructor' : ([c_method], c_int),
+ 'is_destructor' : ([c_method], c_int),
+ 'is_staticmethod' : ([c_method], c_int),
# data member reflection information
'num_datamembers' : ([c_scope], c_int),
@@ -417,13 +416,9 @@
args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs),
_ArgH(cppclass.handle)]
return _cdata_to_cobject(space, call_capi(space, 'call_o', args))
-def c_function_address_from_index(space, cppscope, index):
- args = [_ArgH(cppscope.handle), _ArgL(index)]
+def c_function_address(space, cppmethod):
return rffi.cast(C_FUNC_PTR,
- _cdata_to_ptr(space, call_capi(space, 'function_address_from_index',
args)))
-def c_function_address_from_method(space, cppmethod):
- return rffi.cast(C_FUNC_PTR,
- _cdata_to_ptr(space, call_capi(space, 'function_address_from_method',
[_ArgH(cppmethod)])))
+ _cdata_to_ptr(space, call_capi(space, 'function_address',
[_ArgH(cppmethod)])))
# handling of function argument buffer ---------------------------------------
def c_allocate_function_args(space, size):
@@ -527,30 +522,34 @@
c_free(space, rffi.cast(rffi.VOIDP, indices)) # c_free defined below
return py_indices
-def c_method_name(space, cppscope, index):
+def c_get_method(space, cppscope, index):
args = [_ArgH(cppscope.handle), _ArgL(index)]
- return charp2str_free(space, call_capi(space, 'method_name', args))
-def c_method_result_type(space, cppscope, index):
- args = [_ArgH(cppscope.handle), _ArgL(index)]
- return charp2str_free(space, call_capi(space, 'method_result_type', args))
-def c_method_num_args(space, cppscope, index):
- args = [_ArgH(cppscope.handle), _ArgL(index)]
- return space.int_w(call_capi(space, 'method_num_args', args))
-def c_method_req_args(space, cppscope, index):
- args = [_ArgH(cppscope.handle), _ArgL(index)]
- return space.int_w(call_capi(space, 'method_req_args', args))
-def c_method_arg_type(space, cppscope, index, arg_index):
- args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(arg_index)]
+ return rffi.cast(C_METHOD, space.uint_w(call_capi(space, 'get_method',
args)))
+
+def c_method_name(space, cppmeth):
+ return charp2str_free(space, call_capi(space, 'method_name',
[_ArgH(cppmeth)]))
+def c_method_mangled_name(space, cppmeth):
+ return charp2str_free(space, call_capi(space, 'method_mangled_name',
[_ArgH(cppmeth)]))
+def c_method_result_type(space, cppmeth):
+ return charp2str_free(space, call_capi(space, 'method_result_type',
[_ArgH(cppmeth)]))
+def c_method_num_args(space, cppmeth):
+ return space.int_w(call_capi(space, 'method_num_args', [_ArgH(cppmeth)]))
+def c_method_req_args(space, cppmeth):
+ return space.int_w(call_capi(space, 'method_req_args', [_ArgH(cppmeth)]))
+def c_method_arg_type(space, cppmeth, arg_index):
+ args = [_ArgH(cppmeth), _ArgL(arg_index)]
return charp2str_free(space, call_capi(space, 'method_arg_type', args))
-def c_method_arg_default(space, cppscope, index, arg_index):
- args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(arg_index)]
+def c_method_arg_default(space, cppmeth, arg_index):
+ args = [_ArgH(cppmeth), _ArgL(arg_index)]
return charp2str_free(space, call_capi(space, 'method_arg_default', args))
-def c_method_signature(space, cppscope, index, show_formalargs=True):
- args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(show_formalargs)]
+def c_method_signature(space, cppmeth, show_formalargs=True):
+ args = [_ArgH(cppmeth), _ArgL(show_formalargs)]
return charp2str_free(space, call_capi(space, 'method_signature', args))
-def c_method_prototype(space, cppscope, index, show_formalargs=True):
- args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(show_formalargs)]
+def c_method_prototype(space, cppscope, cppmeth, show_formalargs=True):
+ args = [_ArgH(cppscope.handle), _ArgH(cppmeth), _ArgL(show_formalargs)]
return charp2str_free(space, call_capi(space, 'method_prototype', args))
+def c_is_const_method(space, cppmeth):
+ return space.bool_w(call_capi(space, 'is_const_method', [_ArgH(cppmeth)]))
def c_exists_method_template(space, cppscope, name):
args = [_ArgH(cppscope.handle), _ArgS(name)]
@@ -558,21 +557,10 @@
def c_method_is_template(space, cppscope, index):
args = [_ArgH(cppscope.handle), _ArgL(index)]
return space.bool_w(call_capi(space, 'method_is_template', args))
-def _c_method_num_template_args(space, cppscope, index):
- args = [_ArgH(cppscope.handle), _ArgL(index)]
- return space.int_w(call_capi(space, 'method_num_template_args', args))
-def c_template_args(space, cppscope, index):
- nargs = _c_method_num_template_args(space, cppscope, index)
- arg1 = _ArgH(cppscope.handle)
- arg2 = _ArgL(index)
- args = [c_resolve_name(space, charp2str_free(space,
- call_capi(space, 'method_template_arg_name', [arg1, arg2,
_ArgL(iarg)]))
- ) for iarg in range(nargs)]
- return args
-def c_get_method(space, cppscope, index):
- args = [_ArgH(cppscope.handle), _ArgL(index)]
- return rffi.cast(C_METHOD, space.uint_w(call_capi(space, 'get_method',
args)))
+def c_get_method_template(space, cppscope, name):
+ args = [_ArgH(cppscope.handle), _ArgS(name)]
+ return rffi.cast(C_METHOD, space.uint_w(call_capi(space,
'get_method_template', args)))
def c_get_global_operator(space, nss, lc, rc, op):
if nss is not None:
args = [_ArgH(nss.handle), _ArgH(lc.handle), _ArgH(rc.handle),
_ArgS(op)]
@@ -580,18 +568,14 @@
return rffi.cast(WLAVC_INDEX, -1)
# method properties ----------------------------------------------------------
-def c_is_public_method(space, cppclass, index):
- args = [_ArgH(cppclass.handle), _ArgL(index)]
- return space.bool_w(call_capi(space, 'is_public_method', args))
-def c_is_constructor(space, cppclass, index):
- args = [_ArgH(cppclass.handle), _ArgL(index)]
- return space.bool_w(call_capi(space, 'is_constructor', args))
-def c_is_destructor(space, cppclass, index):
- args = [_ArgH(cppclass.handle), _ArgL(index)]
- return space.bool_w(call_capi(space, 'is_destructor', args))
-def c_is_staticmethod(space, cppclass, index):
- args = [_ArgH(cppclass.handle), _ArgL(index)]
- return space.bool_w(call_capi(space, 'is_staticmethod', args))
+def c_is_public_method(space, cppmeth):
+ return space.bool_w(call_capi(space, 'is_public_method', [_ArgH(cppmeth)]))
+def c_is_constructor(space, cppmeth):
+ return space.bool_w(call_capi(space, 'is_constructor', [_ArgH(cppmeth)]))
+def c_is_destructor(space, cppmeth):
+ return space.bool_w(call_capi(space, 'is_destructor', [_ArgH(cppmeth)]))
+def c_is_staticmethod(space, cppmeth):
+ return space.bool_w(call_capi(space, 'is_staticmethod', [_ArgH(cppmeth)]))
# data member reflection information -----------------------------------------
def c_num_datamembers(space, cppscope):
diff --git a/pypy/module/_cppyy/converter.py b/pypy/module/_cppyy/converter.py
--- a/pypy/module/_cppyy/converter.py
+++ b/pypy/module/_cppyy/converter.py
@@ -69,8 +69,8 @@
# array type
try:
arr = space.interp_w(W_ArrayInstance, w_obj, can_be_None=True)
- if arr:
- return rffi.cast(rffi.VOIDP, space.uint_w(arr.getbuffer(space)))
+ #if arr:
+ #return rffi.cast(rffi.VOIDP, space.uint_w(arr.getbuffer(space)))
except Exception:
pass
# pre-defined nullptr
@@ -384,7 +384,7 @@
arg = space.text_w(w_obj)
x[0] = rffi.cast(rffi.LONG, rffi.str2charp(arg))
ba = rffi.cast(rffi.CCHARP, address)
- ba[capi.c_function_arg_typeoffset(space)] = 'o'
+ ba[capi.c_function_arg_typeoffset(space)] = 'p'
def from_memory(self, space, w_obj, w_pycppclass, offset):
address = self._get_raw_address(space, w_obj, offset)
@@ -500,7 +500,7 @@
obj_address = capi.direct_ptradd(rawobject, offset)
return rffi.cast(capi.C_OBJECT, obj_address)
raise oefmt(space.w_TypeError,
- "cannot pass %T as %s", w_obj, self.clsdecl.name)
+ "cannot pass %T instance as %s", w_obj, self.clsdecl.name)
def cffi_type(self, space):
state = space.fromcache(ffitypes.State)
@@ -615,8 +615,7 @@
address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space,
w_obj, offset))
assign = self.clsdecl.get_overload("__assign__")
from pypy.module._cppyy import interp_cppyy
- assign.call(
- interp_cppyy.wrap_cppinstance(space, address, self.clsdecl,
do_cast=False), [w_value])
+ assign.call_impl(address, [w_value])
except Exception:
InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
@@ -687,8 +686,7 @@
m = cppol.functions[i]
if m.signature(False) == self.signature:
x = rffi.cast(rffi.VOIDPP, address)
- x[0] = rffi.cast(rffi.VOIDP,
- capi.c_function_address_from_method(space, m.cppmethod))
+ x[0] = rffi.cast(rffi.VOIDP, capi.c_function_address(space,
m.cppmethod))
address = rffi.cast(capi.C_OBJECT, address)
ba = rffi.cast(rffi.CCHARP, address)
ba[capi.c_function_arg_typeoffset(space)] = 'p'
@@ -731,7 +729,7 @@
return rffi.cast(capi.C_OBJECT, obj_address)
raise oefmt(space.w_TypeError,
- "cannot pass %T as %s", w_obj, self.clsdecl.name)
+ "cannot pass %T instance as %s", w_obj, self.rawdecl.name)
def convert_argument(self, space, w_obj, address, call_local):
x = rffi.cast(rffi.VOIDPP, address)
@@ -799,6 +797,8 @@
try:
# array_index may be negative to indicate no size or no size found
array_size = helper.array_size(_name) # uses original arg
+ # TODO: using clean_name here drops const (e.g. const char[] will
+ # never be seen this way)
return _a_converters[clean_name+compound](space, array_size)
except KeyError:
pass
@@ -971,6 +971,7 @@
# special case, const char* w/ size and w/o '\0'
_a_converters["const char[]"] = CStringConverterWithSize
+ _a_converters["char[]"] = _a_converters["const char[]"] #
debatable
_build_array_converters()
diff --git a/pypy/module/_cppyy/include/capi.h
b/pypy/module/_cppyy/include/capi.h
--- a/pypy/module/_cppyy/include/capi.h
+++ b/pypy/module/_cppyy/include/capi.h
@@ -76,9 +76,7 @@
cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self,
int nargs, void* args, cppyy_type_t result_type);
RPY_EXTERN
- cppyy_funcaddr_t cppyy_function_address_from_index(cppyy_scope_t scope,
cppyy_index_t idx);
- RPY_EXTERN
- cppyy_funcaddr_t cppyy_function_address_from_method(cppyy_method_t method);
+ cppyy_funcaddr_t cppyy_function_address(cppyy_method_t method);
/* handling of function argument buffer
----------------------------------- */
RPY_EXTERN
@@ -132,23 +130,26 @@
cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t scope, const
char* name);
RPY_EXTERN
- char* cppyy_method_name(cppyy_scope_t scope, cppyy_index_t idx);
+ cppyy_method_t cppyy_get_method(cppyy_scope_t scope, cppyy_index_t idx);
+
RPY_EXTERN
- char* cppyy_method_mangled_name(cppyy_scope_t scope, cppyy_index_t idx);
+ char* cppyy_method_name(cppyy_method_t);
RPY_EXTERN
- char* cppyy_method_result_type(cppyy_scope_t scope, cppyy_index_t idx);
+ char* cppyy_method_mangled_name(cppyy_method_t);
RPY_EXTERN
- int cppyy_method_num_args(cppyy_scope_t scope, cppyy_index_t idx);
+ char* cppyy_method_result_type(cppyy_method_t);
RPY_EXTERN
- int cppyy_method_req_args(cppyy_scope_t scope, cppyy_index_t idx);
+ int cppyy_method_num_args(cppyy_method_t);
RPY_EXTERN
- char* cppyy_method_arg_type(cppyy_scope_t scope, cppyy_index_t idx, int
arg_index);
+ int cppyy_method_req_args(cppyy_method_t);
RPY_EXTERN
- char* cppyy_method_arg_default(cppyy_scope_t scope, cppyy_index_t idx, int
arg_index);
+ char* cppyy_method_arg_type(cppyy_method_t, int arg_index);
RPY_EXTERN
- char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx, int
show_formalargs);
+ char* cppyy_method_arg_default(cppyy_method_t, int arg_index);
RPY_EXTERN
- char* cppyy_method_prototype(cppyy_scope_t scope, cppyy_index_t idx, int
show_formalargs);
+ char* cppyy_method_signature(cppyy_method_t, int show_formalargs);
+ RPY_EXTERN
+ char* cppyy_method_prototype(cppyy_scope_t scope, cppyy_method_t idx, int
show_formalargs);
RPY_EXTERN
int cppyy_is_const_method(cppyy_method_t);
@@ -157,25 +158,21 @@
RPY_EXTERN
int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx);
RPY_EXTERN
- int cppyy_method_num_template_args(cppyy_scope_t scope, cppyy_index_t idx);
- RPY_EXTERN
- char* cppyy_method_template_arg_name(cppyy_scope_t scope, cppyy_index_t
idx, cppyy_index_t iarg);
+ cppyy_method_t cppyy_get_method_template(cppyy_scope_t scope, const char*
name);
RPY_EXTERN
- cppyy_method_t cppyy_get_method(cppyy_scope_t scope, cppyy_index_t idx);
- RPY_EXTERN
cppyy_index_t cppyy_get_global_operator(
cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char*
op);
/* method properties
------------------------------------------------------ */
RPY_EXTERN
- int cppyy_is_publicmethod(cppyy_type_t type, cppyy_index_t idx);
+ int cppyy_is_publicmethod(cppyy_method_t);
RPY_EXTERN
- int cppyy_is_constructor(cppyy_type_t type, cppyy_index_t idx);
+ int cppyy_is_constructor(cppyy_method_t);
RPY_EXTERN
- int cppyy_is_destructor(cppyy_type_t type, cppyy_index_t idx);
+ int cppyy_is_destructor(cppyy_method_t);
RPY_EXTERN
- int cppyy_is_staticmethod(cppyy_type_t type, cppyy_index_t idx);
+ int cppyy_is_staticmethod(cppyy_method_t);
/* data member reflection information
------------------------------------- */
RPY_EXTERN
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
@@ -158,17 +158,17 @@
#-----
-# Classes involved with methods and functions:
+# Classes involved with methods and functions come at two levels:
+# - overloads: user-facing collections of overloaded functions
+# - wrappers: internal holders of the individual C++ methods
#
-# CPPMethod: base class wrapping a single function or method
-# CPPConstructor: specialization for allocating a new object
-# CPPFunction: specialization for free and static functions
+# W_CPPOverload: instance methods (base class)
+# W_CPPConstructorOverload: constructors
+# W_CPPStaticOverload: free and static functions
+# W_CPPTemplateOverload: templated methods/functions
+#
+# CPPMethod: a single function or method (base class)
# CPPSetItem: specialization for Python's __setitem__
-# CPPTemplateMethod: trampoline to instantiate and bind templated functions
-# W_CPPOverload, W_CPPConstructorOverload, W_CPPTemplateOverload:
-# user-facing, app-level, collection of overloads, with specializations
-# for constructors and templates
-# W_CPPBoundMethod: instantiated template method
#
# All methods/functions derive from CPPMethod and are collected as overload
# candidates in user-facing overload classes. Templated methods are a two-step
@@ -181,15 +181,15 @@
also takes care of offset casting and recycling of known objects through
the memory_regulator."""
- _attrs_ = ['space', 'scope', 'index', 'cppmethod', 'arg_defs',
'args_required',
+ _attrs_ = ['space', 'scope', 'cppmethod', 'arg_defs', 'args_required',
'converters', 'executor', '_funcaddr', 'cif_descr',
'uses_local']
- _immutable_ = True
+ _immutable_fields_ = ['scope', 'cppmethod', 'arg_defs', 'args_required',
+ 'converters', 'executor', 'uses_local']
- def __init__(self, space, declaring_scope, method_index, arg_defs,
args_required):
+ def __init__(self, space, declaring_scope, cppmethod, arg_defs,
args_required):
self.space = space
self.scope = declaring_scope
- self.index = method_index
- self.cppmethod = capi.c_get_method(self.space, self.scope,
method_index)
+ self.cppmethod = cppmethod
self.arg_defs = arg_defs
self.args_required = args_required
@@ -201,12 +201,6 @@
self._funcaddr = lltype.nullptr(capi.C_FUNC_PTR.TO)
self.uses_local = False
- @staticmethod
- def unpack_cppthis(space, w_cppinstance, declaring_scope):
- cppinstance = space.interp_w(W_CPPInstance, w_cppinstance)
- cppinstance._nullcheck()
- return cppinstance.get_cppthis(declaring_scope)
-
def _address_from_local_buffer(self, call_local, idx):
if not call_local:
return call_local
@@ -349,7 +343,7 @@
self.converters = [converter.get_converter(self.space, arg_type,
arg_dflt)
for arg_type, arg_dflt in self.arg_defs]
self.executor = executor.get_executor(
- self.space, capi.c_method_result_type(self.space, self.scope,
self.index))
+ self.space, capi.c_method_result_type(self.space, self.cppmethod))
for conv in self.converters:
if conv.uses_local:
@@ -359,7 +353,7 @@
# Each CPPMethod corresponds one-to-one to a C++ equivalent and cppthis
# has been offset to the matching class. Hence, the libffi pointer is
# uniquely defined and needs to be setup only once.
- funcaddr = capi.c_function_address_from_index(self.space, self.scope,
self.index)
+ funcaddr = capi.c_function_address(self.space, self.cppmethod)
if funcaddr and cppthis: # TODO: methods only for now
state = self.space.fromcache(ffitypes.State)
@@ -427,10 +421,10 @@
capi.c_deallocate_function_args(self.space, args)
def signature(self, show_formalargs=True):
- return capi.c_method_signature(self.space, self.scope, self.index,
show_formalargs)
+ return capi.c_method_signature(self.space, self.cppmethod,
show_formalargs)
def prototype(self, show_formalargs=True):
- return capi.c_method_prototype(self.space, self.scope, self.index,
show_formalargs)
+ return capi.c_method_prototype(self.space, self.scope, self.cppmethod,
show_formalargs)
def priority(self):
total_arg_priority = 0
@@ -440,8 +434,11 @@
@rgc.must_be_light_finalizer
def __del__(self):
- if self.cif_descr:
- lltype.free(self.cif_descr, flavor='raw')
+ try:
+ if self.cif_descr:
+ lltype.free(self.cif_descr, flavor='raw')
+ except Exception: # TODO: happens for templates, why?
+ pass
def __repr__(self):
return "CPPMethod: %s" % self.prototype()
@@ -450,80 +447,12 @@
assert 0, "you should never have a pre-built instance of this!"
-class CPPFunction(CPPMethod):
- """Global (namespaced) / static function dispatcher."""
-
- _immutable_ = True
-
- @staticmethod
- def unpack_cppthis(space, w_cppinstance, declaring_scope):
- return capi.C_NULL_OBJECT
-
- def __repr__(self):
- return "CPPFunction: %s" % self.prototype()
-
-
-class CPPTemplateMethod(CPPMethod):
- """Method dispatcher that first resolves the template instance."""
-
- _attrs_ = ['space', 'templ_args']
- _immutable_ = True
-
- def __init__(self, space, templ_args, declaring_scope, method_index,
arg_defs, args_required):
- self.space = space
- self.templ_args = templ_args
- # TODO: might have to specialize for CPPTemplateMethod on
CPPMethod/CPPFunction here
- CPPMethod.__init__(self, space, declaring_scope, method_index,
arg_defs, args_required)
-
- def call(self, cppthis, args_w, useffi):
- assert lltype.typeOf(cppthis) == capi.C_OBJECT
- for i in range(len(args_w)):
- try:
- s = self.space.text_w(args_w[i])
- except OperationError:
- s = self.space.text_w(self.space.getattr(args_w[i],
self.space.newtext('__name__')))
- s = capi.c_resolve_name(self.space, s)
- if s != self.templ_args[i]:
- raise oefmt(self.space.w_TypeError,
- "non-matching template (got %s where %s expected)",
- s, self.templ_args[i])
- return W_CPPBoundMethod(cppthis, self, useffi)
-
- def bound_call(self, cppthis, args_w, useffi):
- return CPPMethod.call(self, cppthis, args_w, useffi)
-
- def __repr__(self):
- return "CPPTemplateMethod: %s" % self.prototype()
-
-
-class CPPConstructor(CPPMethod):
- """Method dispatcher that constructs new objects. This method can not have
- a fast path, as the allocation of the object is currently left to the
- reflection layer only, since the C++ class may have an overloaded operator
- new, disallowing malloc here."""
-
- _immutable_ = True
-
- @staticmethod
- def unpack_cppthis(space, w_cppinstance, declaring_scope):
- return rffi.cast(capi.C_OBJECT, declaring_scope.handle)
-
- def call(self, cppthis, args_w, useffi):
- # Note: this does not return a wrapped instance, just a pointer to the
- # new instance; the overload must still wrap it before returning. Also,
- # cppthis is declaring_scope.handle (as per unpack_cppthis(), above).
- return CPPMethod.call(self, cppthis, args_w, useffi)
-
- def __repr__(self):
- return "CPPConstructor: %s" % self.prototype()
-
-
class CPPSetItem(CPPMethod):
"""Method dispatcher specific to Python's __setitem__ mapped onto C++'s
operator[](int). The former function takes an extra argument to assign to
the return type of the latter."""
- _immutable_ = True
+ _attrs_ = []
def call(self, cppthis, args_w, useffi):
end = len(args_w)-1
@@ -537,46 +466,44 @@
class W_CPPOverload(W_Root):
- """Dispatcher that is actually available at the app-level: it is a
- collection of (possibly) overloaded methods or functions. It calls these
- in order and deals with error handling and reporting."""
+ """App-level dispatcher: controls a collection of (potentially) overloaded
methods
+ or functions. Calls these in order and deals with error handling and
reporting."""
- _attrs_ = ['space', 'scope', 'functions', 'flags']
+ _attrs_ = ['space', 'scope', 'functions', 'flags', 'w_this']
_immutable_fields_ = ['scope', 'functions[*]']
- def __init__(self, space, declaring_scope, functions):
- self.space = space
- self.scope = declaring_scope
- assert len(functions)
+ def __init__(self, space, declaring_scope, functions, flags =
OVERLOAD_FLAGS_USE_FFI):
+ self.space = space
+ self.scope = declaring_scope
from rpython.rlib import debug
self.functions = debug.make_sure_not_resized(functions)
- self.flags = 0
- self.flags |= OVERLOAD_FLAGS_USE_FFI
+ self.flags = flags
+ self.w_this = self.space.w_None
- # allow user to determine ffi use rules per overload
- def fget_useffi(self, space):
- return space.newbool(bool(self.flags & OVERLOAD_FLAGS_USE_FFI))
+ @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, so no new instance needed
+ cppol = W_CPPOverload(self.space, self.scope, self.functions,
self.flags)
+ cppol.w_this = w_cppinstance
+ return cppol # bound
- @unwrap_spec(value=bool)
- def fset_useffi(self, space, value):
- if space.is_true(value):
- self.flags |= OVERLOAD_FLAGS_USE_FFI
+ @unwrap_spec(args_w='args_w')
+ def call(self, args_w):
+ if self.space.is_w(self.w_this, self.space.w_None) and len(args_w):
+ w_this = args_w[0]
+ args_w = args_w[1:]
else:
- self.flags &= ~OVERLOAD_FLAGS_USE_FFI
-
- @jit.elidable_promote()
- def is_static(self):
- if isinstance(self.functions[0], CPPFunction):
- return self.space.w_True
- return self.space.w_False
+ w_this = self.w_this
+ cppinstance = self.space.interp_w(W_CPPInstance, w_this)
+ cppinstance._nullcheck()
+ if not capi.c_is_subtype(self.space, cppinstance.clsdecl, self.scope):
+ raise oefmt(self.space.w_TypeError,
+ "cannot pass %T instance as %s", w_this, self.scope.name)
+ return self.call_impl(cppinstance.get_cppthis(self.scope), args_w)
@jit.unroll_safe
- @unwrap_spec(args_w='args_w')
- def call(self, w_cppinstance, args_w):
- # instance handling is specific to the function type only, so take it
out
- # of the loop over function overloads
- cppthis = self.functions[0].unpack_cppthis(
- self.space, w_cppinstance, self.functions[0].scope)
+ def call_impl(self, cppthis, args_w):
assert lltype.typeOf(cppthis) == capi.C_OBJECT
# The following code tries out each of the functions in order. If
@@ -634,38 +561,96 @@
sig += '\n'+self.functions[i].prototype()
return self.space.newtext(sig)
+ # allow user to determine ffi use rules per overload
+ def fget_useffi(self, space):
+ return space.newbool(bool(self.flags & OVERLOAD_FLAGS_USE_FFI))
+
+ @unwrap_spec(value=bool)
+ def fset_useffi(self, space, value):
+ if space.is_true(value):
+ self.flags |= OVERLOAD_FLAGS_USE_FFI
+ else:
+ self.flags &= ~OVERLOAD_FLAGS_USE_FFI
+
+ def fget_doc(self, space):
+ return self.prototype()
+
def __repr__(self):
return "W_CPPOverload(%s)" % [f.prototype() for f in self.functions]
W_CPPOverload.typedef = TypeDef(
'CPPOverload',
- call = interp2app(W_CPPOverload.call),
- is_static = interp2app(W_CPPOverload.is_static),
+ __get__ = interp2app(W_CPPOverload.descr_get),
+ __call__ = interp2app(W_CPPOverload.call),
__useffi__ = GetSetProperty(W_CPPOverload.fget_useffi,
W_CPPOverload.fset_useffi),
- prototype = interp2app(W_CPPOverload.prototype),
+ __doc__ = GetSetProperty(W_CPPOverload.fget_doc)
)
+# overload collection of static (class and free) functions; these differ
+# from methods only in the handling of 'cppthis'
+class W_CPPStaticOverload(W_CPPOverload):
+ _attrs_ = []
+
+ @unwrap_spec(args_w='args_w')
+ def descr_get(self, w_cppinstance, args_w):
+ if isinstance(w_cppinstance, W_CPPInstance):
+ # two possibilities: this is a static function called on an
+ # instance and w_this must not be set, or a free function rebound
+ # onto a class and w_this should be set
+ cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance)
+ if cppinstance.clsdecl.handle != self.scope.handle:
+ cppol = W_CPPStaticOverload(self.space, self.scope,
self.functions, self.flags)
+ cppol.w_this = w_cppinstance
+ return cppol # bound
+ return self # unbound
+
+ @unwrap_spec(args_w='args_w')
+ def call(self, args_w):
+ if not self.space.is_w(self.w_this, self.space.w_None):
+ # free function used as bound method, put self back into args_w
+ cppinstance = self.space.interp_w(W_CPPInstance, self.w_this)
+ cppinstance._nullcheck()
+ args_w = [self.w_this] + args_w
+ return self.call_impl(capi.C_NULL_OBJECT, args_w)
+
+ def __repr__(self):
+ return "W_CPPStaticOverload(%s)" % [f.prototype() for f in
self.functions]
+
+W_CPPStaticOverload.typedef = TypeDef(
+ 'CPPStaticOverload',
+ __get__ = interp2app(W_CPPStaticOverload.descr_get),
+ __call__ = interp2app(W_CPPStaticOverload.call),
+ __useffi__ = GetSetProperty(W_CPPStaticOverload.fget_useffi,
W_CPPStaticOverload.fset_useffi),
+ __doc__ = GetSetProperty(W_CPPStaticOverload.fget_doc)
+)
+
+
class W_CPPConstructorOverload(W_CPPOverload):
- @jit.elidable_promote()
- def is_static(self):
- return self.space.w_False
+ _attrs_ = []
- @jit.elidable_promote()
- def unpack_cppthis(self, w_cppinstance):
- return rffi.cast(capi.C_OBJECT, self.scope.handle)
+ @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 (TODO: probably useless)
+ cppol = W_CPPConstructorOverload(self.space, self.scope,
self.functions, self.flags)
+ cppol.w_this = w_cppinstance
+ return cppol # bound
- @jit.unroll_safe
@unwrap_spec(args_w='args_w')
- def call(self, w_cppinstance, args_w):
+ def call(self, args_w):
# TODO: factor out the following:
if capi.c_is_abstract(self.space, self.scope.handle):
raise oefmt(self.space.w_TypeError,
"cannot instantiate abstract class '%s'",
self.scope.name)
- w_result = W_CPPOverload.call(self, w_cppinstance, args_w)
+ if self.space.is_w(self.w_this, self.space.w_None) and len(args_w):
+ cppinstance = self.space.interp_w(W_CPPInstance, args_w[0])
+ args_w = args_w[1:]
+ else:
+ cppinstance = self.space.interp_w(W_CPPInstance, self.w_this)
+ w_result = self.call_impl(rffi.cast(capi.C_OBJECT, self.scope.handle),
args_w)
newthis = rffi.cast(capi.C_OBJECT, self.space.uint_w(w_result))
- cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance,
can_be_None=True)
if cppinstance is not None:
cppinstance._rawobject = newthis
memory_regulator.register(cppinstance)
@@ -675,47 +660,86 @@
W_CPPConstructorOverload.typedef = TypeDef(
'CPPConstructorOverload',
- call = interp2app(W_CPPConstructorOverload.call),
- is_static = interp2app(W_CPPConstructorOverload.is_static),
- prototype = interp2app(W_CPPConstructorOverload.prototype),
+ __get__ = interp2app(W_CPPConstructorOverload.descr_get),
+ __call__ = interp2app(W_CPPConstructorOverload.call),
+ __doc__ = GetSetProperty(W_CPPConstructorOverload.fget_doc)
)
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."""
+
+ _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 = None
+
@unwrap_spec(args_w='args_w')
- def __getitem__(self, args_w):
- pass
+ 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
+ return cppol # bound
+
+ @unwrap_spec(args_w='args_w')
+ def getitem(self, args_w):
+ space = self.space
+ tmpl_args = ''
+ for i in range(len(args_w)):
+ w_obj = args_w[i]
+ if space.isinstance_w(w_obj, space.w_text):
+ s = space.text_w(w_obj) # string describing type
+ elif space.isinstance_w(w_obj, space.w_type):
+ try:
+ # cppyy bound types
+ name = space.getattr(w_obj, space.newtext('__cppname__'))
+ except OperationError:
+ # generic python types
+ name = space.getattr(w_obj, space.newtext('__name__'))
+ s = space.text_w(name)
+ else:
+ # builtin types etc.
+ s = space.text_w(space.str(w_obj))
+ if i != 0: tmpl_args += ', '
+ tmpl_args += s
+ fullname = self.name+'<'+tmpl_args+'>'
+
+ # find/instantiate new callable function
+ master = self.master
+ if not master:
+ master = self
+ try:
+ return master.overloads[fullname].descr_get(self.w_this, [])
+ except KeyError:
+ pass
+
+ cppmeth = capi.c_get_method_template(space, self.scope, fullname)
+ funcs = []
+ ftype = self.scope._make_cppfunction(fullname, cppmeth, funcs)
+ if ftype & FUNCTION_IS_STATIC:
+ cppol = W_CPPStaticOverload(space, self.scope, funcs[:],
self.flags)
+ else:
+ cppol = W_CPPOverload(space, self.scope, funcs[:], self.flags)
+ master.overloads[fullname] = cppol
+ return cppol.descr_get(self.w_this, [])
def __repr__(self):
return "W_CPPTemplateOverload(%s)" % [f.prototype() for f in
self.functions]
W_CPPTemplateOverload.typedef = TypeDef(
'CPPTemplateOverload',
- __getitem__ = interp2app(W_CPPTemplateOverload.call),
- call = interp2app(W_CPPTemplateOverload.call),
- is_static = interp2app(W_CPPTemplateOverload.is_static),
- __useffi__ = GetSetProperty(W_CPPTemplateOverload.fget_useffi,
W_CPPTemplateOverload.fset_useffi),
- prototype = interp2app(W_CPPTemplateOverload.prototype),
-)
-
-
-class W_CPPBoundMethod(W_Root):
- _attrs_ = ['cppthis', 'method', 'useffi']
-
- def __init__(self, cppthis, method, useffi):
- self.cppthis = cppthis
- self.method = method
- self.useffi = useffi
-
- def __call__(self, args_w):
- return self.method.bound_call(self.cppthis, args_w, self.useffi)
-
- def __repr__(self):
- return "W_CPPBoundMethod(%s)" % self.method.prototype()
-
-W_CPPBoundMethod.typedef = TypeDef(
- 'CPPBoundMethod',
- __call__ = interp2app(W_CPPBoundMethod.__call__),
+ __get__ = interp2app(W_CPPTemplateOverload.descr_get),
+ __getitem__ = interp2app(W_CPPTemplateOverload.getitem),
+ __call__ = interp2app(W_CPPTemplateOverload.call),
+ __useffi__ = GetSetProperty(W_CPPTemplateOverload.fget_useffi,
W_CPPTemplateOverload.fset_useffi),
+ __doc__ = GetSetProperty(W_CPPTemplateOverload.fget_doc)
)
@@ -826,7 +850,16 @@
return space.w_False
#-----
-
+# Classes for data members:
+#
+# W_CPPScopeDecl : scope base class
+# W_CPPNamespaceDecl : namespace scope
+# W_CPPClassDecl : class scope
+#
+# Namespaces and classes mainly differ in lookups of methods. Whereas classes
+# can grown templated methods, namespaces are wide open to any additions. Such
+# lookups are triggered from get_scoped_pycppitem (in pythonify.py). Further
+# specialization is done on the type of data/methods that each can have.
class W_CPPScopeDecl(W_Root):
_attrs_ = ['space', 'handle', 'flags', 'name', 'overloads', 'datamembers']
@@ -897,15 +930,15 @@
_attrs_ = ['space', 'handle', 'name', 'overloads', 'datamembers']
_immutable_fields_ = ['handle', 'name']
- def _make_cppfunction(self, pyname, index, funcs):
- num_args = capi.c_method_num_args(self.space, self, index)
- args_required = capi.c_method_req_args(self.space, self, index)
+ def _make_cppfunction(self, pyname, cppmeth, funcs):
+ num_args = capi.c_method_num_args(self.space, cppmeth)
+ args_required = capi.c_method_req_args(self.space, cppmeth)
arg_defs = []
for i in range(num_args):
- arg_type = capi.c_method_arg_type(self.space, self, index, i)
- arg_dflt = capi.c_method_arg_default(self.space, self, index, i)
+ arg_type = capi.c_method_arg_type(self.space, cppmeth, i)
+ arg_dflt = capi.c_method_arg_default(self.space, cppmeth, i)
arg_defs.append((arg_type, arg_dflt))
- funcs.append(CPPFunction(self.space, self, index, arg_defs,
args_required))
+ funcs.append(CPPMethod(self.space, self, cppmeth, arg_defs,
args_required))
return FUNCTION_IS_GLOBAL
def _make_datamember(self, dm_name, dm_idx):
@@ -922,14 +955,20 @@
def find_overload(self, meth_name):
indices = capi.c_method_indices_from_name(self.space, self, meth_name)
- if not indices:
- raise self.missing_attribute_error(meth_name)
- cppfunctions, ftype = [], 0
- for meth_idx in indices:
- ftype |= self._make_cppfunction(meth_name, meth_idx, cppfunctions)
- if ftype & FUNCTION_IS_TEMPLATE:
- return W_CPPTemplateOverload(self.sace, self, cppfunctions)
- return W_CPPOverload(self.space, self, cppfunctions)
+ if indices:
+ cppfunctions, ftype = [], 0
+ templated = False
+ for idx in indices:
+ cppmeth = capi.c_get_method(self.space, self, idx)
+ ftype |= self._make_cppfunction(meth_name, cppmeth,
cppfunctions)
+ 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_CPPStaticOverload(self.space, self, cppfunctions[:])
+ elif capi.c_exists_method_template(self.space, self, meth_name):
+ return W_CPPTemplateOverload(self.space, meth_name, self, [])
+ raise self.missing_attribute_error(meth_name)
def find_datamember(self, dm_name):
dm_idx = capi.c_datamember_index(self.space, self, dm_name)
@@ -973,69 +1012,71 @@
def _build_overloads(self):
assert len(self.overloads) == 0
- overloads_temp = {}
+ methods_tmp = {}; ftype_tmp = {}
for idx in range(capi.c_num_methods(self.space, self)):
- if capi.c_is_constructor(self.space, self, idx):
+ cppmeth = capi.c_get_method(self.space, self, idx)
+ if capi.c_is_constructor(self.space, cppmeth):
pyname = '__init__'
else:
pyname = helper.map_operator_name(self.space,
- capi.c_method_name(self.space, self, idx),
- capi.c_method_num_args(self.space, self, idx),
- capi.c_method_result_type(self.space, self, idx))
+ capi.c_method_name(self.space, cppmeth),
+ capi.c_method_num_args(self.space, cppmeth),
+ capi.c_method_result_type(self.space, cppmeth))
try:
- detail = overloads_temp[pyname]
+ methods = methods_tmp[pyname]
except KeyError:
- detail = [[], 0]; overloads_temp[pyname] = detail
- detail[1] |= self._make_cppfunction(pyname, idx, detail[0])
+ methods_tmp[pyname] = []; ftype_tmp[pyname] = 0
+ methods = methods_tmp[pyname]
+ ftype_tmp[pyname] |= self._make_cppfunction(pyname, cppmeth,
methods)
+ if capi.c_method_is_template(self.space, self, idx):
+ ftype_tmp[pyname] |= FUNCTION_IS_TEMPLATE
# the following covers the case where the only kind of operator[](idx)
# returns are the ones that produce non-const references; these can be
# used for __getitem__ just as much as for __setitem__, though
- if not "__getitem__" in overloads_temp:
+ if not "__getitem__" in methods_tmp:
try:
- sid = overloads_temp["__setitem__"]
- gid = [[], 0]; overloads_temp["__getitem__"] = gid
- for m in sid[0]:
- gid[1] |= self._make_cppfunction("__getitem__", m.index,
gid[0])
+ si_methods = methods_tmp["__setitem__"]
+ gi_methods = []; ftype = 0
+ for m in si_methods:
+ ftype |= self._make_cppfunction("__getitem__",
m.cppmethod, gi_methods)
+ methods_tmp["__getitem__"] = gi_methods;
ftype_tmp["__getitem__"] = ftype
except KeyError:
pass # just means there's no __setitem__ either
# create the overloads from the method sets
- for pyname, detail in overloads_temp.iteritems():
- methods = detail[0]
+ for pyname, methods in methods_tmp.iteritems():
+ ftype = ftype_tmp[pyname]
CPPMethodSort(methods).sort()
- if pyname == '__init__':
- overload = W_CPPConstructorOverload(self.space, self, methods)
- elif detail[1] & FUNCTION_IS_TEMPLATE:
- overload = W_CPPTemplateOverload(self.space, self, methods)
+ if ftype & FUNCTION_IS_CONSTRUCTOR:
+ overload = W_CPPConstructorOverload(self.space, self,
methods[:])
+ elif ftype & FUNCTION_IS_STATIC:
+ overload = W_CPPStaticOverload(self.space, self, methods[:])
+ elif ftype & FUNCTION_IS_TEMPLATE:
+ overload = W_CPPTemplateOverload(self.space, pyname, self,
methods[:])
else:
- overload = W_CPPOverload(self.space, self, methods)
+ overload = W_CPPOverload(self.space, self, methods[:])
self.overloads[pyname] = overload
- def _make_cppfunction(self, pyname, index, funcs):
- num_args = capi.c_method_num_args(self.space, self, index)
- args_required = capi.c_method_req_args(self.space, self, index)
+ def _make_cppfunction(self, pyname, cppmeth, funcs):
+ num_args = capi.c_method_num_args(self.space, cppmeth)
+ args_required = capi.c_method_req_args(self.space, cppmeth)
arg_defs = []
for i in range(num_args):
- arg_type = capi.c_method_arg_type(self.space, self, index, i)
- arg_dflt = capi.c_method_arg_default(self.space, self, index, i)
+ arg_type = capi.c_method_arg_type(self.space, cppmeth, i)
+ arg_dflt = capi.c_method_arg_default(self.space, cppmeth, i)
arg_defs.append((arg_type, arg_dflt))
ftype = 0
- if capi.c_is_constructor(self.space, self, index):
- cppfunction = CPPConstructor(self.space, self, index, arg_defs,
args_required)
- ftype = FUNCTION_IS_CONSTRUCTOR
- elif capi.c_method_is_template(self.space, self, index):
- templ_args = capi.c_template_args(self.space, self, index)
- cppfunction = CPPTemplateMethod(self.space, templ_args, self,
index, arg_defs, args_required)
- ftype = FUNCTION_IS_TEMPLATE
- elif capi.c_is_staticmethod(self.space, self, index):
- cppfunction = CPPFunction(self.space, self, index, arg_defs,
args_required)
- ftype = FUNCTION_IS_STATIC
- elif pyname == "__setitem__":
- cppfunction = CPPSetItem(self.space, self, index, arg_defs,
args_required)
+ if pyname == "__setitem__":
+ cppfunction = CPPSetItem(self.space, self, cppmeth, arg_defs,
args_required)
ftype = FUNCTION_IS_SETITEM
else:
- cppfunction = CPPMethod(self.space, self, index, arg_defs,
args_required)
- ftype = FUNCTION_IS_METHOD
+ cppfunction = CPPMethod(self.space, self, cppmeth, arg_defs,
args_required)
+ if capi.c_is_constructor(self.space, cppmeth):
+ ftype = FUNCTION_IS_CONSTRUCTOR
+ elif capi.c_is_staticmethod(self.space, cppmeth):
+ ftype = FUNCTION_IS_STATIC
+ else:
+ ftype = FUNCTION_IS_METHOD
funcs.append(cppfunction)
return ftype
@@ -1061,8 +1102,8 @@
datamember = W_CPPDataMember(self.space, self, type_name,
offset)
self.datamembers[datamember_name] = datamember
- def find_overload(self, name):
- raise self.missing_attribute_error(name)
+ def find_overload(self, meth_name):
+ raise self.missing_attribute_error(meth_name)
def find_datamember(self, name):
raise self.missing_attribute_error(name)
@@ -1227,11 +1268,12 @@
self.space, nss, self.clsdecl, other.clsdecl, "operator==")
if meth_idx != -1:
funcs = []
- nss._make_cppfunction("operator==", meth_idx, funcs)
- ol = W_CPPOverload(self.space, nss, funcs)
+ cppmeth = capi.c_get_method(self.space, nss, meth_idx)
+ nss._make_cppfunction("operator==", cppmeth, funcs)
+ ol = W_CPPStaticOverload(self.space, nss, funcs[:])
# TODO: cache this operator (not done yet, as the above
does not
# select all overloads)
- return ol.call(self, [self, w_other])
+ return ol.call([self, w_other])
except OperationError as e:
if not e.match(self.space, self.space.w_TypeError):
raise
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
@@ -111,14 +111,6 @@
return scope.__module__ + '.' + scope.__name__
return 'cppyy'
-def make_static_function(func_name, cppol):
- def function(*args):
- return cppol.call(None, *args)
- function.__name__ = func_name
- function.__doc__ = cppol.prototype()
- return staticmethod(function)
-
-
def make_cppnamespace(scope, name, decl):
# build up a representation of a C++ namespace (namespaces are classes)
@@ -147,7 +139,6 @@
break
return tuple(bases)
-
def make_new(decl):
def __new__(cls, *args):
# create a place-holder only as there may be a derived class defined
@@ -160,13 +151,6 @@
return instance
return __new__
-def make_method(meth_name, cppol):
- def method(self, *args):
- return cppol.call(self, *args)
- method.__name__ = meth_name
- method.__doc__ = cppol.prototype()
- return method
-
def make_cppclass(scope, cl_name, decl):
import _cppyy
@@ -188,7 +172,7 @@
# prepare dictionary for python-side C++ class representation
def dispatch(self, m_name, signature):
cppol = decl.__dispatch__(m_name, signature)
- return types.MethodType(make_method(m_name, cppol), self, type(self))
+ return types.MethodType(cppol, self, type(self))
d_class = {"__cppdecl__" : decl,
"__new__" : make_new(decl),
"__module__" : make_module_name(scope),
@@ -199,10 +183,7 @@
# insert (static) methods into the class dictionary
for m_name in decl.get_method_names():
cppol = decl.get_overload(m_name)
- if cppol.is_static():
- d_class[m_name] = make_static_function(m_name, cppol)
- else:
- d_class[m_name] = make_method(m_name, cppol)
+ d_class[m_name] = cppol
# add all data members to the dictionary of the class to be created, and
# static ones also to the metaclass (needed for property setters)
@@ -267,8 +248,7 @@
if not cppitem:
try:
cppitem = scope.__cppdecl__.get_overload(name)
- pycppitem = make_static_function(name, cppitem)
- setattr(scope.__class__, name, pycppitem)
+ setattr(scope.__class__, name, cppitem)
pycppitem = getattr(scope, name) # binds function as needed
except AttributeError:
pass
diff --git a/pypy/module/_cppyy/src/dummy_backend.cxx
b/pypy/module/_cppyy/src/dummy_backend.cxx
--- a/pypy/module/_cppyy/src/dummy_backend.cxx
+++ b/pypy/module/_cppyy/src/dummy_backend.cxx
@@ -924,6 +924,15 @@
/* method/function reflection information --------------------------------- */
+cppyy_method_t cppyy_get_method(cppyy_scope_t handle, cppyy_index_t
method_index) {
+ if (s_scopes.find(handle) != s_scopes.end()) {
+ long id = s_scopes[handle].m_method_offset + (long)method_index;
+ return (cppyy_method_t)id;
+ }
+ assert(!"unknown class in cppyy_get_method");
+ return (cppyy_method_t)0;
+}
+
int cppyy_num_methods(cppyy_scope_t handle) {
return s_scopes[handle].m_methods.size();
}
@@ -948,18 +957,15 @@
return
cppstring_to_cstring(s_scopes[handle].m_methods[method_index].m_argtypes[arg_index]);
}
-char* cppyy_method_arg_default(
- cppyy_scope_t /* handle */, cppyy_index_t /* method_index */, int /*
arg_index */) {
+char* cppyy_method_arg_default(cppyy_method_t, int /* arg_index */) {
return cppstring_to_cstring("");
}
-char* cppyy_method_signature(
- cppyy_scope_t /* handle */, cppyy_index_t /* method_index */, int /*
show_formalargs */) {
+char* cppyy_method_signature(cppyy_method_t, int /* show_formalargs */) {
return cppstring_to_cstring("");
}
-char* cppyy_method_prototype(
- cppyy_scope_t /* handle */, cppyy_index_t /* method_index */, int /*
show_formalargs */) {
+char* cppyy_method_prototype(cppyy_scope_t, cppyy_method_t, int /*
show_formalargs */) {
return cppstring_to_cstring("");
}
@@ -967,15 +973,6 @@
return 0;
}
-cppyy_method_t cppyy_get_method(cppyy_scope_t handle, cppyy_index_t
method_index) {
- if (s_scopes.find(handle) != s_scopes.end()) {
- long id = s_scopes[handle].m_method_offset + (long)method_index;
- return (cppyy_method_t)id;
- }
- assert(!"unknown class in cppyy_get_method");
- return (cppyy_method_t)0;
-}
-
cppyy_index_t cppyy_get_global_operator(cppyy_scope_t /* scope */,
cppyy_scope_t /* lc */, cppyy_scope_t /* rc */, const char* /* op */) {
return (cppyy_index_t)-1;
diff --git a/pypy/module/_cppyy/test/test_advancedcpp.py
b/pypy/module/_cppyy/test/test_advancedcpp.py
--- a/pypy/module/_cppyy/test/test_advancedcpp.py
+++ b/pypy/module/_cppyy/test/test_advancedcpp.py
@@ -663,9 +663,8 @@
import _cppyy as cppyy
Thrower = cppyy.gbl.Thrower
- # TODO: clean up this interface:
- Thrower.__cppdecl__.get_overload('throw_anything').__useffi__ = False
- Thrower.__cppdecl__.get_overload('throw_exception').__useffi__ = False
+ Thrower.throw_anything.__useffi__ = False
+ Thrower.throw_exception.__useffi__ = False
t = Thrower()
diff --git a/pypy/module/_cppyy/test/test_cppyy.py
b/pypy/module/_cppyy/test/test_cppyy.py
--- a/pypy/module/_cppyy/test/test_cppyy.py
+++ b/pypy/module/_cppyy/test/test_cppyy.py
@@ -37,7 +37,8 @@
lib = ctypes.CDLL(%r, ctypes.RTLD_GLOBAL)
def cpp_instantiate(tt, *args):
inst = _cppyy._bind_object(0, tt, True)
- tt.get_overload("__init__").call(inst, *args)
+ ol = tt.get_overload("__init__").__get__(inst)
+ ol(*args)
return inst
return lib, cpp_instantiate, _cppyy._scope_byname('example01'),\
_cppyy._scope_byname('payload')""" % (test_dct, )))
@@ -49,30 +50,30 @@
import sys, math
t = self.example01
- res = t.get_overload("staticAddOneToInt").call(None, 1)
+ res = t.get_overload("staticAddOneToInt")(1)
assert res == 2
- res = t.get_overload("staticAddOneToInt").call(None, 1L)
+ res = t.get_overload("staticAddOneToInt")(1L)
assert res == 2
- res = t.get_overload("staticAddOneToInt").call(None, 1, 2)
+ res = t.get_overload("staticAddOneToInt")(1, 2)
assert res == 4
- res = t.get_overload("staticAddOneToInt").call(None, -1)
+ res = t.get_overload("staticAddOneToInt")(-1)
assert res == 0
maxint32 = int(2 ** 31 - 1)
- res = t.get_overload("staticAddOneToInt").call(None, maxint32-1)
+ res = t.get_overload("staticAddOneToInt")(maxint32-1)
assert res == maxint32
- res = t.get_overload("staticAddOneToInt").call(None, maxint32)
+ res = t.get_overload("staticAddOneToInt")(maxint32)
assert res == -maxint32-1
- raises(TypeError, 't.get_overload("staticAddOneToInt").call(None, 1,
[])')
- raises(TypeError, 't.get_overload("staticAddOneToInt").call(None, 1.)')
- raises(TypeError, 't.get_overload("staticAddOneToInt").call(None,
maxint32+1)')
+ raises(TypeError, 't.get_overload("staticAddOneToInt")(1, [])')
+ raises(TypeError, 't.get_overload("staticAddOneToInt")(1.)')
+ raises(TypeError, 't.get_overload("staticAddOneToInt")(maxint32+1)')
def test02_static_double(self):
"""Test passing of a double and returning of a double on a static
function."""
t = self.example01
- res = t.get_overload("staticAddToDouble").call(None, 0.09)
+ res = t.get_overload("staticAddToDouble")(0.09)
assert res == 0.09 + 0.01
def test03_static_constcharp(self):
@@ -81,14 +82,14 @@
t = self.example01
- res = t.get_overload("staticAtoi").call(None, "1")
+ res = t.get_overload("staticAtoi")("1")
assert res == 1
- res = t.get_overload("staticStrcpy").call(None, "aap") # TODO:
this leaks
+ res = t.get_overload("staticStrcpy")("aap") # TODO: this leaks
assert res == "aap"
- res = t.get_overload("staticStrcpy").call(None, u"aap") # TODO:
this leaks
+ res = t.get_overload("staticStrcpy")(u"aap") # TODO: this leaks
assert res == "aap"
- raises(TypeError, 't.get_overload("staticStrcpy").call(None, 1.)')
# TODO: this leaks
+ raises(TypeError, 't.get_overload("staticStrcpy")(1.)') # TODO: this
leaks
def test04_method_int(self):
"""Test passing of a int, returning of a int, and memory cleanup, on
@@ -97,30 +98,30 @@
t = self.example01
- assert t.get_overload("getCount").call(None) == 0
+ assert t.get_overload("getCount")() == 0
e1 = self.instantiate(t, 7)
- assert t.get_overload("getCount").call(None) == 1
- res = t.get_overload("addDataToInt").call(e1, 4)
+ assert t.get_overload("getCount")() == 1
+ res = t.get_overload("addDataToInt")(e1, 4)
assert res == 11
- res = t.get_overload("addDataToInt").call(e1, -4)
+ res = t.get_overload("addDataToInt")(e1, -4)
assert res == 3
e1.__destruct__()
- assert t.get_overload("getCount").call(None) == 0
- raises(ReferenceError, 't.get_overload("addDataToInt").call(e1, 4)')
+ assert t.get_overload("getCount")() == 0
+ raises(ReferenceError, 't.get_overload("addDataToInt")(e1, 4)')
e1 = self.instantiate(t, 7)
e2 = self.instantiate(t, 8)
- assert t.get_overload("getCount").call(None) == 2
+ assert t.get_overload("getCount")() == 2
e1.__destruct__()
- assert t.get_overload("getCount").call(None) == 1
+ assert t.get_overload("getCount")() == 1
e2.__destruct__()
- assert t.get_overload("getCount").call(None) == 0
+ assert t.get_overload("getCount")() == 0
e2.__destruct__()
- assert t.get_overload("getCount").call(None) == 0
+ assert t.get_overload("getCount")() == 0
- raises(TypeError, t.get_overload("addDataToInt").call, 41, 4)
+ raises(TypeError, t.get_overload("addDataToInt"), 41, 4)
def test05_memory(self):
"""Test memory destruction and integrity."""
@@ -130,29 +131,29 @@
t = self.example01
- assert t.get_overload("getCount").call(None) == 0
+ assert t.get_overload("getCount")() == 0
e1 = self.instantiate(t, 7)
- assert t.get_overload("getCount").call(None) == 1
- res = t.get_overload("addDataToInt").call(e1, 4)
+ assert t.get_overload("getCount")() == 1
+ res = t.get_overload("addDataToInt")(e1, 4)
assert res == 11
- res = t.get_overload("addDataToInt").call(e1, -4)
+ res = t.get_overload("addDataToInt")(e1, -4)
assert res == 3
e1 = None
gc.collect()
- assert t.get_overload("getCount").call(None) == 0
+ assert t.get_overload("getCount")() == 0
e1 = self.instantiate(t, 7)
e2 = self.instantiate(t, 8)
- assert t.get_overload("getCount").call(None) == 2
+ assert t.get_overload("getCount")() == 2
e1 = None
gc.collect()
- assert t.get_overload("getCount").call(None) == 1
+ assert t.get_overload("getCount")() == 1
e2.__destruct__()
- assert t.get_overload("getCount").call(None) == 0
+ assert t.get_overload("getCount")() == 0
e2 = None
gc.collect()
- assert t.get_overload("getCount").call(None) == 0
+ assert t.get_overload("getCount")() == 0
def test05a_memory2(self):
"""Test ownership control."""
@@ -161,18 +162,18 @@
t = self.example01
- assert t.get_overload("getCount").call(None) == 0
+ assert t.get_overload("getCount")() == 0
e1 = self.instantiate(t, 7)
- assert t.get_overload("getCount").call(None) == 1
+ assert t.get_overload("getCount")() == 1
assert e1.__python_owns__ == True
e1.__python_owns__ = False
e1 = None
gc.collect()
- assert t.get_overload("getCount").call(None) == 1
+ assert t.get_overload("getCount")() == 1
# forced fix-up of object count for later tests
- t.get_overload("setCount").call(None, 0)
+ t.get_overload("setCount")(0)
def test06_method_double(self):
@@ -183,15 +184,15 @@
t = self.example01
e = self.instantiate(t, 13)
- res = t.get_overload("addDataToDouble").call(e, 16)
+ res = t.get_overload("addDataToDouble")(e, 16)
assert round(res-29, 8) == 0.
e.__destruct__()
e = self.instantiate(t, -13)
- res = t.get_overload("addDataToDouble").call(e, 16)
+ res = t.get_overload("addDataToDouble")(e, 16)
assert round(res-3, 8) == 0.
e.__destruct__()
- assert t.get_overload("getCount").call(None) == 0
+ assert t.get_overload("getCount")() == 0
def test07_method_constcharp(self):
"""Test passing of a C string and returning of a C string on a
@@ -201,14 +202,14 @@
t = self.example01
e = self.instantiate(t, 42)
- res = t.get_overload("addDataToAtoi").call(e, "13")
+ res = t.get_overload("addDataToAtoi")(e, "13")
assert res == 55
- res = t.get_overload("addToStringValue").call(e, "12") # TODO:
this leaks
+ res = t.get_overload("addToStringValue")(e, "12") # TODO: this
leaks
assert res == "54"
- res = t.get_overload("addToStringValue").call(e, "-12") # TODO:
this leaks
+ res = t.get_overload("addToStringValue")(e, "-12") # TODO: this
leaks
assert res == "30"
e.__destruct__()
- assert t.get_overload("getCount").call(None) == 0
+ assert t.get_overload("getCount")() == 0
def test08_pass_object_by_pointer(self):
"""Test passing of an instance as an argument."""
@@ -218,17 +219,17 @@
t2 = self.payload
pl = self.instantiate(t2, 3.14)
- assert round(t2.get_overload("getData").call(pl)-3.14, 8) == 0
- t1.get_overload("staticSetPayload").call(None, pl, 41.)
- assert t2.get_overload("getData").call(pl) == 41.
+ assert round(t2.get_overload("getData")(pl)-3.14, 8) == 0
+ t1.get_overload("staticSetPayload")(pl, 41.)
+ assert t2.get_overload("getData")(pl) == 41.
e = self.instantiate(t1, 50)
- t1.get_overload("setPayload").call(e, pl);
- assert round(t2.get_overload("getData").call(pl)-50., 8) == 0
+ t1.get_overload("setPayload")(e, pl);
+ assert round(t2.get_overload("getData")(pl)-50., 8) == 0
e.__destruct__()
pl.__destruct__()
- assert t1.get_overload("getCount").call(None) == 0
+ assert t1.get_overload("getCount")() == 0
def test09_return_object_by_pointer(self):
"""Test returning of an instance as an argument."""
@@ -238,14 +239,14 @@
t2 = self.payload
pl1 = self.instantiate(t2, 3.14)
- assert round(t2.get_overload("getData").call(pl1)-3.14, 8) == 0
- pl2 = t1.get_overload("staticCyclePayload").call(None, pl1, 38.)
- assert t2.get_overload("getData").call(pl2) == 38.
+ assert round(t2.get_overload("getData")(pl1)-3.14, 8) == 0
+ pl2 = t1.get_overload("staticCyclePayload")(pl1, 38.)
+ assert t2.get_overload("getData")(pl2) == 38.
e = self.instantiate(t1, 50)
- pl2 = t1.get_overload("cyclePayload").call(e, pl1);
- assert round(t2.get_overload("getData").call(pl2)-50., 8) == 0
+ pl2 = t1.get_overload("cyclePayload")(e, pl1);
+ assert round(t2.get_overload("getData")(pl2)-50., 8) == 0
e.__destruct__()
pl1.__destruct__()
- assert t1.get_overload("getCount").call(None) == 0
+ assert t1.get_overload("getCount")() == 0
diff --git a/pypy/module/_cppyy/test/test_datatypes.py
b/pypy/module/_cppyy/test/test_datatypes.py
--- a/pypy/module/_cppyy/test/test_datatypes.py
+++ b/pypy/module/_cppyy/test/test_datatypes.py
@@ -767,7 +767,4 @@
raises(TypeError, f3, f1, 2, 3)
- # TODO: get straightforward access to the overload type
- f2 = cppyy.gbl.__cppdecl__.get_overload('sum_of_double')
-
assert 5. == f3(f2, 5., 0.)
diff --git a/pypy/module/_cppyy/test/test_pythonify.py
b/pypy/module/_cppyy/test/test_pythonify.py
--- a/pypy/module/_cppyy/test/test_pythonify.py
+++ b/pypy/module/_cppyy/test/test_pythonify.py
@@ -318,7 +318,7 @@
_cppyy.gbl.example01.fresh = _cppyy.gbl.installableAddOneToInt
- e = _cppyy.gbl.example01(0)
+ e = _cppyy.gbl.example01(0)
assert 2 == e.fresh(1)
assert 3 == e.fresh(2)
diff --git a/pypy/module/_cppyy/test/test_zjit.py
b/pypy/module/_cppyy/test/test_zjit.py
--- a/pypy/module/_cppyy/test/test_zjit.py
+++ b/pypy/module/_cppyy/test/test_zjit.py
@@ -268,19 +268,19 @@
def f():
cls = interp_cppyy.scope_byname(space, "example01")
inst = interp_cppyy._bind_object(space, FakeInt(0), cls, True)
- cls.get_overload("__init__").call(inst, [FakeInt(0)])
+ cls.get_overload("__init__").descr_get(inst, []).call([FakeInt(0)])
cppmethod = cls.get_overload(method_name)
assert isinstance(inst, interp_cppyy.W_CPPInstance)
i = 10
while i > 0:
drv.jit_merge_point(inst=inst, cppmethod=cppmethod, i=i)
- cppmethod.call(inst, [FakeInt(i)])
+ cppmethod.descr_get(inst, []).call([FakeInt(i)])
i -= 1
return 7
f()
space = FakeSpace()
result = self.meta_interp(f, [], listops=True, backendopt=True,
listcomp=True)
- self.check_jitcell_token_count(1) # same for fast and slow path??
+ self.check_jitcell_token_count(0) # same for fast and slow path??
# rely on replacement of capi calls to raise exception instead (see
FakeSpace.__init__)
@py.test.mark.dont_track_allocations("cppmethod.cif_descr kept 'leaks'")
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit