[pypy-commit] pypy reflex-support: write support for static (class-level) data members
wlav
noreply at buildbot.pypy.org
Wed May 11 00:42:53 CEST 2011
Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r44065:0bb7cb080a74
Date: 2011-05-10 15:49 -0700
http://bitbucket.org/pypy/pypy/changeset/0bb7cb080a74/
Log: write support for static (class-level) data members
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
@@ -16,12 +16,16 @@
def get_rawobject(space, w_obj):
from pypy.module.cppyy.interp_cppyy import W_CPPInstance
- w_obj = space.findattr(w_obj, space.wrap("_cppinstance"))
+ w_obj = space.wrap(space.findattr(w_obj, space.wrap("_cppinstance")))
obj = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
- return obj.rawobject
+ if obj:
+ return obj.rawobject
+ else:
+ return lltype.nullptr(rffi.CCHARP.TO)
class TypeConverter(object):
+ _immutable = True
libffitype = libffi.types.NULL
def __init__(self, space, array_size):
@@ -30,13 +34,15 @@
@jit.dont_look_inside
def _get_fieldptr(self, space, w_obj, offset):
rawobject = get_rawobject(space, w_obj)
- return lltype.direct_ptradd(rawobject, offset)
+ if rawobject:
+ fieldptr = lltype.direct_ptradd(rawobject, offset)
+ else:
+ fieldptr = rffi.cast(rffi.CCHARP, offset)
+ return fieldptr
def _get_address(self, space, w_obj, offset):
- if space.eq_w(w_obj, space.w_None): # meaning, static/global data
- address = rffi.cast(rffi.CCHARP, offset)
- else:
- address = self._get_fieldptr(space, w_obj, offset)
+ fieldptr = self._get_fieldptr(space, w_obj, offset)
+ address = rffi.cast(rffi.CCHARP, fieldptr)
return address
def _is_abstract(self):
@@ -61,6 +67,7 @@
class ArrayTypeConverter(TypeConverter):
+ _immutable = True
typecode = ''
typesize = 0 # TODO: get sizeof(type) from system
@@ -72,7 +79,8 @@
def from_memory(self, space, w_obj, offset):
# read access, so no copy needed
- address = self._get_address(space, w_obj, offset)
+ address_value = self._get_address(space, w_obj, offset)
+ address = rffi.cast(rffi.UINT, address_value)
arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap(self.typecode)))
return arr.fromaddress(space, address, self.size)
@@ -92,6 +100,7 @@
class VoidConverter(TypeConverter):
+ _immutable = True
libffitype = libffi.types.void
def __init__(self, space, name):
@@ -130,6 +139,7 @@
address[0] = '\x00'
class CharConverter(TypeConverter):
+ _immutable = True
libffitype = libffi.types.schar
def _from_space(self, space, w_value):
@@ -163,15 +173,15 @@
address[0] = self._from_space(space, w_value)
class LongConverter(TypeConverter):
+ _immutable = True
libffitype = libffi.types.slong
- rffiptrtype = rffi.LONGP
def _unwrap_object(self, space, w_obj):
return space.c_int_w(w_obj)
def convert_argument(self, space, w_obj):
arg = self._unwrap_object(space, w_obj)
- x = lltype.malloc(self.rffiptrtype.TO, 1, flavor='raw')
+ x = lltype.malloc(rffi.LONGP.TO, 1, flavor='raw')
x[0] = arg
return rffi.cast(rffi.VOIDP, x)
@@ -180,22 +190,39 @@
def from_memory(self, space, w_obj, offset):
address = self._get_address(space, w_obj, offset)
- longptr = rffi.cast(self.rffiptrtype, address)
+ longptr = rffi.cast(rffi.LONGP, address)
return space.wrap(longptr[0])
def to_memory(self, space, w_obj, w_value, offset):
address = self._get_address(space, w_obj, offset)
- longptr = rffi.cast(self.rffiptrtype, address)
- longptr[0] = self._unwrap_object(space, w_value)
+ longptr = rffi.cast(rffi.LONGP, address)
+ longptr[0] = space.c_int_w(w_value)
class UnsignedLongConverter(LongConverter):
+ _immutable = True
libffitype = libffi.types.ulong
- rffiptrtype = rffi.ULONGP
def _unwrap_object(self, space, w_obj):
return space.c_uint_w(w_obj)
+ def convert_argument(self, space, w_obj):
+ arg = self._unwrap_object(space, w_obj)
+ x = lltype.malloc(rffi.ULONGP.TO, 1, flavor='raw')
+ x[0] = arg
+ return rffi.cast(rffi.VOIDP, x)
+
+ def from_memory(self, space, w_obj, offset):
+ address = self._get_address(space, w_obj, offset)
+ ulongptr = rffi.cast(rffi.ULONGP, address)
+ return space.wrap(ulongptr[0])
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ address = self._get_address(space, w_obj, offset)
+ ulongptr = rffi.cast(rffi.ULONGP, address)
+ ulongptr[0] = space.c_uint_w(w_value)
+
class ShortConverter(LongConverter):
+ _immutable = True
libffitype = libffi.types.sshort
def from_memory(self, space, w_obj, offset):
@@ -206,7 +233,7 @@
def to_memory(self, space, w_obj, w_value, offset):
address = self._get_address(space, w_obj, offset)
shortptr = rffi.cast(rffi.SHORTP, address)
- shortptr[0] = rffi.cast(rffi.SHORT, space.c_int_w(w_value))
+ shortptr[0] = rffi.cast(rffi.SHORT, self._unwrap_object(space, w_value))
class FloatConverter(TypeConverter):
def _unwrap_object(self, space, w_obj):
@@ -228,6 +255,7 @@
floatptr[0] = r_singlefloat(space.float_w(w_value))
class DoubleConverter(TypeConverter):
+ _immutable = True
libffitype = libffi.types.double
def _unwrap_object(self, space, w_obj):
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
@@ -31,9 +31,9 @@
def execute(self, space, func, cppthis, num_args, args):
lresult = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args)
- spresult = rffi.cast(rffi.SHORTP, lresult)
+ address = rffi.cast(rffi.UINT, lresult)
arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap(self.typecode)))
- return arr.fromaddress(space, spresult, sys.maxint)
+ return arr.fromaddress(space, address, sys.maxint)
class VoidExecutor(FunctionExecutor):
@@ -50,6 +50,7 @@
class BoolExecutor(FunctionExecutor):
_immutable_ = True
+
def execute(self, space, func, cppthis, num_args, args):
result = capi.c_call_b(func.cpptype.handle, func.method_index, cppthis, num_args, args)
return space.wrap(result)
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
@@ -247,6 +247,9 @@
self.converter = converter.get_converter(self.space, cpptype)
self.offset = offset
+ def is_static(self):
+ return self.space.wrap(False)
+
def __get__(self, args_w):
return self.converter.from_memory(self.space, args_w[0], self.offset)
@@ -256,12 +259,16 @@
W_CPPDataMember.typedef = TypeDef(
'CPPDataMember',
+ is_static = interp2app(W_CPPDataMember.is_static, unwrap_spec=['self']),
__get__ = interp2app(W_CPPDataMember.__get__, unwrap_spec=['self', 'args_w']),
__set__ = interp2app(W_CPPDataMember.__set__, unwrap_spec=['self', 'args_w']),
)
class W_CPPStaticDataMember(W_CPPDataMember):
+ def is_static(self):
+ return self.space.wrap(True)
+
def __get__(self, args_w):
return self.converter.from_memory(self.space, self.space.w_None, self.offset)
@@ -271,6 +278,7 @@
W_CPPStaticDataMember.typedef = TypeDef(
'CPPStaticDataMember',
+ is_static = interp2app(W_CPPStaticDataMember.is_static, unwrap_spec=['self']),
__get__ = interp2app(W_CPPStaticDataMember.__get__, unwrap_spec=['self', 'args_w']),
__set__ = interp2app(W_CPPStaticDataMember.__set__, unwrap_spec=['self', 'args_w']),
)
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
@@ -51,9 +51,12 @@
pass
# if failed, create
- # TODO: handle base classes
+
+ # TODO: handle base classes through lookup
cpptype = cppyy._type_byname(name)
d = {"_cppyyclass" : cpptype}
+
+ # insert (static) methods in the class dictionary
for f in cpptype.get_method_names():
cppol = cpptype.get_overload(f)
if cppol.is_static():
@@ -61,14 +64,24 @@
else:
d[f] = make_method(f, cppol.get_returntype())
+ # create a meta class to allow properties (for static data write access)
+ metacpp = type(CppyyClass)(name+'_meta', (type,), {})
+
+ # add all data members to the dictionary of the class to be created, and
+ # static ones also to the meta class (needed for property setters)
for dm in cpptype.get_data_member_names():
- d[dm] = cpptype.get_data_member(dm)
+ cppdm = cpptype.get_data_member(dm)
- pycpptype = CppyyClass(name, (CppyyObject,), d)
+ d[dm] = cppdm
+ if cppdm.is_static():
+ setattr(metacpp, dm, cppdm)
+ # create the python-side C++ class representation
+ pycpptype = metacpp(name, (CppyyObject,), d)
return pycpptype
-# raise TypeError("no such C++ class %s" % name)
+ # TODO: better error reporting
+ # raise TypeError("no such C++ class %s" % name)
class _gbl(object):
@@ -81,6 +94,7 @@
return cppclass
except TypeError, e:
import traceback
+ traceback.print_exc()
raise AttributeError("'gbl' object has no attribute '%s'" % attr)
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
@@ -211,10 +211,10 @@
assert c.s_int == -202
assert c.s_uint == 202
assert cppyy_test_data.s_uint == 202
- assert cppyy_test_data.s_long == -303
- assert c.s_long == -303
- assert c.s_ulong == 303
- assert cppyy_test_data.s_ulong == 303
+ assert cppyy_test_data.s_long == -303L
+ assert c.s_long == -303L
+ assert c.s_ulong == 303L
+ assert cppyy_test_data.s_ulong == 303L
# floating point types
assert round(cppyy_test_data.s_float + 404., 5) == 0
@@ -227,7 +227,66 @@
def test4ClassDataWriteAccess(self):
"""Test write access to class public data and verify values"""
- pass
+ import cppyy, sys
+ cppyy_test_data = cppyy.gbl.cppyy_test_data
+
+ c = cppyy_test_data()
+ assert isinstance(c, cppyy_test_data)
+
+ # char types
+ cppyy_test_data.s_char = 'a'
+ assert c.s_char == 'a'
+ c.s_char = 'b'
+ assert cppyy_test_data.s_char == 'b'
+ cppyy_test_data.s_uchar = 'c'
+ assert c.s_uchar == 'c'
+ c.s_uchar = 'd'
+ assert cppyy_test_data.s_uchar == 'd'
+ raises(TypeError, setattr, cppyy_test_data, 's_uchar', -1)
+ raises(TypeError, setattr, c, 's_uchar', -1)
+
+ # integer types
+ c.s_short = -102
+ assert cppyy_test_data.s_short == -102
+ cppyy_test_data.s_short = -203
+ assert c.s_short == -203
+ c.s_ushort = 127
+ assert cppyy_test_data.s_ushort == 127
+ cppyy_test_data.s_ushort = 227
+ assert c.s_ushort == 227
+ cppyy_test_data.s_int = -234
+ assert c.s_int == -234
+ c.s_int = -321
+ assert cppyy_test_data.s_int == -321
+ cppyy_test_data.s_uint = 1234
+ assert c.s_uint == 1234
+ c.s_uint = 4321
+ assert cppyy_test_data.s_uint == 4321
+ raises(ValueError, setattr, c, 's_uint', -1)
+ raises(ValueError, setattr, cppyy_test_data, 's_uint', -1)
+ cppyy_test_data.s_long = -87L
+ assert c.s_long == -87L
+ c.s_long = 876L
+ assert cppyy_test_data.s_long == 876L
+ cppyy_test_data.s_ulong = 876L
+ assert c.s_ulong == 876L
+ c.s_ulong = 678L
+ assert cppyy_test_data.s_ulong == 678L
+ raises(ValueError, setattr, cppyy_test_data, 's_ulong', -1)
+ raises(ValueError, setattr, c, 's_ulong', -1)
+
+ # floating point types
+ cppyy_test_data.s_float = -3.1415
+ assert round(c.s_float, 5 ) == -3.1415
+ c.s_float = 3.1415
+ assert round(cppyy_test_data.s_float, 5 ) == 3.1415
+ import math
+ c.s_double = -math.pi
+ assert cppyy_test_data.s_double == -math.pi
+ cppyy_test_data.s_double = math.pi
+ assert c.s_double == math.pi
+
+ c.destruct()
def test5RangeAccess(self):
"""Test the ranges of integer types"""
@@ -238,6 +297,8 @@
c = cppyy_test_data()
assert isinstance(c, cppyy_test_data)
+ # TODO: should these be TypeErrors, or should char/bool raise
+ # ValueErrors? In any case, consistency is needed ...
raises(ValueError, setattr, c, 'm_uint', -1)
raises(ValueError, setattr, c, 'm_ulong', -1)
More information about the pypy-commit
mailing list