Author: Wim Lavrijsen <[email protected]>
Branch: reflex-support
Changeset: r68861:1edf9b7c3bdb
Date: 2014-01-22 18:39 -0800
http://bitbucket.org/pypy/pypy/changeset/1edf9b7c3bdb/

Log:    support access to void* data members and add cppyy.gbl.nullptr (and
        associated tests)

diff --git a/pypy/module/cppyy/__init__.py b/pypy/module/cppyy/__init__.py
--- a/pypy/module/cppyy/__init__.py
+++ b/pypy/module/cppyy/__init__.py
@@ -15,6 +15,7 @@
         '_set_function_generator': 'interp_cppyy.set_function_generator',
         '_register_class'        : 'interp_cppyy.register_class',
         '_is_static'             : 'interp_cppyy.is_static',
+        '_get_nullptr'           : 'interp_cppyy.get_nullptr',
         'CPPInstance'            : 'interp_cppyy.W_CPPInstance',
         'addressof'              : 'interp_cppyy.addressof',
         'bind_object'            : 'interp_cppyy.bind_object',
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
@@ -7,7 +7,7 @@
 from rpython.rlib import jit_libffi, rfloat
 
 from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
-from pypy.module._rawffi.array import W_Array
+from pypy.module._rawffi.array import W_Array, W_ArrayInstance
 
 from pypy.module.cppyy import helper, capi, ffitypes
 
@@ -48,20 +48,33 @@
     return capi.C_NULL_OBJECT
 
 def is_nullpointer_specialcase(space, w_obj):
-    # special case: allow integer 0 as (void*)0
+    # 0, None, and nullptr may serve as "NULL", check for any of them
+
+    # integer 0
     try:
         return space.int_w(w_obj) == 0
     except Exception:
         pass
-    # special case: allow None as (void*)0
-    return space.is_true(space.is_(w_obj, space.w_None))
+    # None or nullptr
+    from pypy.module.cppyy import interp_cppyy
+    return space.is_true(space.is_(w_obj, space.w_None)) or \
+        space.is_true(space.is_(w_obj, interp_cppyy.get_nullptr(space)))
 
 def get_rawbuffer(space, w_obj):
+    # raw buffer
     try:
         buf = space.buffer_w(w_obj)
         return rffi.cast(rffi.VOIDP, buf.get_raw_address())
     except Exception:
         pass
+    # 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)))
+    except Exception:
+        pass
+    # pre-defined NULL
     if is_nullpointer_specialcase(space, w_obj):
         return rffi.cast(rffi.VOIDP, 0)
     raise TypeError("not an addressable buffer")
@@ -140,8 +153,6 @@
             self.size = array_size
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
-        if hasattr(space, "fake"):
-            raise NotImplementedError
         # read access, so no copy needed
         address_value = self._get_raw_address(space, w_obj, offset)
         address = rffi.cast(rffi.ULONG, address_value)
@@ -390,6 +401,24 @@
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = self._unwrap_object(space, w_obj)
 
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        # returned as a long value for the address (INTPTR_T is not proper
+        # per se, but rffi does not come with a PTRDIFF_T)
+        address = self._get_raw_address(space, w_obj, offset)
+        ptrval = rffi.cast(rffi.ULONG, rffi.cast(rffi.VOIDPP, address)[0])
+        if ptrval == 0:
+            from pypy.module.cppyy import interp_cppyy
+            return interp_cppyy.get_nullptr(space)
+        arr = space.interp_w(W_Array, unpack_simple_shape(space, 
space.wrap('P')))
+        return arr.fromaddress(space, ptrval, sys.maxint)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, 
offset))
+        if is_nullpointer_specialcase(space, w_value):
+            address[0] = rffi.cast(rffi.VOIDP, 0)
+        else:
+            address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, 
w_value))
+
 class VoidPtrPtrConverter(TypeConverter):
     _immutable_fields_ = ['uses_local']
 
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
@@ -53,17 +53,12 @@
         if hasattr(space, "fake"):
             raise NotImplementedError
         lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
-        address = rffi.cast(rffi.ULONG, lresult)
+        ptrval = rffi.cast(rffi.ULONG, lresult)
         arr = space.interp_w(W_Array, unpack_simple_shape(space, 
space.wrap(self.typecode)))
-        if address == 0:
-            # TODO: fix this hack; fromaddress() will allocate memory if 
address
-            # is null and there seems to be no way around it (ll_buffer can not
-            # be touched directly)
-            nullarr = arr.fromaddress(space, address, 0)
-            assert isinstance(nullarr, W_ArrayInstance)
-            nullarr.free(space)
-            return nullarr
-        return arr.fromaddress(space, address, sys.maxint)
+        if ptrval == 0:
+            from pypy.module.cppyy import interp_cppyy
+            return interp_cppyy.get_nullptr(space)
+        return arr.fromaddress(space, ptrval, sys.maxint)
 
 
 class VoidExecutor(FunctionExecutor):
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
@@ -40,11 +40,29 @@
     def __init__(self, space):
         self.cppscope_cache = {
             "void" : W_CPPClass(space, "void", capi.C_NULL_TYPE) }
+        self.w_nullptr = None
         self.cpptemplate_cache = {}
         self.cppclass_registry = {}
         self.w_clgen_callback = None
         self.w_fngen_callback = None
 
+def get_nullptr(space):
+    if hasattr(space, "fake"):
+        raise NotImplementedError
+    state = space.fromcache(State)
+    if state.w_nullptr is None:
+        from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+        from pypy.module._rawffi.array import W_Array, W_ArrayInstance
+        arr = space.interp_w(W_Array, unpack_simple_shape(space, 
space.wrap('P')))
+        # TODO: fix this hack; fromaddress() will allocate memory if address
+        # is null and there seems to be no way around it (ll_buffer can not
+        # be touched directly)
+        nullarr = arr.fromaddress(space, rffi.cast(rffi.ULONG, 0), 0)
+        assert isinstance(nullarr, W_ArrayInstance)
+        nullarr.free(space)
+        state.w_nullptr = space.wrap(nullarr)
+    return state.w_nullptr
+
 @unwrap_spec(name=str)
 def resolve_name(space, name):
     return space.wrap(capi.c_resolve_name(space, name))
@@ -1184,16 +1202,30 @@
     memory_regulator.register(cppinstance)
     return w_cppinstance
 
-@unwrap_spec(w_cppinstance=W_CPPInstance)
-def addressof(space, w_cppinstance):
-    """Takes a bound C++ instance, returns the raw address."""
-    address = rffi.cast(rffi.LONG, w_cppinstance.get_rawobject())
+def _addressof(space, w_obj):
+    try:
+        # attempt to extract address from array
+        return rffi.cast(rffi.INTPTR_T, converter.get_rawbuffer(space, w_obj))
+    except TypeError:
+        pass
+    # attempt to get address of C++ instance
+    return rffi.cast(rffi.INTPTR_T, converter.get_rawobject(space, w_obj))
+
+@unwrap_spec(w_obj=W_Root)
+def addressof(space, w_obj):
+    """Takes a bound C++ instance or array, returns the raw address."""
+    address = _addressof(space, w_obj)
     return space.wrap(address)
 
-@unwrap_spec(address=int, owns=bool)
-def bind_object(space, address, w_pycppclass, owns=False):
+@unwrap_spec(owns=bool)
+def bind_object(space, w_obj, w_pycppclass, owns=False):
     """Takes an address and a bound C++ class proxy, returns a bound 
instance."""
-    rawobject = rffi.cast(capi.C_OBJECT, address)
+    try:
+        # attempt address from array or C++ instance
+        rawobject = rffi.cast(capi.C_OBJECT, _addressof(space, w_obj))
+    except Exception:
+        # accept integer value as address
+        rawobject = rffi.cast(capi.C_OBJECT, space.uint_w(w_obj))
     w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
     if not w_cppclass:
         w_cppclass = scope_byname(space, space.str_w(w_pycppclass))
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
@@ -447,6 +447,9 @@
     # be the same issue for all typedef'd builtin types
     setattr(gbl, 'unsigned int', int)
 
+    # install nullptr as a unique reference
+    setattr(gbl, 'nullptr', cppyy._get_nullptr())
+
     # install for user access
     cppyy.gbl = gbl
 
diff --git a/pypy/module/cppyy/test/datatypes.cxx 
b/pypy/module/cppyy/test/datatypes.cxx
--- a/pypy/module/cppyy/test/datatypes.cxx
+++ b/pypy/module/cppyy/test/datatypes.cxx
@@ -18,6 +18,7 @@
     m_float  = -66.f;
     m_double = -77.;
     m_enum   = kNothing;
+    m_voidp  = (void*)0;
 
     m_bool_array2   = new bool[N];
     m_short_array2  = new short[N];
@@ -97,6 +98,7 @@
 float          cppyy_test_data::get_float()  { return m_float; }
 double         cppyy_test_data::get_double() { return m_double; }
 cppyy_test_data::what cppyy_test_data::get_enum() { return m_enum; }
+void*          cppyy_test_data::get_voidp()  { return m_voidp; }
 
 bool*           cppyy_test_data::get_bool_array()    { return m_bool_array; }
 bool*           cppyy_test_data::get_bool_array2()   { return m_bool_array2; }
@@ -150,6 +152,7 @@
 void cppyy_test_data::set_double(double d)                   { m_double = d; }
 void cppyy_test_data::set_double_c(const double& d)          { m_double = d; }
 void cppyy_test_data::set_enum(what w)                       { m_enum   = w; }
+void cppyy_test_data::set_voidp(void* p)                     { m_voidp  = p; }
 
 void cppyy_test_data::set_pod_val(cppyy_test_pod p)            { m_pod = p; }
 void cppyy_test_data::set_pod_ptr_in(cppyy_test_pod* pp)       { m_pod = *pp; }
@@ -186,6 +189,7 @@
 float               cppyy_test_data::s_float  = -606.f;
 double              cppyy_test_data::s_double = -707.;
 cppyy_test_data::what  cppyy_test_data::s_enum = cppyy_test_data::kNothing;
+void*               cppyy_test_data::s_voidp  = (void*)0;
 
 //- strings -----------------------------------------------------------------
 const char* cppyy_test_data::get_valid_string(const char* in) { return in; }
diff --git a/pypy/module/cppyy/test/datatypes.h 
b/pypy/module/cppyy/test/datatypes.h
--- a/pypy/module/cppyy/test/datatypes.h
+++ b/pypy/module/cppyy/test/datatypes.h
@@ -68,6 +68,7 @@
     float                get_float();
     double               get_double();
     what                 get_enum();
+    void*                get_voidp();
 
     bool*           get_bool_array();
     bool*           get_bool_array2();
@@ -121,6 +122,7 @@
     void set_double(double d);
     void set_double_c(const double& d);
     void set_enum(what w);
+    void set_voidp(void* p);
 
     void set_pod_val(cppyy_test_pod);             // for m_pod
     void set_pod_ptr_in(cppyy_test_pod*);
@@ -172,6 +174,7 @@
     float                m_float;
     double               m_double;
     what                 m_enum;
+    void*                m_voidp;
 
 // array types
     bool            m_bool_array[N];
@@ -212,6 +215,7 @@
     static float                   s_float;
     static double                  s_double;
     static what                    s_enum;
+    static void*                   s_voidp;
 
 private:
     bool m_owns_arrays;
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
@@ -232,11 +232,13 @@
             for i in range(self.N):
                 assert ca[i] == b[i]
 
-        # NULL/None passing (will use short*)
+        # NULL/None/nullptr passing (will use short*)
         assert not c.pass_array(0)
         raises(Exception, c.pass_array(0).__getitem__, 0)    # raises 
SegfaultException
         assert not c.pass_array(None)
         raises(Exception, c.pass_array(None).__getitem__, 0) # id.
+        assert not c.pass_array(cppyy.gbl.nullptr)
+        raises(Exception, c.pass_array(cppyy.gbl.nullptr).__getitem__, 0) # 
id. id.
 
         c.destruct()
 
@@ -694,3 +696,51 @@
             l = list(arr)
             for i in range(self.N):
                 assert arr[i] == l[i]
+
+    def test21_voidp(self):
+        """Test usage of void* data"""
+
+        import cppyy
+        cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+        c = cppyy_test_data()
+
+        assert not cppyy.gbl.nullptr
+
+        assert c.s_voidp                is cppyy.gbl.nullptr
+        assert cppyy_test_data.s_voidp  is cppyy.gbl.nullptr
+
+        assert c.m_voidp                is cppyy.gbl.nullptr
+        assert c.get_voidp()            is cppyy.gbl.nullptr
+
+        c2 = cppyy_test_data()
+        assert c2.m_voidp               is cppyy.gbl.nullptr
+        c.set_voidp(c2.m_voidp)
+        assert c.m_voidp                is cppyy.gbl.nullptr
+        c.set_voidp(c2.get_voidp())
+        assert c.m_voidp                is cppyy.gbl.nullptr
+        c.set_voidp(cppyy.gbl.nullptr)
+        assert c.m_voidp                is cppyy.gbl.nullptr
+
+        c.set_voidp(c2)
+        def address_equality_test(a, b):
+            assert cppyy.addressof(a) == cppyy.addressof(b)
+            b2 = cppyy.bind_object(a, cppyy_test_data)
+            assert b is b2    # memory regulator recycles
+            b3 = cppyy.bind_object(cppyy.addressof(a), cppyy_test_data)
+            assert b is b3    # likewise
+
+        address_equality_test(c.m_voidp, c2)
+        address_equality_test(c.get_voidp(), c2)
+
+        def null_test(null):
+            c.m_voidp = null
+            assert c.m_voidp is cppyy.gbl.nullptr
+        map(null_test, [0, None, cppyy.gbl.nullptr])
+
+        c.m_voidp = c2
+        address_equality_test(c.m_voidp,     c2)
+        address_equality_test(c.get_voidp(), c2)
+
+        c.s_voidp = c2
+        address_equality_test(c.s_voidp, c2)
diff --git a/pypy/module/cppyy/test/test_fragile.py 
b/pypy/module/cppyy/test/test_fragile.py
--- a/pypy/module/cppyy/test/test_fragile.py
+++ b/pypy/module/cppyy/test/test_fragile.py
@@ -109,9 +109,11 @@
 
         cppyy.addressof(f)
         raises(TypeError, cppyy.addressof, o)
-        raises(TypeError, cppyy.addressof, 0)
         raises(TypeError, cppyy.addressof, 1)
-        raises(TypeError, cppyy.addressof, None)
+        # 0, None, and nullptr allowed
+        assert cppyy.addressof(0)                 == 0
+        assert cppyy.addressof(None)              == 0
+        assert cppyy.addressof(cppyy.gbl.nullptr) == 0
 
     def test06_wrong_this(self):
         """Test that using an incorrect self argument raises"""
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to