|
1 | | -from cpython cimport PyBytes_FromStringAndSize, PyBytes_AsString |
2 | | -from cpython.ref cimport PyObject |
| 1 | +from cpython cimport PyBytes_AsString |
3 | 2 |
|
| 3 | +#from cpython cimport PyByteArray_AsString # cython still not exports that |
4 | 4 | cdef extern from "Python.h": |
5 | | - char* PyByteArray_AsString(object bytearray) except NULL |
| 5 | + char* PyByteArray_AsString(bytearray ba) except NULL |
6 | 6 |
|
| 7 | +from libc.stdint cimport uint32_t, uint64_t, uintmax_t |
7 | 8 |
|
8 | 9 | def _websocket_mask_cython(bytes mask, bytearray data): |
9 | | - cdef Py_ssize_t mask_len, data_len, i |
10 | | - cdef char * in_buf |
11 | | - cdef char * out_buf |
12 | | - cdef char * mask_buf |
13 | | - cdef bytes ret |
14 | | - mask_len = len(mask) |
| 10 | + """Note, this function mutates it's `data` argument |
| 11 | + """ |
| 12 | + cdef: |
| 13 | + Py_ssize_t data_len, i |
| 14 | + # bit operations on signed integers are implementation-specific |
| 15 | + unsigned char * in_buf |
| 16 | + const unsigned char * mask_buf |
| 17 | + uint32_t uint32_msk |
| 18 | + uint64_t uint64_msk |
| 19 | + |
| 20 | + assert len(mask) == 4 |
| 21 | + |
15 | 22 | data_len = len(data) |
16 | | - in_buf = PyByteArray_AsString(data) |
17 | | - mask_buf = PyBytes_AsString(mask) |
| 23 | + in_buf = <unsigned char*>PyByteArray_AsString(data) |
| 24 | + mask_buf = <const unsigned char*>PyBytes_AsString(mask) |
| 25 | + uint32_msk = (<uint32_t*>mask_buf)[0] |
| 26 | + |
| 27 | + # TODO: align in_data ptr to achieve even faster speeds |
| 28 | + # does it need in python ?! malloc() always aligns to sizeof(long) bytes |
| 29 | + |
| 30 | + if sizeof(uintmax_t) >= 8: |
| 31 | + uint64_msk = uint32_msk |
| 32 | + uint64_msk = (uint64_msk << 32) | uint32_msk |
| 33 | + |
| 34 | + while data_len >= 8: |
| 35 | + (<uint64_t*>in_buf)[0] ^= uint64_msk |
| 36 | + in_buf += 8 |
| 37 | + data_len -= 8 |
| 38 | + |
| 39 | + |
| 40 | + while data_len >= 4: |
| 41 | + (<uint32_t*>in_buf)[0] ^= uint32_msk |
| 42 | + in_buf += 4 |
| 43 | + data_len -= 4 |
| 44 | + |
18 | 45 | for i in range(0, data_len): |
19 | | - in_buf[i] = in_buf[i] ^ mask_buf[i % 4] |
| 46 | + in_buf[i] ^= mask_buf[i] |
| 47 | + |
20 | 48 | return data |
0 commit comments