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 ...@@ -33,48 +33,15 @@ Defining external declarations
You can download CAlg `here <https://github.com/fragglet/c-algorithms/archive/master.zip>`_. 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 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 */ .. literalinclude:: ../../examples/tutorial/clibraries/c-algorithms/src/queue.h
:language: C
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);
To get started, the first step is to redefine the C API in a ``.pxd`` To get started, the first step is to redefine the C API in a ``.pxd``
file, say, ``cqueue.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)
bint queue_is_empty(Queue* queue) .. literalinclude:: ../../examples/tutorial/clibraries/cqueue.pxd
Note how these declarations are almost identical to the header file Note how these declarations are almost identical to the header file
declarations, so you can often just copy them over. However, you do 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 ...@@ -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 library, there must not be a ``.pyx`` file with the same name
that Cython associates with it. 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 .. literalinclude:: ../../examples/tutorial/clibraries/queue.pyx
cimport cqueue
cdef class Queue:
cdef cqueue.Queue* _c_queue
def __cinit__(self):
self._c_queue = cqueue.queue_new()
Note that it says ``__cinit__`` rather than ``__init__``. While Note that it says ``__cinit__`` rather than ``__init__``. While
``__init__`` is available as well, it is not guaranteed to be run (for ``__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 ...@@ -190,16 +150,9 @@ that case, it will return ``NULL``, whereas it would normally return a
pointer to the new queue. pointer to the new queue.
The Python way to get out of this is to raise a ``MemoryError`` [#]_. The Python way to get out of this is to raise a ``MemoryError`` [#]_.
We can thus change the init function as follows:: We can thus change the init function as follows:
cimport cqueue
cdef class Queue: .. literalinclude:: ../../examples/tutorial/clibraries/queue2.pyx
cdef cqueue.Queue* _c_queue
def __cinit__(self):
self._c_queue = cqueue.queue_new()
if self._c_queue is NULL:
raise MemoryError()
.. [#] In the specific case of a ``MemoryError``, creating a new .. [#] In the specific case of a ``MemoryError``, creating a new
exception instance in order to raise it may actually fail because exception instance in order to raise it may actually fail because
...@@ -587,44 +540,9 @@ instead that accepts an arbitrary Python iterable:: ...@@ -587,44 +540,9 @@ instead that accepts an arbitrary Python iterable::
Now we can test our Queue implementation using a python script, Now we can test our Queue implementation using a python script,
for example here :file:`test_queue.py`.:: 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())
.. literalinclude:: ../../examples/tutorial/clibraries/test_queue.py
As a quick test with 10000 numbers on the author's machine indicates, 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 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