Author: Wim Lavrijsen <[email protected]>
Branch: reflex-support
Changeset: r52079:2d3f34563372
Date: 2012-02-03 16:12 -0800
http://bitbucket.org/pypy/pypy/changeset/2d3f34563372/
Log: o) default function values on fast path for integer types
diff --git a/pypy/module/cppyy/capi/__init__.py
b/pypy/module/cppyy/capi/__init__.py
--- a/pypy/module/cppyy/capi/__init__.py
+++ b/pypy/module/cppyy/capi/__init__.py
@@ -168,6 +168,10 @@
"cppyy_method_arg_type",
[C_TYPEHANDLE, rffi.INT, rffi.INT], rffi.CCHARP,
compilation_info=backend.eci)
+c_method_arg_default = rffi.llexternal(
+ "cppyy_method_arg_default",
+ [C_TYPEHANDLE, rffi.INT, rffi.INT], rffi.CCHARP,
+ compilation_info=backend.eci)
c_is_constructor = rffi.llexternal(
"cppyy_is_constructor",
@@ -204,6 +208,11 @@
[C_TYPEHANDLE, rffi.INT], rffi.INT,
compilation_info=backend.eci)
+c_atoi = rffi.llexternal(
+ "cppyy_atoi",
+ [rffi.CCHARP], rffi.INT,
+ compilation_info=backend.eci)
+
c_free = rffi.llexternal(
"cppyy_free",
[rffi.VOIDP], lltype.Void,
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
@@ -32,7 +32,7 @@
name = ""
- def __init__(self, space, array_size):
+ def __init__(self, space, extra):
pass
@jit.dont_look_inside
@@ -221,6 +221,9 @@
_immutable_ = True
libffitype = libffi.types.sint
+ def __init__(self, space, default):
+ self.default = capi.c_atoi(default)
+
def _unwrap_object(self, space, w_obj):
return rffi.cast(rffi.INT, space.c_int_w(w_obj))
@@ -231,6 +234,9 @@
def convert_argument_libffi(self, space, w_obj, argchain):
argchain.arg(self._unwrap_object(space, w_obj))
+ def default_argument_libffi(self, space, argchain):
+ argchain.arg(self.default)
+
def from_memory(self, space, w_obj, w_type, offset):
address = self._get_raw_address(space, w_obj, offset)
intptr = rffi.cast(rffi.INTP, address)
@@ -558,11 +564,13 @@
return interp_cppyy.new_instance(space, w_type, self.cpptype, address,
False)
-_converters = {}
-def get_converter(space, name):
+_converters = {} # builtin and custom types
+_a_converters = {} # array and ptr versions of above
+def get_converter(space, name, default):
from pypy.module.cppyy import interp_cppyy
# The matching of the name to a converter should follow:
# 1) full, exact match
+ # 1a) const-removed match
# 2) match of decorated, unqualified type
# 3) accept const ref as by value
# 4) accept ref as pointer
@@ -573,7 +581,13 @@
# 1) full, exact match
try:
- return _converters[name](space, -1)
+ return _converters[name](space, default)
+ except KeyError, k:
+ pass
+
+ # 1a) const-removed match
+ try:
+ return _converters[helper.remove_const(name)](space, default)
except KeyError, k:
pass
@@ -583,14 +597,14 @@
try:
# array_index may be negative to indicate no size or no size found
array_size = helper.array_size(name)
- return _converters[clean_name+compound](space, array_size)
+ return _a_converters[clean_name+compound](space, array_size)
except KeyError, k:
pass
# 3) accept const ref as by value
if compound and compound[len(compound)-1] == "&":
try:
- return _converters[clean_name](space, -1)
+ return _converters[clean_name](space, default)
except KeyError:
pass
@@ -617,42 +631,44 @@
_converters["unsigned char"] = CharConverter
_converters["short int"] = ShortConverter
_converters["short"] = _converters["short int"]
-_converters["short int*"] = ShortPtrConverter
-_converters["short*"] = _converters["short int*"]
-_converters["short int[]"] = ShortArrayConverter
-_converters["short[]"] = _converters["short int[]"]
_converters["unsigned short int"] = ShortConverter
_converters["unsigned short"] = _converters["unsigned short int"]
-_converters["unsigned short int*"] = ShortPtrConverter
-_converters["unsigned short*"] = _converters["unsigned short int*"]
-_converters["unsigned short int[]"] = ShortArrayConverter
-_converters["unsigned short[]"] = _converters["unsigned short int[]"]
_converters["int"] = IntConverter
-_converters["int*"] = IntPtrConverter
-_converters["int[]"] = IntArrayConverter
_converters["unsigned int"] = UnsignedIntConverter
-_converters["unsigned int*"] = UnsignedIntPtrConverter
-_converters["unsigned int[]"] = UnsignedIntArrayConverter
_converters["long int"] = LongConverter
_converters["long"] = _converters["long int"]
-_converters["long int*"] = LongPtrConverter
-_converters["long*"] = _converters["long int*"]
-_converters["long int[]"] = LongArrayConverter
-_converters["long[]"] = _converters["long int[]"]
_converters["unsigned long int"] = UnsignedLongConverter
_converters["unsigned long"] = _converters["unsigned long int"]
-_converters["unsigned long int*"] = LongPtrConverter
-_converters["unsigned long*"] = _converters["unsigned long int*"]
-_converters["unsigned long int[]"] = LongArrayConverter
-_converters["unsigned long[]"] = _converters["unsigned long int[]"]
_converters["float"] = FloatConverter
-_converters["float*"] = FloatPtrConverter
-_converters["float[]"] = FloatArrayConverter
_converters["double"] = DoubleConverter
-_converters["double*"] = DoublePtrConverter
-_converters["double[]"] = DoubleArrayConverter
_converters["const char*"] = CStringConverter
_converters["char*"] = CStringConverter
_converters["void*"] = VoidPtrConverter
_converters["void**"] = VoidPtrPtrConverter
_converters["void*&"] = VoidPtrRefConverter
+
+# it should be possible to generate these:
+_a_converters["short int*"] = ShortPtrConverter
+_a_converters["short*"] = _a_converters["short int*"]
+_a_converters["short int[]"] = ShortArrayConverter
+_a_converters["short[]"] = _a_converters["short int[]"]
+_a_converters["unsigned short int*"] = ShortPtrConverter
+_a_converters["unsigned short*"] = _a_converters["unsigned short
int*"]
+_a_converters["unsigned short int[]"] = ShortArrayConverter
+_a_converters["unsigned short[]"] = _a_converters["unsigned short
int[]"]
+_a_converters["int*"] = IntPtrConverter
+_a_converters["int[]"] = IntArrayConverter
+_a_converters["unsigned int*"] = UnsignedIntPtrConverter
+_a_converters["unsigned int[]"] = UnsignedIntArrayConverter
+_a_converters["long int*"] = LongPtrConverter
+_a_converters["long*"] = _a_converters["long int*"]
+_a_converters["long int[]"] = LongArrayConverter
+_a_converters["long[]"] = _a_converters["long int[]"]
+_a_converters["unsigned long int*"] = LongPtrConverter
+_a_converters["unsigned long*"] = _a_converters["unsigned long int*"]
+_a_converters["unsigned long int[]"] = LongArrayConverter
+_a_converters["unsigned long[]"] = _a_converters["unsigned long
int[]"]
+_a_converters["float*"] = FloatPtrConverter
+_a_converters["float[]"] = FloatArrayConverter
+_a_converters["double*"] = DoublePtrConverter
+_a_converters["double[]"] = DoubleArrayConverter
diff --git a/pypy/module/cppyy/helper.py b/pypy/module/cppyy/helper.py
--- a/pypy/module/cppyy/helper.py
+++ b/pypy/module/cppyy/helper.py
@@ -5,6 +5,9 @@
def _remove_const(name):
return "".join(rstring.split(name, "const")) # poor man's replace
+def remove_const(name):
+ return _remove_const(name).strip(' ')
+
def compound(name):
name = _remove_const(name)
if name.endswith("]"): # array type?
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
@@ -6,7 +6,7 @@
#ifdef __cplusplus
extern "C" {
#endif // ifdef __cplusplus
- typedef long cppyy_typehandle_t;
+ typedef void* cppyy_typehandle_t;
typedef void* cppyy_object_t;
typedef void* (*cppyy_methptrgetter_t)(cppyy_object_t);
@@ -55,6 +55,7 @@
int cppyy_method_num_args(cppyy_typehandle_t handle, int method_index);
int cppyy_method_req_args(cppyy_typehandle_t handle, int method_index);
char* cppyy_method_arg_type(cppyy_typehandle_t handle, int method_index,
int index);
+ char* cppyy_method_arg_default(cppyy_typehandle_t handle, int
method_index, int index);
/* method properties */
int cppyy_is_constructor(cppyy_typehandle_t handle, int method_index);
@@ -70,8 +71,9 @@
int cppyy_is_publicdata(cppyy_typehandle_t handle, int data_member_index);
int cppyy_is_staticdata(cppyy_typehandle_t handle, int data_member_index);
- /* misc helper */
+ /* misc helpers */
void cppyy_free(void* ptr);
+ int cppyy_atoi(const char* str);
#ifdef __cplusplus
}
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
@@ -93,13 +93,13 @@
class CPPMethod(object):
""" A concrete function after overloading has been resolved """
_immutable_ = True
- _immutable_fields_ = ["arg_types[*]", "arg_converters[*]"]
+ _immutable_fields_ = ["arg_defs[*]", "arg_converters[*]"]
- def __init__(self, cpptype, method_index, result_type, arg_types,
args_required):
+ def __init__(self, cpptype, method_index, result_type, arg_defs,
args_required):
self.cpptype = cpptype
self.space = cpptype.space
self.method_index = method_index
- self.arg_types = arg_types
+ self.arg_defs = arg_defs
self.args_required = args_required
self.executor = executor.get_executor(self.space, result_type)
self.arg_converters = None
@@ -114,7 +114,7 @@
if self.executor is None:
raise OperationError(self.space.w_TypeError,
self.space.wrap("return type not handled"))
- if len(self.arg_types) < len(args_w) or len(args_w) <
self.args_required:
+ if len(self.arg_defs) < len(args_w) or len(args_w) <
self.args_required:
raise OperationError(self.space.w_TypeError,
self.space.wrap("wrong number of arguments"))
if self.methgetter and cppthis: # only for methods
@@ -142,10 +142,14 @@
argchain = libffi.ArgChain()
argchain.arg(cppthis)
+ i = len(self.arg_defs)
for i in range(len(args_w)):
conv = self.arg_converters[i]
w_arg = args_w[i]
conv.convert_argument_libffi(space, w_arg, argchain)
+ for j in range(i+1, len(self.arg_defs)):
+ conv = self.arg_converters[j]
+ conv.default_argument_libffi(space, argchain)
return self.executor.execute_libffi(space, w_type, libffi_func,
argchain)
@jit.elidable_promote()
@@ -167,8 +171,8 @@
return libffifunc
def _build_converters(self):
- self.arg_converters = [converter.get_converter(self.space, arg_type)
- for arg_type in self.arg_types]
+ self.arg_converters = [converter.get_converter(self.space, arg_type,
arg_dflt)
+ for arg_type, arg_dflt in self.arg_defs]
@jit.unroll_safe
def prepare_arguments(self, args_w):
@@ -205,7 +209,7 @@
def __repr__(self):
return "CPPFunction(%s, %s, %r, %s)" % (
- self.cpptype, self.method_index, self.executor, self.arg_types)
+ self.cpptype, self.method_index, self.executor, self.arg_defs)
def _freeze_(self):
assert 0, "you should never have a pre-built instance of this!"
@@ -302,7 +306,7 @@
self.space = space
assert lltype.typeOf(scope_handle) == capi.C_TYPEHANDLE
self.scope_handle = scope_handle
- self.converter = converter.get_converter(self.space, type_name)
+ self.converter = converter.get_converter(self.space, type_name, '')
self.offset = offset
self._is_static = is_static
@@ -415,11 +419,12 @@
result_type =
capi.charp2str_free(capi.c_method_result_type(self.handle, method_index))
num_args = capi.c_method_num_args(self.handle, method_index)
args_required = capi.c_method_req_args(self.handle, method_index)
- argtypes = []
+ arg_defs = []
for i in range(num_args):
- argtype = capi.charp2str_free(capi.c_method_arg_type(self.handle,
method_index, i))
- argtypes.append(argtype)
- return CPPFunction(self, method_index, result_type, argtypes,
args_required)
+ arg_type = capi.charp2str_free(capi.c_method_arg_type(self.handle,
method_index, i))
+ arg_dflt =
capi.charp2str_free(capi.c_method_arg_default(self.handle, method_index, i))
+ arg_defs.append((arg_type, arg_dflt))
+ return CPPFunction(self, method_index, result_type, arg_defs,
args_required)
def _find_data_members(self):
num_data_members = capi.c_num_data_members(self.handle)
@@ -460,10 +465,11 @@
result_type =
capi.charp2str_free(capi.c_method_result_type(self.handle, method_index))
num_args = capi.c_method_num_args(self.handle, method_index)
args_required = capi.c_method_req_args(self.handle, method_index)
- argtypes = []
+ arg_defs = []
for i in range(num_args):
- argtype = capi.charp2str_free(capi.c_method_arg_type(self.handle,
method_index, i))
- argtypes.append(argtype)
+ arg_type = capi.charp2str_free(capi.c_method_arg_type(self.handle,
method_index, i))
+ arg_dflt =
capi.charp2str_free(capi.c_method_arg_default(self.handle, method_index, i))
+ arg_defs.append((arg_type, arg_dflt))
if capi.c_is_constructor(self.handle, method_index):
result_type = "void" # b/c otherwise CINT v.s. Reflex
difference
cls = CPPConstructor
@@ -471,7 +477,7 @@
cls = CPPFunction
else:
cls = CPPMethod
- return cls(self, method_index, result_type, argtypes, args_required)
+ return cls(self, method_index, result_type, arg_defs, args_required)
def _find_data_members(self):
num_data_members = capi.c_num_data_members(self.handle)
diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx
b/pypy/module/cppyy/src/cintcwrapper.cxx
--- a/pypy/module/cppyy/src/cintcwrapper.cxx
+++ b/pypy/module/cppyy/src/cintcwrapper.cxx
@@ -462,6 +462,10 @@
/* misc helpers ----------------------------------------------------------- */
+int cppyy_atoi(const char* str) {
+ return atoi(str);
+}
+
void cppyy_free(void* ptr) {
free(ptr);
}
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
@@ -14,6 +14,8 @@
#include <utility>
#include <vector>
+#include <stdlib.h>
+
/* local helpers ---------------------------------------------------------- */
static inline char* cppstring_to_cstring(const std::string& name) {
@@ -296,6 +298,13 @@
return cppstring_to_cstring(name);
}
+char* cppyy_method_arg_default(cppyy_typehandle_t handle, int method_index,
int arg_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ std::string dflt = m.FunctionParameterDefaultAt(arg_index);
+ return cppstring_to_cstring(dflt);
+}
+
int cppyy_is_constructor(cppyy_typehandle_t handle, int method_index) {
Reflex::Scope s = scope_from_handle(handle);
@@ -350,7 +359,11 @@
}
-/* misc helper ------------------------------------------------------------ */
+/* misc helpers ----------------------------------------------------------- */
+int cppyy_atoi(const char* str) {
+ return atoi(str);
+}
+
void cppyy_free(void* ptr) {
free(ptr);
}
diff --git a/pypy/module/cppyy/test/example01.cxx
b/pypy/module/cppyy/test/example01.cxx
--- a/pypy/module/cppyy/test/example01.cxx
+++ b/pypy/module/cppyy/test/example01.cxx
@@ -137,5 +137,42 @@
}
+// argument passing
+int ArgPasser::intValue(int arg0, int argn, int arg1, int arg2)
+{
+ switch (argn) {
+ case 0:
+ return arg0;
+ case 1:
+ return arg1;
+ case 2:
+ return arg2;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+std::string ArgPasser::stringValue(std::string arg0, int argn, std::string
arg1)
+{
+ switch (argn) {
+ case 0:
+ return arg0;
+ case 1:
+ return arg1;
+ default:
+ break;
+ }
+
+ return "argn invalid";
+}
+
+std::string ArgPasser::stringRef(const std::string& arg0, int argn, const
std::string& arg1)
+{
+ return stringValue(arg0, argn, arg1);
+}
+
+
// special case naming
z_& z_::gime_z_(z_& z) { return z; }
diff --git a/pypy/module/cppyy/test/example01.h
b/pypy/module/cppyy/test/example01.h
--- a/pypy/module/cppyy/test/example01.h
+++ b/pypy/module/cppyy/test/example01.h
@@ -1,3 +1,5 @@
+#include <string>
+
class payload {
public:
payload(double d = 0.);
@@ -60,6 +62,19 @@
}
+// argument passing
+class ArgPasser { // use a class for now as methptrgetter not
+public: // implemented for global functions
+ int intValue(int arg0, int argn=0, int arg1=1, int arg2=2);
+
+ std::string stringValue(
+ std::string arg0, int argn=0, std::string arg1 = "default");
+
+ std::string stringRef(
+ const std::string& arg0, int argn=0, const std::string& arg1="default");
+};
+
+
// special case naming
class z_ {
public:
diff --git a/pypy/module/cppyy/test/example01.xml
b/pypy/module/cppyy/test/example01.xml
--- a/pypy/module/cppyy/test/example01.xml
+++ b/pypy/module/cppyy/test/example01.xml
@@ -2,6 +2,7 @@
<class name="payload" />
<class name="example01" />
+ <class name="std::string" />
<class name="z_" />
<function name="globalAddOneToInt" />
@@ -9,4 +10,6 @@
<namespace name="ns_example01" />
<function name="ns_example01::globalAddOneToInt" />
+ <class name="ArgPasser" />
+
</lcgdict>
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
@@ -24,7 +24,7 @@
adddouble = w_cppyyclass.methods["staticAddToDouble"]
func, = adddouble.functions
assert isinstance(func.executor, executor.DoubleExecutor)
- assert func.arg_types == ["double"]
+ assert func.arg_defs == [("double", "")]
class AppTestCPPYY:
diff --git a/pypy/module/cppyy/test/test_helper.py
b/pypy/module/cppyy/test/test_helper.py
--- a/pypy/module/cppyy/test/test_helper.py
+++ b/pypy/module/cppyy/test/test_helper.py
@@ -1,5 +1,8 @@
from pypy.module.cppyy import helper
+def test_remove_const():
+ assert helper.remove_const("const int") == "int"
+
def test_compound():
assert helper.compound("int*") == "*"
assert helper.compound("int* const *&") == "**&"
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
@@ -37,7 +37,7 @@
cl2 = cppyy.gbl.example01
assert example01_class is cl2
- raises(AttributeError, "cppyy.gbl.nonexistingclass")
+ raises(AttributeError, 'cppyy.gbl.nonexistingclass')
def test03_calling_static_functions(self):
"""Test calling of static methods."""
@@ -244,7 +244,30 @@
# TODO: need ReferenceError on touching pl_a
- def test10_underscore_in_class_name(self):
+ def test10_default_arguments(self):
+ """Test propagation of default function arguments"""
+
+ import cppyy
+ a = cppyy.gbl.ArgPasser()
+
+ # NOTE: when called through the stub, default args are fine
+ f = a.stringRef
+ s = cppyy.gbl.std.string
+ assert f(s("aap"), 0, s("noot")).c_str() == "aap"
+ assert f(s("noot"), 1).c_str() == "default"
+ assert f(s("mies")).c_str() == "mies"
+
+ g = a.intValue
+ raises(TypeError, 'g(1, 2, 3, 4, 6)')
+ assert g(11, 0, 12, 13) == 11
+ assert g(11, 1, 12, 13) == 12
+ assert g(11, 1, 12) == 12
+ assert g(11, 2, 12) == 2
+ assert g(11, 1) == 1
+ assert g(11, 2) == 2
+ assert g(11) == 11
+
+ def test12_underscore_in_class_name(self):
"""Test recognition of '_' as part of a valid class name"""
import cppyy
@@ -255,4 +278,3 @@
assert hasattr(z, 'myint')
assert z.gime_z_(z)
-
diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py
--- a/pypy/rlib/libffi.py
+++ b/pypy/rlib/libffi.py
@@ -238,7 +238,7 @@
self = jit.promote(self)
if argchain.numargs != len(self.argtypes):
raise TypeError, 'Wrong number of arguments: %d expected, got %d'
%\
- (argchain.numargs, len(self.argtypes))
+ (len(self.argtypes), argchain.numargs)
ll_args = self._prepare()
i = 0
arg = argchain.first
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit