/rpython/rlib/rstruct/nativefmttable.py
Python | 160 lines | 158 code | 0 blank | 2 comment | 0 complexity | 11a644af5de109bfd4d6a5fb3881f50a MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
- """
- Native type codes.
- The table 'native_fmttable' is also used by pypy.module.array.interp_array.
- """
- import struct
- from rpython.rlib import jit, longlong2float
- from rpython.rlib.objectmodel import specialize
- from rpython.rlib.rarithmetic import r_singlefloat, widen
- from rpython.rlib.rstruct import standardfmttable as std
- from rpython.rlib.rstruct.standardfmttable import native_is_bigendian
- from rpython.rlib.rstruct.error import StructError
- from rpython.rlib.unroll import unrolling_iterable
- from rpython.rtyper.lltypesystem import lltype, rffi
- from rpython.rtyper.tool import rffi_platform
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- native_fmttable = {
- 'x': std.standard_fmttable['x'],
- 'c': std.standard_fmttable['c'],
- 's': std.standard_fmttable['s'],
- 'p': std.standard_fmttable['p'],
- }
- # ____________________________________________________________
- range_8_unroll = unrolling_iterable(list(reversed(range(8))))
- range_4_unroll = unrolling_iterable(list(reversed(range(4))))
- def pack_double(fmtiter):
- doubleval = fmtiter.accept_float_arg()
- value = longlong2float.float2longlong(doubleval)
- if fmtiter.bigendian:
- for i in range_8_unroll:
- x = (value >> (8*i)) & 0xff
- fmtiter.result.append(chr(x))
- else:
- for i in range_8_unroll:
- fmtiter.result.append(chr(value & 0xff))
- value >>= 8
- def pack_float(fmtiter):
- doubleval = fmtiter.accept_float_arg()
- floatval = r_singlefloat(doubleval)
- value = longlong2float.singlefloat2uint(floatval)
- value = widen(value)
- if fmtiter.bigendian:
- for i in range_4_unroll:
- x = (value >> (8*i)) & 0xff
- fmtiter.result.append(chr(x))
- else:
- for i in range_4_unroll:
- fmtiter.result.append(chr(value & 0xff))
- value >>= 8
- # ____________________________________________________________
- #
- # Use rffi_platform to get the native sizes and alignments from the C compiler
- def setup():
- INSPECT = {'b': 'signed char',
- 'h': 'signed short',
- 'i': 'signed int',
- 'l': 'signed long',
- 'q': 'signed long long',
- 'B': 'unsigned char',
- 'H': 'unsigned short',
- 'I': 'unsigned int',
- 'L': 'unsigned long',
- 'Q': 'unsigned long long',
- 'P': 'char *',
- 'f': 'float',
- 'd': 'double',
- '?': '_Bool',
- }
- pre_include_bits = ["""
- #ifdef _MSC_VER
- #define _Bool char
- #endif"""]
- field_names = dict.fromkeys(INSPECT)
- for fmtchar, ctype in INSPECT.iteritems():
- field_name = ctype.replace(" ", "_").replace("*", "star")
- field_names[fmtchar] = field_name
- pre_include_bits.append("""
- struct about_%s {
- char pad;
- %s field;
- };
- """ % (field_name, ctype))
- class CConfig:
- _compilation_info_ = ExternalCompilationInfo(
- pre_include_bits = pre_include_bits
- )
- for fmtchar, ctype in INSPECT.items():
- setattr(CConfig, field_names[fmtchar], rffi_platform.Struct(
- "struct about_%s" % (field_names[fmtchar],),
- [('field', lltype.FixedSizeArray(rffi.CHAR, 1))]))
- cConfig = rffi_platform.configure(CConfig)
- for fmtchar, ctype in INSPECT.items():
- S = cConfig[field_names[fmtchar]]
- alignment = rffi.offsetof(S, 'c_field')
- size = rffi.sizeof(S.c_field)
- signed = 'a' <= fmtchar <= 'z'
- if fmtchar == 'f':
- pack = pack_float
- unpack = std.unpack_float
- elif fmtchar == 'd':
- pack = pack_double
- unpack = std.unpack_double
- elif fmtchar == '?':
- pack = std.pack_bool
- unpack = std.unpack_bool
- else:
- pack = std.make_int_packer(size, signed)
- unpack = std.make_int_unpacker(size, signed)
- native_fmttable[fmtchar] = {'size': size,
- 'alignment': alignment,
- 'pack': pack,
- 'unpack': unpack}
- setup()
- sizeof_double = native_fmttable['d']['size']
- sizeof_float = native_fmttable['f']['size']
- # ____________________________________________________________
- #
- # A PyPy extension: accepts the 'u' format character in native mode,
- # just like the array module does. (This is actually used in the
- # implementation of our interp-level array module.)
- from rpython.rlib.rstruct import unichar
- def pack_unichar(fmtiter):
- unistr = fmtiter.accept_unicode_arg()
- if len(unistr) != 1:
- raise StructError("expected a unicode string of length 1")
- c = unistr[0] # string->char conversion for the annotator
- unichar.pack_unichar(c, fmtiter.result)
- @specialize.argtype(0)
- def unpack_unichar(fmtiter):
- data = fmtiter.read(unichar.UNICODE_SIZE)
- fmtiter.appendobj(unichar.unpack_unichar(data))
- native_fmttable['u'] = {'size': unichar.UNICODE_SIZE,
- 'alignment': unichar.UNICODE_SIZE,
- 'pack': pack_unichar,
- 'unpack': unpack_unichar,
- }