Commit fa4c43b9 authored by scoder's avatar scoder Committed by GitHub

Merge pull request #2327 from gabrieldemarmiesse/test_calling_c_libraries

Added tests for some of the code snippets in "calling C libraries"
parents 6e4779ce 8e3a8af1
/* queue.h */
typedef struct _Queue Queue;
typedef void *QueueValue;
Queue *queue_new(void);
void queue_free(Queue *queue);
int queue_push_head(Queue *queue, QueueValue data);
QueueValue queue_pop_head(Queue *queue);
QueueValue queue_peek_head(Queue *queue);
int queue_push_tail(Queue *queue, QueueValue data);
QueueValue queue_pop_tail(Queue *queue);
QueueValue queue_peek_tail(Queue *queue);
int queue_is_empty(Queue *queue);
# cqueue.pxd
cdef extern from "c-algorithms/src/queue.h":
ctypedef struct Queue:
pass
ctypedef void* QueueValue
Queue* queue_new()
void queue_free(Queue* queue)
int queue_push_head(Queue* queue, QueueValue data)
QueueValue queue_pop_head(Queue* queue)
QueueValue queue_peek_head(Queue* queue)
int queue_push_tail(Queue* queue, QueueValue data)
QueueValue queue_pop_tail(Queue* queue)
QueueValue queue_peek_tail(Queue* queue)
bint queue_is_empty(Queue* queue)
# queue.pyx
cimport cqueue
cdef class Queue:
cdef cqueue.Queue* _c_queue
def __cinit__(self):
self._c_queue = cqueue.queue_new()
# queue.pyx
cimport cqueue
cdef class Queue:
cdef cqueue.Queue* _c_queue
def __cinit__(self):
self._c_queue = cqueue.queue_new()
if self._c_queue is NULL:
raise MemoryError()
from __future__ import print_function
import time
import queue
Q = queue.Queue()
Q.append(10)
Q.append(20)
print(Q.peek())
print(Q.pop())
print(Q.pop())
try:
print(Q.pop())
except IndexError as e:
print("Error message:", e) # Prints "Queue is empty"
i = 10000
values = range(i)
start_time = time.time()
Q.extend(values)
end_time = time.time() - start_time
print("Adding {} items took {:1.3f} msecs.".format(i, 1000 * end_time))
for i in range(41):
Q.pop()
Q.pop()
print("The answer is:")
print(Q.pop())
......@@ -33,48 +33,15 @@ Defining external declarations
You can download CAlg `here <https://github.com/fragglet/c-algorithms/archive/master.zip>`_.
The C API of the queue implementation, which is defined in the header
file ``c-algorithms/src/queue.h``, essentially looks like this::
file ``c-algorithms/src/queue.h``, essentially looks like this:
/* file: queue.h */
typedef struct _Queue Queue;
typedef void *QueueValue;
Queue *queue_new(void);
void queue_free(Queue *queue);
int queue_push_head(Queue *queue, QueueValue data);
QueueValue queue_pop_head(Queue *queue);
QueueValue queue_peek_head(Queue *queue);
int queue_push_tail(Queue *queue, QueueValue data);
QueueValue queue_pop_tail(Queue *queue);
QueueValue queue_peek_tail(Queue *queue);
int queue_is_empty(Queue *queue);
.. literalinclude:: ../../examples/tutorial/clibraries/c-algorithms/src/queue.h
:language: C
To get started, the first step is to redefine the C API in a ``.pxd``
file, say, ``cqueue.pxd``::
# file: cqueue.pxd
cdef extern from "c-algorithms/src/queue.h":
ctypedef struct Queue:
pass
ctypedef void* QueueValue
Queue* queue_new()
void queue_free(Queue* queue)
int queue_push_head(Queue* queue, QueueValue data)
QueueValue queue_pop_head(Queue* queue)
QueueValue queue_peek_head(Queue* queue)
int queue_push_tail(Queue* queue, QueueValue data)
QueueValue queue_pop_tail(Queue* queue)
QueueValue queue_peek_tail(Queue* queue)
file, say, ``cqueue.pxd``:
bint queue_is_empty(Queue* queue)
.. literalinclude:: ../../examples/tutorial/clibraries/cqueue.pxd
Note how these declarations are almost identical to the header file
declarations, so you can often just copy them over. However, you do
......@@ -144,16 +111,9 @@ class that should wrap the C queue. It will live in a file called
library, there must not be a ``.pyx`` file with the same name
that Cython associates with it.
Here is a first start for the Queue class::
Here is a first start for the Queue class:
# file: queue.pyx
cimport cqueue
cdef class Queue:
cdef cqueue.Queue* _c_queue
def __cinit__(self):
self._c_queue = cqueue.queue_new()
.. literalinclude:: ../../examples/tutorial/clibraries/queue.pyx
Note that it says ``__cinit__`` rather than ``__init__``. While
``__init__`` is available as well, it is not guaranteed to be run (for
......@@ -190,16 +150,9 @@ that case, it will return ``NULL``, whereas it would normally return a
pointer to the new queue.
The Python way to get out of this is to raise a ``MemoryError`` [#]_.
We can thus change the init function as follows::
cimport cqueue
We can thus change the init function as follows:
cdef class Queue:
cdef cqueue.Queue* _c_queue
def __cinit__(self):
self._c_queue = cqueue.queue_new()
if self._c_queue is NULL:
raise MemoryError()
.. literalinclude:: ../../examples/tutorial/clibraries/queue2.pyx
.. [#] In the specific case of a ``MemoryError``, creating a new
exception instance in order to raise it may actually fail because
......@@ -587,44 +540,9 @@ instead that accepts an arbitrary Python iterable::
Now we can test our Queue implementation using a python script,
for example here :file:`test_queue.py`.::
from __future__ import print_function
import queue
Q = queue.Queue()
Q.append(10)
Q.append(20)
print(Q.peek())
print(Q.pop())
print(Q.pop())
try:
print(Q.pop())
except IndexError as e:
print("Error message:", e) # Prints "Queue is empty"
i = 10000
values = range(i)
start_time = time.time()
Q.extend(values)
end_time = time.time() - start_time
print("Adding {} items took {:1.3f} msecs.".format(i, 1000 * end_time))
for i in range(41):
Q.pop()
Q.pop()
print("The answer is:")
print(Q.pop())
for example here :file:`test_queue.py`:
.. literalinclude:: ../../examples/tutorial/clibraries/test_queue.py
As a quick test with 10000 numbers on the author's machine indicates,
using this Queue from Cython code with C ``int`` values is about five
......
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