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
06f56ee1
Commit
06f56ee1
authored
Apr 28, 2016
by
Wenzel Jakob
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
opaque type redesign
parent
f64feaf3
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
72 additions
and
52 deletions
+72
-52
README.md
+2
-0
docs/advanced.rst
+26
-11
docs/basics.rst
+1
-1
example/example14.cpp
+14
-10
example/example14.py
+5
-1
example/example14.ref
+4
-1
include/pybind11/cast.h
+20
-28
No files found.
README.md
View file @
06f56ee1
...
@@ -32,6 +32,8 @@ simpler binding code in many common situations.
...
@@ -32,6 +32,8 @@ simpler binding code in many common situations.
Tutorial and reference documentation is provided at
Tutorial and reference documentation is provided at
[
http://pybind11.readthedocs.org/en/latest
](
http://pybind11.readthedocs.org/en/latest
)
.
[
http://pybind11.readthedocs.org/en/latest
](
http://pybind11.readthedocs.org/en/latest
)
.
A PDF version of the manual is available
[
here
](
https://media.readthedocs.org/pdf/pybind11/latest/pybind11.pdf
)
.
## Core features
## Core features
pybind11 can map the following core C++ features to Python
pybind11 can map the following core C++ features to Python
...
...
docs/advanced.rst
View file @
06f56ee1
...
@@ -1203,7 +1203,7 @@ Suppose we bind the following function
...
@@ -1203,7 +1203,7 @@ Suppose we bind the following function
v.push_back(1);
v.push_back(1);
}
}
and call it
as follows from Python
:
and call it
from Python, the following happens
:
.. code-block:: python
.. code-block:: python
...
@@ -1244,21 +1244,36 @@ In this case, properties can be read and written in their entirety. However, an
...
@@ -1244,21 +1244,36 @@ In this case, properties can be read and written in their entirety. However, an
>>> print(m.contents)
>>> print(m.contents)
[5, 6]
[5, 6]
To deal with both of the above situations, pybind11 contains a simple template
To deal with both of the above situations, pybind11 provides a macro named
wrapper class named ``opaque<T>``.
``PYBIND11_MAKE_OPAQUE(T)`` that disables the template-based conversion
machinery of types, thus rendering them *opaque*. The contents of opaque
objects are never inspected or extracted, hence they can be passed by
reference. For instance, to turn ``std::vector<int>`` into an opaque type, add
the declaration
``opaque<T>`` disables pybind11's template-based conversion machinery for
.. code-block:: cpp
``T`` and can be used to treat STL types as opaque objects, whose contents are
never inspected or extracted (thus, they can be passed by reference).
PYBIND11_MAKE_OPAQUE(std::vector<int>);
The downside of this approach is that it the binding code becomes a bit more
wordy. The above function can be bound using the following wrapper code:
before any binding code (e.g. invocations to ``class_::def()``, etc). This
macro must be specified at the top level, since instantiates a partial template
overload. If your binding code consists of multiple compilation units, it must
be present in every file preceding any usage of ``std::vector<int>``. Opaque
types must also have a corresponding ``class_`` declaration to associate them
with a name in Python, and to define a set of available operations:
.. code-block:: cpp
.. code-block:: cpp
m.def("append_1", [](py::opaque<std::vector<int>> &v) { append_1(v); });
py::class_<std::vector<int>>(m, "IntVector")
.def(py::init<>())
.def("clear", &std::vector<int>::clear)
.def("pop_back", &std::vector<int>::pop_back)
.def("__len__", [](const std::vector<int> &v) { return v.size(); })
.def("__iter__", [](std::vector<int> &v) {
return py::make_iterator(v.begin(), v.end());
}, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */
// ....
Opaque types must also have a dedicated ``class_`` declaration to define a
set of admissible operations.
.. seealso::
.. seealso::
...
...
docs/basics.rst
View file @
06f56ee1
...
@@ -117,7 +117,7 @@ example can be compiled using the following command
...
@@ -117,7 +117,7 @@ example can be compiled using the following command
.. code-block:: bash
.. code-block:: bash
$ c++ -O3 -shared -std=c++11 -I <path-to-pybind11>/include `python-config --cflags --ldflags
--libs
` example.cpp -o example.so
$ c++ -O3 -shared -std=c++11 -I <path-to-pybind11>/include `python-config --cflags --ldflags` example.cpp -o example.so
In general, it is advisable to include several additional build parameters
In general, it is advisable to include several additional build parameters
that can considerably reduce the size of the created binary. Refer to section
that can considerably reduce the size of the created binary. Refer to section
...
...
example/example14.cpp
View file @
06f56ee1
...
@@ -18,22 +18,26 @@ public:
...
@@ -18,22 +18,26 @@ public:
StringList
stringList
;
StringList
stringList
;
};
};
/* IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures */
PYBIND11_MAKE_OPAQUE
(
StringList
);
void
init_ex14
(
py
::
module
&
m
)
{
void
init_ex14
(
py
::
module
&
m
)
{
py
::
class_
<
py
::
opaque
<
StringList
>
>
(
m
,
"StringList"
)
py
::
class_
<
StringList
>
(
m
,
"StringList"
)
.
def
(
py
::
init
<>
())
.
def
(
py
::
init
<>
())
.
def
(
"push_back"
,
[](
py
::
opaque
<
StringList
>
&
l
,
const
std
::
string
&
str
)
{
l
->
push_back
(
str
);
})
.
def
(
"pop_back"
,
&
StringList
::
pop_back
)
.
def
(
"pop_back"
,
[](
py
::
opaque
<
StringList
>
&
l
)
{
l
->
pop_back
();
})
/* There are multiple versions of push_back(), etc. Select the right ones. */
.
def
(
"back"
,
[](
py
::
opaque
<
StringList
>
&
l
)
{
return
l
->
back
();
});
.
def
(
"push_back"
,
(
void
(
StringList
::*
)(
const
std
::
string
&
))
&
StringList
::
push_back
)
.
def
(
"back"
,
(
std
::
string
&
(
StringList
::*
)())
&
StringList
::
back
)
.
def
(
"__len__"
,
[](
const
StringList
&
v
)
{
return
v
.
size
();
})
.
def
(
"__iter__"
,
[](
StringList
&
v
)
{
return
py
::
make_iterator
(
v
.
begin
(),
v
.
end
());
},
py
::
keep_alive
<
0
,
1
>
());
py
::
class_
<
ClassWithSTLVecProperty
>
(
m
,
"ClassWithSTLVecProperty"
)
py
::
class_
<
ClassWithSTLVecProperty
>
(
m
,
"ClassWithSTLVecProperty"
)
.
def
(
py
::
init
<>
())
.
def
(
py
::
init
<>
())
/* Need to cast properties to opaque types to avoid pybind11-internal
.
def_readwrite
(
"stringList"
,
&
ClassWithSTLVecProperty
::
stringList
);
STL conversion code from becoming active */
.
def_readwrite
(
"stringList"
,
(
py
::
opaque
<
StringList
>
ClassWithSTLVecProperty
::
*
)
&
ClassWithSTLVecProperty
::
stringList
);
m
.
def
(
"print_opaque_list"
,
[](
py
::
opaque
<
StringList
>
&
_l
)
{
m
.
def
(
"print_opaque_list"
,
[](
const
StringList
&
l
)
{
StringList
&
l
=
_l
;
std
::
cout
<<
"Opaque list: ["
;
std
::
cout
<<
"Opaque list: ["
;
bool
first
=
true
;
bool
first
=
true
;
for
(
auto
entry
:
l
)
{
for
(
auto
entry
:
l
)
{
...
...
example/example14.py
View file @
06f56ee1
...
@@ -16,6 +16,8 @@ l.push_back("Element 1")
...
@@ -16,6 +16,8 @@ l.push_back("Element 1")
l
.
push_back
(
"Element 2"
)
l
.
push_back
(
"Element 2"
)
print_opaque_list
(
l
)
print_opaque_list
(
l
)
print
(
"Back element is
%
s"
%
l
.
back
())
print
(
"Back element is
%
s"
%
l
.
back
())
for
i
,
k
in
enumerate
(
l
):
print
(
"
%
i/
%
i :
%
s"
%
(
i
+
1
,
len
(
l
),
k
))
l
.
pop_back
()
l
.
pop_back
()
print_opaque_list
(
l
)
print_opaque_list
(
l
)
...
@@ -36,4 +38,6 @@ print_null_str(return_null_str())
...
@@ -36,4 +38,6 @@ print_null_str(return_null_str())
#####
#####
print
(
return_unique_ptr
())
ptr
=
return_unique_ptr
()
print
(
ptr
)
print_opaque_list
(
ptr
)
example/example14.ref
View file @
06f56ee1
Opaque list: [Element 1, Element 2]
Opaque list: [Element 1, Element 2]
Back element is Element 2
Back element is Element 2
1/2 : Element 1
2/2 : Element 2
Opaque list: [Element 1]
Opaque list: [Element 1]
Opaque list: []
Opaque list: []
Opaque list: [Element 1, Element 3]
Opaque list: [Element 1, Element 3]
Got void ptr : 1234
Got void ptr : 1234
None
None
Got null str : 0
Got null str : 0
[u'some value']
<example.StringList object at 0x104a47500>
Opaque list: [some value]
include/pybind11/cast.h
View file @
06f56ee1
...
@@ -17,21 +17,6 @@
...
@@ -17,21 +17,6 @@
#include <limits>
#include <limits>
NAMESPACE_BEGIN
(
pybind11
)
NAMESPACE_BEGIN
(
pybind11
)
/// Thin wrapper type used to treat certain data types as opaque (e.g. STL vectors, etc.)
template
<
typename
Type
>
class
opaque
{
public
:
template
<
typename
...
Args
>
opaque
(
Args
&&
...
args
)
:
value
(
std
::
forward
<
Args
>
(
args
)...)
{
}
operator
Type
&
()
{
return
value
;
}
operator
const
Type
&
()
const
{
return
value
;
}
operator
Type
*
()
{
return
&
value
;
}
operator
const
Type
*
()
const
{
return
&
value
;
}
Type
*
operator
->
()
{
return
&
value
;
}
const
Type
*
operator
->
()
const
{
return
&
value
;
}
private
:
Type
value
;
};
NAMESPACE_BEGIN
(
detail
)
NAMESPACE_BEGIN
(
detail
)
/// Additional type information which does not fit into the PyTypeObject
/// Additional type information which does not fit into the PyTypeObject
...
@@ -238,11 +223,11 @@ using cast_op_type = typename std::conditional<std::is_pointer<typename std::rem
...
@@ -238,11 +223,11 @@ using cast_op_type = typename std::conditional<std::is_pointer<typename std::rem
typename
std
::
add_lvalue_reference
<
typename
intrinsic_type
<
T
>::
type
>::
type
>::
type
;
typename
std
::
add_lvalue_reference
<
typename
intrinsic_type
<
T
>::
type
>::
type
>::
type
;
/// Generic type caster for objects stored on the heap
/// Generic type caster for objects stored on the heap
template
<
typename
type
,
typename
Enable
=
void
>
class
type_caster
:
public
type_caster_generic
{
template
<
typename
type
>
class
type_caster_base
:
public
type_caster_generic
{
public
:
public
:
static
PYBIND11_DESCR
name
()
{
return
type_descr
(
_
<
type
>
());
}
static
PYBIND11_DESCR
name
()
{
return
type_descr
(
_
<
type
>
());
}
type_caster
()
:
type_caster_generic
(
typeid
(
type
))
{
}
type_caster
_base
()
:
type_caster_generic
(
typeid
(
type
))
{
}
static
handle
cast
(
const
type
&
src
,
return_value_policy
policy
,
handle
parent
)
{
static
handle
cast
(
const
type
&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
automatic
||
policy
==
return_value_policy
::
automatic_reference
)
if
(
policy
==
return_value_policy
::
automatic
||
policy
==
return_value_policy
::
automatic_reference
)
...
@@ -277,10 +262,12 @@ protected:
...
@@ -277,10 +262,12 @@ protected:
static
void
*
move_constructor
(
const
void
*
)
{
return
nullptr
;
}
static
void
*
move_constructor
(
const
void
*
)
{
return
nullptr
;
}
};
};
template
<
typename
type
>
class
type_caster
<
std
::
reference_wrapper
<
type
>>
:
public
type_caster
<
type
>
{
template
<
typename
type
,
typename
SFINAE
=
void
>
class
type_caster
:
public
type_caster_base
<
type
>
{
};
template
<
typename
type
>
class
type_caster
<
std
::
reference_wrapper
<
type
>>
:
public
type_caster_base
<
type
>
{
public
:
public
:
static
handle
cast
(
const
std
::
reference_wrapper
<
type
>
&
src
,
return_value_policy
policy
,
handle
parent
)
{
static
handle
cast
(
const
std
::
reference_wrapper
<
type
>
&
src
,
return_value_policy
policy
,
handle
parent
)
{
return
type_caster
<
type
>::
cast
(
&
src
.
get
(),
policy
,
parent
);
return
type_caster
_base
<
type
>::
cast
(
&
src
.
get
(),
policy
,
parent
);
}
}
template
<
typename
T
>
using
cast_op_type
=
std
::
reference_wrapper
<
type
>
;
template
<
typename
T
>
using
cast_op_type
=
std
::
reference_wrapper
<
type
>
;
operator
std
::
reference_wrapper
<
type
>
()
{
return
std
::
ref
(
*
((
type
*
)
this
->
value
));
}
operator
std
::
reference_wrapper
<
type
>
()
{
return
std
::
ref
(
*
((
type
*
)
this
->
value
));
}
...
@@ -461,12 +448,12 @@ protected:
...
@@ -461,12 +448,12 @@ protected:
template
<
typename
type
>
class
type_caster
<
std
::
unique_ptr
<
type
>>
{
template
<
typename
type
>
class
type_caster
<
std
::
unique_ptr
<
type
>>
{
public
:
public
:
static
handle
cast
(
std
::
unique_ptr
<
type
>
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
static
handle
cast
(
std
::
unique_ptr
<
type
>
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
handle
result
=
type_caster
<
type
>::
cast
(
src
.
get
(),
policy
,
parent
);
handle
result
=
type_caster
_base
<
type
>::
cast
(
src
.
get
(),
policy
,
parent
);
if
(
result
)
if
(
result
)
src
.
release
();
src
.
release
();
return
result
;
return
result
;
}
}
static
PYBIND11_DESCR
name
()
{
return
type_caster
<
type
>::
name
();
}
static
PYBIND11_DESCR
name
()
{
return
type_caster
_base
<
type
>::
name
();
}
};
};
template
<>
class
type_caster
<
std
::
wstring
>
{
template
<>
class
type_caster
<
std
::
wstring
>
{
...
@@ -672,14 +659,14 @@ protected:
...
@@ -672,14 +659,14 @@ protected:
};
};
/// Type caster for holder types like std::shared_ptr, etc.
/// Type caster for holder types like std::shared_ptr, etc.
template
<
typename
type
,
typename
holder_type
>
class
type_caster_holder
:
public
type_caster
<
type
>
{
template
<
typename
type
,
typename
holder_type
>
class
type_caster_holder
:
public
type_caster
_base
<
type
>
{
public
:
public
:
using
type_caster
<
type
>::
cast
;
using
type_caster
_base
<
type
>::
cast
;
using
type_caster
<
type
>::
typeinfo
;
using
type_caster
_base
<
type
>::
typeinfo
;
using
type_caster
<
type
>::
value
;
using
type_caster
_base
<
type
>::
value
;
using
type_caster
<
type
>::
temp
;
using
type_caster
_base
<
type
>::
temp
;
using
type_caster
<
type
>::
copy_constructor
;
using
type_caster
_base
<
type
>::
copy_constructor
;
using
type_caster
<
type
>::
move_constructor
;
using
type_caster
_base
<
type
>::
move_constructor
;
bool
load
(
handle
src
,
bool
convert
)
{
bool
load
(
handle
src
,
bool
convert
)
{
if
(
!
src
||
!
typeinfo
)
{
if
(
!
src
||
!
typeinfo
)
{
...
@@ -790,4 +777,9 @@ template <typename... Args> inline object handle::call(Args&&... args) const {
...
@@ -790,4 +777,9 @@ template <typename... Args> inline object handle::call(Args&&... args) const {
return
result
;
return
result
;
}
}
#define PYBIND11_MAKE_OPAQUE(Type) \
namespace pybind11 { namespace detail { \
template<> class type_caster<Type> : public type_caster_base<Type> { }; \
}}
NAMESPACE_END
(
pybind11
)
NAMESPACE_END
(
pybind11
)
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