byteswap.pyx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. """
  2. The following are faster versions of struct.unpack that avoid the overhead of Python
  3. function calls.
  4. In the SAS7BDAT parser, they may be called up to (n_rows * n_cols) times.
  5. """
  6. from cython cimport Py_ssize_t
  7. from libc.stdint cimport (
  8. uint16_t,
  9. uint32_t,
  10. uint64_t,
  11. )
  12. def read_float_with_byteswap(bytes data, Py_ssize_t offset, bint byteswap):
  13. assert offset + 4 < len(data)
  14. cdef:
  15. const char *data_ptr = data
  16. float res = (<float*>(data_ptr + offset))[0]
  17. if byteswap:
  18. res = _byteswap_float(res)
  19. return res
  20. def read_double_with_byteswap(bytes data, Py_ssize_t offset, bint byteswap):
  21. assert offset + 8 < len(data)
  22. cdef:
  23. const char *data_ptr = data
  24. double res = (<double*>(data_ptr + offset))[0]
  25. if byteswap:
  26. res = _byteswap_double(res)
  27. return res
  28. def read_uint16_with_byteswap(bytes data, Py_ssize_t offset, bint byteswap):
  29. assert offset + 2 < len(data)
  30. cdef:
  31. const char *data_ptr = data
  32. uint16_t res = (<uint16_t *>(data_ptr + offset))[0]
  33. if byteswap:
  34. res = _byteswap2(res)
  35. return res
  36. def read_uint32_with_byteswap(bytes data, Py_ssize_t offset, bint byteswap):
  37. assert offset + 4 < len(data)
  38. cdef:
  39. const char *data_ptr = data
  40. uint32_t res = (<uint32_t *>(data_ptr + offset))[0]
  41. if byteswap:
  42. res = _byteswap4(res)
  43. return res
  44. def read_uint64_with_byteswap(bytes data, Py_ssize_t offset, bint byteswap):
  45. assert offset + 8 < len(data)
  46. cdef:
  47. const char *data_ptr = data
  48. uint64_t res = (<uint64_t *>(data_ptr + offset))[0]
  49. if byteswap:
  50. res = _byteswap8(res)
  51. return res
  52. # Byteswapping
  53. cdef extern from *:
  54. """
  55. #ifdef _MSC_VER
  56. #define _byteswap2 _byteswap_ushort
  57. #define _byteswap4 _byteswap_ulong
  58. #define _byteswap8 _byteswap_uint64
  59. #else
  60. #define _byteswap2 __builtin_bswap16
  61. #define _byteswap4 __builtin_bswap32
  62. #define _byteswap8 __builtin_bswap64
  63. #endif
  64. """
  65. uint16_t _byteswap2(uint16_t)
  66. uint32_t _byteswap4(uint32_t)
  67. uint64_t _byteswap8(uint64_t)
  68. cdef float _byteswap_float(float num):
  69. cdef uint32_t *intptr = <uint32_t *>&num
  70. intptr[0] = _byteswap4(intptr[0])
  71. return num
  72. cdef double _byteswap_double(double num):
  73. cdef uint64_t *intptr = <uint64_t *>&num
  74. intptr[0] = _byteswap8(intptr[0])
  75. return num