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
Hide 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
# queue.pyx
from
libc.stdint
cimport
intptr_t
cimport
cqueue
cimport
cqueue
cdef
class
Queue
:
cdef
class
Queue
:
...
@@ -23,12 +22,12 @@ cdef class Queue:
...
@@ -23,12 +22,12 @@ cdef class Queue:
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
ptr_t
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
*>
value
):
raise
MemoryError
()
raise
MemoryError
()
cdef
extend
(
self
,
int
ptr_t
*
values
,
size_t
count
):
cdef
extend
(
self
,
int
*
values
,
size_t
count
):
cdef
size_t
i
cdef
size_t
i
for
i
in
range
(
count
):
for
i
in
range
(
count
):
if
not
cqueue
.
queue_push_tail
(
if
not
cqueue
.
queue_push_tail
(
...
@@ -43,8 +42,8 @@ cdef class Queue:
...
@@ -43,8 +42,8 @@ cdef class Queue:
for
value
in
values
:
for
value
in
values
:
self
.
append
(
value
)
self
.
append
(
value
)
cpdef
int
ptr_t
peek
(
self
)
except
?
-
1
:
cpdef
int
peek
(
self
)
except
?
-
1
:
cdef
int
ptr_t
value
=
<
intptr
_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,
...
@@ -53,10 +52,10 @@ cdef class Queue:
...
@@ -53,10 +52,10 @@ cdef class Queue:
raise
IndexError
(
"Queue is empty"
)
raise
IndexError
(
"Queue is empty"
)
return
value
return
value
cpdef
int
ptr_t
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
<
intptr
_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
)
docs/src/tutorial/clibraries.rst
View file @
d1595a99
...
@@ -318,27 +318,28 @@ to give them a straight C interface.
...
@@ -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
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,
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``
which usually fit into the size of a pointer type, we can avoid
as it is garanteed to be at least as big as an ``int`` and the same size
additional memory allocations through a trick: we cast our ``int`` values
as a ``void*``
to ``void*`` and vice versa, and store the value directly as the
pointer value.
Here is a simple implementation for the ``append()`` method::
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)
cqueue.queue_push_tail(self._c_queue, <void*>value)
Again, the same error handling considerations as for the
Again, the same error handling considerations as for the
``__cinit__()`` method apply, so that we end up with this
``__cinit__()`` method apply, so that we end up with this
implementation instead::
implementation instead::
cdef append(self, int
ptr_t
value):
cdef 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*>value):
raise MemoryError()
raise MemoryError()
Adding an ``extend()`` method should now be straight forward::
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.
"""Append all ints to the queue.
"""
"""
cdef size_t i
cdef size_t i
...
@@ -352,13 +353,15 @@ example.
...
@@ -352,13 +353,15 @@ example.
So far, we can only add data to the queue. The next step is to write
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()``,
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):
cdef int peek(self):
return <
intptr
_t>cqueue.queue_peek_head(self._c_queue)
return <
Py_ssize
_t>cqueue.queue_peek_head(self._c_queue)
cdef int
ptr_t
pop(self):
cdef int pop(self):
return <
intptr
_t>cqueue.queue_pop_head(self._c_queue)
return <
Py_ssize
_t>cqueue.queue_pop_head(self._c_queue)
Handling errors
Handling errors
...
@@ -374,8 +377,8 @@ first case to raise an exception, whereas the second case should
...
@@ -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
simply return ``0``. To deal with this, we need to special case this
value, and check if the queue really is empty or not::
value, and check if the queue really is empty or not::
cdef int
ptr_t
peek(self) except? -1:
cdef int peek(self) except? -1:
value = <intptr
_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, or
# this may mean that the queue is empty, or
# that it happens to contain a 0 value
# that it happens to contain a 0 value
...
@@ -424,10 +427,10 @@ also needs adaptation. Since it removes a value from the queue,
...
@@ -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
however, it is not enough to test if the queue is empty *after* the
removal. Instead, we must test it on entry::
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):
if cqueue.queue_is_empty(self._c_queue):
raise IndexError("Queue is empty")
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
The return value for exception propagation is declared exactly as for
``peek()``.
``peek()``.
...
@@ -476,7 +479,7 @@ for example here :file:`test_queue.py`:
...
@@ -476,7 +479,7 @@ for example here :file:`test_queue.py`:
.. literalinclude:: ../../examples/tutorial/clibraries/test_queue.py
.. 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
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
,
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
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
loop
,
and
still
more
than
twice
as
fast
as
using
Python
's highly
...
@@ -505,12 +508,12 @@ predicate. The API could look as follows::
...
@@ -505,12 +508,12 @@ predicate. The API could look as follows::
*
0
for
reject
*
0
for
reject
*
1
for
accept
*
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
,
/*
Pop
values
as
long
as
the
predicate
evaluates
to
true
for
them
,
*
returns
-
1
if
the
predicate
failed
with
an
error
and
0
otherwise
.
*
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
);
void
*
user_context
);
It
is
normal
for
C
callback
functions
to
have
a
generic
:
c
:
type
:`
void
*`
It
is
normal
for
C
callback
functions
to
have
a
generic
:
c
:
type
:`
void
*`
...
@@ -521,13 +524,13 @@ predicate function.
...
@@ -521,13 +524,13 @@ predicate function.
First
,
we
have
to
define
a
callback
function
with
the
expected
First
,
we
have
to
define
a
callback
function
with
the
expected
signature
that
we
can
pass
into
the
C
-
API
function
::
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"
"Callback function that can be passed as predicate_func"
try
:
try
:
#
recover
Python
function
object
from
void
*
argument
#
recover
Python
function
object
from
void
*
argument
func
=
<
object
>
context
func
=
<
object
>
context
#
call
function
,
convert
result
into
0
/
1
for
True
/
False
#
call
function
,
convert
result
into
0
/
1
for
True
/
False
return
bool
(
func
(<
int
ptr_t
>
value
))
return
bool
(
func
(<
int
>
value
))
except
:
except
:
#
catch
any
Python
errors
and
return
error
indicator
#
catch
any
Python
errors
and
return
error
indicator
return
-
1
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