[pypy-commit] pypy reflex-support: merge heads

cfbolz noreply at buildbot.pypy.org
Wed Jul 13 14:12:52 CEST 2011


Author: Carl Friedrich Bolz <cfbolz at 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


More information about the pypy-commit mailing list