PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/rlib/rstruct/nativefmttable.py

https://bitbucket.org/pypy/pypy/
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
  1. """
  2. Native type codes.
  3. The table 'native_fmttable' is also used by pypy.module.array.interp_array.
  4. """
  5. import struct
  6. from rpython.rlib import jit, longlong2float
  7. from rpython.rlib.objectmodel import specialize
  8. from rpython.rlib.rarithmetic import r_singlefloat, widen
  9. from rpython.rlib.rstruct import standardfmttable as std
  10. from rpython.rlib.rstruct.standardfmttable import native_is_bigendian
  11. from rpython.rlib.rstruct.error import StructError
  12. from rpython.rlib.unroll import unrolling_iterable
  13. from rpython.rtyper.lltypesystem import lltype, rffi
  14. from rpython.rtyper.tool import rffi_platform
  15. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  16. native_fmttable = {
  17. 'x': std.standard_fmttable['x'],
  18. 'c': std.standard_fmttable['c'],
  19. 's': std.standard_fmttable['s'],
  20. 'p': std.standard_fmttable['p'],
  21. }
  22. # ____________________________________________________________
  23. range_8_unroll = unrolling_iterable(list(reversed(range(8))))
  24. range_4_unroll = unrolling_iterable(list(reversed(range(4))))
  25. def pack_double(fmtiter):
  26. doubleval = fmtiter.accept_float_arg()
  27. value = longlong2float.float2longlong(doubleval)
  28. if fmtiter.bigendian:
  29. for i in range_8_unroll:
  30. x = (value >> (8*i)) & 0xff
  31. fmtiter.result.append(chr(x))
  32. else:
  33. for i in range_8_unroll:
  34. fmtiter.result.append(chr(value & 0xff))
  35. value >>= 8
  36. def pack_float(fmtiter):
  37. doubleval = fmtiter.accept_float_arg()
  38. floatval = r_singlefloat(doubleval)
  39. value = longlong2float.singlefloat2uint(floatval)
  40. value = widen(value)
  41. if fmtiter.bigendian:
  42. for i in range_4_unroll:
  43. x = (value >> (8*i)) & 0xff
  44. fmtiter.result.append(chr(x))
  45. else:
  46. for i in range_4_unroll:
  47. fmtiter.result.append(chr(value & 0xff))
  48. value >>= 8
  49. # ____________________________________________________________
  50. #
  51. # Use rffi_platform to get the native sizes and alignments from the C compiler
  52. def setup():
  53. INSPECT = {'b': 'signed char',
  54. 'h': 'signed short',
  55. 'i': 'signed int',
  56. 'l': 'signed long',
  57. 'q': 'signed long long',
  58. 'B': 'unsigned char',
  59. 'H': 'unsigned short',
  60. 'I': 'unsigned int',
  61. 'L': 'unsigned long',
  62. 'Q': 'unsigned long long',
  63. 'P': 'char *',
  64. 'f': 'float',
  65. 'd': 'double',
  66. '?': '_Bool',
  67. }
  68. pre_include_bits = ["""
  69. #ifdef _MSC_VER
  70. #define _Bool char
  71. #endif"""]
  72. field_names = dict.fromkeys(INSPECT)
  73. for fmtchar, ctype in INSPECT.iteritems():
  74. field_name = ctype.replace(" ", "_").replace("*", "star")
  75. field_names[fmtchar] = field_name
  76. pre_include_bits.append("""
  77. struct about_%s {
  78. char pad;
  79. %s field;
  80. };
  81. """ % (field_name, ctype))
  82. class CConfig:
  83. _compilation_info_ = ExternalCompilationInfo(
  84. pre_include_bits = pre_include_bits
  85. )
  86. for fmtchar, ctype in INSPECT.items():
  87. setattr(CConfig, field_names[fmtchar], rffi_platform.Struct(
  88. "struct about_%s" % (field_names[fmtchar],),
  89. [('field', lltype.FixedSizeArray(rffi.CHAR, 1))]))
  90. cConfig = rffi_platform.configure(CConfig)
  91. for fmtchar, ctype in INSPECT.items():
  92. S = cConfig[field_names[fmtchar]]
  93. alignment = rffi.offsetof(S, 'c_field')
  94. size = rffi.sizeof(S.c_field)
  95. signed = 'a' <= fmtchar <= 'z'
  96. if fmtchar == 'f':
  97. pack = pack_float
  98. unpack = std.unpack_float
  99. elif fmtchar == 'd':
  100. pack = pack_double
  101. unpack = std.unpack_double
  102. elif fmtchar == '?':
  103. pack = std.pack_bool
  104. unpack = std.unpack_bool
  105. else:
  106. pack = std.make_int_packer(size, signed)
  107. unpack = std.make_int_unpacker(size, signed)
  108. native_fmttable[fmtchar] = {'size': size,
  109. 'alignment': alignment,
  110. 'pack': pack,
  111. 'unpack': unpack}
  112. setup()
  113. sizeof_double = native_fmttable['d']['size']
  114. sizeof_float = native_fmttable['f']['size']
  115. # ____________________________________________________________
  116. #
  117. # A PyPy extension: accepts the 'u' format character in native mode,
  118. # just like the array module does. (This is actually used in the
  119. # implementation of our interp-level array module.)
  120. from rpython.rlib.rstruct import unichar
  121. def pack_unichar(fmtiter):
  122. unistr = fmtiter.accept_unicode_arg()
  123. if len(unistr) != 1:
  124. raise StructError("expected a unicode string of length 1")
  125. c = unistr[0] # string->char conversion for the annotator
  126. unichar.pack_unichar(c, fmtiter.result)
  127. @specialize.argtype(0)
  128. def unpack_unichar(fmtiter):
  129. data = fmtiter.read(unichar.UNICODE_SIZE)
  130. fmtiter.appendobj(unichar.unpack_unichar(data))
  131. native_fmttable['u'] = {'size': unichar.UNICODE_SIZE,
  132. 'alignment': unichar.UNICODE_SIZE,
  133. 'pack': pack_unichar,
  134. 'unpack': unpack_unichar,
  135. }