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
8774a186
Commit
8774a186
authored
Nov 03, 2017
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
git+ssh://github.com/cython/cython
parents
ed48d2d8
dc8e8c64
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
141 additions
and
38 deletions
+141
-38
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+52
-20
Cython/Includes/numpy/__init__.pxd
Cython/Includes/numpy/__init__.pxd
+4
-18
tests/buffers/userbuffer.pyx
tests/buffers/userbuffer.pyx
+85
-0
No files found.
Cython/Compiler/Nodes.py
View file @
8774a186
...
...
@@ -1854,6 +1854,10 @@ class FuncDefNode(StatNode, BlockNode):
code_object
=
self
.
code_object
.
calculate_result_code
(
code
)
if
self
.
code_object
else
None
code
.
put_trace_frame_init
(
code_object
)
# ----- Special check for getbuffer
if
is_getbuffer_slot
:
self
.
getbuffer_check
(
code
)
# ----- set up refnanny
if
use_refnanny
:
tempvardecl_code
.
put_declare_refcount_context
()
...
...
@@ -2201,30 +2205,58 @@ class FuncDefNode(StatNode, BlockNode):
#
# Special code for the __getbuffer__ function
#
def
getbuffer_init
(
self
,
code
):
info
=
self
.
local_scope
.
arg_entries
[
1
].
cname
# Python 3.0 betas have a bug in memoryview which makes it call
# getbuffer with a NULL parameter. For now we work around this;
# the following block should be removed when this bug is fixed.
code
.
putln
(
"if (%s != NULL) {"
%
info
)
code
.
putln
(
"%s->obj = Py_None; __Pyx_INCREF(Py_None);"
%
info
)
code
.
put_giveref
(
"%s->obj"
%
info
)
# Do not refnanny object within structs
def
_get_py_buffer_info
(
self
):
py_buffer
=
self
.
local_scope
.
arg_entries
[
1
]
try
:
# Check builtin definition of struct Py_buffer
obj_type
=
py_buffer
.
type
.
base_type
.
scope
.
entries
[
'obj'
].
type
except
(
AttributeError
,
KeyError
):
# User code redeclared struct Py_buffer
obj_type
=
None
return
py_buffer
,
obj_type
# Old Python 3 used to support write-locks on buffer-like objects by
# calling PyObject_GetBuffer() with a view==NULL parameter. This obscure
# feature is obsolete, it was almost never used (only one instance in
# `Modules/posixmodule.c` in Python 3.1) and it is now officially removed
# (see bpo-14203). We add an extra check here to prevent legacy code from
# from trying to use the feature and prevent segmentation faults.
def
getbuffer_check
(
self
,
code
):
py_buffer
,
_
=
self
.
_get_py_buffer_info
()
view
=
py_buffer
.
cname
code
.
putln
(
"if (%s == NULL) {"
%
view
)
code
.
putln
(
"PyErr_SetString(PyExc_BufferError, "
"
\
"
PyObject_GetBuffer: view==NULL argument is obsolete
\
"
);"
)
code
.
putln
(
"return -1;"
)
code
.
putln
(
"}"
)
def
getbuffer_init
(
self
,
code
):
py_buffer
,
obj_type
=
self
.
_get_py_buffer_info
()
view
=
py_buffer
.
cname
if
obj_type
and
obj_type
.
is_pyobject
:
code
.
put_init_to_py_none
(
"%s->obj"
%
view
,
obj_type
)
code
.
put_giveref
(
"%s->obj"
%
view
)
# Do not refnanny object within structs
else
:
code
.
putln
(
"%s->obj = NULL;"
%
view
)
def
getbuffer_error_cleanup
(
self
,
code
):
info
=
self
.
local_scope
.
arg_entries
[
1
].
cname
code
.
putln
(
"if (%s != NULL && %s->obj != NULL) {"
%
(
info
,
info
))
code
.
put_gotref
(
"%s->obj"
%
info
)
code
.
putln
(
"__Pyx_DECREF(%s->obj); %s->obj = NULL;"
%
(
info
,
info
)
)
py_buffer
,
obj_type
=
self
.
_get_py_buffer_info
()
view
=
py_buffer
.
cname
if
obj_type
and
obj_type
.
is_pyobject
:
code
.
putln
(
"if (%s->obj != NULL) {"
%
view
)
code
.
put_gotref
(
"%s->obj"
%
view
)
code
.
put_decref_clear
(
"%s->obj"
%
view
,
obj_type
)
code
.
putln
(
"}"
)
else
:
code
.
putln
(
"Py_CLEAR(%s->obj);"
%
view
)
def
getbuffer_normal_cleanup
(
self
,
code
):
info
=
self
.
local_scope
.
arg_entries
[
1
].
cname
code
.
putln
(
"if (%s != NULL && %s->obj == Py_None) {"
%
(
info
,
info
))
code
.
put_gotref
(
"Py_None"
)
code
.
putln
(
"__Pyx_DECREF(Py_None); %s->obj = NULL;"
%
info
)
py_buffer
,
obj_type
=
self
.
_get_py_buffer_info
()
view
=
py_buffer
.
cname
if
obj_type
and
obj_type
.
is_pyobject
:
code
.
putln
(
"if (%s->obj == Py_None) {"
%
view
)
code
.
put_gotref
(
"%s->obj"
%
view
)
code
.
put_decref_clear
(
"%s->obj"
%
view
,
obj_type
)
code
.
putln
(
"}"
)
def
get_preprocessor_guard
(
self
):
...
...
Cython/Includes/numpy/__init__.pxd
View file @
8774a186
...
...
@@ -217,19 +217,12 @@ cdef extern from "numpy/arrayobject.h":
# In particular strided access is always provided regardless
# of flags
if
info
==
NULL
:
return
cdef
int
copy_shape
,
i
,
ndim
cdef
int
i
,
ndim
cdef
int
endian_detector
=
1
cdef
bint
little_endian
=
((
<
char
*>&
endian_detector
)[
0
]
!=
0
)
ndim
=
PyArray_NDIM
(
self
)
if
sizeof
(
npy_intp
)
!=
sizeof
(
Py_ssize_t
):
copy_shape
=
1
else
:
copy_shape
=
0
if
((
flags
&
pybuf
.
PyBUF_C_CONTIGUOUS
==
pybuf
.
PyBUF_C_CONTIGUOUS
)
and
not
PyArray_CHKFLAGS
(
self
,
NPY_C_CONTIGUOUS
)):
raise
ValueError
(
u"ndarray is not C contiguous"
)
...
...
@@ -240,7 +233,7 @@ cdef extern from "numpy/arrayobject.h":
info
.
buf
=
PyArray_DATA
(
self
)
info
.
ndim
=
ndim
if
copy_shape
:
if
sizeof
(
npy_intp
)
!=
sizeof
(
Py_ssize_t
)
:
# Allocate new buffer for strides and shape info.
# This is allocated as one block, strides first.
info
.
strides
=
<
Py_ssize_t
*>
PyObject_Malloc
(
sizeof
(
Py_ssize_t
)
*
2
*
<
size_t
>
ndim
)
...
...
@@ -260,16 +253,9 @@ cdef extern from "numpy/arrayobject.h":
cdef
dtype
descr
=
self
.
descr
cdef
int
offset
cdef
bint
hasfields
=
PyDataType_HASFIELDS
(
descr
)
if
not
hasfields
and
not
copy_shape
:
# do not call releasebuffer
info
.
obj
=
None
else
:
# need to call releasebuffer
info
.
obj
=
self
if
not
hasfields
:
if
not
PyDataType_HASFIELDS
(
descr
)
:
t
=
descr
.
type_num
if
((
descr
.
byteorder
==
c
'>'
and
little_endian
)
or
(
descr
.
byteorder
==
c
'<'
and
not
little_endian
)):
...
...
tests/buffers/userbuffer.pyx
0 → 100644
View file @
8774a186
import
sys
__doc__
=
u""
if
sys
.
version_info
[:
2
]
==
(
2
,
6
):
__doc__
+=
u"""
>>> memoryview = _memoryview
"""
__doc__
+=
u"""
>>> b1 = UserBuffer1()
>>> m1 = memoryview(b1)
>>> m1.tolist()
[0, 1, 2, 3, 4]
>>> del m1, b1
"""
__doc__
+=
u"""
>>> b2 = UserBuffer2()
>>> m2 = memoryview(b2)
UserBuffer2: getbuffer
>>> m2.tolist()
[5, 6, 7, 8, 9]
>>> del m2, b2
UserBuffer2: release
"""
cdef
extern
from
*
:
ctypedef
struct
Py_buffer
# redeclared
enum
:
PyBUF_SIMPLE
int
PyBuffer_FillInfo
(
Py_buffer
*
,
object
,
void
*
,
Py_ssize_t
,
bint
,
int
)
except
-
1
int
PyObject_GetBuffer
(
object
,
Py_buffer
*
,
int
)
except
-
1
void
PyBuffer_Release
(
Py_buffer
*
)
cdef
char
global_buf
[
5
]
global_buf
[
0
:
5
]
=
[
0
,
1
,
2
,
3
,
4
]
cdef
class
UserBuffer1
:
def
__getbuffer__
(
self
,
Py_buffer
*
view
,
int
flags
):
PyBuffer_FillInfo
(
view
,
None
,
global_buf
,
5
,
1
,
flags
)
cdef
class
UserBuffer2
:
cdef
char
buf
[
5
]
def
__cinit__
(
self
):
self
.
buf
[
0
:
5
]
=
[
5
,
6
,
7
,
8
,
9
]
def
__getbuffer__
(
self
,
Py_buffer
*
view
,
int
flags
):
print
(
'UserBuffer2: getbuffer'
)
PyBuffer_FillInfo
(
view
,
self
,
self
.
buf
,
5
,
0
,
flags
)
def
__releasebuffer__
(
self
,
Py_buffer
*
view
):
print
(
'UserBuffer2: release'
)
cdef
extern
from
*
:
ctypedef
struct
PyBuffer
"Py_buffer"
:
void
*
buf
Py_ssize_t
len
bint
readonly
cdef
class
_memoryview
:
"""
Memory
"""
cdef
PyBuffer
view
def
__cinit__
(
self
,
obj
):
cdef
Py_buffer
*
view
=
<
Py_buffer
*>&
self
.
view
PyObject_GetBuffer
(
obj
,
view
,
PyBUF_SIMPLE
)
def
__dealloc__
(
self
):
cdef
Py_buffer
*
view
=
<
Py_buffer
*>&
self
.
view
PyBuffer_Release
(
view
)
def
__getbuffer__
(
self
,
Py_buffer
*
view
,
int
flags
):
PyBuffer_FillInfo
(
view
,
self
,
self
.
view
.
buf
,
self
.
view
.
len
,
self
.
view
.
readonly
,
flags
)
def
tolist
(
self
):
cdef
char
*
b
=
<
char
*>
self
.
view
.
buf
return
[
b
[
i
]
for
i
in
range
(
self
.
view
.
len
)]
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