Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pybind11
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
pybind11
Commits
dc65d661
Commit
dc65d661
authored
Nov 24, 2019
by
Sebastian Koslowski
Committed by
Wenzel Jakob
Nov 24, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
support for readonly buffers (#863) (#1466)
parent
bd24155b
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
83 additions
and
13 deletions
+83
-13
include/pybind11/buffer_info.h
+17
-11
include/pybind11/detail/class.h
+7
-0
include/pybind11/pytypes.h
+1
-1
tests/constructor_stats.h
+1
-1
tests/test_buffers.cpp
+26
-0
tests/test_buffers.py
+31
-0
No files found.
include/pybind11/buffer_info.h
View file @
dc65d661
...
...
@@ -22,13 +22,14 @@ struct buffer_info {
ssize_t
ndim
=
0
;
// Number of dimensions
std
::
vector
<
ssize_t
>
shape
;
// Shape of the tensor (1 entry per dimension)
std
::
vector
<
ssize_t
>
strides
;
// Number of bytes between adjacent entries (for each per dimension)
bool
readonly
=
false
;
// flag to indicate if the underlying storage may be written to
buffer_info
()
{
}
buffer_info
(
void
*
ptr
,
ssize_t
itemsize
,
const
std
::
string
&
format
,
ssize_t
ndim
,
detail
::
any_container
<
ssize_t
>
shape_in
,
detail
::
any_container
<
ssize_t
>
strides_in
)
detail
::
any_container
<
ssize_t
>
shape_in
,
detail
::
any_container
<
ssize_t
>
strides_in
,
bool
readonly
=
false
)
:
ptr
(
ptr
),
itemsize
(
itemsize
),
size
(
1
),
format
(
format
),
ndim
(
ndim
),
shape
(
std
::
move
(
shape_in
)),
strides
(
std
::
move
(
strides_in
))
{
shape
(
std
::
move
(
shape_in
)),
strides
(
std
::
move
(
strides_in
))
,
readonly
(
readonly
)
{
if
(
ndim
!=
(
ssize_t
)
shape
.
size
()
||
ndim
!=
(
ssize_t
)
strides
.
size
())
pybind11_fail
(
"buffer_info: ndim doesn't match shape and/or strides length"
);
for
(
size_t
i
=
0
;
i
<
(
size_t
)
ndim
;
++
i
)
...
...
@@ -36,19 +37,23 @@ struct buffer_info {
}
template
<
typename
T
>
buffer_info
(
T
*
ptr
,
detail
::
any_container
<
ssize_t
>
shape_in
,
detail
::
any_container
<
ssize_t
>
strides_in
)
:
buffer_info
(
private_ctr_tag
(),
ptr
,
sizeof
(
T
),
format_descriptor
<
T
>::
format
(),
static_cast
<
ssize_t
>
(
shape_in
->
size
()),
std
::
move
(
shape_in
),
std
::
move
(
strides_in
))
{
}
buffer_info
(
T
*
ptr
,
detail
::
any_container
<
ssize_t
>
shape_in
,
detail
::
any_container
<
ssize_t
>
strides_in
,
bool
readonly
=
false
)
:
buffer_info
(
private_ctr_tag
(),
ptr
,
sizeof
(
T
),
format_descriptor
<
T
>::
format
(),
static_cast
<
ssize_t
>
(
shape_in
->
size
()),
std
::
move
(
shape_in
),
std
::
move
(
strides_in
)
,
readonly
)
{
}
buffer_info
(
void
*
ptr
,
ssize_t
itemsize
,
const
std
::
string
&
format
,
ssize_t
size
)
:
buffer_info
(
ptr
,
itemsize
,
format
,
1
,
{
size
},
{
itemsize
})
{
}
buffer_info
(
void
*
ptr
,
ssize_t
itemsize
,
const
std
::
string
&
format
,
ssize_t
size
,
bool
readonly
=
false
)
:
buffer_info
(
ptr
,
itemsize
,
format
,
1
,
{
size
},
{
itemsize
}
,
readonly
)
{
}
template
<
typename
T
>
buffer_info
(
T
*
ptr
,
ssize_t
size
)
:
buffer_info
(
ptr
,
sizeof
(
T
),
format_descriptor
<
T
>::
format
(),
size
)
{
}
buffer_info
(
T
*
ptr
,
ssize_t
size
,
bool
readonly
=
false
)
:
buffer_info
(
ptr
,
sizeof
(
T
),
format_descriptor
<
T
>::
format
(),
size
,
readonly
)
{
}
template
<
typename
T
>
buffer_info
(
const
T
*
ptr
,
ssize_t
size
,
bool
readonly
=
true
)
:
buffer_info
(
const_cast
<
T
*>
(
ptr
),
sizeof
(
T
),
format_descriptor
<
T
>::
format
(),
size
,
readonly
)
{
}
explicit
buffer_info
(
Py_buffer
*
view
,
bool
ownview
=
true
)
:
buffer_info
(
view
->
buf
,
view
->
itemsize
,
view
->
format
,
view
->
ndim
,
{
view
->
shape
,
view
->
shape
+
view
->
ndim
},
{
view
->
strides
,
view
->
strides
+
view
->
ndim
})
{
{
view
->
shape
,
view
->
shape
+
view
->
ndim
},
{
view
->
strides
,
view
->
strides
+
view
->
ndim
}
,
view
->
readonly
)
{
this
->
view
=
view
;
this
->
ownview
=
ownview
;
}
...
...
@@ -70,6 +75,7 @@ struct buffer_info {
strides
=
std
::
move
(
rhs
.
strides
);
std
::
swap
(
view
,
rhs
.
view
);
std
::
swap
(
ownview
,
rhs
.
ownview
);
readonly
=
rhs
.
readonly
;
return
*
this
;
}
...
...
@@ -81,8 +87,8 @@ private:
struct
private_ctr_tag
{
};
buffer_info
(
private_ctr_tag
,
void
*
ptr
,
ssize_t
itemsize
,
const
std
::
string
&
format
,
ssize_t
ndim
,
detail
::
any_container
<
ssize_t
>
&&
shape_in
,
detail
::
any_container
<
ssize_t
>
&&
strides_in
)
:
buffer_info
(
ptr
,
itemsize
,
format
,
ndim
,
std
::
move
(
shape_in
),
std
::
move
(
strides_in
))
{
}
detail
::
any_container
<
ssize_t
>
&&
shape_in
,
detail
::
any_container
<
ssize_t
>
&&
strides_in
,
bool
readonly
)
:
buffer_info
(
ptr
,
itemsize
,
format
,
ndim
,
std
::
move
(
shape_in
),
std
::
move
(
strides_in
)
,
readonly
)
{
}
Py_buffer
*
view
=
nullptr
;
bool
ownview
=
false
;
...
...
include/pybind11/detail/class.h
View file @
dc65d661
...
...
@@ -491,6 +491,13 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
view
->
len
=
view
->
itemsize
;
for
(
auto
s
:
info
->
shape
)
view
->
len
*=
s
;
view
->
readonly
=
info
->
readonly
;
if
((
flags
&
PyBUF_WRITABLE
)
==
PyBUF_WRITABLE
&&
info
->
readonly
)
{
if
(
view
)
view
->
obj
=
nullptr
;
PyErr_SetString
(
PyExc_BufferError
,
"Writable buffer requested for readonly storage"
);
return
-
1
;
}
if
((
flags
&
PyBUF_FORMAT
)
==
PyBUF_FORMAT
)
view
->
format
=
const_cast
<
char
*>
(
info
->
format
.
c_str
());
if
((
flags
&
PyBUF_STRIDES
)
==
PyBUF_STRIDES
)
{
...
...
include/pybind11/pytypes.h
View file @
dc65d661
...
...
@@ -1345,7 +1345,7 @@ public:
buf
.
strides
=
py_strides
.
data
();
buf
.
shape
=
py_shape
.
data
();
buf
.
suboffsets
=
nullptr
;
buf
.
readonly
=
false
;
buf
.
readonly
=
info
.
readonly
;
buf
.
internal
=
nullptr
;
m_ptr
=
PyMemoryView_FromBuffer
(
&
buf
);
...
...
tests/constructor_stats.h
View file @
dc65d661
...
...
@@ -180,7 +180,7 @@ public:
}
}
}
catch
(
const
std
::
out_of_range
&
)
{}
catch
(
const
std
::
out_of_range
&
)
{}
if
(
!
t1
)
throw
std
::
runtime_error
(
"Unknown class passed to ConstructorStats::get()"
);
auto
&
cs1
=
get
(
*
t1
);
// If we have both a t1 and t2 match, one is probably the trampoline class; return whichever
...
...
tests/test_buffers.cpp
View file @
dc65d661
...
...
@@ -166,4 +166,30 @@ TEST_SUBMODULE(buffers, m) {
.
def_readwrite
(
"value"
,
(
int32_t
DerivedBuffer
::*
)
&
DerivedBuffer
::
value
)
.
def_buffer
(
&
DerivedBuffer
::
get_buffer_info
);
struct
BufferReadOnly
{
const
uint8_t
value
=
0
;
BufferReadOnly
(
uint8_t
value
)
:
value
(
value
)
{}
py
::
buffer_info
get_buffer_info
()
{
return
py
::
buffer_info
(
&
value
,
1
);
}
};
py
::
class_
<
BufferReadOnly
>
(
m
,
"BufferReadOnly"
,
py
::
buffer_protocol
())
.
def
(
py
::
init
<
uint8_t
>
())
.
def_buffer
(
&
BufferReadOnly
::
get_buffer_info
);
struct
BufferReadOnlySelect
{
uint8_t
value
=
0
;
bool
readonly
=
false
;
py
::
buffer_info
get_buffer_info
()
{
return
py
::
buffer_info
(
&
value
,
1
,
readonly
);
}
};
py
::
class_
<
BufferReadOnlySelect
>
(
m
,
"BufferReadOnlySelect"
,
py
::
buffer_protocol
())
.
def
(
py
::
init
<>
())
.
def_readwrite
(
"value"
,
&
BufferReadOnlySelect
::
value
)
.
def_readwrite
(
"readonly"
,
&
BufferReadOnlySelect
::
readonly
)
.
def_buffer
(
&
BufferReadOnlySelect
::
get_buffer_info
);
}
tests/test_buffers.py
View file @
dc65d661
import
io
import
struct
import
sys
import
pytest
from
pybind11_tests
import
buffers
as
m
from
pybind11_tests
import
ConstructorStats
PY3
=
sys
.
version_info
[
0
]
>=
3
pytestmark
=
pytest
.
requires_numpy
with
pytest
.
suppress
(
ImportError
):
...
...
@@ -85,3 +91,28 @@ def test_pointer_to_member_fn():
buf
.
value
=
0x12345678
value
=
struct
.
unpack
(
'i'
,
bytearray
(
buf
))[
0
]
assert
value
==
0x12345678
@pytest.unsupported_on_pypy
def
test_readonly_buffer
():
buf
=
m
.
BufferReadOnly
(
0x64
)
view
=
memoryview
(
buf
)
assert
view
[
0
]
==
0x64
if
PY3
else
b
'd'
assert
view
.
readonly
@pytest.unsupported_on_pypy
def
test_selective_readonly_buffer
():
buf
=
m
.
BufferReadOnlySelect
()
memoryview
(
buf
)[
0
]
=
0x64
if
PY3
else
b
'd'
assert
buf
.
value
==
0x64
io
.
BytesIO
(
b
'A'
)
.
readinto
(
buf
)
assert
buf
.
value
==
ord
(
b
'A'
)
buf
.
readonly
=
True
with
pytest
.
raises
(
TypeError
):
memoryview
(
buf
)[
0
]
=
0
if
PY3
else
b
'
\0
'
with
pytest
.
raises
(
TypeError
):
io
.
BytesIO
(
b
'1'
)
.
readinto
(
buf
)
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