# -- cython: profile=True # # Copyright 2013-2015 DataStax, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import six from libc.stdint cimport (int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t) from cassandra.buffer cimport Buffer, buf_read, to_bytes cdef bint is_little_endian from cassandra.util import is_little_endian cdef bint PY3 = six.PY3 cdef inline void swap_order(char *buf, Py_ssize_t size): """ Swap the byteorder of `buf` in-place on little-endian platforms (reverse all the bytes). There are functions ntohl etc, but these may be POSIX-dependent. """ cdef Py_ssize_t start, end, i cdef char c if is_little_endian: for i in range(div2(size)): end = size - i - 1 c = buf[i] buf[i] = buf[end] buf[end] = c cdef inline Py_ssize_t div2(Py_ssize_t x): return x >> 1 ### Unpacking of signed integers cdef inline int64_t int64_unpack(Buffer *buf) except ?0xDEAD: cdef int64_t x = ( buf_read(buf, 8))[0] cdef char *p = &x swap_order( &x, 8) return x cdef inline int32_t int32_unpack(Buffer *buf) except ?0xDEAD: cdef int32_t x = ( buf_read(buf, 4))[0] cdef char *p = &x swap_order( &x, 4) return x cdef inline int16_t int16_unpack(Buffer *buf) except ?0xDED: cdef int16_t x = ( buf_read(buf, 2))[0] swap_order( &x, 2) return x cdef inline int8_t int8_unpack(Buffer *buf) except ?80: return ( buf_read(buf, 1))[0] cdef inline uint64_t uint64_unpack(Buffer *buf) except ?0xDEAD: cdef uint64_t x = ( buf_read(buf, 8))[0] swap_order( &x, 8) return x cdef inline uint32_t uint32_unpack(Buffer *buf) except ?0xDEAD: cdef uint32_t x = ( buf_read(buf, 4))[0] swap_order( &x, 4) return x cdef inline uint16_t uint16_unpack(Buffer *buf) except ?0xDEAD: cdef uint16_t x = ( buf_read(buf, 2))[0] swap_order( &x, 2) return x cdef inline uint8_t uint8_unpack(Buffer *buf) except ?0xff: return ( buf_read(buf, 1))[0] cdef inline double double_unpack(Buffer *buf) except ?1.74: cdef double x = ( buf_read(buf, 8))[0] swap_order( &x, 8) return x cdef inline float float_unpack(Buffer *buf) except ?1.74: cdef float x = ( buf_read(buf, 4))[0] swap_order( &x, 4) return x cdef varint_unpack(Buffer *term): """Unpack a variable-sized integer""" if PY3: return varint_unpack_py3(to_bytes(term)) else: return varint_unpack_py2(to_bytes(term)) # TODO: Optimize these two functions cdef varint_unpack_py3(bytes term): cdef int64_t one = 1L val = int(''.join("%02x" % i for i in term), 16) if (term[0] & 128) != 0: # There is a bug in Cython (0.20 - 0.22), where if we do # '1 << (len(term) * 8)' Cython generates '1' directly into the # C code, causing integer overflows val -= one << (len(term) * 8) return val cdef varint_unpack_py2(bytes term): # noqa cdef int64_t one = 1L val = int(term.encode('hex'), 16) if (ord(term[0]) & 128) != 0: val = val - (one << (len(term) * 8)) return val