Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Gwenaël Samain
cython
Commits
d1595a99
Commit
d1595a99
authored
Jun 17, 2018
by
gabrieldemarmiesse
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Put back int as the main data type for the interface.
parent
d055de85
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
29 additions
and
27 deletions
+29
-27
docs/examples/tutorial/clibraries/queue3.pyx
docs/examples/tutorial/clibraries/queue3.pyx
+6
-7
docs/src/tutorial/clibraries.rst
docs/src/tutorial/clibraries.rst
+23
-20
No files found.
docs/examples/tutorial/clibraries/queue3.pyx
View file @
d1595a99
# queue.pyx
from
libc.stdint
cimport
intptr_t
cimport
cqueue
cdef
class
Queue
:
...
...
@@ -23,12 +22,12 @@ cdef class Queue:
if
self
.
_c_queue
is
not
NULL
:
cqueue
.
queue_free
(
self
.
_c_queue
)
cpdef
append
(
self
,
int
ptr_t
value
):
cpdef
append
(
self
,
int
value
):
if
not
cqueue
.
queue_push_tail
(
self
.
_c_queue
,
<
void
*>
value
):
raise
MemoryError
()
cdef
extend
(
self
,
int
ptr_t
*
values
,
size_t
count
):
cdef
extend
(
self
,
int
*
values
,
size_t
count
):
cdef
size_t
i
for
i
in
range
(
count
):
if
not
cqueue
.
queue_push_tail
(
...
...
@@ -43,8 +42,8 @@ cdef class Queue:
for
value
in
values
:
self
.
append
(
value
)
cpdef
int
ptr_t
peek
(
self
)
except
?
-
1
:
cdef
int
ptr_t
value
=
<
intptr
_t
>
cqueue
.
queue_peek_head
(
self
.
_c_queue
)
cpdef
int
peek
(
self
)
except
?
-
1
:
cdef
int
value
=
<
Py_ssize
_t
>
cqueue
.
queue_peek_head
(
self
.
_c_queue
)
if
value
==
0
:
# this may mean that the queue is empty,
...
...
@@ -53,10 +52,10 @@ cdef class Queue:
raise
IndexError
(
"Queue is empty"
)
return
value
cpdef
int
ptr_t
pop
(
self
)
except
?
-
1
:
cpdef
int
pop
(
self
)
except
?
-
1
:
if
cqueue
.
queue_is_empty
(
self
.
_c_queue
):
raise
IndexError
(
"Queue is empty"
)
return
<
intptr
_t
>
cqueue
.
queue_pop_head
(
self
.
_c_queue
)
return
<
Py_ssize
_t
>
cqueue
.
queue_pop_head
(
self
.
_c_queue
)
def
__bool__
(
self
):
return
not
cqueue
.
queue_is_empty
(
self
.
_c_queue
)
docs/src/tutorial/clibraries.rst
View file @
d1595a99
...
...
@@ -318,27 +318,28 @@ to give them a straight C interface.
In C, it is common for data structures to store data as a ``void*`` to
whatever data item type. Since we only want to store ``int`` values,
which usually fit into the size of a pointer type, we will use ``intptr_t``
as it is garanteed to be at least as big as an ``int`` and the same size
as a ``void*``
which usually fit into the size of a pointer type, we can avoid
additional memory allocations through a trick: we cast our ``int`` values
to ``void*`` and vice versa, and store the value directly as the
pointer value.
Here is a simple implementation for the ``append()`` method::
cdef append(self, int
ptr_t
value):
cdef append(self, int value):
cqueue.queue_push_tail(self._c_queue, <void*>value)
Again, the same error handling considerations as for the
``__cinit__()`` method apply, so that we end up with this
implementation instead::
cdef append(self, int
ptr_t
value):
cdef append(self, int value):
if not cqueue.queue_push_tail(self._c_queue,
<void*>value):
raise MemoryError()
Adding an ``extend()`` method should now be straight forward::
cdef extend(self, int
ptr_t
* values, size_t count):
cdef extend(self, int* values, size_t count):
"""Append all ints to the queue.
"""
cdef size_t i
...
...
@@ -352,13 +353,15 @@ example.
So far, we can only add data to the queue. The next step is to write
the two methods to get the first element: ``peek()`` and ``pop()``,
which provide read-only and destructive read access respectively::
which provide read-only and destructive read access respectively.
To avoid the compiler warning when casting ``void*`` to ``int`` directly,
we use an intermediate data type big enough to hold a ``void*``. Here ``Py_ssize_t``::
cdef int
ptr_t
peek(self):
return <
intptr
_t>cqueue.queue_peek_head(self._c_queue)
cdef int peek(self):
return <
Py_ssize
_t>cqueue.queue_peek_head(self._c_queue)
cdef int
ptr_t
pop(self):
return <
intptr
_t>cqueue.queue_pop_head(self._c_queue)
cdef int pop(self):
return <
Py_ssize
_t>cqueue.queue_pop_head(self._c_queue)
Handling errors
...
...
@@ -374,8 +377,8 @@ first case to raise an exception, whereas the second case should
simply return ``0``. To deal with this, we need to special case this
value, and check if the queue really is empty or not::
cdef int
ptr_t
peek(self) except? -1:
value = <intptr
_t>cqueue.queue_peek_head(self._c_queue)
cdef int peek(self) except? -1:
cdef int value = <Py_ssize
_t>cqueue.queue_peek_head(self._c_queue)
if value == 0:
# this may mean that the queue is empty, or
# that it happens to contain a 0 value
...
...
@@ -424,10 +427,10 @@ also needs adaptation. Since it removes a value from the queue,
however, it is not enough to test if the queue is empty *after* the
removal. Instead, we must test it on entry::
cdef int
ptr_t
pop(self) except? -1:
cdef int pop(self) except? -1:
if cqueue.queue_is_empty(self._c_queue):
raise IndexError("Queue is empty")
return <
intptr
_t>cqueue.queue_pop_head(self._c_queue)
return <
Py_ssize
_t>cqueue.queue_pop_head(self._c_queue)
The return value for exception propagation is declared exactly as for
``peek()``.
...
...
@@ -476,7 +479,7 @@ 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
ptr_t
``
values
is
about
five
using
this
Queue
from
Cython
code
with
C
``
int
``
values
is
about
five
times
as
fast
as
using
it
from
Cython
code
with
Python
object
values
,
almost
eight
times
faster
than
using
it
from
Python
code
in
a
Python
loop
,
and
still
more
than
twice
as
fast
as
using
Python
's highly
...
...
@@ -505,12 +508,12 @@ predicate. The API could look as follows::
*
0
for
reject
*
1
for
accept
*/
typedef
int
ptr_t
(*
predicate_func
)(
void
*
user_context
,
QueueValue
data
);
typedef
int
(*
predicate_func
)(
void
*
user_context
,
QueueValue
data
);
/*
Pop
values
as
long
as
the
predicate
evaluates
to
true
for
them
,
*
returns
-
1
if
the
predicate
failed
with
an
error
and
0
otherwise
.
*/
int
ptr_t
queue_pop_head_until
(
Queue
*
queue
,
predicate_func
predicate
,
int
queue_pop_head_until
(
Queue
*
queue
,
predicate_func
predicate
,
void
*
user_context
);
It
is
normal
for
C
callback
functions
to
have
a
generic
:
c
:
type
:`
void
*`
...
...
@@ -521,13 +524,13 @@ predicate function.
First
,
we
have
to
define
a
callback
function
with
the
expected
signature
that
we
can
pass
into
the
C
-
API
function
::
cdef
int
ptr_t
evaluate_predicate
(
void
*
context
,
cqueue
.
QueueValue
value
):
cdef
int
evaluate_predicate
(
void
*
context
,
cqueue
.
QueueValue
value
):
"Callback function that can be passed as predicate_func"
try
:
#
recover
Python
function
object
from
void
*
argument
func
=
<
object
>
context
#
call
function
,
convert
result
into
0
/
1
for
True
/
False
return
bool
(
func
(<
int
ptr_t
>
value
))
return
bool
(
func
(<
int
>
value
))
except
:
#
catch
any
Python
errors
and
return
error
indicator
return
-
1
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment