Author: Carl Friedrich Bolz <cfb...@gmx.de> Branch: reflex-support Changeset: r45538:6ff6f4beb1bf Date: 2011-07-13 14:07 +0200 http://bitbucket.org/pypy/pypy/changeset/6ff6f4beb1bf/
Log: merge heads diff --git a/pypy/module/cppyy/capi/cint_capi.py b/pypy/module/cppyy/capi/cint_capi.py --- a/pypy/module/cppyy/capi/cint_capi.py +++ b/pypy/module/cppyy/capi/cint_capi.py @@ -107,6 +107,10 @@ "cppyy_call_h", [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.SHORT, compilation_info=eci) +c_call_i = rffi.llexternal( + "cppyy_call_i", + [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.INT, + compilation_info=eci) c_call_l = rffi.llexternal( "cppyy_call_l", [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.LONG, diff --git a/pypy/module/cppyy/capi/reflex_capi.py b/pypy/module/cppyy/capi/reflex_capi.py --- a/pypy/module/cppyy/capi/reflex_capi.py +++ b/pypy/module/cppyy/capi/reflex_capi.py @@ -108,7 +108,7 @@ [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.SHORT, compilation_info=eci) c_call_i = rffi.llexternal( - "cppyy_call_l", + "cppyy_call_i", [C_TYPEHANDLE, rffi.INT, C_OBJECT, rffi.INT, rffi.VOIDPP], rffi.INT, compilation_info=eci) c_call_l = rffi.llexternal( 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 @@ -288,7 +288,7 @@ libffitype = libffi.types.ulong def _unwrap_object(self, space, w_obj): - return space.c_uint_w(w_obj) + return space.uint_w(w_obj) def convert_argument(self, space, w_obj): arg = self._unwrap_object(space, w_obj) @@ -376,6 +376,11 @@ x = rffi.str2charp(arg) return rffi.cast(rffi.VOIDP, x) + def from_memory(self, space, w_obj, offset): + address = self._get_raw_address(space, w_obj, offset) + charpptr = rffi.cast(rffi.CCHARPP, address) + return space.wrap(rffi.charp2str(charpptr[0])) + class ShortArrayConverter(ArrayTypeConverterMixin, TypeConverter): _immutable_=True @@ -566,3 +571,4 @@ _converters["double*"] = DoublePtrConverter _converters["double[]"] = DoubleArrayConverter _converters["const char*"] = CStringConverter +_converters["char*"] = CStringConverter diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py --- a/pypy/module/cppyy/executor.py +++ b/pypy/module/cppyy/executor.py @@ -92,10 +92,10 @@ libffitype = libffi.types.uint def _wrap_result(self, space, result): - return space.wrap(result) + return space.wrap(rffi.cast(rffi.UINT, result)) def execute(self, space, func, cppthis, num_args, args): - result = capi.c_call_i(func.cpptype.handle, func.method_index, cppthis, num_args, args) + result = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) return self._wrap_result(space, result) class LongExecutor(FunctionExecutor): @@ -112,6 +112,13 @@ def execute_libffi(self, space, libffifunc, argchain): return space.wrap(libffifunc.call(argchain, lltype.Signed)) +class UnsignedLongExecutor(LongExecutor): + _immutable_ = True + libffitype = libffi.types.ulong + + def _wrap_result(self, space, result): + return space.wrap(rffi.cast(rffi.ULONG, result)) + class ConstIntRefExecutor(LongExecutor): _immutable_ = True @@ -170,6 +177,10 @@ _immutable_ = True typecode = 'l' +class UnsignedLongPtrExecutor(PtrTypeExecutor): + _immutable_ = True + typecode = 'L' + class FloatPtrExecutor(PtrTypeExecutor): _immutable_ = True typecode = 'f' @@ -189,7 +200,7 @@ from pypy.module.cppyy import interp_cppyy long_result = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args) ptr_result = rffi.cast(rffi.VOIDP, long_result) - return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result) + return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, False) class InstanceExecutor(InstancePtrExecutor): _immutable_ = True @@ -199,8 +210,7 @@ long_result = capi.c_call_o( func.cpptype.handle, func.method_index, cppthis, num_args, args, self.cpptype.handle) ptr_result = rffi.cast(rffi.VOIDP, long_result) - # TODO: take ownership of result ... - return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result) + return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, True) _executors = {} @@ -275,8 +285,8 @@ _executors["unsigned int*"] = UnsignedIntPtrExecutor _executors["long int"] = LongExecutor _executors["long int*"] = LongPtrExecutor -_executors["unsigned long int"] = LongExecutor -_executors["unsigned long int*"] = LongPtrExecutor +_executors["unsigned long int"] = UnsignedLongExecutor +_executors["unsigned long int*"] = UnsignedLongPtrExecutor _executors["float"] = FloatExecutor _executors["float*"] = FloatPtrExecutor _executors["double"] = DoubleExecutor 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 @@ -227,7 +227,7 @@ except Exception, e: capi.c_deallocate(self.cpptype.handle, newthis) raise - return W_CPPInstance(self.space, self.cpptype, newthis) + return W_CPPInstance(self.space, self.cpptype, newthis, True) class W_CPPOverload(Wrappable): @@ -246,13 +246,22 @@ return self.space.wrap(self.functions[0].executor.name) @jit.unroll_safe - def call(self, cppthis, args_w): + def call(self, cppinstance, args_w): + if cppinstance: + cppthis = cppinstance.rawobject + else: + cppthis = NULL_VOIDP + space = self.space errmsg = 'None of the overloads matched:' for i in range(len(self.functions)): cppyyfunc = self.functions[i] try: - return cppyyfunc.call(cppthis, args_w) + cppresult = cppyyfunc.call(cppthis, args_w) + if cppinstance and isinstance(cppresult, W_CPPInstance): + if cppresult.rawobject == cppinstance.rawobject: + return cppinstance # recycle object to preserve identity + return cppresult except OperationError, e: if not e.match(space, space.w_TypeError): raise @@ -377,7 +386,7 @@ self.space.wrap(str("class %s has no attribute %s" % (self.name, name)))) def invoke(self, overload, args_w): - return overload.call(NULL_VOIDP, args_w) + return overload.call(None, args_w) W_CPPScope.typedef = TypeDef( 'CPPScope', @@ -484,7 +493,7 @@ self.space.wrap("%s is abstract" % self.name)) raise - return overload.call(NULL_VOIDP, args_w) + return overload.call(None, args_w) W_CPPType.typedef = TypeDef( 'CPPType', @@ -521,10 +530,11 @@ class W_CPPInstance(Wrappable): _immutable_fields_ = ["cppclass"] - def __init__(self, space, cppclass, rawobject): + def __init__(self, space, cppclass, rawobject, python_owns): self.space = space self.cppclass = cppclass self.rawobject = rawobject + self.python_owns = python_owns def _nullcheck(self): if not self.rawobject: @@ -532,11 +542,16 @@ def invoke(self, overload, args_w): self._nullcheck() - return overload.call(self.rawobject, args_w) + return overload.call(self, args_w) def destruct(self): - capi.c_destruct(self.cppclass.handle, self.rawobject) - self.rawobject = NULL_VOIDP + if self.rawobject: + capi.c_destruct(self.cppclass.handle, self.rawobject) + self.rawobject = NULL_VOIDP + + def __del__(self): + if self.python_owns: + self.destruct() W_CPPInstance.typedef = TypeDef( 'CPPInstance', 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 @@ -128,6 +128,12 @@ return (short)G__int(result); } +int cppyy_call_i(cppyy_typehandle_t handle, int method_index, + cppyy_object_t self, int numargs, void* args[]) { + G__value result = cppyy_call_T(handle, method_index, self, numargs, args); + return (int)G__int(result); +} + long cppyy_call_l(cppyy_typehandle_t handle, int method_index, cppyy_object_t self, int numargs, void* args[]) { G__value result = cppyy_call_T(handle, method_index, self, numargs, args); 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 @@ -7,12 +7,28 @@ #include "example01.h" //=========================================================================== -payload::payload(double d) : m_data(d) {} -payload::payload(const payload& p) : m_data(p.m_data) {} +payload::payload(double d) : m_data(d) { + count++; +} +payload::payload(const payload& p) : m_data(p.m_data) { + count++; +} +payload& payload::operator=(const payload& p) { + if (this != &p) { + m_data = p.m_data; + } + return *this; +} +payload::~payload() { + count--; +} double payload::getData() { return m_data; } void payload::setData(double d) { m_data = d; } +// class-level data +int payload::count = 0; + //=========================================================================== example01::example01() : m_somedata(-99) { 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 @@ -2,10 +2,15 @@ public: payload(double d); payload(const payload& p); + payload& operator=(const payload& e); + ~payload(); double getData(); void setData(double d); +public: // class-level data + static int count; + private: double m_data; }; diff --git a/pypy/module/cppyy/test/operators.cxx b/pypy/module/cppyy/test/operators.cxx new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/operators.cxx @@ -0,0 +1,1 @@ +#include "operators.h" diff --git a/pypy/module/cppyy/test/operators.h b/pypy/module/cppyy/test/operators.h new file mode 100644 --- /dev/null +++ b/pypy/module/cppyy/test/operators.h @@ -0,0 +1,97 @@ +class number { +public: + number() { m_int = 0; } + number(int i) { m_int = i; } + + int AsInt() { return m_int; } + + number operator+(const number& n) const { return number(m_int + n.m_int); } + number operator+(int n) const { return number(m_int + n); } + number operator-(const number& n) const { return number(m_int - n.m_int); } + number operator-(int n) const { return number(m_int - n); } + number operator*(const number& n) const { return number(m_int * n.m_int); } + number operator*(int n) const { return number(m_int * n); } + number operator/(const number& n) const { return number(m_int / n.m_int); } + number operator/(int n) const { return number(m_int / n); } + number operator%(const number& n) const { return number(m_int % n.m_int); } + number operator%(int n) const { return number(m_int % n); } + + number& operator+=(const number& n) { m_int += n.m_int; return *this; } + number& operator-=(const number& n) { m_int -= n.m_int; return *this; } + number& operator*=(const number& n) { m_int *= n.m_int; return *this; } + number& operator/=(const number& n) { m_int /= n.m_int; return *this; } + number& operator%=(const number& n) { m_int %= n.m_int; return *this; } + + number operator-() { return number( -m_int ); } + + bool operator<(const number& n) const { return m_int < n.m_int; } + bool operator>(const number& n) const { return m_int > n.m_int; } + bool operator<=(const number& n) const { return m_int <= n.m_int; } + bool operator>=(const number& n) const { return m_int >= n.m_int; } + bool operator!=(const number& n) const { return m_int != n.m_int; } + bool operator==(const number& n) const { return m_int == n.m_int; } + + operator bool() { return m_int != 0; } + + number operator&(const number& n) const { return number(m_int & n.m_int); } + number operator|(const number& n) const { return number(m_int | n.m_int); } + number operator^(const number& n) const { return number(m_int ^ n.m_int); } + + number& operator&=(const number& n) { m_int &= n.m_int; return *this; } + number& operator|=(const number& n) { m_int |= n.m_int; return *this; } + number& operator^=(const number& n) { m_int ^= n.m_int; return *this; } + + number operator<<(int i) const { return number(m_int << i); } + number operator>>(int i) const { return number(m_int >> i); } + +private: + int m_int; +}; + +//---------------------------------------------------------------------------- +struct operator_char_star { // for testing user-defined implicit casts + operator_char_star() : m_str((char*)"operator_char_star") {} + operator char*() { return m_str; } + char* m_str; +}; + +struct operator_const_char_star { + operator_const_char_star() : m_str("operator_const_char_star" ) {} + operator const char*() { return m_str; } + const char* m_str; +}; + +struct operator_int { + operator int() { return m_int; } + int m_int; +}; + +struct operator_long { + operator long() { return m_long; } + long m_long; +}; + +struct operator_double { + operator double() { return m_double; } + double m_double; +}; + +struct operator_short { + operator short() { return m_short; } + unsigned short m_short; +}; + +struct operator_unsigned_int { + operator unsigned int() { return m_uint; } + unsigned int m_uint; +}; + +struct operator_unsigned_long { + operator unsigned long() { return m_ulong; } + unsigned long m_ulong; +}; + +struct operator_float { + operator float() { return m_float; } + float m_float; +}; 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 @@ -111,6 +111,40 @@ e2.destruct() assert t.invoke(t.get_overload("getCount")) == 0 + e2.destruct() + assert t.invoke(t.get_overload("getCount")) == 0 + + def test_example01memory(self): + """Test memory destruction and integrity.""" + + import gc + + t = self.example01 + + assert t.invoke(t.get_overload("getCount")) == 0 + + e1 = t.construct(7) + assert t.invoke(t.get_overload("getCount")) == 1 + res = e1.invoke(t.get_overload("addDataToInt"), 4) + assert res == 11 + res = e1.invoke(t.get_overload("addDataToInt"), -4) + assert res == 3 + e1 = None + gc.collect() + assert t.invoke(t.get_overload("getCount")) == 0 + + e1 = t.construct(7) + e2 = t.construct(8) + assert t.invoke(t.get_overload("getCount")) == 2 + e1 = None + gc.collect() + assert t.invoke(t.get_overload("getCount")) == 1 + e2.destruct() + assert t.invoke(t.get_overload("getCount")) == 0 + e2 = None + gc.collect() + assert t.invoke(t.get_overload("getCount")) == 0 + def test_example01method_double(self): """Test passing of a double and returning of double on a method""" diff --git a/pypy/module/cppyy/test/test_operators.py b/pypy/module/cppyy/test/test_operators.py new file mode 100755 --- /dev/null +++ b/pypy/module/cppyy/test/test_operators.py @@ -0,0 +1,141 @@ +import py, os, sys +from pypy.conftest import gettestobjspace + + +currpath = py.path.local(__file__).dirpath() +shared_lib = str(currpath.join("operatorsDict.so")) + +space = gettestobjspace(usemodules=['cppyy']) + +def setup_module(mod): + if sys.platform == 'win32': + py.test.skip("win32 not supported so far") + err = os.system("cd '%s' && make operatorsDict.so" % currpath) + if err: + raise OSError("'make' failed (see stderr)") + +class AppTestOPERATORS: + def setup_class(cls): + cls.space = space + env = os.environ + cls.w_N = space.wrap(5) # should be imported from the dictionary + cls.w_shared_lib = space.wrap(shared_lib) + cls.w_datatypes = cls.space.appexec([], """(): + import cppyy + return cppyy.load_lib(%r)""" % (shared_lib, )) + + def teardown_method(self, meth): + import gc + gc.collect() + + def test01_math_operators(self): + """Test overloading of math operators""" + + import cppyy + number = cppyy.gbl.number + + assert (number(20) + number(10)) == number(30) + assert (number(20) + 10 ) == number(30) + assert (number(20) - number(10)) == number(10) + assert (number(20) - 10 ) == number(10) + assert (number(20) / number(10)) == number(2) + assert (number(20) / 10 ) == number(2) + assert (number(20) * number(10)) == number(200) + assert (number(20) * 10 ) == number(200) + assert (number(20) % 10 ) == number(0) + assert (number(20) % number(10)) == number(0) + assert (number(5) & number(14)) == number(4) + assert (number(5) | number(14)) == number(15) + assert (number(5) ^ number(14)) == number(11) + assert (number(5) << 2) == number(20) + assert (number(20) >> 2) == number(5) + + def test02_unary_math_operators(self): + """Test overloading of unary math operators""" + + import cppyy + number = cppyy.gbl.number + + n = number(20) + n += number(10) + n -= number(10) + n *= number(10) + n /= number(2) + assert n == number(100) + + nn = -n; + assert nn == number(-100) + + def test03_comparison_operators(self): + """Test overloading of comparison operators""" + + import cppyy + number = cppyy.gbl.number + + assert (number(20) > number(10)) == True + assert (number(20) < number(10)) == False + assert (number(20) >= number(20)) == True + assert (number(20) <= number(10)) == False + assert (number(20) != number(10)) == True + assert (number(20) == number(10)) == False + + def test04_boolean_operator(self): + """Test implementation of operator bool""" + + import cppyy + number = cppyy.gbl.number + + n = number(20) + assert n + + n = number(0) + assert not n + + def test05_exact_types(self): + """Test converter operators of exact types""" + + import cppyy + gbl = cppyy.gbl + + o = gbl.operator_char_star() + assert o.m_str == 'operator_char_star' + assert str(o) == 'operator_char_star' + + o = gbl.operator_const_char_star() + assert o.m_str == 'operator_const_char_star' + assert str(o) == 'operator_const_char_star' + + o = gbl.operator_int(); o.m_int = -13 + assert o.m_int == -13 + assert int(o) == -13 + + o = gbl.operator_long(); o.m_long = 42 + assert o.m_long == 42 + assert long(o) == 42 + + o = gbl.operator_double(); o.m_double = 3.1415 + assert o.m_double == 3.1415 + assert float(o) == 3.1415 + + def test06_approximate_types(self): + """Test converter operators of approximate types""" + + import cppyy, sys + gbl = cppyy.gbl + + o = gbl.operator_short(); o.m_short = 256 + assert o.m_short == 256 + assert int(o) == 256 + + o = gbl.operator_unsigned_int(); o.m_uint = 2147483647 + 32 + assert o.m_uint == 2147483647 + 32 + assert long(o) == 2147483647 + 32 + + o = gbl.operator_unsigned_long(); + o.m_ulong = sys.maxint + 128 + assert o.m_ulong == sys.maxint + 128 + assert long(o) == sys.maxint + 128 + + o = gbl.operator_float(); o.m_float = 3.14 + assert round(o.m_float - 3.14, 5) == 0. + assert round(float(o) - 3.14, 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 @@ -199,3 +199,44 @@ assert cppyy.gbl.ns_example01.globalAddOneToInt(4) == 5 assert cppyy.gbl.ns_example01.globalAddOneToInt(4) == 5 + + def test09_memory(self): + import cppyy, gc + example01_class = cppyy.gbl.example01 + payload_class = cppyy.gbl.payload + + pl = payload_class(3.14) + assert payload_class.count == 1 + assert round(pl.getData()-3.14, 8) == 0 + + pl2 = example01_class.staticCopyCyclePayload(pl, 38.) + assert payload_class.count == 2 + assert pl2.getData() == 38. + pl2 = None + gc.collect() + assert payload_class.count == 1 + + e = example01_class(14) + + pl2 = e.copyCyclePayload(pl) + assert payload_class.count == 2 + assert round(pl2.getData()-14., 8) == 0 + pl2 = None + gc.collect() + assert payload_class.count == 1 + + pl = None + e = None + gc.collect() + assert payload_class.count == 0 + assert example01_class.getCount() == 0 + + pl = payload_class(3.14) + pl_a = example01_class.staticCyclePayload(pl, 66.) + pl_a.getData() == 66. + assert payload_class.count == 1 + pl = None + gc.collect() + assert payload_class.count == 0 + + # TODO: need ReferenceError on touching pl_a _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit