Commit 0041db28 authored by Stefan Behnel's avatar Stefan Behnel

Add safety cast in queue tutorial code that avoids casting a potentially...

Add safety cast in queue tutorial code that avoids casting a potentially non-pointer-sized "int" to a "void*".
parent bf817f15
# queue.pyx # queue.pyx
cimport cqueue cimport cqueue
cdef class Queue: cdef class Queue:
"""A queue class for C integer values. """A queue class for C integer values.
>>> q = Queue() >>> q = Queue()
>>> q.append(5) >>> q.append(5)
>>> q.peek() >>> q.peek()
5 5
>>> q.pop() >>> q.pop()
5 5
""" """
cdef cqueue.Queue* _c_queue cdef cqueue.Queue* _c_queue
def __cinit__(self): def __cinit__(self):
self._c_queue = cqueue.queue_new() self._c_queue = cqueue.queue_new()
if self._c_queue is NULL: if self._c_queue is NULL:
raise MemoryError() raise MemoryError()
def __dealloc__(self): def __dealloc__(self):
if self._c_queue is not NULL: if self._c_queue is not NULL:
cqueue.queue_free(self._c_queue) cqueue.queue_free(self._c_queue)
cpdef append(self, int value): cpdef append(self, int value):
if not cqueue.queue_push_tail(self._c_queue, if not cqueue.queue_push_tail(self._c_queue,
<void*> value): <void*> <Py_ssize_t> value):
raise MemoryError() raise MemoryError()
# The `cpdef` feature is obviously not available for the original "extend()" # The `cpdef` feature is obviously not available for the original "extend()"
# method, as the method signature is incompatible with Python argument # method, as the method signature is incompatible with Python argument
# types (Python does not have pointers). However, we can rename # types (Python does not have pointers). However, we can rename
# the C-ish "extend()" method to e.g. "extend_ints()", and write # the C-ish "extend()" method to e.g. "extend_ints()", and write
# a new "extend()" method that provides a suitable Python interface by # a new "extend()" method that provides a suitable Python interface by
# accepting an arbitrary Python iterable. # accepting an arbitrary Python iterable.
cpdef extend(self, values): cpdef extend(self, values):
for value in values: for value in values:
self.append(value) self.append(value)
cdef extend_ints(self, int* values, size_t count): cdef extend_ints(self, int* values, size_t count):
cdef int value cdef int value
for value in values[:count]: # Slicing pointer to limit the iteration boundaries. for value in values[:count]: # Slicing pointer to limit the iteration boundaries.
self.append(value) self.append(value)
cpdef int peek(self) except? -1: cpdef int peek(self) except? -1:
cdef int value = <Py_ssize_t> cqueue.queue_peek_head(self._c_queue) cdef int value = <Py_ssize_t> cqueue.queue_peek_head(self._c_queue)
if value == 0: if value == 0:
# this may mean that the queue is empty, # this may mean that the queue is empty,
# or that it happens to contain a 0 value # or that it happens to contain a 0 value
if cqueue.queue_is_empty(self._c_queue): if cqueue.queue_is_empty(self._c_queue):
raise IndexError("Queue is empty") raise IndexError("Queue is empty")
return value return value
cpdef int pop(self) except? -1: cpdef int pop(self) except? -1:
if cqueue.queue_is_empty(self._c_queue): if cqueue.queue_is_empty(self._c_queue):
raise IndexError("Queue is empty") raise IndexError("Queue is empty")
return <Py_ssize_t> cqueue.queue_pop_head(self._c_queue) return <Py_ssize_t> cqueue.queue_pop_head(self._c_queue)
def __bool__(self): def __bool__(self):
return not cqueue.queue_is_empty(self._c_queue) return not cqueue.queue_is_empty(self._c_queue)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment