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