[pypy-commit] pypy pypy_swappedbytes: Added _swappedbytes_ support for ctypes.Structure
smihnea
pypy.commits at gmail.com
Sun Aug 27 02:54:05 EDT 2017
Author: Mihnea Saracin <mihnea.saracin at rinftech.com>
Branch: pypy_swappedbytes
Changeset: r92262:7ec88773f8b9
Date: 2017-07-27 17:29 +0300
http://bitbucket.org/pypy/pypy/changeset/7ec88773f8b9/
Log: Added _swappedbytes_ support for ctypes.Structure
diff --git a/lib-python/2.7/ctypes/test/test_unaligned_structures.py b/lib-python/2.7/ctypes/test/test_unaligned_structures.py
--- a/lib-python/2.7/ctypes/test/test_unaligned_structures.py
+++ b/lib-python/2.7/ctypes/test/test_unaligned_structures.py
@@ -37,10 +37,7 @@
for typ in byteswapped_structures:
## print >> sys.stderr, typ.value
self.assertEqual(typ.value.offset, 1)
- try:
- o = typ()
- except NotImplementedError as e:
- self.skipTest(str(e)) # for PyPy
+ o = typ()
o.value = 4
self.assertEqual(o.value, 4)
diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py
--- a/lib_pypy/_ctypes/structure.py
+++ b/lib_pypy/_ctypes/structure.py
@@ -130,6 +130,7 @@
obj._buffer.__setattr__(self.name, arg)
+
def _set_shape(tp, rawfields, is_union=False):
tp._ffistruct_ = _rawffi.Structure(rawfields, is_union,
getattr(tp, '_pack_', 0))
@@ -224,7 +225,6 @@
res.__dict__['_index'] = -1
return res
-
class StructOrUnion(_CData):
__metaclass__ = StructOrUnionMeta
@@ -234,9 +234,6 @@
if ('_abstract_' in cls.__dict__ or cls is Structure
or cls is union.Union):
raise TypeError("abstract class")
- if hasattr(cls, '_swappedbytes_'):
- raise NotImplementedError("missing in PyPy: structure/union with "
- "swapped (non-native) byte ordering")
if hasattr(cls, '_ffistruct_'):
self.__dict__['_buffer'] = self._ffistruct_(autofree=True)
return self
@@ -253,6 +250,17 @@
for name, arg in kwds.items():
self.__setattr__(name, arg)
+ def __getattribute__(self, item):
+ if item in (field[0] for field in object.__getattribute__(self, "_fields_"))\
+ and hasattr(self.__class__, '_swappedbytes_'):
+ self._swap_bytes(item, 'get')
+ return object.__getattribute__(self, item)
+
+ def __setattr__(self, key, value):
+ object.__setattr__(self, key, value)
+ if key in (field[0] for field in self._fields_) and hasattr(self.__class__, '_swappedbytes_'):
+ self._swap_bytes(key, 'set')
+
def _subarray(self, fieldtype, name):
"""Return a _rawffi array of length 1 whose address is the same as
the address of the field 'name' of self."""
@@ -269,6 +277,63 @@
def _to_ffi_param(self):
return self._buffer
+ def _swap_bytes(self, field, get_or_set):
+ def swap_2(v):
+ return ((v >> 8) & 0x00FF) | ((v << 8) & 0xFF00)
+
+ def swap_4(v):
+ return ((v & 0x000000FF) << 24) | \
+ ((v & 0x0000FF00) << 8) | \
+ ((v & 0x00FF0000) >> 8) | \
+ ((v >> 24) & 0xFF)
+
+ def swap_8(v):
+ return ((v & 0x00000000000000FFL) << 56) | \
+ ((v & 0x000000000000FF00L) << 40) | \
+ ((v & 0x0000000000FF0000L) << 24) | \
+ ((v & 0x00000000FF000000L) << 8) | \
+ ((v & 0x000000FF00000000L) >> 8) | \
+ ((v & 0x0000FF0000000000L) >> 24) | \
+ ((v & 0x00FF000000000000L) >> 40) | \
+ ((v >> 56) & 0xFF)
+
+ def swap_double_float(v, typ):
+ from struct import pack, unpack
+ st = ''
+ if get_or_set == 'set':
+ if sys.byteorder == 'little':
+ st = pack(''.join(['>', typ]), v)
+ else:
+ st = pack(''.join(['<', typ]), v)
+ return unpack(typ, st)[0]
+ else:
+ packed = pack(typ, v)
+ if sys.byteorder == 'little':
+ st = unpack(''.join(['>', typ]), packed)
+ else:
+ st = unpack(''.join(['<', typ]), packed)
+ return st[0]
+
+ from ctypes import sizeof, c_double, c_float
+ sizeof_field = 0
+ typeof_field = None
+ for i in self._fields_:
+ if i[0] == field:
+ sizeof_field = sizeof(i[1])
+ typeof_field = i[1]
+ field_value = object.__getattribute__(self, field)
+ if typeof_field == c_float:
+ object.__setattr__(self, field, swap_double_float(field_value, 'f'))
+ elif typeof_field == c_double:
+ object.__setattr__(self, field, swap_double_float(field_value, 'd'))
+ else:
+ if sizeof_field == 2:
+ object.__setattr__(self, field, swap_2(field_value))
+ elif sizeof_field == 4:
+ object.__setattr__(self, field, swap_4(field_value))
+ elif sizeof_field == 8:
+ object.__setattr__(self, field, swap_8(field_value))
+
class StructureMeta(StructOrUnionMeta):
_is_union = False
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py
@@ -460,6 +460,38 @@
class X(Structure):
_fields_ = [(u"i", c_int)]
+ def test_swapped_bytes(self):
+ import sys
+
+ for i in [c_short, c_int, c_long, c_longlong,
+ c_float, c_double, c_ushort, c_uint,
+ c_ulong, c_ulonglong]:
+ FIELDS = [
+ ('n', i)
+ ]
+
+ class Native(Structure):
+ _fields_ = FIELDS
+
+ class Big(BigEndianStructure):
+ _fields_ = FIELDS
+
+ class Little(LittleEndianStructure):
+ _fields_ = FIELDS
+
+ def dostruct(c):
+ ba = create_string_buffer(sizeof(c))
+ ms = c.from_buffer(ba)
+ ms.n = 0xff00
+ return repr(ba[:])
+
+ if sys.byteorder == 'little':
+ assert dostruct(Native) == dostruct(Little)
+ assert dostruct(Native) != dostruct(Big)
+ else:
+ assert dostruct(Native) == dostruct(Big)
+ assert dostruct(Native) != dostruct(Little)
+
class TestPointerMember(BaseCTypesTestChecker):
def test_1(self):
More information about the pypy-commit
mailing list