Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions cassandra/buffer.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,13 @@ cdef inline char *buf_read(Buffer *buf, Py_ssize_t size) except NULL:
raise IndexError("Requested more than length of buffer")
return buf.ptr

cdef inline int slice_buffer(Buffer *buf, Buffer *out,
Py_ssize_t start, Py_ssize_t size) except -1:
if size < 0:
raise ValueError("Length must be positive")
cdef inline void from_ptr_and_size(char *ptr, Py_ssize_t size, Buffer *buf):
"""Initialize buf from ptr and size.

if start + size > buf.size:
raise IndexError("Buffer slice out of bounds")
Negative sizes are valid sentinel values: -1 means NULL, -2 means not-set.
Callers should check buf.size < 0 to detect these cases.
"""
buf.ptr = ptr
buf.size = size

out.ptr = buf.ptr + start
out.size = size
return 0

cdef inline void from_ptr_and_size(char *ptr, Py_ssize_t size, Buffer *out):
out.ptr = ptr
out.size = size
58 changes: 38 additions & 20 deletions cassandra/cython_marshal.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ from libc.stdint cimport (int8_t, int16_t, int32_t, int64_t,
from libc.string cimport memcpy
from cassandra.buffer cimport Buffer, buf_read, to_bytes

# Use ntohs/ntohl for efficient big-endian to native conversion (single bswap instruction on x86)
# Platform-specific header: arpa/inet.h on POSIX, winsock2.h on Windows
cdef extern from *:
"""
#ifdef _WIN32
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
"""
uint16_t ntohs(uint16_t netshort) nogil
uint32_t ntohl(uint32_t netlong) nogil

cdef bint is_little_endian
from cassandra.util import is_little_endian

Expand All @@ -36,35 +49,40 @@ ctypedef fused num_t:

cdef inline num_t unpack_num(Buffer *buf, num_t *dummy=NULL): # dummy pointer because cython wants the fused type as an arg
"""
Copy to aligned destination, conditionally swapping to native byte order
Copy to aligned destination, conditionally swapping to native byte order.
Uses ntohs/ntohl for 16/32-bit types (compiles to single bswap instruction).
"""
cdef Py_ssize_t start, end, i
cdef Py_ssize_t i
cdef char *src = buf_read(buf, sizeof(num_t))
cdef num_t ret = 0
cdef num_t ret
cdef char *out = <char*> &ret
cdef uint32_t temp32 # For float byte-swapping

# Copy to aligned location first
memcpy(&ret, src, sizeof(num_t))

if not is_little_endian:
return ret

if is_little_endian:
# Use optimized byte-swap intrinsics for 16-bit and 32-bit types
if num_t is int16_t or num_t is uint16_t:
return <num_t>ntohs(<uint16_t>ret)
elif num_t is int32_t or num_t is uint32_t:
return <num_t>ntohl(<uint32_t>ret)
elif num_t is float:
# For float, reinterpret bits as uint32, swap, then reinterpret back
temp32 = (<uint32_t*>&ret)[0]
temp32 = ntohl(temp32)
return (<float*>&temp32)[0]
else:
# 64-bit, double, or 8-bit: use byte-swap loop (8-bit loop is no-op)
for i in range(sizeof(num_t)):
out[sizeof(num_t) - i - 1] = src[i]
else:
memcpy(out, src, sizeof(num_t))

return ret
return ret

cdef varint_unpack(Buffer *term):
"""Unpack a variable-sized integer"""
return varint_unpack_py3(to_bytes(term))

# TODO: Optimize these two functions
cdef varint_unpack_py3(bytes term):
val = int(''.join(["%02x" % i for i in term]), 16)
if (term[0] & 128) != 0:
shift = len(term) * 8 # * Note below
val -= 1 << shift
return val

# * Note *
# '1 << (len(term) * 8)' Cython tries to do native
# integer shifts, which overflows. We need this to
# emulate Python shifting, which will expand the long
# to accommodate
return int.from_bytes(term, byteorder='big', signed=True)
Loading
Loading