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
ddbc74c6
Commit
ddbc74c6
authored
Feb 07, 2022
by
Ralf W. Grosse-Kunstleve
Committed by
Ralf W. Grosse-Kunstleve
Feb 08, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adding .clang-tidy readability-braces-around-statements option.
clang-tidy automatic changes. NO manual changes.
parent
8581584e
Hide whitespace changes
Inline
Side-by-side
Showing
49 changed files
with
1363 additions
and
678 deletions
+1363
-678
.clang-tidy
+1
-0
include/pybind11/attr.h
+21
-11
include/pybind11/buffer_info.h
+10
-5
include/pybind11/cast.h
+77
-36
include/pybind11/chrono.h
+12
-5
include/pybind11/complex.h
+4
-2
include/pybind11/detail/class.h
+71
-37
include/pybind11/detail/init.h
+21
-10
include/pybind11/detail/internals.h
+5
-2
include/pybind11/detail/type_caster_base.h
+113
-55
include/pybind11/detail/typeid.h
+5
-2
include/pybind11/eigen.h
+59
-27
include/pybind11/embed.h
+12
-6
include/pybind11/eval.h
+8
-4
include/pybind11/functional.h
+9
-4
include/pybind11/gil.h
+9
-5
include/pybind11/iostream.h
+14
-8
include/pybind11/numpy.h
+114
-59
include/pybind11/pybind11.h
+244
-130
include/pybind11/pytypes.h
+122
-52
include/pybind11/stl.h
+38
-20
include/pybind11/stl_bind.h
+68
-40
tests/constructor_stats.h
+15
-6
tests/object.h
+26
-13
tests/pybind11_cross_module_tests.cpp
+3
-1
tests/pybind11_tests.cpp
+2
-1
tests/test_buffers.cpp
+6
-3
tests/test_builtin_casters.cpp
+20
-5
tests/test_call_policies.cpp
+2
-1
tests/test_callbacks.cpp
+12
-6
tests/test_class.cpp
+9
-4
tests/test_copy_move.cpp
+5
-2
tests/test_eigen.cpp
+15
-7
tests/test_embed/test_interpreter.cpp
+5
-1
tests/test_eval.cpp
+2
-1
tests/test_exceptions.cpp
+25
-10
tests/test_iostream.cpp
+2
-1
tests/test_kwargs_and_defaults.cpp
+6
-3
tests/test_local_bindings.cpp
+2
-1
tests/test_numpy_array.cpp
+48
-24
tests/test_numpy_dtypes.cpp
+43
-28
tests/test_opaque_types.cpp
+2
-1
tests/test_pickling.cpp
+12
-6
tests/test_pytypes.cpp
+9
-6
tests/test_sequences_and_iterators.cpp
+27
-13
tests/test_smart_ptr.cpp
+6
-3
tests/test_stl_binders.cpp
+14
-8
tests/test_tagbased_polymorphic.cpp
+6
-2
tests/test_virtual_functions.cpp
+2
-1
No files found.
.clang-tidy
View file @
ddbc74c6
...
...
@@ -31,6 +31,7 @@ modernize-use-override,
modernize-use-using,
*performance*,
readability-avoid-const-params-in-decls,
readability-braces-around-statements,
readability-const-return-type,
readability-container-size-empty,
readability-delete-null-pointer,
...
...
include/pybind11/attr.h
View file @
ddbc74c6
...
...
@@ -330,11 +330,13 @@ struct type_record {
bases
.
append
((
PyObject
*
)
base_info
->
type
);
if
(
base_info
->
type
->
tp_dictoffset
!=
0
)
if
(
base_info
->
type
->
tp_dictoffset
!=
0
)
{
dynamic_attr
=
true
;
}
if
(
caster
)
if
(
caster
)
{
base_info
->
implicit_casts
.
emplace_back
(
type
,
caster
);
}
}
};
...
...
@@ -410,13 +412,16 @@ template <> struct process_attribute<is_new_style_constructor> : process_attribu
};
inline
void
check_kw_only_arg
(
const
arg
&
a
,
function_record
*
r
)
{
if
(
r
->
args
.
size
()
>
r
->
nargs_pos
&&
(
!
a
.
name
||
a
.
name
[
0
]
==
'\0'
))
pybind11_fail
(
"arg(): cannot specify an unnamed argument after a kw_only() annotation or args() argument"
);
if
(
r
->
args
.
size
()
>
r
->
nargs_pos
&&
(
!
a
.
name
||
a
.
name
[
0
]
==
'\0'
))
{
pybind11_fail
(
"arg(): cannot specify an unnamed argument after a kw_only() annotation or "
"args() argument"
);
}
}
inline
void
append_self_arg_if_needed
(
function_record
*
r
)
{
if
(
r
->
is_method
&&
r
->
args
.
empty
())
r
->
args
.
emplace_back
(
"self"
,
nullptr
,
handle
(),
/*convert=*/
true
,
/*none=*/
false
);
if
(
r
->
is_method
&&
r
->
args
.
empty
())
{
r
->
args
.
emplace_back
(
"self"
,
nullptr
,
handle
(),
/*convert=*/
true
,
/*none=*/
false
);
}
}
/// Process a keyword argument attribute (*without* a default value)
...
...
@@ -432,8 +437,10 @@ template <> struct process_attribute<arg> : process_attribute_default<arg> {
/// Process a keyword argument attribute (*with* a default value)
template
<>
struct
process_attribute
<
arg_v
>
:
process_attribute_default
<
arg_v
>
{
static
void
init
(
const
arg_v
&
a
,
function_record
*
r
)
{
if
(
r
->
is_method
&&
r
->
args
.
empty
())
r
->
args
.
emplace_back
(
"self"
,
/*descr=*/
nullptr
,
/*parent=*/
handle
(),
/*convert=*/
true
,
/*none=*/
false
);
if
(
r
->
is_method
&&
r
->
args
.
empty
())
{
r
->
args
.
emplace_back
(
"self"
,
/*descr=*/
nullptr
,
/*parent=*/
handle
(),
/*convert=*/
true
,
/*none=*/
false
);
}
if
(
!
a
.
value
)
{
#if !defined(NDEBUG)
...
...
@@ -466,8 +473,10 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
template
<>
struct
process_attribute
<
kw_only
>
:
process_attribute_default
<
kw_only
>
{
static
void
init
(
const
kw_only
&
,
function_record
*
r
)
{
append_self_arg_if_needed
(
r
);
if
(
r
->
has_args
&&
r
->
nargs_pos
!=
static_cast
<
std
::
uint16_t
>
(
r
->
args
.
size
()))
pybind11_fail
(
"Mismatched args() and kw_only(): they must occur at the same relative argument location (or omit kw_only() entirely)"
);
if
(
r
->
has_args
&&
r
->
nargs_pos
!=
static_cast
<
std
::
uint16_t
>
(
r
->
args
.
size
()))
{
pybind11_fail
(
"Mismatched args() and kw_only(): they must occur at the same relative "
"argument location (or omit kw_only() entirely)"
);
}
r
->
nargs_pos
=
static_cast
<
std
::
uint16_t
>
(
r
->
args
.
size
());
}
};
...
...
@@ -477,8 +486,9 @@ template <> struct process_attribute<pos_only> : process_attribute_default<pos_o
static
void
init
(
const
pos_only
&
,
function_record
*
r
)
{
append_self_arg_if_needed
(
r
);
r
->
nargs_pos_only
=
static_cast
<
std
::
uint16_t
>
(
r
->
args
.
size
());
if
(
r
->
nargs_pos_only
>
r
->
nargs_pos
)
if
(
r
->
nargs_pos_only
>
r
->
nargs_pos
)
{
pybind11_fail
(
"pos_only(): cannot follow a py::args() argument"
);
}
// It also can't follow a kw_only, but a static_assert in pybind11.h checks that
}
};
...
...
include/pybind11/buffer_info.h
View file @
ddbc74c6
...
...
@@ -19,9 +19,11 @@ PYBIND11_NAMESPACE_BEGIN(detail)
inline
std
::
vector
<
ssize_t
>
c_strides
(
const
std
::
vector
<
ssize_t
>
&
shape
,
ssize_t
itemsize
)
{
auto
ndim
=
shape
.
size
();
std
::
vector
<
ssize_t
>
strides
(
ndim
,
itemsize
);
if
(
ndim
>
0
)
for
(
size_t
i
=
ndim
-
1
;
i
>
0
;
--
i
)
if
(
ndim
>
0
)
{
for
(
size_t
i
=
ndim
-
1
;
i
>
0
;
--
i
)
{
strides
[
i
-
1
]
=
strides
[
i
]
*
shape
[
i
];
}
}
return
strides
;
}
...
...
@@ -29,8 +31,9 @@ inline std::vector<ssize_t> c_strides(const std::vector<ssize_t> &shape, ssize_t
inline
std
::
vector
<
ssize_t
>
f_strides
(
const
std
::
vector
<
ssize_t
>
&
shape
,
ssize_t
itemsize
)
{
auto
ndim
=
shape
.
size
();
std
::
vector
<
ssize_t
>
strides
(
ndim
,
itemsize
);
for
(
size_t
i
=
1
;
i
<
ndim
;
++
i
)
for
(
size_t
i
=
1
;
i
<
ndim
;
++
i
)
{
strides
[
i
]
=
strides
[
i
-
1
]
*
shape
[
i
-
1
];
}
return
strides
;
}
...
...
@@ -53,10 +56,12 @@ struct buffer_info {
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
)),
readonly
(
readonly
)
{
if
(
ndim
!=
(
ssize_t
)
shape
.
size
()
||
ndim
!=
(
ssize_t
)
strides
.
size
())
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
)
}
for
(
size_t
i
=
0
;
i
<
(
size_t
)
ndim
;
++
i
)
{
size
*=
shape
[
i
];
}
}
template
<
typename
T
>
...
...
include/pybind11/cast.h
View file @
ddbc74c6
...
...
@@ -60,8 +60,10 @@ public:
static
constexpr
auto
name
=
caster_t
::
name
;
static
handle
cast
(
const
std
::
reference_wrapper
<
type
>
&
src
,
return_value_policy
policy
,
handle
parent
)
{
// It is definitely wrong to take ownership of this pointer, so mask that rvp
if
(
policy
==
return_value_policy
::
take_ownership
||
policy
==
return_value_policy
::
automatic
)
if
(
policy
==
return_value_policy
::
take_ownership
||
policy
==
return_value_policy
::
automatic
)
{
policy
=
return_value_policy
::
automatic_reference
;
}
return
caster_t
::
cast
(
&
src
.
get
(),
policy
,
parent
);
}
template
<
typename
T
>
using
cast_op_type
=
std
::
reference_wrapper
<
type
>
;
...
...
@@ -112,8 +114,9 @@ public:
bool
load
(
handle
src
,
bool
convert
)
{
py_type
py_value
;
if
(
!
src
)
if
(
!
src
)
{
return
false
;
}
#if !defined(PYPY_VERSION)
auto
index_check
=
[](
PyObject
*
o
)
{
return
PyIndex_Check
(
o
);
};
...
...
@@ -124,10 +127,11 @@ public:
#endif
if
(
std
::
is_floating_point
<
T
>::
value
)
{
if
(
convert
||
PyFloat_Check
(
src
.
ptr
()))
if
(
convert
||
PyFloat_Check
(
src
.
ptr
()))
{
py_value
=
(
py_type
)
PyFloat_AsDouble
(
src
.
ptr
());
else
}
else
{
return
false
;
}
}
else
if
(
PyFloat_Check
(
src
.
ptr
())
||
(
!
convert
&&
!
PYBIND11_LONG_CHECK
(
src
.
ptr
())
&&
!
index_check
(
src
.
ptr
())))
{
return
false
;
...
...
@@ -214,8 +218,9 @@ public:
template
<
typename
T
>
struct
void_caster
{
public
:
bool
load
(
handle
src
,
bool
)
{
if
(
src
&&
src
.
is_none
())
if
(
src
&&
src
.
is_none
())
{
return
true
;
}
return
false
;
}
static
handle
cast
(
T
,
return_value_policy
/* policy */
,
handle
/* parent */
)
{
...
...
@@ -257,8 +262,9 @@ public:
}
static
handle
cast
(
const
void
*
ptr
,
return_value_policy
/* policy */
,
handle
/* parent */
)
{
if
(
ptr
)
if
(
ptr
)
{
return
capsule
(
ptr
).
release
();
}
return
none
().
inc_ref
();
}
...
...
@@ -274,7 +280,9 @@ template <> class type_caster<std::nullptr_t> : public void_caster<std::nullptr_
template
<>
class
type_caster
<
bool
>
{
public
:
bool
load
(
handle
src
,
bool
convert
)
{
if
(
!
src
)
return
false
;
if
(
!
src
)
{
return
false
;
}
if
(
src
.
ptr
()
==
Py_True
)
{
value
=
true
;
return
true
;
...
...
@@ -391,8 +399,9 @@ template <typename StringType, bool IsView = false> struct string_caster {
value
=
StringType
(
buffer
,
length
);
// If we're loading a string_view we need to keep the encoded Python object alive:
if
(
IsView
)
if
(
IsView
)
{
loader_life_support
::
add_patient
(
utfNbytes
);
}
return
true
;
}
...
...
@@ -401,7 +410,9 @@ template <typename StringType, bool IsView = false> struct string_caster {
const
char
*
buffer
=
reinterpret_cast
<
const
char
*>
(
src
.
data
());
auto
nbytes
=
ssize_t
(
src
.
size
()
*
sizeof
(
CharT
));
handle
s
=
decode_utfN
(
buffer
,
nbytes
);
if
(
!
s
)
throw
error_already_set
();
if
(
!
s
)
{
throw
error_already_set
();
}
return
s
;
}
...
...
@@ -463,10 +474,14 @@ template <typename CharT> struct type_caster<CharT, enable_if_t<is_std_char_type
CharT
one_char
=
0
;
public
:
bool
load
(
handle
src
,
bool
convert
)
{
if
(
!
src
)
return
false
;
if
(
!
src
)
{
return
false
;
}
if
(
src
.
is_none
())
{
// Defer accepting None to other overloads (if we aren't in convert mode):
if
(
!
convert
)
return
false
;
if
(
!
convert
)
{
return
false
;
}
none
=
true
;
return
true
;
}
...
...
@@ -474,14 +489,18 @@ public:
}
static
handle
cast
(
const
CharT
*
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
src
==
nullptr
)
return
pybind11
::
none
().
inc_ref
();
if
(
src
==
nullptr
)
{
return
pybind11
::
none
().
inc_ref
();
}
return
StringCaster
::
cast
(
StringType
(
src
),
policy
,
parent
);
}
static
handle
cast
(
CharT
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
std
::
is_same
<
char
,
CharT
>::
value
)
{
handle
s
=
PyUnicode_DecodeLatin1
((
const
char
*
)
&
src
,
1
,
nullptr
);
if
(
!
s
)
throw
error_already_set
();
if
(
!
s
)
{
throw
error_already_set
();
}
return
s
;
}
return
StringCaster
::
cast
(
StringType
(
1
,
src
),
policy
,
parent
);
...
...
@@ -491,13 +510,15 @@ public:
return
none
?
nullptr
:
const_cast
<
CharT
*>
(
static_cast
<
StringType
&>
(
str_caster
).
c_str
());
}
explicit
operator
CharT
&
()
{
if
(
none
)
if
(
none
)
{
throw
value_error
(
"Cannot convert None to a character"
);
}
auto
&
value
=
static_cast
<
StringType
&>
(
str_caster
);
size_t
str_len
=
value
.
size
();
if
(
str_len
==
0
)
if
(
str_len
==
0
)
{
throw
value_error
(
"Cannot convert empty string to a character"
);
}
// If we're in UTF-8 mode, we have two possible failures: one for a unicode character that
// is too high, and one for multiple unicode characters (caught later), so we need to figure
...
...
@@ -531,12 +552,14 @@ public:
// string was too long" error).
else
if
(
PYBIND11_SILENCE_MSVC_C4127
(
StringCaster
::
UTF_N
==
16
)
&&
str_len
==
2
)
{
one_char
=
static_cast
<
CharT
>
(
value
[
0
]);
if
(
one_char
>=
0xD800
&&
one_char
<
0xE000
)
if
(
one_char
>=
0xD800
&&
one_char
<
0xE000
)
{
throw
value_error
(
"Character code point not in range(0x10000)"
);
}
}
if
(
str_len
!=
1
)
if
(
str_len
!=
1
)
{
throw
value_error
(
"Expected a character, but multi-character string found"
);
}
one_char
=
value
[
0
];
return
one_char
;
...
...
@@ -554,11 +577,13 @@ template <template<typename...> class Tuple, typename... Ts> class tuple_caster
public
:
bool
load
(
handle
src
,
bool
convert
)
{
if
(
!
isinstance
<
sequence
>
(
src
))
if
(
!
isinstance
<
sequence
>
(
src
))
{
return
false
;
}
const
auto
seq
=
reinterpret_borrow
<
sequence
>
(
src
);
if
(
seq
.
size
()
!=
size
)
if
(
seq
.
size
()
!=
size
)
{
return
false
;
}
return
load_impl
(
seq
,
convert
,
indices
{});
}
...
...
@@ -570,7 +595,9 @@ public:
// copied from the PYBIND11_TYPE_CASTER macro
template
<
typename
T
>
static
handle
cast
(
T
*
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
!
src
)
return
none
().
release
();
if
(
!
src
)
{
return
none
().
release
();
}
if
(
policy
==
return_value_policy
::
take_ownership
)
{
auto
h
=
cast
(
std
::
move
(
*
src
),
policy
,
parent
);
delete
src
;
...
...
@@ -597,8 +624,9 @@ protected:
template
<
size_t
...
Is
>
bool
load_impl
(
const
sequence
&
seq
,
bool
convert
,
index_sequence
<
Is
...
>
)
{
#ifdef __cpp_fold_expressions
if
((...
||
!
std
::
get
<
Is
>
(
subcasters
).
load
(
seq
[
Is
],
convert
)))
if
((...
||
!
std
::
get
<
Is
>
(
subcasters
).
load
(
seq
[
Is
],
convert
)))
{
return
false
;
}
#else
for
(
bool
r
:
{
std
::
get
<
Is
>
(
subcasters
).
load
(
seq
[
Is
],
convert
)...})
if
(
!
r
)
...
...
@@ -615,13 +643,16 @@ protected:
std
::
array
<
object
,
size
>
entries
{{
reinterpret_steal
<
object
>
(
make_caster
<
Ts
>::
cast
(
std
::
get
<
Is
>
(
std
::
forward
<
T
>
(
src
)),
policy
,
parent
))...
}};
for
(
const
auto
&
entry
:
entries
)
if
(
!
entry
)
for
(
const
auto
&
entry
:
entries
)
{
if
(
!
entry
)
{
return
handle
();
}
}
tuple
result
(
size
);
int
counter
=
0
;
for
(
auto
&
entry
:
entries
)
for
(
auto
&
entry
:
entries
)
{
PyTuple_SET_ITEM
(
result
.
ptr
(),
counter
++
,
entry
.
release
().
ptr
());
}
return
result
.
release
();
}
...
...
@@ -676,8 +707,9 @@ public:
protected
:
friend
class
type_caster_generic
;
void
check_holder_compat
()
{
if
(
typeinfo
->
default_holder
)
if
(
typeinfo
->
default_holder
)
{
throw
cast_error
(
"Unable to load a custom holder type from a default-holder instance"
);
}
}
bool
load_value
(
value_and_holder
&&
v_h
)
{
...
...
@@ -793,8 +825,9 @@ struct pyobject_caster {
return
true
;
}
#endif
if
(
!
isinstance
<
type
>
(
src
))
if
(
!
isinstance
<
type
>
(
src
))
{
return
false
;
}
value
=
reinterpret_borrow
<
type
>
(
src
);
return
true
;
}
...
...
@@ -901,12 +934,14 @@ template <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> =
object
cast
(
T
&&
value
,
return_value_policy
policy
=
return_value_policy
::
automatic_reference
,
handle
parent
=
handle
())
{
using
no_ref_T
=
typename
std
::
remove_reference
<
T
>::
type
;
if
(
policy
==
return_value_policy
::
automatic
)
if
(
policy
==
return_value_policy
::
automatic
)
{
policy
=
std
::
is_pointer
<
no_ref_T
>::
value
?
return_value_policy
::
take_ownership
:
std
::
is_lvalue_reference
<
T
>::
value
?
return_value_policy
::
copy
:
return_value_policy
::
move
;
else
if
(
policy
==
return_value_policy
::
automatic_reference
)
policy
=
std
::
is_pointer
<
no_ref_T
>::
value
?
return_value_policy
::
reference
:
std
::
is_lvalue_reference
<
T
>::
value
?
return_value_policy
::
copy
:
return_value_policy
::
move
;
}
else
if
(
policy
==
return_value_policy
::
automatic_reference
)
{
policy
=
std
::
is_pointer
<
no_ref_T
>::
value
?
return_value_policy
::
reference
:
std
::
is_lvalue_reference
<
T
>::
value
?
return_value_policy
::
copy
:
return_value_policy
::
move
;
}
return
reinterpret_steal
<
object
>
(
detail
::
make_caster
<
T
>::
cast
(
std
::
forward
<
T
>
(
value
),
policy
,
parent
));
}
...
...
@@ -939,8 +974,9 @@ template <typename T> detail::enable_if_t<detail::move_always<T>::value, T> cast
return
move
<
T
>
(
std
::
move
(
object
));
}
template
<
typename
T
>
detail
::
enable_if_t
<
detail
::
move_if_unreferenced
<
T
>::
value
,
T
>
cast
(
object
&&
object
)
{
if
(
object
.
ref_count
()
>
1
)
if
(
object
.
ref_count
()
>
1
)
{
return
cast
<
T
>
(
object
);
}
return
move
<
T
>
(
std
::
move
(
object
));
}
template
<
typename
T
>
detail
::
enable_if_t
<
detail
::
move_never
<
T
>::
value
,
T
>
cast
(
object
&&
object
)
{
...
...
@@ -1018,8 +1054,9 @@ template <return_value_policy policy = return_value_policy::automatic_reference,
}
tuple
result
(
size
);
int
counter
=
0
;
for
(
auto
&
arg_value
:
args
)
for
(
auto
&
arg_value
:
args
)
{
PyTuple_SET_ITEM
(
result
.
ptr
(),
counter
++
,
arg_value
.
release
().
ptr
());
}
return
result
;
}
...
...
@@ -1231,8 +1268,9 @@ public:
/// Call a Python function and pass the collected arguments
object
call
(
PyObject
*
ptr
)
const
{
PyObject
*
result
=
PyObject_CallObject
(
ptr
,
m_args
.
ptr
());
if
(
!
result
)
if
(
!
result
)
{
throw
error_already_set
();
}
return
reinterpret_steal
<
object
>
(
result
);
}
...
...
@@ -1264,8 +1302,9 @@ public:
/// Call a Python function and pass the collected arguments
object
call
(
PyObject
*
ptr
)
const
{
PyObject
*
result
=
PyObject_Call
(
ptr
,
m_args
.
ptr
(),
m_kwargs
.
ptr
());
if
(
!
result
)
if
(
!
result
)
{
throw
error_already_set
();
}
return
reinterpret_steal
<
object
>
(
result
);
}
...
...
@@ -1285,8 +1324,9 @@ private:
}
void
process
(
list
&
args_list
,
detail
::
args_proxy
ap
)
{
for
(
auto
a
:
ap
)
for
(
auto
a
:
ap
)
{
args_list
.
append
(
a
);
}
}
void
process
(
list
&
/*args_list*/
,
arg_v
a
)
{
...
...
@@ -1315,8 +1355,9 @@ private:
}
void
process
(
list
&
/*args_list*/
,
detail
::
kwargs_proxy
kp
)
{
if
(
!
kp
)
if
(
!
kp
)
{
return
;
}
for
(
auto
k
:
reinterpret_borrow
<
dict
>
(
kp
))
{
if
(
m_kwargs
.
contains
(
k
.
first
))
{
#if defined(NDEBUG)
...
...
include/pybind11/chrono.h
View file @
ddbc74c6
...
...
@@ -46,7 +46,9 @@ public:
// Lazy initialise the PyDateTime import
if
(
!
PyDateTimeAPI
)
{
PyDateTime_IMPORT
;
}
if
(
!
src
)
return
false
;
if
(
!
src
)
{
return
false
;
}
// If invoked with datetime.delta object
if
(
PyDelta_Check
(
src
.
ptr
()))
{
value
=
type
(
duration_cast
<
duration
<
rep
,
period
>>
(
...
...
@@ -124,7 +126,9 @@ public:
// Lazy initialise the PyDateTime import
if
(
!
PyDateTimeAPI
)
{
PyDateTime_IMPORT
;
}
if
(
!
src
)
return
false
;
if
(
!
src
)
{
return
false
;
}
std
::
tm
cal
;
microseconds
msecs
;
...
...
@@ -156,8 +160,9 @@ public:
cal
.
tm_year
=
70
;
// earliest available date for Python's datetime
cal
.
tm_isdst
=
-
1
;
msecs
=
microseconds
(
PyDateTime_TIME_GET_MICROSECOND
(
src
.
ptr
()));
}
else
{
return
false
;
}
else
return
false
;
value
=
time_point_cast
<
Duration
>
(
system_clock
::
from_time_t
(
std
::
mktime
(
&
cal
))
+
msecs
);
return
true
;
...
...
@@ -173,8 +178,9 @@ public:
// (cfr. https://github.com/pybind/pybind11/issues/2417)
using
us_t
=
duration
<
int
,
std
::
micro
>
;
auto
us
=
duration_cast
<
us_t
>
(
src
.
time_since_epoch
()
%
seconds
(
1
));
if
(
us
.
count
()
<
0
)
if
(
us
.
count
()
<
0
)
{
us
+=
seconds
(
1
);
}
// Subtract microseconds BEFORE `system_clock::to_time_t`, because:
// > If std::time_t has lower precision, it is implementation-defined whether the value is rounded or truncated.
...
...
@@ -183,8 +189,9 @@ public:
std
::
tm
localtime
;
std
::
tm
*
localtime_ptr
=
localtime_thread_safe
(
&
tt
,
&
localtime
);
if
(
!
localtime_ptr
)
if
(
!
localtime_ptr
)
{
throw
cast_error
(
"Unable to represent system_clock in local time"
);
}
return
PyDateTime_FromDateAndTime
(
localtime
.
tm_year
+
1900
,
localtime
.
tm_mon
+
1
,
localtime
.
tm_mday
,
...
...
include/pybind11/complex.h
View file @
ddbc74c6
...
...
@@ -42,10 +42,12 @@ template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t
template
<
typename
T
>
class
type_caster
<
std
::
complex
<
T
>>
{
public
:
bool
load
(
handle
src
,
bool
convert
)
{
if
(
!
src
)
if
(
!
src
)
{
return
false
;
if
(
!
convert
&&
!
PyComplex_Check
(
src
.
ptr
()))
}
if
(
!
convert
&&
!
PyComplex_Check
(
src
.
ptr
()))
{
return
false
;
}
Py_complex
result
=
PyComplex_AsCComplex
(
src
.
ptr
());
if
(
result
.
real
==
-
1
.
0
&&
PyErr_Occurred
())
{
PyErr_Clear
();
...
...
include/pybind11/detail/class.h
View file @
ddbc74c6
...
...
@@ -66,8 +66,9 @@ inline PyTypeObject *make_static_property_type() {
garbage collector (the GC will call type_traverse(), which will in
turn find the newly constructed type in an invalid state) */
auto
heap_type
=
(
PyHeapTypeObject
*
)
PyType_Type
.
tp_alloc
(
&
PyType_Type
,
0
);
if
(
!
heap_type
)
if
(
!
heap_type
)
{
pybind11_fail
(
"make_static_property_type(): error allocating type!"
);
}
heap_type
->
ht_name
=
name_obj
.
inc_ref
().
ptr
();
#ifdef PYBIND11_BUILTIN_QUALNAME
...
...
@@ -81,8 +82,9 @@ inline PyTypeObject *make_static_property_type() {
type
->
tp_descr_get
=
pybind11_static_get
;
type
->
tp_descr_set
=
pybind11_static_set
;
if
(
PyType_Ready
(
type
)
<
0
)
if
(
PyType_Ready
(
type
)
<
0
)
{
pybind11_fail
(
"make_static_property_type(): failure in PyType_Ready()!"
);
}
setattr
((
PyObject
*
)
type
,
"__module__"
,
str
(
"pybind11_builtins"
));
PYBIND11_SET_OLDPY_QUALNAME
(
type
,
name_obj
);
...
...
@@ -209,19 +211,21 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
auto
tindex
=
std
::
type_index
(
*
tinfo
->
cpptype
);
internals
.
direct_conversions
.
erase
(
tindex
);
if
(
tinfo
->
module_local
)
if
(
tinfo
->
module_local
)
{
get_local_internals
().
registered_types_cpp
.
erase
(
tindex
);
else
}
else
{
internals
.
registered_types_cpp
.
erase
(
tindex
);
}
internals
.
registered_types_py
.
erase
(
tinfo
->
type
);
// Actually just `std::erase_if`, but that's only available in C++20
auto
&
cache
=
internals
.
inactive_override_cache
;
for
(
auto
it
=
cache
.
begin
(),
last
=
cache
.
end
();
it
!=
last
;
)
{
if
(
it
->
first
==
(
PyObject
*
)
tinfo
->
type
)
if
(
it
->
first
==
(
PyObject
*
)
tinfo
->
type
)
{
it
=
cache
.
erase
(
it
);
else
}
else
{
++
it
;
}
}
delete
tinfo
;
...
...
@@ -242,8 +246,9 @@ inline PyTypeObject* make_default_metaclass() {
garbage collector (the GC will call type_traverse(), which will in
turn find the newly constructed type in an invalid state) */
auto
heap_type
=
(
PyHeapTypeObject
*
)
PyType_Type
.
tp_alloc
(
&
PyType_Type
,
0
);
if
(
!
heap_type
)
if
(
!
heap_type
)
{
pybind11_fail
(
"make_default_metaclass(): error allocating metaclass!"
);
}
heap_type
->
ht_name
=
name_obj
.
inc_ref
().
ptr
();
#ifdef PYBIND11_BUILTIN_QUALNAME
...
...
@@ -264,8 +269,9 @@ inline PyTypeObject* make_default_metaclass() {
type
->
tp_dealloc
=
pybind11_meta_dealloc
;
if
(
PyType_Ready
(
type
)
<
0
)
if
(
PyType_Ready
(
type
)
<
0
)
{
pybind11_fail
(
"make_default_metaclass(): failure in PyType_Ready()!"
);
}
setattr
((
PyObject
*
)
type
,
"__module__"
,
str
(
"pybind11_builtins"
));
PYBIND11_SET_OLDPY_QUALNAME
(
type
,
name_obj
);
...
...
@@ -283,8 +289,9 @@ inline void traverse_offset_bases(void *valueptr, const detail::type_info *tinfo
for
(
auto
&
c
:
parent_tinfo
->
implicit_casts
)
{
if
(
c
.
first
==
tinfo
->
cpptype
)
{
auto
*
parentptr
=
c
.
second
(
valueptr
);
if
(
parentptr
!=
valueptr
)
if
(
parentptr
!=
valueptr
)
{
f
(
parentptr
,
self
);
}
traverse_offset_bases
(
parentptr
,
parent_tinfo
,
self
,
f
);
break
;
}
...
...
@@ -311,14 +318,16 @@ inline bool deregister_instance_impl(void *ptr, instance *self) {
inline
void
register_instance
(
instance
*
self
,
void
*
valptr
,
const
type_info
*
tinfo
)
{
register_instance_impl
(
valptr
,
self
);
if
(
!
tinfo
->
simple_ancestors
)
if
(
!
tinfo
->
simple_ancestors
)
{
traverse_offset_bases
(
valptr
,
tinfo
,
self
,
register_instance_impl
);
}
}
inline
bool
deregister_instance
(
instance
*
self
,
void
*
valptr
,
const
type_info
*
tinfo
)
{
bool
ret
=
deregister_instance_impl
(
valptr
,
self
);
if
(
!
tinfo
->
simple_ancestors
)
if
(
!
tinfo
->
simple_ancestors
)
{
traverse_offset_bases
(
valptr
,
tinfo
,
self
,
deregister_instance_impl
);
}
return
ret
;
}
...
...
@@ -377,8 +386,9 @@ inline void clear_patients(PyObject *self) {
auto
patients
=
std
::
move
(
pos
->
second
);
internals
.
patients
.
erase
(
pos
);
instance
->
has_patients
=
false
;
for
(
PyObject
*&
patient
:
patients
)
for
(
PyObject
*&
patient
:
patients
)
{
Py_CLEAR
(
patient
);
}
}
/// Clears all internal data from the instance and removes it from registered instances in
...
...
@@ -392,25 +402,32 @@ inline void clear_instance(PyObject *self) {
// We have to deregister before we call dealloc because, for virtual MI types, we still
// need to be able to get the parent pointers.
if
(
v_h
.
instance_registered
()
&&
!
deregister_instance
(
instance
,
v_h
.
value_ptr
(),
v_h
.
type
))
pybind11_fail
(
"pybind11_object_dealloc(): Tried to deallocate unregistered instance!"
);
if
(
v_h
.
instance_registered
()
&&
!
deregister_instance
(
instance
,
v_h
.
value_ptr
(),
v_h
.
type
))
{
pybind11_fail
(
"pybind11_object_dealloc(): Tried to deallocate unregistered instance!"
);
}
if
(
instance
->
owned
||
v_h
.
holder_constructed
())
if
(
instance
->
owned
||
v_h
.
holder_constructed
())
{
v_h
.
type
->
dealloc
(
v_h
);
}
}
}
// Deallocate the value/holder layout internals:
instance
->
deallocate_layout
();
if
(
instance
->
weakrefs
)
if
(
instance
->
weakrefs
)
{
PyObject_ClearWeakRefs
(
self
);
}
PyObject
**
dict_ptr
=
_PyObject_GetDictPtr
(
self
);
if
(
dict_ptr
)
if
(
dict_ptr
)
{
Py_CLEAR
(
*
dict_ptr
);
}
if
(
instance
->
has_patients
)
if
(
instance
->
has_patients
)
{
clear_patients
(
self
);
}
}
/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc`
...
...
@@ -448,8 +465,9 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
garbage collector (the GC will call type_traverse(), which will in
turn find the newly constructed type in an invalid state) */
auto
heap_type
=
(
PyHeapTypeObject
*
)
metaclass
->
tp_alloc
(
metaclass
,
0
);
if
(
!
heap_type
)
if
(
!
heap_type
)
{
pybind11_fail
(
"make_object_base_type(): error allocating type!"
);
}
heap_type
->
ht_name
=
name_obj
.
inc_ref
().
ptr
();
#ifdef PYBIND11_BUILTIN_QUALNAME
...
...
@@ -469,8 +487,9 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
/* Support weak references (needed for the keep_alive feature) */
type
->
tp_weaklistoffset
=
offsetof
(
instance
,
weakrefs
);
if
(
PyType_Ready
(
type
)
<
0
)
if
(
PyType_Ready
(
type
)
<
0
)
{
pybind11_fail
(
"PyType_Ready failed in make_object_base_type():"
+
error_string
());
}
setattr
((
PyObject
*
)
type
,
"__module__"
,
str
(
"pybind11_builtins"
));
PYBIND11_SET_OLDPY_QUALNAME
(
type
,
name_obj
);
...
...
@@ -482,8 +501,9 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
/// dynamic_attr: Support for `d = instance.__dict__`.
extern
"C"
inline
PyObject
*
pybind11_get_dict
(
PyObject
*
self
,
void
*
)
{
PyObject
*&
dict
=
*
_PyObject_GetDictPtr
(
self
);
if
(
!
dict
)
if
(
!
dict
)
{
dict
=
PyDict_New
();
}
Py_XINCREF
(
dict
);
return
dict
;
}
...
...
@@ -538,12 +558,14 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
type_info
*
tinfo
=
nullptr
;
for
(
auto
type
:
reinterpret_borrow
<
tuple
>
(
Py_TYPE
(
obj
)
->
tp_mro
))
{
tinfo
=
get_type_info
((
PyTypeObject
*
)
type
.
ptr
());
if
(
tinfo
&&
tinfo
->
get_buffer
)
if
(
tinfo
&&
tinfo
->
get_buffer
)
{
break
;
}
}
if
(
view
==
nullptr
||
!
tinfo
||
!
tinfo
->
get_buffer
)
{
if
(
view
)
if
(
view
)
{
view
->
obj
=
nullptr
;
}
PyErr_SetString
(
PyExc_BufferError
,
"pybind11_getbuffer(): Internal error"
);
return
-
1
;
}
...
...
@@ -561,11 +583,13 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
view
->
buf
=
info
->
ptr
;
view
->
itemsize
=
info
->
itemsize
;
view
->
len
=
view
->
itemsize
;
for
(
auto
s
:
info
->
shape
)
for
(
auto
s
:
info
->
shape
)
{
view
->
len
*=
s
;
}
view
->
readonly
=
static_cast
<
int
>
(
info
->
readonly
);
if
((
flags
&
PyBUF_FORMAT
)
==
PyBUF_FORMAT
)
if
((
flags
&
PyBUF_FORMAT
)
==
PyBUF_FORMAT
)
{
view
->
format
=
const_cast
<
char
*>
(
info
->
format
.
c_str
());
}
if
((
flags
&
PyBUF_STRIDES
)
==
PyBUF_STRIDES
)
{
view
->
ndim
=
(
int
)
info
->
ndim
;
view
->
strides
=
info
->
strides
.
data
();
...
...
@@ -608,10 +632,11 @@ inline PyObject* make_new_python_type(const type_record &rec) {
object
module_
;
if
(
rec
.
scope
)
{
if
(
hasattr
(
rec
.
scope
,
"__module__"
))
if
(
hasattr
(
rec
.
scope
,
"__module__"
))
{
module_
=
rec
.
scope
.
attr
(
"__module__"
);
else
if
(
hasattr
(
rec
.
scope
,
"__name__"
))
}
else
if
(
hasattr
(
rec
.
scope
,
"__name__"
))
{
module_
=
rec
.
scope
.
attr
(
"__name__"
);
}
}
auto
full_name
=
c_str
(
...
...
@@ -642,8 +667,9 @@ inline PyObject* make_new_python_type(const type_record &rec) {
:
internals
.
default_metaclass
;
auto
heap_type
=
(
PyHeapTypeObject
*
)
metaclass
->
tp_alloc
(
metaclass
,
0
);
if
(
!
heap_type
)
if
(
!
heap_type
)
{
pybind11_fail
(
std
::
string
(
rec
.
name
)
+
": Unable to create type object!"
);
}
heap_type
->
ht_name
=
name
.
release
().
ptr
();
#ifdef PYBIND11_BUILTIN_QUALNAME
...
...
@@ -655,8 +681,9 @@ inline PyObject* make_new_python_type(const type_record &rec) {
type
->
tp_doc
=
tp_doc
;
type
->
tp_base
=
type_incref
((
PyTypeObject
*
)
base
);
type
->
tp_basicsize
=
static_cast
<
ssize_t
>
(
sizeof
(
instance
));
if
(
!
bases
.
empty
())
if
(
!
bases
.
empty
())
{
type
->
tp_bases
=
bases
.
release
().
ptr
();
}
/* Don't inherit base __init__ */
type
->
tp_init
=
pybind11_object_init
;
...
...
@@ -674,31 +701,38 @@ inline PyObject* make_new_python_type(const type_record &rec) {
#if PY_MAJOR_VERSION < 3
type
->
tp_flags
|=
Py_TPFLAGS_CHECKTYPES
;
#endif
if
(
!
rec
.
is_final
)
if
(
!
rec
.
is_final
)
{
type
->
tp_flags
|=
Py_TPFLAGS_BASETYPE
;
}
if
(
rec
.
dynamic_attr
)
if
(
rec
.
dynamic_attr
)
{
enable_dynamic_attributes
(
heap_type
);
}
if
(
rec
.
buffer_protocol
)
if
(
rec
.
buffer_protocol
)
{
enable_buffer_protocol
(
heap_type
);
}
if
(
rec
.
custom_type_setup_callback
)
if
(
rec
.
custom_type_setup_callback
)
{
rec
.
custom_type_setup_callback
(
heap_type
);
}
if
(
PyType_Ready
(
type
)
<
0
)
if
(
PyType_Ready
(
type
)
<
0
)
{
pybind11_fail
(
std
::
string
(
rec
.
name
)
+
": PyType_Ready failed ("
+
error_string
()
+
")!"
);
}
assert
(
!
rec
.
dynamic_attr
||
PyType_HasFeature
(
type
,
Py_TPFLAGS_HAVE_GC
));
/* Register type with the parent scope */
if
(
rec
.
scope
)
if
(
rec
.
scope
)
{
setattr
(
rec
.
scope
,
rec
.
name
,
(
PyObject
*
)
type
);
else
}
else
{
Py_INCREF
(
type
);
// Keep it alive forever (reference leak)
}
if
(
module_
)
// Needed by pydoc
if
(
module_
)
{
// Needed by pydoc
setattr
((
PyObject
*
)
type
,
"__module__"
,
module_
);
}
PYBIND11_SET_OLDPY_QUALNAME
(
type
,
qualname
);
...
...
include/pybind11/detail/init.h
View file @
ddbc74c6
...
...
@@ -33,7 +33,9 @@ private:
PYBIND11_NAMESPACE_BEGIN
(
initimpl
)
inline
void
no_nullptr
(
void
*
ptr
)
{
if
(
!
ptr
)
throw
type_error
(
"pybind11::init(): factory function returned nullptr"
);
if
(
!
ptr
)
{
throw
type_error
(
"pybind11::init(): factory function returned nullptr"
);
}
}
// Implementing functions for all forms of py::init<...> and py::init(...)
...
...
@@ -136,9 +138,10 @@ void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
auto
*
ptr
=
holder_helper
<
Holder
<
Class
>>::
get
(
holder
);
no_nullptr
(
ptr
);
// If we need an alias, check that the held pointer is actually an alias instance
if
(
PYBIND11_SILENCE_MSVC_C4127
(
Class
::
has_alias
)
&&
need_alias
&&
!
is_alias
<
Class
>
(
ptr
))
if
(
PYBIND11_SILENCE_MSVC_C4127
(
Class
::
has_alias
)
&&
need_alias
&&
!
is_alias
<
Class
>
(
ptr
))
{
throw
type_error
(
"pybind11::init(): construction failed: returned holder-wrapped instance "
"is not an alias instance"
);
}
v_h
.
value_ptr
()
=
ptr
;
v_h
.
type
->
init_instance
(
v_h
.
inst
,
&
holder
);
...
...
@@ -153,10 +156,11 @@ void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100
(
need_alias
);
static_assert
(
std
::
is_move_constructible
<
Cpp
<
Class
>>::
value
,
"pybind11::init() return-by-value factory function requires a movable class"
);
if
(
PYBIND11_SILENCE_MSVC_C4127
(
Class
::
has_alias
)
&&
need_alias
)
if
(
PYBIND11_SILENCE_MSVC_C4127
(
Class
::
has_alias
)
&&
need_alias
)
{
construct_alias_from_cpp
<
Class
>
(
is_alias_constructible
<
Class
>
{},
v_h
,
std
::
move
(
result
));
else
}
else
{
v_h
.
value_ptr
()
=
new
Cpp
<
Class
>
(
std
::
move
(
result
));
}
}
// return-by-value version 2: returning a value of the alias type itself. We move-construct an
...
...
@@ -183,12 +187,19 @@ struct constructor {
enable_if_t
<
Class
::
has_alias
&&
std
::
is_constructible
<
Cpp
<
Class
>
,
Args
...
>::
value
,
int
>
=
0
>
static
void
execute
(
Class
&
cl
,
const
Extra
&
...
extra
)
{
cl
.
def
(
"__init__"
,
[](
value_and_holder
&
v_h
,
Args
...
args
)
{
if
(
Py_TYPE
(
v_h
.
inst
)
==
v_h
.
type
->
type
)
v_h
.
value_ptr
()
=
construct_or_initialize
<
Cpp
<
Class
>>
(
std
::
forward
<
Args
>
(
args
)...);
else
v_h
.
value_ptr
()
=
construct_or_initialize
<
Alias
<
Class
>>
(
std
::
forward
<
Args
>
(
args
)...);
},
is_new_style_constructor
(),
extra
...);
cl
.
def
(
"__init__"
,
[](
value_and_holder
&
v_h
,
Args
...
args
)
{
if
(
Py_TYPE
(
v_h
.
inst
)
==
v_h
.
type
->
type
)
{
v_h
.
value_ptr
()
=
construct_or_initialize
<
Cpp
<
Class
>>
(
std
::
forward
<
Args
>
(
args
)...);
}
else
{
v_h
.
value_ptr
()
=
construct_or_initialize
<
Alias
<
Class
>>
(
std
::
forward
<
Args
>
(
args
)...);
}
},
is_new_style_constructor
(),
extra
...);
}
template
<
typename
Class
,
typename
...
Extra
,
...
...
include/pybind11/detail/internals.h
View file @
ddbc74c6
...
...
@@ -398,8 +398,9 @@ inline void translate_local_exception(std::exception_ptr p) {
/// Return a reference to the current `internals` data
PYBIND11_NOINLINE
internals
&
get_internals
()
{
auto
**&
internals_pp
=
get_internals_pp
();
if
(
internals_pp
&&
*
internals_pp
)
if
(
internals_pp
&&
*
internals_pp
)
{
return
**
internals_pp
;
}
// Ensure that the GIL is held since we will need to make Python calls.
// Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
...
...
@@ -425,7 +426,9 @@ PYBIND11_NOINLINE internals &get_internals() {
(
*
internals_pp
)
->
registered_exception_translators
.
push_front
(
&
translate_local_exception
);
#endif
}
else
{
if
(
!
internals_pp
)
internals_pp
=
new
internals
*
();
if
(
!
internals_pp
)
{
internals_pp
=
new
internals
*
();
}
auto
*&
internals_ptr
=
*
internals_pp
;
internals_ptr
=
new
internals
();
#if defined(WITH_THREAD)
...
...
include/pybind11/detail/type_caster_base.h
View file @
ddbc74c6
...
...
@@ -69,11 +69,13 @@ public:
/// ... and destroyed after it returns
~
loader_life_support
()
{
if
(
get_stack_top
()
!=
this
)
if
(
get_stack_top
()
!=
this
)
{
pybind11_fail
(
"loader_life_support: internal error"
);
}
set_stack_top
(
parent
);
for
(
auto
*
item
:
keep_alive
)
for
(
auto
*
item
:
keep_alive
)
{
Py_DECREF
(
item
);
}
}
/// This can only be used inside a pybind11-bound function, either by `argument_loader`
...
...
@@ -90,8 +92,9 @@ public:
"of temporary values"
);
}
if
(
frame
->
keep_alive
.
insert
(
h
.
ptr
()).
second
)
if
(
frame
->
keep_alive
.
insert
(
h
.
ptr
()).
second
)
{
Py_INCREF
(
h
.
ptr
());
}
}
};
...
...
@@ -103,14 +106,17 @@ inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_t
// Populates a just-created cache entry.
PYBIND11_NOINLINE
void
all_type_info_populate
(
PyTypeObject
*
t
,
std
::
vector
<
type_info
*>
&
bases
)
{
std
::
vector
<
PyTypeObject
*>
check
;
for
(
handle
parent
:
reinterpret_borrow
<
tuple
>
(
t
->
tp_bases
))
for
(
handle
parent
:
reinterpret_borrow
<
tuple
>
(
t
->
tp_bases
))
{
check
.
push_back
((
PyTypeObject
*
)
parent
.
ptr
());
}
auto
const
&
type_dict
=
get_internals
().
registered_types_py
;
for
(
size_t
i
=
0
;
i
<
check
.
size
();
i
++
)
{
auto
type
=
check
[
i
];
// Ignore Python2 old-style class super type:
if
(
!
PyType_Check
((
PyObject
*
)
type
))
continue
;
if
(
!
PyType_Check
((
PyObject
*
)
type
))
{
continue
;
}
// Check `type` in the current set of registered python types:
auto
it
=
type_dict
.
find
(
type
);
...
...
@@ -127,7 +133,9 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_
for
(
auto
*
known
:
bases
)
{
if
(
known
==
tinfo
)
{
found
=
true
;
break
;
}
}
if
(
!
found
)
bases
.
push_back
(
tinfo
);
if
(
!
found
)
{
bases
.
push_back
(
tinfo
);
}
}
}
else
if
(
type
->
tp_bases
)
{
...
...
@@ -140,8 +148,9 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_
check
.
pop_back
();
i
--
;
}
for
(
handle
parent
:
reinterpret_borrow
<
tuple
>
(
type
->
tp_bases
))
for
(
handle
parent
:
reinterpret_borrow
<
tuple
>
(
type
->
tp_bases
))
{
check
.
push_back
((
PyTypeObject
*
)
parent
.
ptr
());
}
}
}
}
...
...
@@ -158,9 +167,10 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_
*/
inline
const
std
::
vector
<
detail
::
type_info
*>
&
all_type_info
(
PyTypeObject
*
type
)
{
auto
ins
=
all_type_info_get_cache
(
type
);
if
(
ins
.
second
)
if
(
ins
.
second
)
{
// New cache entry: populate it
all_type_info_populate
(
type
,
ins
.
first
->
second
);
}
return
ins
.
first
->
second
;
}
...
...
@@ -172,36 +182,43 @@ inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type)
*/
PYBIND11_NOINLINE
detail
::
type_info
*
get_type_info
(
PyTypeObject
*
type
)
{
auto
&
bases
=
all_type_info
(
type
);
if
(
bases
.
empty
())
if
(
bases
.
empty
())
{
return
nullptr
;
if
(
bases
.
size
()
>
1
)
pybind11_fail
(
"pybind11::detail::get_type_info: type has multiple pybind11-registered bases"
);
}
if
(
bases
.
size
()
>
1
)
{
pybind11_fail
(
"pybind11::detail::get_type_info: type has multiple pybind11-registered bases"
);
}
return
bases
.
front
();
}
inline
detail
::
type_info
*
get_local_type_info
(
const
std
::
type_index
&
tp
)
{
auto
&
locals
=
get_local_internals
().
registered_types_cpp
;
auto
it
=
locals
.
find
(
tp
);
if
(
it
!=
locals
.
end
())
if
(
it
!=
locals
.
end
())
{
return
it
->
second
;
}
return
nullptr
;
}
inline
detail
::
type_info
*
get_global_type_info
(
const
std
::
type_index
&
tp
)
{
auto
&
types
=
get_internals
().
registered_types_cpp
;
auto
it
=
types
.
find
(
tp
);
if
(
it
!=
types
.
end
())
if
(
it
!=
types
.
end
())
{
return
it
->
second
;
}
return
nullptr
;
}
/// Return the type info for a given C++ type; on lookup failure can either throw or return nullptr.
PYBIND11_NOINLINE
detail
::
type_info
*
get_type_info
(
const
std
::
type_index
&
tp
,
bool
throw_if_missing
=
false
)
{
if
(
auto
ltype
=
get_local_type_info
(
tp
))
if
(
auto
ltype
=
get_local_type_info
(
tp
))
{
return
ltype
;
if
(
auto
gtype
=
get_global_type_info
(
tp
))
}
if
(
auto
gtype
=
get_global_type_info
(
tp
))
{
return
gtype
;
}
if
(
throw_if_missing
)
{
std
::
string
tname
=
tp
.
name
();
...
...
@@ -222,8 +239,9 @@ PYBIND11_NOINLINE handle find_registered_python_instance(void *src,
auto
it_instances
=
get_internals
().
registered_instances
.
equal_range
(
src
);
for
(
auto
it_i
=
it_instances
.
first
;
it_i
!=
it_instances
.
second
;
++
it_i
)
{
for
(
auto
instance_type
:
detail
::
all_type_info
(
Py_TYPE
(
it_i
->
second
)))
{
if
(
instance_type
&&
same_type
(
*
instance_type
->
cpptype
,
*
tinfo
->
cpptype
))
if
(
instance_type
&&
same_type
(
*
instance_type
->
cpptype
,
*
tinfo
->
cpptype
))
{
return
handle
((
PyObject
*
)
it_i
->
second
).
inc_ref
();
}
}
}
return
handle
();
...
...
@@ -263,12 +281,13 @@ struct value_and_holder {
}
// NOLINTNEXTLINE(readability-make-member-function-const)
void
set_holder_constructed
(
bool
v
=
true
)
{
if
(
inst
->
simple_layout
)
if
(
inst
->
simple_layout
)
{
inst
->
simple_holder_constructed
=
v
;
else
if
(
v
)
}
else
if
(
v
)
{
inst
->
nonsimple
.
status
[
index
]
|=
instance
::
status_holder_constructed
;
else
}
else
{
inst
->
nonsimple
.
status
[
index
]
&=
(
std
::
uint8_t
)
~
instance
::
status_holder_constructed
;
}
}
bool
instance_registered
()
const
{
return
inst
->
simple_layout
...
...
@@ -277,12 +296,13 @@ struct value_and_holder {
}
// NOLINTNEXTLINE(readability-make-member-function-const)
void
set_instance_registered
(
bool
v
=
true
)
{
if
(
inst
->
simple_layout
)
if
(
inst
->
simple_layout
)
{
inst
->
simple_instance_registered
=
v
;
else
if
(
v
)
}
else
if
(
v
)
{
inst
->
nonsimple
.
status
[
index
]
|=
instance
::
status_instance_registered
;
else
}
else
{
inst
->
nonsimple
.
status
[
index
]
&=
(
std
::
uint8_t
)
~
instance
::
status_instance_registered
;
}
}
};
...
...
@@ -317,8 +337,9 @@ public:
bool
operator
==
(
const
iterator
&
other
)
const
{
return
curr
.
index
==
other
.
curr
.
index
;
}
bool
operator
!=
(
const
iterator
&
other
)
const
{
return
curr
.
index
!=
other
.
curr
.
index
;
}
iterator
&
operator
++
()
{
if
(
!
inst
->
simple_layout
)
if
(
!
inst
->
simple_layout
)
{
curr
.
vh
+=
1
+
(
*
types
)[
curr
.
index
]
->
holder_size_in_ptrs
;
}
++
curr
.
index
;
curr
.
type
=
curr
.
index
<
types
->
size
()
?
(
*
types
)[
curr
.
index
]
:
nullptr
;
return
*
this
;
...
...
@@ -332,7 +353,9 @@ public:
iterator
find
(
const
type_info
*
find_type
)
{
auto
it
=
begin
(),
endit
=
end
();
while
(
it
!=
endit
&&
it
->
type
!=
find_type
)
++
it
;
while
(
it
!=
endit
&&
it
->
type
!=
find_type
)
{
++
it
;
}
return
it
;
}
...
...
@@ -351,16 +374,19 @@ public:
*/
PYBIND11_NOINLINE
value_and_holder
instance
::
get_value_and_holder
(
const
type_info
*
find_type
/*= nullptr default in common.h*/
,
bool
throw_if_missing
/*= true in common.h*/
)
{
// Optimize common case:
if
(
!
find_type
||
Py_TYPE
(
this
)
==
find_type
->
type
)
if
(
!
find_type
||
Py_TYPE
(
this
)
==
find_type
->
type
)
{
return
value_and_holder
(
this
,
find_type
,
0
,
0
);
}
detail
::
values_and_holders
vhs
(
this
);
auto
it
=
vhs
.
find
(
find_type
);
if
(
it
!=
vhs
.
end
())
if
(
it
!=
vhs
.
end
())
{
return
*
it
;
}
if
(
!
throw_if_missing
)
if
(
!
throw_if_missing
)
{
return
value_and_holder
();
}
#if defined(NDEBUG)
pybind11_fail
(
"pybind11::detail::instance::get_value_and_holder: "
...
...
@@ -378,8 +404,10 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
const
size_t
n_types
=
tinfo
.
size
();
if
(
n_types
==
0
)
pybind11_fail
(
"instance allocation failed: new instance has no pybind11-registered base types"
);
if
(
n_types
==
0
)
{
pybind11_fail
(
"instance allocation failed: new instance has no pybind11-registered base types"
);
}
simple_layout
=
n_types
==
1
&&
tinfo
.
front
()
->
holder_size_in_ptrs
<=
instance_simple_holder_in_ptrs
();
...
...
@@ -410,7 +438,9 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
// just wrappers around malloc.
#if PY_VERSION_HEX >= 0x03050000
nonsimple
.
values_and_holders
=
(
void
**
)
PyMem_Calloc
(
space
,
sizeof
(
void
*
));
if
(
!
nonsimple
.
values_and_holders
)
throw
std
::
bad_alloc
();
if
(
!
nonsimple
.
values_and_holders
)
{
throw
std
::
bad_alloc
();
}
#else
nonsimple
.
values_and_holders
=
(
void
**
)
PyMem_New
(
void
*
,
space
);
if
(
!
nonsimple
.
values_and_holders
)
throw
std
::
bad_alloc
();
...
...
@@ -423,14 +453,16 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
// NOLINTNEXTLINE(readability-make-member-function-const)
PYBIND11_NOINLINE
void
instance
::
deallocate_layout
()
{
if
(
!
simple_layout
)
if
(
!
simple_layout
)
{
PyMem_Free
(
nonsimple
.
values_and_holders
);
}
}
PYBIND11_NOINLINE
bool
isinstance_generic
(
handle
obj
,
const
std
::
type_info
&
tp
)
{
handle
type
=
detail
::
get_type_handle
(
tp
,
false
);
if
(
!
type
)
if
(
!
type
)
{
return
false
;
}
return
isinstance
(
obj
,
type
);
}
...
...
@@ -447,14 +479,16 @@ PYBIND11_NOINLINE std::string error_string() {
errorString
+=
handle
(
scope
.
type
).
attr
(
"__name__"
).
cast
<
std
::
string
>
();
errorString
+=
": "
;
}
if
(
scope
.
value
)
if
(
scope
.
value
)
{
errorString
+=
(
std
::
string
)
str
(
scope
.
value
);
}
PyErr_NormalizeException
(
&
scope
.
type
,
&
scope
.
value
,
&
scope
.
trace
);
#if PY_MAJOR_VERSION >= 3
if
(
scope
.
trace
!=
nullptr
)
if
(
scope
.
trace
!=
nullptr
)
{
PyException_SetTraceback
(
scope
.
value
,
scope
.
trace
);
}
#endif
#if !defined(PYPY_VERSION)
...
...
@@ -462,8 +496,9 @@ PYBIND11_NOINLINE std::string error_string() {
auto
*
trace
=
(
PyTracebackObject
*
)
scope
.
trace
;
/* Get the deepest trace possible */
while
(
trace
->
tb_next
)
while
(
trace
->
tb_next
)
{
trace
=
trace
->
tb_next
;
}
PyFrameObject
*
frame
=
trace
->
tb_frame
;
errorString
+=
"
\n\n
At:
\n
"
;
...
...
@@ -493,8 +528,9 @@ PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_i
auto
range
=
instances
.
equal_range
(
ptr
);
for
(
auto
it
=
range
.
first
;
it
!=
range
.
second
;
++
it
)
{
for
(
const
auto
&
vh
:
values_and_holders
(
it
->
second
))
{
if
(
vh
.
type
==
type
)
if
(
vh
.
type
==
type
)
{
return
handle
((
PyObject
*
)
it
->
second
);
}
}
}
return
handle
();
...
...
@@ -535,15 +571,18 @@ public:
void
*
(
*
copy_constructor
)(
const
void
*
),
void
*
(
*
move_constructor
)(
const
void
*
),
const
void
*
existing_holder
=
nullptr
)
{
if
(
!
tinfo
)
// no type info: error will be set already
if
(
!
tinfo
)
{
// no type info: error will be set already
return
handle
();
}
void
*
src
=
const_cast
<
void
*>
(
_src
);
if
(
src
==
nullptr
)
if
(
src
==
nullptr
)
{
return
none
().
release
();
}
if
(
handle
registered_inst
=
find_registered_python_instance
(
src
,
tinfo
))
if
(
handle
registered_inst
=
find_registered_python_instance
(
src
,
tinfo
))
{
return
registered_inst
;
}
auto
inst
=
reinterpret_steal
<
object
>
(
make_new_instance
(
tinfo
->
type
));
auto
wrapper
=
reinterpret_cast
<
instance
*>
(
inst
.
ptr
());
...
...
@@ -564,9 +603,9 @@ public:
break
;
case
return_value_policy
:
:
copy
:
if
(
copy_constructor
)
if
(
copy_constructor
)
{
valueptr
=
copy_constructor
(
src
);
else
{
}
else
{
#if defined(NDEBUG)
throw
cast_error
(
"return_value_policy = copy, but type is "
"non-copyable! (compile in debug mode for details)"
);
...
...
@@ -581,11 +620,11 @@ public:
break
;
case
return_value_policy
:
:
move
:
if
(
move_constructor
)
if
(
move_constructor
)
{
valueptr
=
move_constructor
(
src
);
else
if
(
copy_constructor
)
}
else
if
(
copy_constructor
)
{
valueptr
=
copy_constructor
(
src
);
else
{
}
else
{
#if defined(NDEBUG)
throw
cast_error
(
"return_value_policy = move, but type is neither "
"movable nor copyable! "
...
...
@@ -650,8 +689,9 @@ public:
}
bool
try_direct_conversions
(
handle
src
)
{
for
(
auto
&
converter
:
*
typeinfo
->
direct_conversions
)
{
if
(
converter
(
src
.
ptr
(),
value
))
if
(
converter
(
src
.
ptr
(),
value
))
{
return
true
;
}
}
return
false
;
}
...
...
@@ -659,8 +699,9 @@ public:
PYBIND11_NOINLINE
static
void
*
local_load
(
PyObject
*
src
,
const
type_info
*
ti
)
{
auto
caster
=
type_caster_generic
(
ti
);
if
(
caster
.
load
(
src
,
false
))
if
(
caster
.
load
(
src
,
false
))
{
return
caster
.
value
;
}
return
nullptr
;
}
...
...
@@ -669,14 +710,16 @@ public:
PYBIND11_NOINLINE
bool
try_load_foreign_module_local
(
handle
src
)
{
constexpr
auto
*
local_key
=
PYBIND11_MODULE_LOCAL_ID
;
const
auto
pytype
=
type
::
handle_of
(
src
);
if
(
!
hasattr
(
pytype
,
local_key
))
if
(
!
hasattr
(
pytype
,
local_key
))
{
return
false
;
}
type_info
*
foreign_typeinfo
=
reinterpret_borrow
<
capsule
>
(
getattr
(
pytype
,
local_key
));
// Only consider this foreign loader if actually foreign and is a loader of the correct cpp type
if
(
foreign_typeinfo
->
module_local_load
==
&
local_load
||
(
cpptype
&&
!
same_type
(
*
cpptype
,
*
foreign_typeinfo
->
cpptype
)))
||
(
cpptype
&&
!
same_type
(
*
cpptype
,
*
foreign_typeinfo
->
cpptype
)))
{
return
false
;
}
if
(
auto
result
=
foreign_typeinfo
->
module_local_load
(
src
.
ptr
(),
foreign_typeinfo
))
{
value
=
result
;
...
...
@@ -690,8 +733,12 @@ public:
// logic (without having to resort to virtual inheritance).
template
<
typename
ThisT
>
PYBIND11_NOINLINE
bool
load_impl
(
handle
src
,
bool
convert
)
{
if
(
!
src
)
return
false
;
if
(
!
typeinfo
)
return
try_load_foreign_module_local
(
src
);
if
(
!
src
)
{
return
false
;
}
if
(
!
typeinfo
)
{
return
try_load_foreign_module_local
(
src
);
}
auto
&
this_
=
static_cast
<
ThisT
&>
(
*
this
);
this_
.
check_holder_compat
();
...
...
@@ -734,8 +781,9 @@ public:
// Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type match
// in the registered bases, above, so try implicit casting (needed for proper C++ casting
// when MI is involved).
if
(
this_
.
try_implicit_casts
(
src
,
convert
))
if
(
this_
.
try_implicit_casts
(
src
,
convert
))
{
return
true
;
}
}
// Perform an implicit conversion
...
...
@@ -747,8 +795,9 @@ public:
return
true
;
}
}
if
(
this_
.
try_direct_conversions
(
src
))
if
(
this_
.
try_direct_conversions
(
src
))
{
return
true
;
}
}
// Failed to match local typeinfo. Try again with global.
...
...
@@ -767,7 +816,9 @@ public:
// Custom converters didn't take None, now we convert None to nullptr.
if
(
src
.
is_none
())
{
// Defer accepting None to other overloads (if we aren't in convert mode):
if
(
!
convert
)
return
false
;
if
(
!
convert
)
{
return
false
;
}
value
=
nullptr
;
return
true
;
}
...
...
@@ -907,8 +958,10 @@ public:
explicit
type_caster_base
(
const
std
::
type_info
&
info
)
:
type_caster_generic
(
info
)
{
}
static
handle
cast
(
const
itype
&
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
)
{
policy
=
return_value_policy
::
copy
;
}
return
cast
(
&
src
,
policy
,
parent
);
}
...
...
@@ -960,7 +1013,12 @@ public:
// NOLINTNEXTLINE(google-explicit-constructor)
operator
itype
*
()
{
return
(
type
*
)
value
;
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator
itype
&
()
{
if
(
!
value
)
throw
reference_cast_error
();
return
*
((
itype
*
)
value
);
}
operator
itype
&
()
{
if
(
!
value
)
{
throw
reference_cast_error
();
}
return
*
((
itype
*
)
value
);
}
protected
:
using
Constructor
=
void
*
(
*
)(
const
void
*
);
...
...
include/pybind11/detail/typeid.h
View file @
ddbc74c6
...
...
@@ -24,7 +24,9 @@ PYBIND11_NAMESPACE_BEGIN(detail)
inline
void
erase_all
(
std
::
string
&
string
,
const
std
::
string
&
search
)
{
for
(
size_t
pos
=
0
;;)
{
pos
=
string
.
find
(
search
,
pos
);
if
(
pos
==
std
::
string
::
npos
)
break
;
if
(
pos
==
std
::
string
::
npos
)
{
break
;
}
string
.
erase
(
pos
,
search
.
length
());
}
}
...
...
@@ -34,8 +36,9 @@ PYBIND11_NOINLINE void clean_type_id(std::string &name) {
int
status
=
0
;
std
::
unique_ptr
<
char
,
void
(
*
)(
void
*
)
>
res
{
abi
::
__cxa_demangle
(
name
.
c_str
(),
nullptr
,
nullptr
,
&
status
),
std
::
free
};
if
(
status
==
0
)
if
(
status
==
0
)
{
name
=
res
.
get
();
}
#else
detail
::
erase_all
(
name
,
"class "
);
detail
::
erase_all
(
name
,
"struct "
);
...
...
include/pybind11/eigen.h
View file @
ddbc74c6
...
...
@@ -145,8 +145,9 @@ template <typename Type_> struct EigenProps {
// (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).
static
EigenConformable
<
row_major
>
conformable
(
const
array
&
a
)
{
const
auto
dims
=
a
.
ndim
();
if
(
dims
<
1
||
dims
>
2
)
if
(
dims
<
1
||
dims
>
2
)
{
return
false
;
}
if
(
dims
==
2
)
{
// Matrix type: require exact match (or dynamic)
...
...
@@ -155,9 +156,10 @@ template <typename Type_> struct EigenProps {
np_cols
=
a
.
shape
(
1
),
np_rstride
=
a
.
strides
(
0
)
/
static_cast
<
ssize_t
>
(
sizeof
(
Scalar
)),
np_cstride
=
a
.
strides
(
1
)
/
static_cast
<
ssize_t
>
(
sizeof
(
Scalar
));
if
((
PYBIND11_SILENCE_MSVC_C4127
(
fixed_rows
)
&&
np_rows
!=
rows
)
||
(
PYBIND11_SILENCE_MSVC_C4127
(
fixed_cols
)
&&
np_cols
!=
cols
))
if
((
PYBIND11_SILENCE_MSVC_C4127
(
fixed_rows
)
&&
np_rows
!=
rows
)
||
(
PYBIND11_SILENCE_MSVC_C4127
(
fixed_cols
)
&&
np_cols
!=
cols
))
{
return
false
;
}
return
{
np_rows
,
np_cols
,
np_rstride
,
np_cstride
};
}
...
...
@@ -168,8 +170,9 @@ template <typename Type_> struct EigenProps {
stride
=
a
.
strides
(
0
)
/
static_cast
<
ssize_t
>
(
sizeof
(
Scalar
));
if
(
vector
)
{
// Eigen type is a compile-time vector
if
(
PYBIND11_SILENCE_MSVC_C4127
(
fixed
)
&&
size
!=
n
)
if
(
PYBIND11_SILENCE_MSVC_C4127
(
fixed
)
&&
size
!=
n
)
{
return
false
;
// Vector size mismatch
}
return
{
rows
==
1
?
1
:
n
,
cols
==
1
?
1
:
n
,
stride
};
}
if
(
fixed
)
{
...
...
@@ -179,10 +182,14 @@ template <typename Type_> struct EigenProps {
if
(
fixed_cols
)
{
// Since this isn't a vector, cols must be != 1. We allow this only if it exactly
// equals the number of elements (rows is Dynamic, and so 1 row is allowed).
if
(
cols
!=
n
)
return
false
;
if
(
cols
!=
n
)
{
return
false
;
}
return
{
1
,
n
,
stride
};
}
// Otherwise it's either fully dynamic, or column dynamic; both become a column vector
if
(
PYBIND11_SILENCE_MSVC_C4127
(
fixed_rows
)
&&
rows
!=
n
)
return
false
;
if
(
PYBIND11_SILENCE_MSVC_C4127
(
fixed_rows
)
&&
rows
!=
n
)
{
return
false
;
}
return
{
n
,
1
,
stride
};
}
...
...
@@ -213,14 +220,18 @@ template <typename Type_> struct EigenProps {
template
<
typename
props
>
handle
eigen_array_cast
(
typename
props
::
Type
const
&
src
,
handle
base
=
handle
(),
bool
writeable
=
true
)
{
constexpr
ssize_t
elem_size
=
sizeof
(
typename
props
::
Scalar
);
array
a
;
if
(
props
::
vector
)
if
(
props
::
vector
)
{
a
=
array
({
src
.
size
()
},
{
elem_size
*
src
.
innerStride
()
},
src
.
data
(),
base
);
else
a
=
array
({
src
.
rows
(),
src
.
cols
()
},
{
elem_size
*
src
.
rowStride
(),
elem_size
*
src
.
colStride
()
},
src
.
data
(),
base
);
}
else
{
a
=
array
({
src
.
rows
(),
src
.
cols
()},
{
elem_size
*
src
.
rowStride
(),
elem_size
*
src
.
colStride
()},
src
.
data
(),
base
);
}
if
(
!
writeable
)
if
(
!
writeable
)
{
array_proxy
(
a
.
ptr
())
->
flags
&=
~
detail
::
npy_api
::
NPY_ARRAY_WRITEABLE_
;
}
return
a
.
release
();
}
...
...
@@ -255,28 +266,35 @@ struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
bool
load
(
handle
src
,
bool
convert
)
{
// If we're in no-convert mode, only load if given an array of the correct type
if
(
!
convert
&&
!
isinstance
<
array_t
<
Scalar
>>
(
src
))
if
(
!
convert
&&
!
isinstance
<
array_t
<
Scalar
>>
(
src
))
{
return
false
;
}
// Coerce into an array, but don't do type conversion yet; the copy below handles it.
auto
buf
=
array
::
ensure
(
src
);
if
(
!
buf
)
if
(
!
buf
)
{
return
false
;
}
auto
dims
=
buf
.
ndim
();
if
(
dims
<
1
||
dims
>
2
)
if
(
dims
<
1
||
dims
>
2
)
{
return
false
;
}
auto
fits
=
props
::
conformable
(
buf
);
if
(
!
fits
)
if
(
!
fits
)
{
return
false
;
}
// Allocate the new type, then build a numpy reference into it
value
=
Type
(
fits
.
rows
,
fits
.
cols
);
auto
ref
=
reinterpret_steal
<
array
>
(
eigen_ref_array
<
props
>
(
value
));
if
(
dims
==
1
)
ref
=
ref
.
squeeze
();
else
if
(
ref
.
ndim
()
==
1
)
buf
=
buf
.
squeeze
();
if
(
dims
==
1
)
{
ref
=
ref
.
squeeze
();
}
else
if
(
ref
.
ndim
()
==
1
)
{
buf
=
buf
.
squeeze
();
}
int
result
=
detail
::
npy_api
::
get
().
PyArray_CopyInto_
(
ref
.
ptr
(),
buf
.
ptr
());
...
...
@@ -323,14 +341,18 @@ public:
}
// lvalue reference return; default (automatic) becomes copy
static
handle
cast
(
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
)
{
policy
=
return_value_policy
::
copy
;
}
return
cast_impl
(
&
src
,
policy
,
parent
);
}
// const lvalue reference return; default (automatic) becomes copy
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
)
{
policy
=
return_value_policy
::
copy
;
}
return
cast
(
&
src
,
policy
,
parent
);
}
// non-const pointer return
...
...
@@ -439,11 +461,14 @@ public:
if
(
aref
&&
(
!
need_writeable
||
aref
.
writeable
()))
{
fits
=
props
::
conformable
(
aref
);
if
(
!
fits
)
return
false
;
// Incompatible dimensions
if
(
!
fits
.
template
stride_compatible
<
props
>
())
if
(
!
fits
)
{
return
false
;
// Incompatible dimensions
}
if
(
!
fits
.
template
stride_compatible
<
props
>
())
{
need_copy
=
true
;
else
}
else
{
copy_or_ref
=
std
::
move
(
aref
);
}
}
else
{
need_copy
=
true
;
...
...
@@ -454,13 +479,18 @@ public:
// We need to copy: If we need a mutable reference, or we're not supposed to convert
// (either because we're in the no-convert overload pass, or because we're explicitly
// instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.
if
(
!
convert
||
need_writeable
)
return
false
;
if
(
!
convert
||
need_writeable
)
{
return
false
;
}
Array
copy
=
Array
::
ensure
(
src
);
if
(
!
copy
)
return
false
;
if
(
!
copy
)
{
return
false
;
}
fits
=
props
::
conformable
(
copy
);
if
(
!
fits
||
!
fits
.
template
stride_compatible
<
props
>
())
if
(
!
fits
||
!
fits
.
template
stride_compatible
<
props
>
())
{
return
false
;
}
copy_or_ref
=
std
::
move
(
copy
);
loader_life_support
::
add_patient
(
copy_or_ref
);
}
...
...
@@ -550,8 +580,9 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
static
constexpr
bool
rowMajor
=
Type
::
IsRowMajor
;
bool
load
(
handle
src
,
bool
)
{
if
(
!
src
)
if
(
!
src
)
{
return
false
;
}
auto
obj
=
reinterpret_borrow
<
object
>
(
src
);
object
sparse_module
=
module_
::
import
(
"scipy.sparse"
);
...
...
@@ -572,8 +603,9 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
auto
shape
=
pybind11
::
tuple
((
pybind11
::
object
)
obj
.
attr
(
"shape"
));
auto
nnz
=
obj
.
attr
(
"nnz"
).
cast
<
Index
>
();
if
(
!
values
||
!
innerIndices
||
!
outerIndices
)
if
(
!
values
||
!
innerIndices
||
!
outerIndices
)
{
return
false
;
}
value
=
EigenMapSparseMatrix
<
Scalar
,
Type
::
Flags
&
(
Eigen
::
RowMajor
|
Eigen
::
ColMajor
),
...
...
include/pybind11/embed.h
View file @
ddbc74c6
...
...
@@ -77,12 +77,14 @@ struct embedded_module {
using
init_t
=
void
(
*
)();
#endif
embedded_module
(
const
char
*
name
,
init_t
init
)
{
if
(
Py_IsInitialized
()
!=
0
)
if
(
Py_IsInitialized
()
!=
0
)
{
pybind11_fail
(
"Can't add new modules after the interpreter has been initialized"
);
}
auto
result
=
PyImport_AppendInittab
(
name
,
init
);
if
(
result
==
-
1
)
if
(
result
==
-
1
)
{
pybind11_fail
(
"Insufficient memory to add a new module"
);
}
}
};
...
...
@@ -135,8 +137,9 @@ inline void set_interpreter_argv(int argc, const char *const *argv, bool add_pro
const
char
*
const
empty_argv
[]{
"
\0
"
};
const
char
*
const
*
safe_argv
=
special_case
?
empty_argv
:
argv
;
if
(
special_case
)
if
(
special_case
)
{
argc
=
1
;
}
auto
argv_size
=
static_cast
<
size_t
>
(
argc
);
#if PY_MAJOR_VERSION >= 3
...
...
@@ -192,8 +195,9 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
int
argc
=
0
,
const
char
*
const
*
argv
=
nullptr
,
bool
add_program_dir_to_path
=
true
)
{
if
(
Py_IsInitialized
()
!=
0
)
if
(
Py_IsInitialized
()
!=
0
)
{
pybind11_fail
(
"The interpreter is already running"
);
}
Py_InitializeEx
(
init_signal_handlers
?
1
:
0
);
...
...
@@ -244,8 +248,9 @@ inline void finalize_interpreter() {
// during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
detail
::
internals
**
internals_ptr_ptr
=
detail
::
get_internals_pp
();
// It could also be stashed in builtins, so look there too:
if
(
builtins
.
contains
(
id
)
&&
isinstance
<
capsule
>
(
builtins
[
id
]))
if
(
builtins
.
contains
(
id
)
&&
isinstance
<
capsule
>
(
builtins
[
id
]))
{
internals_ptr_ptr
=
capsule
(
builtins
[
id
]);
}
Py_Finalize
();
...
...
@@ -285,8 +290,9 @@ public:
scoped_interpreter
&
operator
=
(
scoped_interpreter
&&
)
=
delete
;
~
scoped_interpreter
()
{
if
(
is_valid
)
if
(
is_valid
)
{
finalize_interpreter
();
}
}
private
:
...
...
include/pybind11/eval.h
View file @
ddbc74c6
...
...
@@ -46,8 +46,9 @@ enum eval_mode {
template
<
eval_mode
mode
=
eval_expr
>
object
eval
(
const
str
&
expr
,
object
global
=
globals
(),
object
local
=
object
())
{
if
(
!
local
)
if
(
!
local
)
{
local
=
global
;
}
detail
::
ensure_builtins_in_globals
(
global
);
...
...
@@ -64,8 +65,9 @@ object eval(const str &expr, object global = globals(), object local = object())
}
PyObject
*
result
=
PyRun_String
(
buffer
.
c_str
(),
start
,
global
.
ptr
(),
local
.
ptr
());
if
(
!
result
)
if
(
!
result
)
{
throw
error_already_set
();
}
return
reinterpret_steal
<
object
>
(
result
);
}
...
...
@@ -102,8 +104,9 @@ object eval_file(str) {
#else
template
<
eval_mode
mode
=
eval_statements
>
object
eval_file
(
str
fname
,
object
global
=
globals
(),
object
local
=
object
())
{
if
(
!
local
)
if
(
!
local
)
{
local
=
global
;
}
detail
::
ensure_builtins_in_globals
(
global
);
...
...
@@ -154,8 +157,9 @@ object eval_file(str fname, object global = globals(), object local = object())
local
.
ptr
(),
closeFile
);
#endif
if
(
!
result
)
if
(
!
result
)
{
throw
error_already_set
();
}
return
reinterpret_steal
<
object
>
(
result
);
}
#endif
...
...
include/pybind11/functional.h
View file @
ddbc74c6
...
...
@@ -25,12 +25,15 @@ public:
bool
load
(
handle
src
,
bool
convert
)
{
if
(
src
.
is_none
())
{
// Defer accepting None to other overloads (if we aren't in convert mode):
if
(
!
convert
)
return
false
;
if
(
!
convert
)
{
return
false
;
}
return
true
;
}
if
(
!
isinstance
<
function
>
(
src
))
if
(
!
isinstance
<
function
>
(
src
))
{
return
false
;
}
auto
func
=
reinterpret_borrow
<
function
>
(
src
);
...
...
@@ -104,12 +107,14 @@ public:
template
<
typename
Func
>
static
handle
cast
(
Func
&&
f_
,
return_value_policy
policy
,
handle
/* parent */
)
{
if
(
!
f_
)
if
(
!
f_
)
{
return
none
().
inc_ref
();
}
auto
result
=
f_
.
template
target
<
function_type
>
();
if
(
result
)
if
(
result
)
{
return
cpp_function
(
*
result
,
policy
).
release
();
}
return
cpp_function
(
std
::
forward
<
Func
>
(
f_
),
policy
).
release
();
}
...
...
include/pybind11/gil.h
View file @
ddbc74c6
...
...
@@ -99,8 +99,9 @@ public:
pybind11_fail
(
"scoped_acquire::dec_ref(): internal error!"
);
#endif
PyThreadState_Clear
(
tstate
);
if
(
active
)
if
(
active
)
{
PyThreadState_DeleteCurrent
();
}
PYBIND11_TLS_DELETE_VALUE
(
detail
::
get_internals
().
tstate
);
release
=
false
;
}
...
...
@@ -117,8 +118,9 @@ public:
PYBIND11_NOINLINE
~
gil_scoped_acquire
()
{
dec_ref
();
if
(
release
)
PyEval_SaveThread
();
if
(
release
)
{
PyEval_SaveThread
();
}
}
private
:
PyThreadState
*
tstate
=
nullptr
;
...
...
@@ -150,11 +152,13 @@ public:
}
~
gil_scoped_release
()
{
if
(
!
tstate
)
if
(
!
tstate
)
{
return
;
}
// `PyEval_RestoreThread()` should not be called if runtime is finalizing
if
(
active
)
if
(
active
)
{
PyEval_RestoreThread
(
tstate
);
}
if
(
disassoc
)
{
auto
key
=
detail
::
get_internals
().
tstate
;
PYBIND11_TLS_REPLACE_VALUE
(
key
,
tstate
);
...
...
include/pybind11/iostream.h
View file @
ddbc74c6
...
...
@@ -71,23 +71,26 @@ private:
return
static_cast
<
unsigned
char
>
(
c
)
<=
0xEF
;
};
// If the last character is ASCII, there are no incomplete code points
if
(
is_ascii
(
*
rpptr
))
if
(
is_ascii
(
*
rpptr
))
{
return
0
;
}
// Otherwise, work back from the end of the buffer and find the first
// UTF-8 leading byte
const
auto
rpend
=
rbase
-
rpptr
>=
3
?
rpptr
+
3
:
rbase
;
const
auto
leading
=
std
::
find_if
(
rpptr
,
rpend
,
is_leading
);
if
(
leading
==
rbase
)
if
(
leading
==
rbase
)
{
return
0
;
}
const
auto
dist
=
static_cast
<
size_t
>
(
leading
-
rpptr
);
size_t
remainder
=
0
;
if
(
dist
==
0
)
if
(
dist
==
0
)
{
remainder
=
1
;
// 1-byte code point is impossible
else
if
(
dist
==
1
)
}
else
if
(
dist
==
1
)
{
remainder
=
is_leading_2b
(
*
leading
)
?
0
:
dist
+
1
;
else
if
(
dist
==
2
)
}
else
if
(
dist
==
2
)
{
remainder
=
is_leading_3b
(
*
leading
)
?
0
:
dist
+
1
;
}
// else if (dist >= 3), at least 4 bytes before encountering an UTF-8
// leading byte, either no remainder or invalid UTF-8.
// Invalid UTF-8 will cause an exception later when converting
...
...
@@ -110,8 +113,9 @@ private:
}
// Copy the remainder at the end of the buffer to the beginning:
if
(
remainder
>
0
)
if
(
remainder
>
0
)
{
std
::
memmove
(
pbase
(),
pptr
()
-
remainder
,
remainder
);
}
setp
(
pbase
(),
epptr
());
pbump
(
static_cast
<
int
>
(
remainder
));
}
...
...
@@ -223,10 +227,12 @@ public:
:
do_stdout_
(
do_stdout
),
do_stderr_
(
do_stderr
)
{}
void
enter
()
{
if
(
do_stdout_
)
if
(
do_stdout_
)
{
redirect_stdout
.
reset
(
new
scoped_ostream_redirect
());
if
(
do_stderr_
)
}
if
(
do_stderr_
)
{
redirect_stderr
.
reset
(
new
scoped_estream_redirect
());
}
}
void
exit
()
{
...
...
include/pybind11/numpy.h
View file @
ddbc74c6
...
...
@@ -87,10 +87,12 @@ struct numpy_internals {
numpy_type_info
*
get_type_info
(
const
std
::
type_info
&
tinfo
,
bool
throw_if_missing
=
true
)
{
auto
it
=
registered_dtypes
.
find
(
std
::
type_index
(
tinfo
));
if
(
it
!=
registered_dtypes
.
end
())
if
(
it
!=
registered_dtypes
.
end
())
{
return
&
(
it
->
second
);
if
(
throw_if_missing
)
}
if
(
throw_if_missing
)
{
pybind11_fail
(
std
::
string
(
"NumPy type info missing for "
)
+
tinfo
.
name
());
}
return
nullptr
;
}
...
...
@@ -105,8 +107,9 @@ PYBIND11_NOINLINE void load_numpy_internals(numpy_internals* &ptr) {
inline
numpy_internals
&
get_numpy_internals
()
{
static
numpy_internals
*
ptr
=
nullptr
;
if
(
!
ptr
)
if
(
!
ptr
)
{
load_numpy_internals
(
ptr
);
}
return
*
ptr
;
}
...
...
@@ -235,8 +238,9 @@ private:
npy_api
api
;
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
DECL_NPY_API
(
PyArray_GetNDArrayCFeatureVersion
);
if
(
api
.
PyArray_GetNDArrayCFeatureVersion_
()
<
0x7
)
if
(
api
.
PyArray_GetNDArrayCFeatureVersion_
()
<
0x7
)
{
pybind11_fail
(
"pybind11 numpy support requires numpy >= 1.7.0"
);
}
DECL_NPY_API
(
PyArray_Type
);
DECL_NPY_API
(
PyVoidArrType_Type
);
DECL_NPY_API
(
PyArrayDescr_Type
);
...
...
@@ -491,8 +495,9 @@ public:
/// This is essentially the same as calling numpy.dtype(args) in Python.
static
dtype
from_args
(
object
args
)
{
PyObject
*
ptr
=
nullptr
;
if
((
detail
::
npy_api
::
get
().
PyArray_DescrConverter_
(
args
.
ptr
(),
&
ptr
)
==
0
)
||
!
ptr
)
if
((
detail
::
npy_api
::
get
().
PyArray_DescrConverter_
(
args
.
ptr
(),
&
ptr
)
==
0
)
||
!
ptr
)
{
throw
error_already_set
();
}
return
reinterpret_steal
<
dtype
>
(
ptr
);
}
...
...
@@ -536,8 +541,9 @@ private:
dtype
strip_padding
(
ssize_t
itemsize
)
{
// Recursively strip all void fields with empty names that are generated for
// padding fields (as of NumPy v1.11).
if
(
!
has_fields
())
if
(
!
has_fields
())
{
return
*
this
;
}
struct
field_descr
{
PYBIND11_STR_TYPE
name
;
object
format
;
pybind11
::
int_
offset
;
};
std
::
vector
<
field_descr
>
field_descriptors
;
...
...
@@ -547,8 +553,9 @@ private:
auto
name
=
spec
[
0
].
cast
<
pybind11
::
str
>
();
auto
format
=
spec
[
1
].
cast
<
tuple
>
()[
0
].
cast
<
dtype
>
();
auto
offset
=
spec
[
1
].
cast
<
tuple
>
()[
1
].
cast
<
pybind11
::
int_
>
();
if
((
len
(
name
)
==
0u
)
&&
format
.
kind
()
==
'V'
)
if
((
len
(
name
)
==
0u
)
&&
format
.
kind
()
==
'V'
)
{
continue
;
}
field_descriptors
.
push_back
({(
PYBIND11_STR_TYPE
)
name
,
format
.
strip_padding
(
format
.
itemsize
()),
offset
});
}
...
...
@@ -586,22 +593,25 @@ public:
array
(
const
pybind11
::
dtype
&
dt
,
ShapeContainer
shape
,
StridesContainer
strides
,
const
void
*
ptr
=
nullptr
,
handle
base
=
handle
())
{
if
(
strides
->
empty
())
if
(
strides
->
empty
())
{
*
strides
=
detail
::
c_strides
(
*
shape
,
dt
.
itemsize
());
}
auto
ndim
=
shape
->
size
();
if
(
ndim
!=
strides
->
size
())
if
(
ndim
!=
strides
->
size
())
{
pybind11_fail
(
"NumPy: shape ndim doesn't match strides ndim"
);
}
auto
descr
=
dt
;
int
flags
=
0
;
if
(
base
&&
ptr
)
{
if
(
isinstance
<
array
>
(
base
))
if
(
isinstance
<
array
>
(
base
))
{
/* Copy flags from base (except ownership bit) */
flags
=
reinterpret_borrow
<
array
>
(
base
).
flags
()
&
~
detail
::
npy_api
::
NPY_ARRAY_OWNDATA_
;
else
}
else
{
/* Writable by default, easy to downgrade later on if needed */
flags
=
detail
::
npy_api
::
NPY_ARRAY_WRITEABLE_
;
}
}
auto
&
api
=
detail
::
npy_api
::
get
();
...
...
@@ -611,8 +621,9 @@ public:
reinterpret_cast
<
Py_intptr_t
*>
(
shape
->
data
()),
reinterpret_cast
<
Py_intptr_t
*>
(
strides
->
data
()),
const_cast
<
void
*>
(
ptr
),
flags
,
nullptr
));
if
(
!
tmp
)
if
(
!
tmp
)
{
throw
error_already_set
();
}
if
(
ptr
)
{
if
(
base
)
{
api
.
PyArray_SetBaseObject_
(
tmp
.
ptr
(),
base
.
inc_ref
().
ptr
());
...
...
@@ -681,8 +692,9 @@ public:
/// Dimension along a given axis
ssize_t
shape
(
ssize_t
dim
)
const
{
if
(
dim
>=
ndim
())
if
(
dim
>=
ndim
())
{
fail_dim_check
(
dim
,
"invalid axis"
);
}
return
shape
()[
dim
];
}
...
...
@@ -693,8 +705,9 @@ public:
/// Stride along a given axis
ssize_t
strides
(
ssize_t
dim
)
const
{
if
(
dim
>=
ndim
())
if
(
dim
>=
ndim
())
{
fail_dim_check
(
dim
,
"invalid axis"
);
}
return
strides
()[
dim
];
}
...
...
@@ -730,8 +743,9 @@ public:
/// Byte offset from beginning of the array to a given index (full or partial).
/// May throw if the index would lead to out of bounds access.
template
<
typename
...
Ix
>
ssize_t
offset_at
(
Ix
...
index
)
const
{
if
((
ssize_t
)
sizeof
...(
index
)
>
ndim
())
if
((
ssize_t
)
sizeof
...(
index
)
>
ndim
())
{
fail_dim_check
(
sizeof
...(
index
),
"too many indices for an array"
);
}
return
byte_offset
(
ssize_t
(
index
)...);
}
...
...
@@ -750,9 +764,11 @@ public:
* and the caller must take care not to access invalid dimensions or dimension indices.
*/
template
<
typename
T
,
ssize_t
Dims
=
-
1
>
detail
::
unchecked_mutable_reference
<
T
,
Dims
>
mutable_unchecked
()
&
{
if
(
PYBIND11_SILENCE_MSVC_C4127
(
Dims
>=
0
)
&&
ndim
()
!=
Dims
)
throw
std
::
domain_error
(
"array has incorrect number of dimensions: "
+
std
::
to_string
(
ndim
())
+
"; expected "
+
std
::
to_string
(
Dims
));
if
(
PYBIND11_SILENCE_MSVC_C4127
(
Dims
>=
0
)
&&
ndim
()
!=
Dims
)
{
throw
std
::
domain_error
(
"array has incorrect number of dimensions: "
+
std
::
to_string
(
ndim
())
+
"; expected "
+
std
::
to_string
(
Dims
));
}
return
detail
::
unchecked_mutable_reference
<
T
,
Dims
>
(
mutable_data
(),
shape
(),
strides
(),
ndim
());
}
...
...
@@ -764,9 +780,11 @@ public:
* invalid dimensions or dimension indices.
*/
template
<
typename
T
,
ssize_t
Dims
=
-
1
>
detail
::
unchecked_reference
<
T
,
Dims
>
unchecked
()
const
&
{
if
(
PYBIND11_SILENCE_MSVC_C4127
(
Dims
>=
0
)
&&
ndim
()
!=
Dims
)
throw
std
::
domain_error
(
"array has incorrect number of dimensions: "
+
std
::
to_string
(
ndim
())
+
"; expected "
+
std
::
to_string
(
Dims
));
if
(
PYBIND11_SILENCE_MSVC_C4127
(
Dims
>=
0
)
&&
ndim
()
!=
Dims
)
{
throw
std
::
domain_error
(
"array has incorrect number of dimensions: "
+
std
::
to_string
(
ndim
())
+
"; expected "
+
std
::
to_string
(
Dims
));
}
return
detail
::
unchecked_reference
<
T
,
Dims
>
(
data
(),
shape
(),
strides
(),
ndim
());
}
...
...
@@ -789,7 +807,9 @@ public:
auto
new_array
=
reinterpret_steal
<
object
>
(
detail
::
npy_api
::
get
().
PyArray_Resize_
(
m_ptr
,
&
d
,
int
(
refcheck
),
-
1
)
);
if
(
!
new_array
)
throw
error_already_set
();
if
(
!
new_array
)
{
throw
error_already_set
();
}
if
(
isinstance
<
array
>
(
new_array
))
{
*
this
=
std
::
move
(
new_array
);
}
}
...
...
@@ -824,8 +844,9 @@ public:
/// In case of an error, nullptr is returned and the Python error is cleared.
static
array
ensure
(
handle
h
,
int
ExtraFlags
=
0
)
{
auto
result
=
reinterpret_steal
<
array
>
(
raw_array
(
h
.
ptr
(),
ExtraFlags
));
if
(
!
result
)
if
(
!
result
)
{
PyErr_Clear
();
}
return
result
;
}
...
...
@@ -843,8 +864,9 @@ protected:
}
void
check_writeable
()
const
{
if
(
!
writeable
())
if
(
!
writeable
())
{
throw
std
::
domain_error
(
"array is not writeable"
);
}
}
template
<
typename
...
Ix
>
void
check_dimensions
(
Ix
...
index
)
const
{
...
...
@@ -890,13 +912,19 @@ public:
PYBIND11_DEPRECATED
(
"Use array_t<T>::ensure() instead"
)
array_t
(
handle
h
,
bool
is_borrowed
)
:
array
(
raw_array_t
(
h
.
ptr
()),
stolen_t
{})
{
if
(
!
m_ptr
)
PyErr_Clear
();
if
(
!
is_borrowed
)
Py_XDECREF
(
h
.
ptr
());
if
(
!
m_ptr
)
{
PyErr_Clear
();
}
if
(
!
is_borrowed
)
{
Py_XDECREF
(
h
.
ptr
());
}
}
// NOLINTNEXTLINE(google-explicit-constructor)
array_t
(
const
object
&
o
)
:
array
(
raw_array_t
(
o
.
ptr
()),
stolen_t
{})
{
if
(
!
m_ptr
)
throw
error_already_set
();
if
(
!
m_ptr
)
{
throw
error_already_set
();
}
}
explicit
array_t
(
const
buffer_info
&
info
,
handle
base
=
handle
())
:
array
(
info
,
base
)
{
}
...
...
@@ -933,15 +961,17 @@ public:
// Reference to element at a given index
template
<
typename
...
Ix
>
const
T
&
at
(
Ix
...
index
)
const
{
if
((
ssize_t
)
sizeof
...(
index
)
!=
ndim
())
if
((
ssize_t
)
sizeof
...(
index
)
!=
ndim
())
{
fail_dim_check
(
sizeof
...(
index
),
"index dimension mismatch"
);
}
return
*
(
static_cast
<
const
T
*>
(
array
::
data
())
+
byte_offset
(
ssize_t
(
index
)...)
/
itemsize
());
}
// Mutable reference to element at a given index
template
<
typename
...
Ix
>
T
&
mutable_at
(
Ix
...
index
)
{
if
((
ssize_t
)
sizeof
...(
index
)
!=
ndim
())
if
((
ssize_t
)
sizeof
...(
index
)
!=
ndim
())
{
fail_dim_check
(
sizeof
...(
index
),
"index dimension mismatch"
);
}
return
*
(
static_cast
<
T
*>
(
array
::
mutable_data
())
+
byte_offset
(
ssize_t
(
index
)...)
/
itemsize
());
}
...
...
@@ -970,8 +1000,9 @@ public:
/// it). In case of an error, nullptr is returned and the Python error is cleared.
static
array_t
ensure
(
handle
h
)
{
auto
result
=
reinterpret_steal
<
array_t
>
(
raw_array_t
(
h
.
ptr
()));
if
(
!
result
)
if
(
!
result
)
{
PyErr_Clear
();
}
return
result
;
}
...
...
@@ -1032,8 +1063,9 @@ struct pyobject_caster<array_t<T, ExtraFlags>> {
using
type
=
array_t
<
T
,
ExtraFlags
>
;
bool
load
(
handle
src
,
bool
convert
)
{
if
(
!
convert
&&
!
type
::
check_
(
src
))
if
(
!
convert
&&
!
type
::
check_
(
src
))
{
return
false
;
}
value
=
type
::
ensure
(
src
);
return
static_cast
<
bool
>
(
value
);
}
...
...
@@ -1098,8 +1130,9 @@ public:
static
constexpr
int
value
=
values
[
detail
::
is_fmt_numeric
<
T
>::
index
];
static
pybind11
::
dtype
dtype
()
{
if
(
auto
ptr
=
npy_api
::
get
().
PyArray_DescrFromType_
(
value
))
if
(
auto
ptr
=
npy_api
::
get
().
PyArray_DescrFromType_
(
value
))
{
return
reinterpret_steal
<
pybind11
::
dtype
>
(
ptr
);
}
pybind11_fail
(
"Unsupported buffer format!"
);
}
};
...
...
@@ -1147,8 +1180,9 @@ PYBIND11_NOINLINE void register_structured_dtype(
bool
(
*
direct_converter
)(
PyObject
*
,
void
*&
))
{
auto
&
numpy_internals
=
get_numpy_internals
();
if
(
numpy_internals
.
get_type_info
(
tinfo
,
false
))
if
(
numpy_internals
.
get_type_info
(
tinfo
,
false
))
{
pybind11_fail
(
"NumPy: dtype is already registered"
);
}
// Use ordered fields because order matters as of NumPy 1.14:
// https://docs.scipy.org/doc/numpy/release.html#multiple-field-indexing-assignment-of-structured-arrays
...
...
@@ -1158,9 +1192,10 @@ PYBIND11_NOINLINE void register_structured_dtype(
list
names
,
formats
,
offsets
;
for
(
auto
&
field
:
ordered_fields
)
{
if
(
!
field
.
descr
)
pybind11_fail
(
std
::
string
(
"NumPy: unsupported field dtype: `"
)
+
field
.
name
+
"` @ "
+
tinfo
.
name
());
if
(
!
field
.
descr
)
{
pybind11_fail
(
std
::
string
(
"NumPy: unsupported field dtype: `"
)
+
field
.
name
+
"` @ "
+
tinfo
.
name
());
}
names
.
append
(
PYBIND11_STR_TYPE
(
field
.
name
));
formats
.
append
(
field
.
descr
);
offsets
.
append
(
pybind11
::
int_
(
field
.
offset
));
...
...
@@ -1186,21 +1221,24 @@ PYBIND11_NOINLINE void register_structured_dtype(
// isn't guaranteed to work due to https://github.com/numpy/numpy/issues/9049
oss
<<
"^T{"
;
for
(
auto
&
field
:
ordered_fields
)
{
if
(
field
.
offset
>
offset
)
if
(
field
.
offset
>
offset
)
{
oss
<<
(
field
.
offset
-
offset
)
<<
'x'
;
}
oss
<<
field
.
format
<<
':'
<<
field
.
name
<<
':'
;
offset
=
field
.
offset
+
field
.
size
;
}
if
(
itemsize
>
offset
)
if
(
itemsize
>
offset
)
{
oss
<<
(
itemsize
-
offset
)
<<
'x'
;
}
oss
<<
'}'
;
auto
format_str
=
oss
.
str
();
// Sanity check: verify that NumPy properly parses our buffer format string
auto
&
api
=
npy_api
::
get
();
auto
arr
=
array
(
buffer_info
(
nullptr
,
itemsize
,
format_str
,
1
));
if
(
!
api
.
PyArray_EquivTypes_
(
dtype_ptr
,
arr
.
dtype
().
ptr
()))
if
(
!
api
.
PyArray_EquivTypes_
(
dtype_ptr
,
arr
.
dtype
().
ptr
()))
{
pybind11_fail
(
"NumPy: invalid buffer descriptor!"
);
}
auto
tindex
=
std
::
type_index
(
tinfo
);
numpy_internals
.
registered_dtypes
[
tindex
]
=
{
dtype_ptr
,
format_str
};
...
...
@@ -1234,8 +1272,9 @@ private:
static
bool
direct_converter
(
PyObject
*
obj
,
void
*&
value
)
{
auto
&
api
=
npy_api
::
get
();
if
(
!
PyObject_TypeCheck
(
obj
,
api
.
PyVoidArrType_Type_
))
if
(
!
PyObject_TypeCheck
(
obj
,
api
.
PyVoidArrType_Type_
))
{
return
false
;
}
if
(
auto
descr
=
reinterpret_steal
<
object
>
(
api
.
PyArray_DescrFromScalar_
(
obj
)))
{
if
(
api
.
PyArray_EquivTypes_
(
dtype_ptr
(),
descr
.
ptr
()))
{
value
=
((
PyVoidScalarObject_Proxy
*
)
obj
)
->
obval
;
...
...
@@ -1363,12 +1402,14 @@ public:
m_common_iterator
()
{
// Manual copy to avoid conversion warning if using std::copy
for
(
size_t
i
=
0
;
i
<
shape
.
size
();
++
i
)
for
(
size_t
i
=
0
;
i
<
shape
.
size
();
++
i
)
{
m_shape
[
i
]
=
shape
[
i
];
}
container_type
strides
(
shape
.
size
());
for
(
size_t
i
=
0
;
i
<
N
;
++
i
)
for
(
size_t
i
=
0
;
i
<
N
;
++
i
)
{
init_common_iterator
(
buffers
[
i
],
shape
,
m_common_iterator
[
i
],
strides
);
}
}
multi_array_iterator
&
operator
++
()
{
...
...
@@ -1401,10 +1442,11 @@ private:
auto
strides_iter
=
strides
.
rbegin
();
while
(
buffer_shape_iter
!=
buffer
.
shape
.
rend
())
{
if
(
*
shape_iter
==
*
buffer_shape_iter
)
if
(
*
shape_iter
==
*
buffer_shape_iter
)
{
*
strides_iter
=
*
buffer_strides_iter
;
else
}
else
{
*
strides_iter
=
0
;
}
++
buffer_shape_iter
;
++
buffer_strides_iter
;
...
...
@@ -1417,8 +1459,9 @@ private:
}
void
increment_common_iterator
(
size_t
dim
)
{
for
(
auto
&
iter
:
m_common_iterator
)
for
(
auto
&
iter
:
m_common_iterator
)
{
iter
.
increment
(
dim
);
}
}
container_type
m_shape
;
...
...
@@ -1451,26 +1494,30 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &
auto
&
dim_size_out
=
*
res_iter
;
// Each input dimension can either be 1 or `n`, but `n` values must match across buffers
if
(
dim_size_out
==
1
)
if
(
dim_size_out
==
1
)
{
dim_size_out
=
dim_size_in
;
else
if
(
dim_size_in
!=
1
&&
dim_size_in
!=
dim_size_out
)
}
else
if
(
dim_size_in
!=
1
&&
dim_size_in
!=
dim_size_out
)
{
pybind11_fail
(
"pybind11::vectorize: incompatible size/dimension of inputs!"
);
}
}
}
bool
trivial_broadcast_c
=
true
;
bool
trivial_broadcast_f
=
true
;
for
(
size_t
i
=
0
;
i
<
N
&&
(
trivial_broadcast_c
||
trivial_broadcast_f
);
++
i
)
{
if
(
buffers
[
i
].
size
==
1
)
if
(
buffers
[
i
].
size
==
1
)
{
continue
;
}
// Require the same number of dimensions:
if
(
buffers
[
i
].
ndim
!=
ndim
)
if
(
buffers
[
i
].
ndim
!=
ndim
)
{
return
broadcast_trivial
::
non_trivial
;
}
// Require all dimensions be full-size:
if
(
!
std
::
equal
(
buffers
[
i
].
shape
.
cbegin
(),
buffers
[
i
].
shape
.
cend
(),
shape
.
cbegin
()))
if
(
!
std
::
equal
(
buffers
[
i
].
shape
.
cbegin
(),
buffers
[
i
].
shape
.
cend
(),
shape
.
cbegin
()))
{
return
broadcast_trivial
::
non_trivial
;
}
// Check for C contiguity (but only if previous inputs were also C contiguous)
if
(
trivial_broadcast_c
)
{
...
...
@@ -1478,10 +1525,11 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &
auto
end
=
buffers
[
i
].
shape
.
crend
();
for
(
auto
shape_iter
=
buffers
[
i
].
shape
.
crbegin
(),
stride_iter
=
buffers
[
i
].
strides
.
crbegin
();
trivial_broadcast_c
&&
shape_iter
!=
end
;
++
shape_iter
,
++
stride_iter
)
{
if
(
expect_stride
==
*
stride_iter
)
if
(
expect_stride
==
*
stride_iter
)
{
expect_stride
*=
*
shape_iter
;
else
}
else
{
trivial_broadcast_c
=
false
;
}
}
}
...
...
@@ -1491,10 +1539,11 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &
auto
end
=
buffers
[
i
].
shape
.
cend
();
for
(
auto
shape_iter
=
buffers
[
i
].
shape
.
cbegin
(),
stride_iter
=
buffers
[
i
].
strides
.
cbegin
();
trivial_broadcast_f
&&
shape_iter
!=
end
;
++
shape_iter
,
++
stride_iter
)
{
if
(
expect_stride
==
*
stride_iter
)
if
(
expect_stride
==
*
stride_iter
)
{
expect_stride
*=
*
shape_iter
;
else
}
else
{
trivial_broadcast_f
=
false
;
}
}
}
}
...
...
@@ -1527,8 +1576,9 @@ struct vectorize_returned_array {
using
Type
=
array_t
<
Return
>
;
static
Type
create
(
broadcast_trivial
trivial
,
const
std
::
vector
<
ssize_t
>
&
shape
)
{
if
(
trivial
==
broadcast_trivial
::
f_trivial
)
if
(
trivial
==
broadcast_trivial
::
f_trivial
)
{
return
array_t
<
Return
,
array
::
f_style
>
(
shape
);
}
return
array_t
<
Return
>
(
shape
);
}
...
...
@@ -1644,14 +1694,17 @@ private:
auto
result
=
returned_array
::
create
(
trivial
,
shape
);
if
(
size
==
0
)
return
std
::
move
(
result
);
if
(
size
==
0
)
{
return
std
::
move
(
result
);
}
/* Call the function */
auto
mutable_data
=
returned_array
::
mutable_data
(
result
);
if
(
trivial
==
broadcast_trivial
::
non_trivial
)
if
(
trivial
==
broadcast_trivial
::
non_trivial
)
{
apply_broadcast
(
buffers
,
params
,
mutable_data
,
size
,
shape
,
i_seq
,
vi_seq
,
bi_seq
);
else
}
else
{
apply_trivial
(
buffers
,
params
,
mutable_data
,
size
,
i_seq
,
vi_seq
,
bi_seq
);
}
return
std
::
move
(
result
);
}
...
...
@@ -1675,7 +1728,9 @@ private:
for
(
size_t
i
=
0
;
i
<
size
;
++
i
)
{
returned_array
::
call
(
out
,
i
,
f
,
*
reinterpret_cast
<
param_n_t
<
Index
>
*>
(
params
[
Index
])...);
for
(
auto
&
x
:
vecparams
)
x
.
first
+=
x
.
second
;
for
(
auto
&
x
:
vecparams
)
{
x
.
first
+=
x
.
second
;
}
}
}
...
...
include/pybind11/pybind11.h
View file @
ddbc74c6
...
...
@@ -212,8 +212,9 @@ protected:
cast_in
args_converter
;
/* Try to cast the function arguments into the C++ domain */
if
(
!
args_converter
.
load_args
(
call
))
if
(
!
args_converter
.
load_args
(
call
))
{
return
PYBIND11_TRY_NEXT_OVERLOAD
;
}
/* Invoke call policy pre-call hook */
process_attributes
<
Extra
...
>::
precall
(
call
);
...
...
@@ -286,8 +287,9 @@ protected:
class
strdup_guard
{
public
:
~
strdup_guard
()
{
for
(
auto
s
:
strings
)
for
(
auto
s
:
strings
)
{
std
::
free
(
s
);
}
}
char
*
operator
()(
const
char
*
s
)
{
auto
t
=
PYBIND11_COMPAT_STRDUP
(
s
);
...
...
@@ -318,14 +320,18 @@ protected:
/* Create copies of all referenced C-style strings */
rec
->
name
=
guarded_strdup
(
rec
->
name
?
rec
->
name
:
""
);
if
(
rec
->
doc
)
rec
->
doc
=
guarded_strdup
(
rec
->
doc
);
if
(
rec
->
doc
)
{
rec
->
doc
=
guarded_strdup
(
rec
->
doc
);
}
for
(
auto
&
a
:
rec
->
args
)
{
if
(
a
.
name
)
if
(
a
.
name
)
{
a
.
name
=
guarded_strdup
(
a
.
name
);
if
(
a
.
descr
)
}
if
(
a
.
descr
)
{
a
.
descr
=
guarded_strdup
(
a
.
descr
);
else
if
(
a
.
value
)
}
else
if
(
a
.
value
)
{
a
.
descr
=
guarded_strdup
(
repr
(
a
.
value
).
cast
<
std
::
string
>
().
c_str
());
}
}
rec
->
is_constructor
=
(
std
::
strcmp
(
rec
->
name
,
"__init__"
)
==
0
)
...
...
@@ -355,12 +361,14 @@ protected:
if
(
c
==
'{'
)
{
// Write arg name for everything except *args and **kwargs.
is_starred
=
*
(
pc
+
1
)
==
'*'
;
if
(
is_starred
)
if
(
is_starred
)
{
continue
;
}
// Separator for keyword-only arguments, placed before the kw
// arguments start (unless we are already putting an *args)
if
(
!
rec
->
has_args
&&
arg_index
==
rec
->
nargs_pos
)
if
(
!
rec
->
has_args
&&
arg_index
==
rec
->
nargs_pos
)
{
signature
+=
"*, "
;
}
if
(
arg_index
<
rec
->
args
.
size
()
&&
rec
->
args
[
arg_index
].
name
)
{
signature
+=
rec
->
args
[
arg_index
].
name
;
}
else
if
(
arg_index
==
0
&&
rec
->
is_method
)
{
...
...
@@ -377,14 +385,17 @@ protected:
}
// Separator for positional-only arguments (placed after the
// argument, rather than before like *
if
(
rec
->
nargs_pos_only
>
0
&&
(
arg_index
+
1
)
==
rec
->
nargs_pos_only
)
if
(
rec
->
nargs_pos_only
>
0
&&
(
arg_index
+
1
)
==
rec
->
nargs_pos_only
)
{
signature
+=
", /"
;
if
(
!
is_starred
)
}
if
(
!
is_starred
)
{
arg_index
++
;
}
}
else
if
(
c
==
'%'
)
{
const
std
::
type_info
*
t
=
types
[
type_index
++
];
if
(
!
t
)
if
(
!
t
)
{
pybind11_fail
(
"Internal error while parsing type signature (1)"
);
}
if
(
auto
tinfo
=
detail
::
get_type_info
(
*
t
))
{
handle
th
((
PyObject
*
)
tinfo
->
type
);
signature
+=
...
...
@@ -406,8 +417,9 @@ protected:
}
}
if
(
arg_index
!=
args
-
rec
->
has_args
-
rec
->
has_kwargs
||
types
[
type_index
]
!=
nullptr
)
if
(
arg_index
!=
args
-
rec
->
has_args
-
rec
->
has_kwargs
||
types
[
type_index
]
!=
nullptr
)
{
pybind11_fail
(
"Internal error while parsing type signature (2)"
);
}
#if PY_MAJOR_VERSION < 3
if
(
std
::
strcmp
(
rec
->
name
,
"__next__"
)
==
0
)
{
...
...
@@ -422,8 +434,9 @@ protected:
rec
->
args
.
shrink_to_fit
();
rec
->
nargs
=
(
std
::
uint16_t
)
args
;
if
(
rec
->
sibling
&&
PYBIND11_INSTANCE_METHOD_CHECK
(
rec
->
sibling
.
ptr
()))
if
(
rec
->
sibling
&&
PYBIND11_INSTANCE_METHOD_CHECK
(
rec
->
sibling
.
ptr
()))
{
rec
->
sibling
=
PYBIND11_INSTANCE_METHOD_GET_FUNCTION
(
rec
->
sibling
.
ptr
());
}
detail
::
function_record
*
chain
=
nullptr
,
*
chain_start
=
rec
;
if
(
rec
->
sibling
)
{
...
...
@@ -433,13 +446,16 @@ protected:
chain
=
(
detail
::
function_record
*
)
rec_capsule
;
/* Never append a method to an overload chain of a parent class;
instead, hide the parent's overloads in this case */
if
(
!
chain
->
scope
.
is
(
rec
->
scope
))
if
(
!
chain
->
scope
.
is
(
rec
->
scope
))
{
chain
=
nullptr
;
}
}
// Don't trigger for things like the default __init__, which are wrapper_descriptors
// that we are intentionally replacing
else
if
(
!
rec
->
sibling
.
is_none
()
&&
rec
->
name
[
0
]
!=
'_'
)
{
pybind11_fail
(
"Cannot overload existing non-function object
\"
"
+
std
::
string
(
rec
->
name
)
+
"
\"
with a function of the same name"
);
}
// Don't trigger for things like the default __init__, which are wrapper_descriptors that we are intentionally replacing
else
if
(
!
rec
->
sibling
.
is_none
()
&&
rec
->
name
[
0
]
!=
'_'
)
pybind11_fail
(
"Cannot overload existing non-function object
\"
"
+
std
::
string
(
rec
->
name
)
+
"
\"
with a function of the same name"
);
}
if
(
!
chain
)
{
...
...
@@ -466,21 +482,26 @@ protected:
}
m_ptr
=
PyCFunction_NewEx
(
rec
->
def
,
rec_capsule
.
ptr
(),
scope_module
.
ptr
());
if
(
!
m_ptr
)
if
(
!
m_ptr
)
{
pybind11_fail
(
"cpp_function::cpp_function(): Could not allocate function object"
);
}
}
else
{
/* Append at the beginning or end of the overload chain */
m_ptr
=
rec
->
sibling
.
ptr
();
inc_ref
();
if
(
chain
->
is_method
!=
rec
->
is_method
)
pybind11_fail
(
"overloading a method with both static and instance methods is not supported; "
#if defined(NDEBUG)
"compile in debug mode for more details"
if
(
chain
->
is_method
!=
rec
->
is_method
)
{
pybind11_fail
(
"overloading a method with both static and instance methods is not supported; "
#if defined(NDEBUG)
"compile in debug mode for more details"
#else
"error while attempting to bind "
+
std
::
string
(
rec
->
is_method
?
"instance"
:
"static"
)
+
" method "
+
std
::
string
(
pybind11
::
str
(
rec
->
scope
.
attr
(
"__name__"
)))
+
"."
+
std
::
string
(
rec
->
name
)
+
signature
"error while attempting to bind "
+
std
::
string
(
rec
->
is_method
?
"instance"
:
"static"
)
+
" method "
+
std
::
string
(
pybind11
::
str
(
rec
->
scope
.
attr
(
"__name__"
)))
+
"."
+
std
::
string
(
rec
->
name
)
+
signature
#endif
);
}
if
(
rec
->
prepend
)
{
// Beginning of chain; we need to replace the capsule's current head-of-the-chain
...
...
@@ -494,8 +515,9 @@ protected:
}
else
{
// Or end of chain (normal behavior)
chain_start
=
chain
;
while
(
chain
->
next
)
while
(
chain
->
next
)
{
chain
=
chain
->
next
;
}
chain
->
next
=
unique_rec
.
release
();
guarded_strdup
.
release
();
}
...
...
@@ -515,9 +537,12 @@ protected:
bool
first_user_def
=
true
;
for
(
auto
it
=
chain_start
;
it
!=
nullptr
;
it
=
it
->
next
)
{
if
(
options
::
show_function_signatures
())
{
if
(
index
>
0
)
signatures
+=
"
\n
"
;
if
(
chain
)
if
(
index
>
0
)
{
signatures
+=
"
\n
"
;
}
if
(
chain
)
{
signatures
+=
std
::
to_string
(
++
index
)
+
". "
;
}
signatures
+=
rec
->
name
;
signatures
+=
it
->
signature
;
signatures
+=
"
\n
"
;
...
...
@@ -526,12 +551,19 @@ protected:
// If we're appending another docstring, and aren't printing function signatures, we
// need to append a newline first:
if
(
!
options
::
show_function_signatures
())
{
if
(
first_user_def
)
first_user_def
=
false
;
else
signatures
+=
"
\n
"
;
if
(
first_user_def
)
{
first_user_def
=
false
;
}
else
{
signatures
+=
"
\n
"
;
}
}
if
(
options
::
show_function_signatures
())
{
signatures
+=
"
\n
"
;
}
if
(
options
::
show_function_signatures
())
signatures
+=
"
\n
"
;
signatures
+=
it
->
doc
;
if
(
options
::
show_function_signatures
())
signatures
+=
"
\n
"
;
if
(
options
::
show_function_signatures
())
{
signatures
+=
"
\n
"
;
}
}
}
...
...
@@ -544,8 +576,10 @@ protected:
if
(
rec
->
is_method
)
{
m_ptr
=
PYBIND11_INSTANCE_METHOD_NEW
(
m_ptr
,
rec
->
scope
.
ptr
());
if
(
!
m_ptr
)
pybind11_fail
(
"cpp_function::cpp_function(): Could not allocate instance method object"
);
if
(
!
m_ptr
)
{
pybind11_fail
(
"cpp_function::cpp_function(): Could not allocate instance method object"
);
}
Py_DECREF
(
func
);
}
}
...
...
@@ -560,8 +594,9 @@ protected:
while
(
rec
)
{
detail
::
function_record
*
next
=
rec
->
next
;
if
(
rec
->
free_data
)
if
(
rec
->
free_data
)
{
rec
->
free_data
(
rec
);
}
// During initialization, these strings might not have been copied yet,
// so they cannot be freed. Once the function has been created, they can.
// Check `make_function_record` for more details.
...
...
@@ -574,17 +609,19 @@ protected:
std
::
free
(
const_cast
<
char
*>
(
arg
.
descr
));
}
}
for
(
auto
&
arg
:
rec
->
args
)
for
(
auto
&
arg
:
rec
->
args
)
{
arg
.
value
.
dec_ref
();
}
if
(
rec
->
def
)
{
std
::
free
(
const_cast
<
char
*>
(
rec
->
def
->
ml_doc
));
// Python 3.9.0 decref's these in the wrong order; rec->def
// If loaded on 3.9.0, let these leak (use Python 3.9.1 at runtime to fix)
// See https://github.com/python/cpython/pull/22670
#if !defined(PYPY_VERSION) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 9
if
(
!
is_zero
)
delete
rec
->
def
;
#else
if
(
!
is_zero
)
{
delete
rec
->
def
;
}
#else
delete
rec
->
def
;
#endif
}
...
...
@@ -621,8 +658,9 @@ protected:
// If this value is already registered it must mean __init__ is invoked multiple times;
// we really can't support that in C++, so just ignore the second __init__.
if
(
self_value_and_holder
.
instance_registered
())
if
(
self_value_and_holder
.
instance_registered
())
{
return
none
().
release
().
ptr
();
}
}
try
{
...
...
@@ -658,15 +696,22 @@ protected:
const
function_record
&
func
=
*
it
;
size_t
num_args
=
func
.
nargs
;
// Number of positional arguments that we need
if
(
func
.
has_args
)
--
num_args
;
// (but don't count py::args
if
(
func
.
has_kwargs
)
--
num_args
;
// or py::kwargs)
if
(
func
.
has_args
)
{
--
num_args
;
// (but don't count py::args
}
if
(
func
.
has_kwargs
)
{
--
num_args
;
// or py::kwargs)
}
size_t
pos_args
=
func
.
nargs_pos
;
if
(
!
func
.
has_args
&&
n_args_in
>
pos_args
)
if
(
!
func
.
has_args
&&
n_args_in
>
pos_args
)
{
continue
;
// Too many positional arguments for this overload
}
if
(
n_args_in
<
pos_args
&&
func
.
args
.
size
()
<
pos_args
)
continue
;
// Not enough positional arguments given, and not enough defaults to fill in the blanks
if
(
n_args_in
<
pos_args
&&
func
.
args
.
size
()
<
pos_args
)
{
continue
;
// Not enough positional arguments given, and not enough defaults to
// fill in the blanks
}
function_call
call
(
func
,
parent
);
...
...
@@ -677,8 +722,9 @@ protected:
if
(
func
.
is_new_style_constructor
)
{
// The `value` may have been preallocated by an old-style `__init__`
// if it was a preceding candidate for overload resolution.
if
(
self_value_and_holder
)
if
(
self_value_and_holder
)
{
self_value_and_holder
.
type
->
dealloc
(
self_value_and_holder
);
}
call
.
init_self
=
PyTuple_GET_ITEM
(
args_in
,
0
);
call
.
args
.
emplace_back
(
reinterpret_cast
<
PyObject
*>
(
&
self_value_and_holder
));
...
...
@@ -703,8 +749,9 @@ protected:
call
.
args
.
push_back
(
arg
);
call
.
args_convert
.
push_back
(
arg_rec
?
arg_rec
->
convert
:
true
);
}
if
(
bad_arg
)
if
(
bad_arg
)
{
continue
;
// Maybe it was meant for another overload (issue #688)
}
// Keep track of how many position args we copied out in case we need to come back
// to copy the rest into a py::args argument.
...
...
@@ -725,12 +772,14 @@ protected:
if
(
value
)
{
call
.
args
.
push_back
(
value
);
call
.
args_convert
.
push_back
(
arg_rec
.
convert
);
}
else
}
else
{
break
;
}
}
if
(
args_copied
<
func
.
nargs_pos_only
)
if
(
args_copied
<
func
.
nargs_pos_only
)
{
continue
;
// Not enough defaults to fill the positional arguments
}
}
// 2. Check kwargs and, failing that, defaults that may help complete the list
...
...
@@ -741,8 +790,9 @@ protected:
const
auto
&
arg_rec
=
func
.
args
[
args_copied
];
handle
value
;
if
(
kwargs_in
&&
arg_rec
.
name
)
if
(
kwargs_in
&&
arg_rec
.
name
)
{
value
=
dict_getitemstring
(
kwargs
.
ptr
(),
arg_rec
.
name
);
}
if
(
value
)
{
// Consume a kwargs value
...
...
@@ -763,23 +813,27 @@ protected:
if
(
value
)
{
// If we're at the py::args index then first insert a stub for it to be replaced later
if
(
func
.
has_args
&&
call
.
args
.
size
()
==
func
.
nargs_pos
)
if
(
func
.
has_args
&&
call
.
args
.
size
()
==
func
.
nargs_pos
)
{
call
.
args
.
push_back
(
none
());
}
call
.
args
.
push_back
(
value
);
call
.
args_convert
.
push_back
(
arg_rec
.
convert
);
}
else
}
else
{
break
;
}
}
if
(
args_copied
<
num_args
)
continue
;
// Not enough arguments, defaults, or kwargs to fill the positional arguments
if
(
args_copied
<
num_args
)
{
continue
;
// Not enough arguments, defaults, or kwargs to fill the
// positional arguments
}
}
// 3. Check everything was consumed (unless we have a kwargs arg)
if
(
kwargs
&&
!
kwargs
.
empty
()
&&
!
func
.
has_kwargs
)
if
(
kwargs
&&
!
kwargs
.
empty
()
&&
!
func
.
has_kwargs
)
{
continue
;
// Unconsumed kwargs, but no py::kwargs argument to accept them
}
// 4a. If we have a py::args argument, create a new tuple with leftovers
if
(
func
.
has_args
)
{
...
...
@@ -797,18 +851,20 @@ protected:
extra_args
[
i
]
=
PyTuple_GET_ITEM
(
args_in
,
positional_args_copied
+
i
);
}
}
if
(
call
.
args
.
size
()
<=
func
.
nargs_pos
)
if
(
call
.
args
.
size
()
<=
func
.
nargs_pos
)
{
call
.
args
.
push_back
(
extra_args
);
else
}
else
{
call
.
args
[
func
.
nargs_pos
]
=
extra_args
;
}
call
.
args_convert
.
push_back
(
false
);
call
.
args_ref
=
std
::
move
(
extra_args
);
}
// 4b. If we have a py::kwargs, pass on any remaining kwargs
if
(
func
.
has_kwargs
)
{
if
(
!
kwargs
.
ptr
())
if
(
!
kwargs
.
ptr
())
{
kwargs
=
dict
();
// If we didn't get one, send an empty one
}
call
.
args
.
push_back
(
kwargs
);
call
.
args_convert
.
push_back
(
false
);
call
.
kwargs_ref
=
std
::
move
(
kwargs
);
...
...
@@ -838,8 +894,9 @@ protected:
result
=
PYBIND11_TRY_NEXT_OVERLOAD
;
}
if
(
result
.
ptr
()
!=
PYBIND11_TRY_NEXT_OVERLOAD
)
if
(
result
.
ptr
()
!=
PYBIND11_TRY_NEXT_OVERLOAD
)
{
break
;
}
if
(
overloaded
)
{
// The (overloaded) call failed; if the call has at least one argument that
...
...
@@ -870,8 +927,9 @@ protected:
if
(
result
.
ptr
()
!=
PYBIND11_TRY_NEXT_OVERLOAD
)
{
// The error reporting logic below expects 'it' to be valid, as it would be
// if we'd encountered this failure in the first-pass loop.
if
(
!
result
)
if
(
!
result
)
{
it
=
&
call
.
func
;
}
break
;
}
}
...
...
@@ -923,8 +981,9 @@ protected:
};
if
(
result
.
ptr
()
==
PYBIND11_TRY_NEXT_OVERLOAD
)
{
if
(
overloads
->
is_operator
)
if
(
overloads
->
is_operator
)
{
return
handle
(
Py_NotImplemented
).
inc_ref
().
ptr
();
}
std
::
string
msg
=
std
::
string
(
overloads
->
name
)
+
"(): incompatible "
+
std
::
string
(
overloads
->
is_constructor
?
"constructor"
:
"function"
)
+
...
...
@@ -944,7 +1003,9 @@ protected:
size_t
end
=
sig
.
find
(
", "
),
next
=
end
+
2
;
size_t
ret
=
sig
.
rfind
(
" -> "
);
// Or the ), if there is no comma:
if
(
end
>=
sig
.
size
())
next
=
end
=
sig
.
find
(
')'
);
if
(
end
>=
sig
.
size
())
{
next
=
end
=
sig
.
find
(
')'
);
}
if
(
start
<
end
&&
next
<
sig
.
size
())
{
msg
.
append
(
sig
,
start
,
end
-
start
);
msg
+=
'('
;
...
...
@@ -953,7 +1014,9 @@ protected:
}
}
}
if
(
!
wrote_sig
)
msg
+=
it2
->
signature
;
if
(
!
wrote_sig
)
{
msg
+=
it2
->
signature
;
}
msg
+=
"
\n
"
;
}
...
...
@@ -961,8 +1024,11 @@ protected:
auto
args_
=
reinterpret_borrow
<
tuple
>
(
args_in
);
bool
some_args
=
false
;
for
(
size_t
ti
=
overloads
->
is_constructor
?
1
:
0
;
ti
<
args_
.
size
();
++
ti
)
{
if
(
!
some_args
)
some_args
=
true
;
else
msg
+=
", "
;
if
(
!
some_args
)
{
some_args
=
true
;
}
else
{
msg
+=
", "
;
}
try
{
msg
+=
pybind11
::
repr
(
args_
[
ti
]);
}
catch
(
const
error_already_set
&
)
{
...
...
@@ -972,12 +1038,17 @@ protected:
if
(
kwargs_in
)
{
auto
kwargs
=
reinterpret_borrow
<
dict
>
(
kwargs_in
);
if
(
!
kwargs
.
empty
())
{
if
(
some_args
)
msg
+=
"; "
;
if
(
some_args
)
{
msg
+=
"; "
;
}
msg
+=
"kwargs: "
;
bool
first
=
true
;
for
(
auto
kwarg
:
kwargs
)
{
if
(
first
)
first
=
false
;
else
msg
+=
", "
;
if
(
first
)
{
first
=
false
;
}
else
{
msg
+=
", "
;
}
msg
+=
pybind11
::
str
(
"{}="
).
format
(
kwarg
.
first
);
try
{
msg
+=
pybind11
::
repr
(
kwarg
.
second
);
...
...
@@ -1068,8 +1139,9 @@ public:
std
::
string
full_name
=
std
::
string
(
PyModule_GetName
(
m_ptr
))
+
std
::
string
(
"."
)
+
std
::
string
(
name
);
auto
result
=
reinterpret_borrow
<
module_
>
(
PyImport_AddModule
(
full_name
.
c_str
()));
if
(
doc
&&
options
::
show_user_defined_docstrings
())
if
(
doc
&&
options
::
show_user_defined_docstrings
())
{
result
.
attr
(
"__doc__"
)
=
pybind11
::
str
(
doc
);
}
attr
(
name
)
=
result
;
return
result
;
}
...
...
@@ -1077,16 +1149,18 @@ public:
/// Import and return a module or throws `error_already_set`.
static
module_
import
(
const
char
*
name
)
{
PyObject
*
obj
=
PyImport_ImportModule
(
name
);
if
(
!
obj
)
if
(
!
obj
)
{
throw
error_already_set
();
}
return
reinterpret_steal
<
module_
>
(
obj
);
}
/// Reload the module or throws `error_already_set`.
void
reload
()
{
PyObject
*
obj
=
PyImport_ReloadModule
(
ptr
());
if
(
!
obj
)
if
(
!
obj
)
{
throw
error_already_set
();
}
*
this
=
reinterpret_steal
<
module_
>
(
obj
);
}
...
...
@@ -1098,9 +1172,11 @@ public:
established will, in most cases, break things.
\endrst */
PYBIND11_NOINLINE
void
add_object
(
const
char
*
name
,
handle
obj
,
bool
overwrite
=
false
)
{
if
(
!
overwrite
&&
hasattr
(
*
this
,
name
))
pybind11_fail
(
"Error during initialization: multiple incompatible definitions with name
\"
"
+
std
::
string
(
name
)
+
"
\"
"
);
if
(
!
overwrite
&&
hasattr
(
*
this
,
name
))
{
pybind11_fail
(
"Error during initialization: multiple incompatible definitions with name
\"
"
+
std
::
string
(
name
)
+
"
\"
"
);
}
PyModule_AddObject
(
ptr
(),
name
,
obj
.
inc_ref
().
ptr
()
/* steals a reference */
);
}
...
...
@@ -1138,8 +1214,9 @@ public:
auto
m
=
Py_InitModule3
(
name
,
nullptr
,
options
::
show_user_defined_docstrings
()
?
doc
:
nullptr
);
#endif
if
(
m
==
nullptr
)
{
if
(
PyErr_Occurred
())
if
(
PyErr_Occurred
())
{
throw
error_already_set
();
}
pybind11_fail
(
"Internal error in module_::create_extension_module()"
);
}
// TODO: Should be reinterpret_steal for Python 3, but Python also steals it again when returned from PyInit_...
...
...
@@ -1177,14 +1254,17 @@ public:
PYBIND11_OBJECT_DEFAULT
(
generic_type
,
object
,
PyType_Check
)
protected
:
void
initialize
(
const
type_record
&
rec
)
{
if
(
rec
.
scope
&&
hasattr
(
rec
.
scope
,
"__dict__"
)
&&
rec
.
scope
.
attr
(
"__dict__"
).
contains
(
rec
.
name
))
pybind11_fail
(
"generic_type: cannot initialize type
\"
"
+
std
::
string
(
rec
.
name
)
+
"
\"
: an object with that name is already defined"
);
if
(
rec
.
scope
&&
hasattr
(
rec
.
scope
,
"__dict__"
)
&&
rec
.
scope
.
attr
(
"__dict__"
).
contains
(
rec
.
name
))
{
pybind11_fail
(
"generic_type: cannot initialize type
\"
"
+
std
::
string
(
rec
.
name
)
+
"
\"
: an object with that name is already defined"
);
}
if
((
rec
.
module_local
?
get_local_type_info
(
*
rec
.
type
)
:
get_global_type_info
(
*
rec
.
type
))
!=
nullptr
)
pybind11_fail
(
"generic_type: type
\"
"
+
std
::
string
(
rec
.
name
)
+
"
\"
is already registered!"
);
!=
nullptr
)
{
pybind11_fail
(
"generic_type: type
\"
"
+
std
::
string
(
rec
.
name
)
+
"
\"
is already registered!"
);
}
m_ptr
=
make_new_python_type
(
rec
);
...
...
@@ -1206,10 +1286,11 @@ protected:
auto
&
internals
=
get_internals
();
auto
tindex
=
std
::
type_index
(
*
rec
.
type
);
tinfo
->
direct_conversions
=
&
internals
.
direct_conversions
[
tindex
];
if
(
rec
.
module_local
)
if
(
rec
.
module_local
)
{
get_local_internals
().
registered_types_cpp
[
tindex
]
=
tinfo
;
else
}
else
{
internals
.
registered_types_cpp
[
tindex
]
=
tinfo
;
}
internals
.
registered_types_py
[(
PyTypeObject
*
)
m_ptr
]
=
{
tinfo
};
if
(
rec
.
bases
.
size
()
>
1
||
rec
.
multiple_inheritance
)
{
...
...
@@ -1237,8 +1318,9 @@ protected:
auto
t
=
reinterpret_borrow
<
tuple
>
(
value
->
tp_bases
);
for
(
handle
h
:
t
)
{
auto
tinfo2
=
get_type_info
((
PyTypeObject
*
)
h
.
ptr
());
if
(
tinfo2
)
if
(
tinfo2
)
{
tinfo2
->
simple_type
=
false
;
}
mark_parents_nonsimple
((
PyTypeObject
*
)
h
.
ptr
());
}
}
...
...
@@ -1249,12 +1331,12 @@ protected:
auto
*
type
=
(
PyHeapTypeObject
*
)
m_ptr
;
auto
tinfo
=
detail
::
get_type_info
(
&
type
->
ht_type
);
if
(
!
type
->
ht_type
.
tp_as_buffer
)
pybind11_fail
(
"To be able to register buffer protocol support for the type '"
+
get_fully_qualified_tp_name
(
tinfo
->
type
)
+
"' the associated class<>(..) invocation must "
"include the pybind11::buffer_protocol() annotation!"
);
if
(
!
type
->
ht_type
.
tp_as_buffer
)
{
pybind11_fail
(
"To be able to register buffer protocol support for the type '"
+
get_fully_qualified_tp_name
(
tinfo
->
type
)
+
"' the associated class<>(..) invocation must "
"include the pybind11::buffer_protocol() annotation!"
);
}
tinfo
->
get_buffer
=
get_buffer
;
tinfo
->
get_buffer_data
=
get_buffer_data
;
...
...
@@ -1475,8 +1557,9 @@ public:
auto
*
ptr
=
new
capture
{
std
::
forward
<
Func
>
(
func
)
};
install_buffer_funcs
([](
PyObject
*
obj
,
void
*
ptr
)
->
buffer_info
*
{
detail
::
make_caster
<
type
>
caster
;
if
(
!
caster
.
load
(
obj
,
false
))
if
(
!
caster
.
load
(
obj
,
false
))
{
return
nullptr
;
}
return
new
buffer_info
(((
capture
*
)
ptr
)
->
func
(
caster
));
},
ptr
);
weakref
(
m_ptr
,
cpp_function
([
ptr
](
handle
wr
)
{
...
...
@@ -1598,7 +1681,9 @@ public:
std
::
free
(
doc_prev
);
rec_fset
->
doc
=
PYBIND11_COMPAT_STRDUP
(
rec_fset
->
doc
);
}
if
(
!
rec_active
)
rec_active
=
rec_fset
;
if
(
!
rec_active
)
{
rec_active
=
rec_fset
;
}
}
def_property_static_impl
(
name
,
fget
,
fset
,
rec_active
);
return
*
this
;
...
...
@@ -1716,8 +1801,9 @@ PYBIND11_NAMESPACE_BEGIN(detail)
inline
str
enum_name
(
handle
arg
)
{
dict
entries
=
arg
.
get_type
().
attr
(
"__entries"
);
for
(
auto
kv
:
entries
)
{
if
(
handle
(
kv
.
second
[
int_
(
0
)]).
equal
(
arg
))
if
(
handle
(
kv
.
second
[
int_
(
0
)]).
equal
(
arg
))
{
return
pybind11
::
str
(
kv
.
first
);
}
}
return
"???"
;
}
...
...
@@ -1752,15 +1838,17 @@ struct enum_base {
[](
handle
arg
)
->
std
::
string
{
std
::
string
docstring
;
dict
entries
=
arg
.
attr
(
"__entries"
);
if
(((
PyTypeObject
*
)
arg
.
ptr
())
->
tp_doc
)
if
(((
PyTypeObject
*
)
arg
.
ptr
())
->
tp_doc
)
{
docstring
+=
std
::
string
(((
PyTypeObject
*
)
arg
.
ptr
())
->
tp_doc
)
+
"
\n\n
"
;
}
docstring
+=
"Members:"
;
for
(
auto
kv
:
entries
)
{
auto
key
=
std
::
string
(
pybind11
::
str
(
kv
.
first
));
auto
comment
=
kv
.
second
[
int_
(
1
)];
docstring
+=
"
\n\n
"
+
key
;
if
(
!
comment
.
is_none
())
if
(
!
comment
.
is_none
())
{
docstring
+=
" : "
+
(
std
::
string
)
pybind11
::
str
(
comment
);
}
}
return
docstring
;
},
name
(
"__doc__"
)
...
...
@@ -1769,8 +1857,9 @@ struct enum_base {
m_base
.
attr
(
"__members__"
)
=
static_property
(
cpp_function
(
[](
handle
arg
)
->
dict
{
dict
entries
=
arg
.
attr
(
"__entries"
),
m
;
for
(
auto
kv
:
entries
)
for
(
auto
kv
:
entries
)
{
m
[
kv
.
first
]
=
kv
.
second
[
int_
(
0
)];
}
return
m
;
},
name
(
"__members__"
)),
none
(),
none
(),
""
);
...
...
@@ -1865,8 +1954,9 @@ struct enum_base {
PYBIND11_NOINLINE
void
export_values
()
{
dict
entries
=
m_base
.
attr
(
"__entries"
);
for
(
auto
kv
:
entries
)
for
(
auto
kv
:
entries
)
{
m_parent
.
attr
(
kv
.
first
)
=
kv
.
second
[
int_
(
0
)];
}
}
handle
m_base
;
...
...
@@ -1944,11 +2034,13 @@ PYBIND11_NAMESPACE_BEGIN(detail)
PYBIND11_NOINLINE
void
keep_alive_impl
(
handle
nurse
,
handle
patient
)
{
if
(
!
nurse
||
!
patient
)
if
(
!
nurse
||
!
patient
)
{
pybind11_fail
(
"Could not activate keep_alive!"
);
}
if
(
patient
.
is_none
()
||
nurse
.
is_none
())
if
(
patient
.
is_none
()
||
nurse
.
is_none
())
{
return
;
/* Nothing to keep alive or nothing to be kept alive by */
}
auto
tinfo
=
all_type_info
(
Py_TYPE
(
nurse
.
ptr
()));
if
(
!
tinfo
.
empty
())
{
...
...
@@ -1972,12 +2064,15 @@ PYBIND11_NOINLINE void keep_alive_impl(handle nurse, handle patient) {
PYBIND11_NOINLINE
void
keep_alive_impl
(
size_t
Nurse
,
size_t
Patient
,
function_call
&
call
,
handle
ret
)
{
auto
get_arg
=
[
&
](
size_t
n
)
{
if
(
n
==
0
)
if
(
n
==
0
)
{
return
ret
;
if
(
n
==
1
&&
call
.
init_self
)
}
if
(
n
==
1
&&
call
.
init_self
)
{
return
call
.
init_self
;
if
(
n
<=
call
.
args
.
size
())
}
if
(
n
<=
call
.
args
.
size
())
{
return
call
.
args
[
n
-
1
];
}
return
handle
();
};
...
...
@@ -2000,10 +2095,11 @@ inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_t
// TODO consolidate the erasure code in pybind11_meta_dealloc() in class.h
auto
&
cache
=
get_internals
().
inactive_override_cache
;
for
(
auto
it
=
cache
.
begin
(),
last
=
cache
.
end
();
it
!=
last
;
)
{
if
(
it
->
first
==
reinterpret_cast
<
PyObject
*>
(
type
))
if
(
it
->
first
==
reinterpret_cast
<
PyObject
*>
(
type
))
{
it
=
cache
.
erase
(
it
);
else
}
else
{
++
it
;
}
}
wr
.
dec_ref
();
...
...
@@ -2089,19 +2185,24 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&... extra) {
if
(
!
detail
::
get_type_info
(
typeid
(
state
),
false
))
{
class_
<
state
>
(
handle
(),
"iterator"
,
pybind11
::
module_local
())
.
def
(
"__iter__"
,
[](
state
&
s
)
->
state
&
{
return
s
;
})
.
def
(
"__next__"
,
[](
state
&
s
)
->
ValueType
{
if
(
!
s
.
first_or_done
)
++
s
.
it
;
else
s
.
first_or_done
=
false
;
if
(
s
.
it
==
s
.
end
)
{
s
.
first_or_done
=
true
;
throw
stop_iteration
();
}
return
Access
()(
s
.
it
);
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
},
std
::
forward
<
Extra
>
(
extra
)...,
Policy
);
.
def
(
"__iter__"
,
[](
state
&
s
)
->
state
&
{
return
s
;
})
.
def
(
"__next__"
,
[](
state
&
s
)
->
ValueType
{
if
(
!
s
.
first_or_done
)
{
++
s
.
it
;
}
else
{
s
.
first_or_done
=
false
;
}
if
(
s
.
it
==
s
.
end
)
{
s
.
first_or_done
=
true
;
throw
stop_iteration
();
}
return
Access
()(
s
.
it
);
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
},
std
::
forward
<
Extra
>
(
extra
)...,
Policy
);
}
return
cast
(
state
{
first
,
last
,
true
});
...
...
@@ -2187,23 +2288,27 @@ template <typename InputType, typename OutputType> void implicitly_convertible()
};
auto
implicit_caster
=
[](
PyObject
*
obj
,
PyTypeObject
*
type
)
->
PyObject
*
{
static
bool
currently_used
=
false
;
if
(
currently_used
)
// implicit conversions are non-reentrant
if
(
currently_used
)
{
// implicit conversions are non-reentrant
return
nullptr
;
}
set_flag
flag_helper
(
currently_used
);
if
(
!
detail
::
make_caster
<
InputType
>
().
load
(
obj
,
false
))
if
(
!
detail
::
make_caster
<
InputType
>
().
load
(
obj
,
false
))
{
return
nullptr
;
}
tuple
args
(
1
);
args
[
0
]
=
obj
;
PyObject
*
result
=
PyObject_Call
((
PyObject
*
)
type
,
args
.
ptr
(),
nullptr
);
if
(
result
==
nullptr
)
if
(
result
==
nullptr
)
{
PyErr_Clear
();
}
return
result
;
};
if
(
auto
tinfo
=
detail
::
get_type_info
(
typeid
(
OutputType
)))
if
(
auto
tinfo
=
detail
::
get_type_info
(
typeid
(
OutputType
)))
{
tinfo
->
implicit_conversions
.
push_back
(
implicit_caster
);
else
}
else
{
pybind11_fail
(
"implicitly_convertible: Unable to find type "
+
type_id
<
OutputType
>
());
}
}
...
...
@@ -2239,9 +2344,11 @@ public:
std
::
string
full_name
=
scope
.
attr
(
"__name__"
).
cast
<
std
::
string
>
()
+
std
::
string
(
"."
)
+
name
;
m_ptr
=
PyErr_NewException
(
const_cast
<
char
*>
(
full_name
.
c_str
()),
base
.
ptr
(),
NULL
);
if
(
hasattr
(
scope
,
"__dict__"
)
&&
scope
.
attr
(
"__dict__"
).
contains
(
name
))
if
(
hasattr
(
scope
,
"__dict__"
)
&&
scope
.
attr
(
"__dict__"
).
contains
(
name
))
{
pybind11_fail
(
"Error during initialization: multiple incompatible "
"definitions with name
\"
"
+
std
::
string
(
name
)
+
"
\"
"
);
"definitions with name
\"
"
+
std
::
string
(
name
)
+
"
\"
"
);
}
scope
.
attr
(
name
)
=
*
this
;
}
...
...
@@ -2265,13 +2372,17 @@ exception<CppException> ®ister_exception_impl(handle scope,
handle
base
,
bool
isLocal
)
{
auto
&
ex
=
detail
::
get_exception_object
<
CppException
>
();
if
(
!
ex
)
ex
=
exception
<
CppException
>
(
scope
,
name
,
base
);
if
(
!
ex
)
{
ex
=
exception
<
CppException
>
(
scope
,
name
,
base
);
}
auto
register_func
=
isLocal
?
&
register_local_exception_translator
:
&
register_exception_translator
;
register_func
([](
std
::
exception_ptr
p
)
{
if
(
!
p
)
return
;
if
(
!
p
)
{
return
;
}
try
{
std
::
rethrow_exception
(
p
);
}
catch
(
const
CppException
&
e
)
{
...
...
@@ -2339,8 +2450,9 @@ PYBIND11_NOINLINE void print(const tuple &args, const dict &kwargs) {
write
(
line
);
write
(
kwargs
.
contains
(
"end"
)
?
kwargs
[
"end"
]
:
cast
(
"
\n
"
));
if
(
kwargs
.
contains
(
"flush"
)
&&
kwargs
[
"flush"
].
cast
<
bool
>
())
if
(
kwargs
.
contains
(
"flush"
)
&&
kwargs
[
"flush"
].
cast
<
bool
>
())
{
file
.
attr
(
"flush"
)();
}
}
PYBIND11_NAMESPACE_END
(
detail
)
...
...
@@ -2363,16 +2475,18 @@ error_already_set::~error_already_set() {
PYBIND11_NAMESPACE_BEGIN
(
detail
)
inline
function
get_type_override
(
const
void
*
this_ptr
,
const
type_info
*
this_type
,
const
char
*
name
)
{
handle
self
=
get_object_handle
(
this_ptr
,
this_type
);
if
(
!
self
)
if
(
!
self
)
{
return
function
();
}
handle
type
=
type
::
handle_of
(
self
);
auto
key
=
std
::
make_pair
(
type
.
ptr
(),
name
);
/* Cache functions that aren't overridden in Python to avoid
many costly Python dictionary lookups below */
auto
&
cache
=
get_internals
().
inactive_override_cache
;
if
(
cache
.
find
(
key
)
!=
cache
.
end
())
if
(
cache
.
find
(
key
)
!=
cache
.
end
())
{
return
function
();
}
function
override
=
getattr
(
self
,
name
,
function
());
if
(
override
.
is_cpp_function
())
{
...
...
include/pybind11/pytypes.h
View file @
ddbc74c6
...
...
@@ -242,7 +242,11 @@ class object : public handle {
public
:
object
()
=
default
;
PYBIND11_DEPRECATED
(
"Use reinterpret_borrow<object>() or reinterpret_steal<object>()"
)
object
(
handle
h
,
bool
is_borrowed
)
:
handle
(
h
)
{
if
(
is_borrowed
)
inc_ref
();
}
object
(
handle
h
,
bool
is_borrowed
)
:
handle
(
h
)
{
if
(
is_borrowed
)
{
inc_ref
();
}
}
/// Copy constructor; always increases the reference count
object
(
const
object
&
o
)
:
handle
(
o
)
{
inc_ref
();
}
/// Move constructor; steals the object from ``other`` and preserves its reference count
...
...
@@ -458,8 +462,9 @@ template <> inline bool isinstance<object>(handle obj) { return obj.ptr() != nul
/// Return true if ``obj`` is an instance of the ``type``.
inline
bool
isinstance
(
handle
obj
,
handle
type
)
{
const
auto
result
=
PyObject_IsInstance
(
obj
.
ptr
(),
type
.
ptr
());
if
(
result
==
-
1
)
if
(
result
==
-
1
)
{
throw
error_already_set
();
}
return
result
!=
0
;
}
...
...
@@ -529,12 +534,13 @@ PYBIND11_NAMESPACE_BEGIN(detail)
inline
handle
get_function
(
handle
value
)
{
if
(
value
)
{
#if PY_MAJOR_VERSION >= 3
if
(
PyInstanceMethod_Check
(
value
.
ptr
()))
if
(
PyInstanceMethod_Check
(
value
.
ptr
()))
{
value
=
PyInstanceMethod_GET_FUNCTION
(
value
.
ptr
());
else
}
else
#endif
if
(
PyMethod_Check
(
value
.
ptr
()))
if
(
PyMethod_Check
(
value
.
ptr
()))
{
value
=
PyMethod_GET_FUNCTION
(
value
.
ptr
());
}
}
return
value
;
}
...
...
@@ -1076,14 +1082,18 @@ public:
template
<
typename
SzType
,
detail
::
enable_if_t
<
std
::
is_integral
<
SzType
>::
value
,
int
>
=
0
>
str
(
const
char
*
c
,
const
SzType
&
n
)
:
object
(
PyUnicode_FromStringAndSize
(
c
,
ssize_t_cast
(
n
)),
stolen_t
{})
{
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate string object!"
);
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate string object!"
);
}
}
// 'explicit' is explicitly omitted from the following constructors to allow implicit conversion to py::str from C++ string-like objects
// NOLINTNEXTLINE(google-explicit-constructor)
str
(
const
char
*
c
=
""
)
:
object
(
PyUnicode_FromString
(
c
),
stolen_t
{})
{
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate string object!"
);
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate string object!"
);
}
}
// NOLINTNEXTLINE(google-explicit-constructor)
...
...
@@ -1109,20 +1119,26 @@ public:
Return a string representation of the object. This is analogous to
the ``str()`` function in Python.
\endrst */
explicit
str
(
handle
h
)
:
object
(
raw_str
(
h
.
ptr
()),
stolen_t
{})
{
if
(
!
m_ptr
)
throw
error_already_set
();
}
explicit
str
(
handle
h
)
:
object
(
raw_str
(
h
.
ptr
()),
stolen_t
{})
{
if
(
!
m_ptr
)
{
throw
error_already_set
();
}
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator
std
::
string
()
const
{
object
temp
=
*
this
;
if
(
PyUnicode_Check
(
m_ptr
))
{
temp
=
reinterpret_steal
<
object
>
(
PyUnicode_AsUTF8String
(
m_ptr
));
if
(
!
temp
)
if
(
!
temp
)
{
throw
error_already_set
();
}
}
char
*
buffer
=
nullptr
;
ssize_t
length
=
0
;
if
(
PYBIND11_BYTES_AS_STRING_AND_SIZE
(
temp
.
ptr
(),
&
buffer
,
&
length
))
if
(
PYBIND11_BYTES_AS_STRING_AND_SIZE
(
temp
.
ptr
(),
&
buffer
,
&
length
))
{
pybind11_fail
(
"Unable to extract string contents! (invalid type)"
);
}
return
std
::
string
(
buffer
,
(
size_t
)
length
);
}
...
...
@@ -1162,13 +1178,17 @@ public:
// NOLINTNEXTLINE(google-explicit-constructor)
bytes
(
const
char
*
c
=
""
)
:
object
(
PYBIND11_BYTES_FROM_STRING
(
c
),
stolen_t
{})
{
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate bytes object!"
);
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate bytes object!"
);
}
}
template
<
typename
SzType
,
detail
::
enable_if_t
<
std
::
is_integral
<
SzType
>::
value
,
int
>
=
0
>
bytes
(
const
char
*
c
,
const
SzType
&
n
)
:
object
(
PYBIND11_BYTES_FROM_STRING_AND_SIZE
(
c
,
ssize_t_cast
(
n
)),
stolen_t
{})
{
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate bytes object!"
);
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate bytes object!"
);
}
}
// Allow implicit conversion:
...
...
@@ -1181,8 +1201,9 @@ public:
operator
std
::
string
()
const
{
char
*
buffer
=
nullptr
;
ssize_t
length
=
0
;
if
(
PYBIND11_BYTES_AS_STRING_AND_SIZE
(
m_ptr
,
&
buffer
,
&
length
))
if
(
PYBIND11_BYTES_AS_STRING_AND_SIZE
(
m_ptr
,
&
buffer
,
&
length
))
{
pybind11_fail
(
"Unable to extract bytes contents!"
);
}
return
std
::
string
(
buffer
,
(
size_t
)
length
);
}
...
...
@@ -1199,8 +1220,9 @@ public:
operator
std
::
string_view
()
const
{
char
*
buffer
=
nullptr
;
ssize_t
length
=
0
;
if
(
PYBIND11_BYTES_AS_STRING_AND_SIZE
(
m_ptr
,
&
buffer
,
&
length
))
if
(
PYBIND11_BYTES_AS_STRING_AND_SIZE
(
m_ptr
,
&
buffer
,
&
length
))
{
pybind11_fail
(
"Unable to extract bytes contents!"
);
}
return
{
buffer
,
static_cast
<
size_t
>
(
length
)};
}
#endif
...
...
@@ -1214,27 +1236,32 @@ inline bytes::bytes(const pybind11::str &s) {
object
temp
=
s
;
if
(
PyUnicode_Check
(
s
.
ptr
()))
{
temp
=
reinterpret_steal
<
object
>
(
PyUnicode_AsUTF8String
(
s
.
ptr
()));
if
(
!
temp
)
if
(
!
temp
)
{
pybind11_fail
(
"Unable to extract string contents! (encoding issue)"
);
}
}
char
*
buffer
=
nullptr
;
ssize_t
length
=
0
;
if
(
PYBIND11_BYTES_AS_STRING_AND_SIZE
(
temp
.
ptr
(),
&
buffer
,
&
length
))
if
(
PYBIND11_BYTES_AS_STRING_AND_SIZE
(
temp
.
ptr
(),
&
buffer
,
&
length
))
{
pybind11_fail
(
"Unable to extract string contents! (invalid type)"
);
}
auto
obj
=
reinterpret_steal
<
object
>
(
PYBIND11_BYTES_FROM_STRING_AND_SIZE
(
buffer
,
length
));
if
(
!
obj
)
if
(
!
obj
)
{
pybind11_fail
(
"Could not allocate bytes object!"
);
}
m_ptr
=
obj
.
release
().
ptr
();
}
inline
str
::
str
(
const
bytes
&
b
)
{
char
*
buffer
=
nullptr
;
ssize_t
length
=
0
;
if
(
PYBIND11_BYTES_AS_STRING_AND_SIZE
(
b
.
ptr
(),
&
buffer
,
&
length
))
if
(
PYBIND11_BYTES_AS_STRING_AND_SIZE
(
b
.
ptr
(),
&
buffer
,
&
length
))
{
pybind11_fail
(
"Unable to extract bytes contents!"
);
}
auto
obj
=
reinterpret_steal
<
object
>
(
PyUnicode_FromStringAndSize
(
buffer
,
length
));
if
(
!
obj
)
if
(
!
obj
)
{
pybind11_fail
(
"Could not allocate string object!"
);
}
m_ptr
=
obj
.
release
().
ptr
();
}
...
...
@@ -1247,7 +1274,9 @@ public:
template
<
typename
SzType
,
detail
::
enable_if_t
<
std
::
is_integral
<
SzType
>::
value
,
int
>
=
0
>
bytearray
(
const
char
*
c
,
const
SzType
&
n
)
:
object
(
PyByteArray_FromStringAndSize
(
c
,
ssize_t_cast
(
n
)),
stolen_t
{})
{
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate bytearray object!"
);
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate bytearray object!"
);
}
}
bytearray
()
...
...
@@ -1295,7 +1324,9 @@ private:
/// Return the truth value of an object -- always returns a new reference
static
PyObject
*
raw_bool
(
PyObject
*
op
)
{
const
auto
value
=
PyObject_IsTrue
(
op
);
if
(
value
==
-
1
)
return
nullptr
;
if
(
value
==
-
1
)
{
return
nullptr
;
}
return
handle
(
value
!=
0
?
Py_True
:
Py_False
).
inc_ref
().
ptr
();
}
};
...
...
@@ -1330,17 +1361,21 @@ public:
// NOLINTNEXTLINE(google-explicit-constructor)
int_
(
T
value
)
{
if
(
PYBIND11_SILENCE_MSVC_C4127
(
sizeof
(
T
)
<=
sizeof
(
long
)))
{
if
(
std
::
is_signed
<
T
>::
value
)
if
(
std
::
is_signed
<
T
>::
value
)
{
m_ptr
=
PyLong_FromLong
((
long
)
value
);
else
}
else
{
m_ptr
=
PyLong_FromUnsignedLong
((
unsigned
long
)
value
);
}
}
else
{
if
(
std
::
is_signed
<
T
>::
value
)
if
(
std
::
is_signed
<
T
>::
value
)
{
m_ptr
=
PyLong_FromLongLong
((
long
long
)
value
);
else
}
else
{
m_ptr
=
PyLong_FromUnsignedLongLong
((
unsigned
long
long
)
value
);
}
}
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate int object!"
);
}
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate int object!"
);
}
template
<
typename
T
,
...
...
@@ -1361,11 +1396,15 @@ public:
// Allow implicit conversion from float/double:
// NOLINTNEXTLINE(google-explicit-constructor)
float_
(
float
value
)
:
object
(
PyFloat_FromDouble
((
double
)
value
),
stolen_t
{})
{
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate float object!"
);
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate float object!"
);
}
}
// NOLINTNEXTLINE(google-explicit-constructor)
float_
(
double
value
=
.
0
)
:
object
(
PyFloat_FromDouble
((
double
)
value
),
stolen_t
{})
{
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate float object!"
);
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate float object!"
);
}
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator
float
()
const
{
return
(
float
)
PyFloat_AsDouble
(
m_ptr
);
}
...
...
@@ -1378,7 +1417,9 @@ public:
PYBIND11_OBJECT_CVT_DEFAULT
(
weakref
,
object
,
PyWeakref_Check
,
raw_weakref
)
explicit
weakref
(
handle
obj
,
handle
callback
=
{})
:
object
(
PyWeakref_NewRef
(
obj
.
ptr
(),
callback
.
ptr
()),
stolen_t
{})
{
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate weak reference!"
);
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate weak reference!"
);
}
}
private
:
...
...
@@ -1392,8 +1433,9 @@ public:
PYBIND11_OBJECT_DEFAULT
(
slice
,
object
,
PySlice_Check
)
slice
(
handle
start
,
handle
stop
,
handle
step
)
{
m_ptr
=
PySlice_New
(
start
.
ptr
(),
stop
.
ptr
(),
step
.
ptr
());
if
(
!
m_ptr
)
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate slice object!"
);
}
}
#ifdef PYBIND11_HAS_OPTIONAL
...
...
@@ -1434,15 +1476,17 @@ public:
explicit
capsule
(
const
void
*
value
,
const
char
*
name
=
nullptr
,
void
(
*
destructor
)(
PyObject
*
)
=
nullptr
)
:
object
(
PyCapsule_New
(
const_cast
<
void
*>
(
value
),
name
,
destructor
),
stolen_t
{})
{
if
(
!
m_ptr
)
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate capsule object!"
);
}
}
PYBIND11_DEPRECATED
(
"Please pass a destructor that takes a void pointer as input"
)
capsule
(
const
void
*
value
,
void
(
*
destruct
)(
PyObject
*
))
:
object
(
PyCapsule_New
(
const_cast
<
void
*>
(
value
),
nullptr
,
destruct
),
stolen_t
{})
{
if
(
!
m_ptr
)
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate capsule object!"
);
}
}
capsule
(
const
void
*
value
,
void
(
*
destructor
)(
void
*
))
{
...
...
@@ -1452,11 +1496,13 @@ public:
destructor
(
ptr
);
});
if
(
!
m_ptr
)
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate capsule object!"
);
}
if
(
PyCapsule_SetContext
(
m_ptr
,
(
void
*
)
destructor
)
!=
0
)
if
(
PyCapsule_SetContext
(
m_ptr
,
(
void
*
)
destructor
)
!=
0
)
{
pybind11_fail
(
"Could not set capsule context!"
);
}
}
explicit
capsule
(
void
(
*
destructor
)())
{
...
...
@@ -1465,8 +1511,9 @@ public:
destructor
();
});
if
(
!
m_ptr
)
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate capsule object!"
);
}
}
// NOLINTNEXTLINE(google-explicit-constructor)
...
...
@@ -1504,7 +1551,9 @@ public:
detail
::
enable_if_t
<
std
::
is_integral
<
SzType
>::
value
,
int
>
=
0
>
// Some compilers generate link errors when using `const SzType &` here:
explicit
tuple
(
SzType
size
=
0
)
:
object
(
PyTuple_New
(
ssize_t_cast
(
size
)),
stolen_t
{})
{
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate tuple object!"
);
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate tuple object!"
);
}
}
size_t
size
()
const
{
return
(
size_t
)
PyTuple_Size
(
m_ptr
);
}
bool
empty
()
const
{
return
size
()
==
0
;
}
...
...
@@ -1527,7 +1576,9 @@ class dict : public object {
public
:
PYBIND11_OBJECT_CVT
(
dict
,
object
,
PyDict_Check
,
raw_dict
)
dict
()
:
object
(
PyDict_New
(),
stolen_t
{})
{
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate dict object!"
);
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate dict object!"
);
}
}
template
<
typename
...
Args
,
typename
=
detail
::
enable_if_t
<
args_are_all_keyword_or_ds
<
Args
...
>
()
>
,
...
...
@@ -1547,8 +1598,9 @@ public:
private
:
/// Call the `dict` Python type -- always returns a new reference
static
PyObject
*
raw_dict
(
PyObject
*
op
)
{
if
(
PyDict_Check
(
op
))
if
(
PyDict_Check
(
op
))
{
return
handle
(
op
).
inc_ref
().
ptr
();
}
return
PyObject_CallFunctionObjArgs
((
PyObject
*
)
&
PyDict_Type
,
op
,
nullptr
);
}
};
...
...
@@ -1558,8 +1610,9 @@ public:
PYBIND11_OBJECT_DEFAULT
(
sequence
,
object
,
PySequence_Check
)
size_t
size
()
const
{
ssize_t
result
=
PySequence_Size
(
m_ptr
);
if
(
result
==
-
1
)
if
(
result
==
-
1
)
{
throw
error_already_set
();
}
return
(
size_t
)
result
;
}
bool
empty
()
const
{
return
size
()
==
0
;
}
...
...
@@ -1576,7 +1629,9 @@ public:
detail
::
enable_if_t
<
std
::
is_integral
<
SzType
>::
value
,
int
>
=
0
>
// Some compilers generate link errors when using `const SzType &` here:
explicit
list
(
SzType
size
=
0
)
:
object
(
PyList_New
(
ssize_t_cast
(
size
)),
stolen_t
{})
{
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate list object!"
);
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate list object!"
);
}
}
size_t
size
()
const
{
return
(
size_t
)
PyList_Size
(
m_ptr
);
}
bool
empty
()
const
{
return
size
()
==
0
;
}
...
...
@@ -1603,7 +1658,9 @@ class set : public object {
public
:
PYBIND11_OBJECT_CVT
(
set
,
object
,
PySet_Check
,
PySet_New
)
set
()
:
object
(
PySet_New
(
nullptr
),
stolen_t
{})
{
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate set object!"
);
if
(
!
m_ptr
)
{
pybind11_fail
(
"Could not allocate set object!"
);
}
}
size_t
size
()
const
{
return
(
size_t
)
PySet_Size
(
m_ptr
);
}
bool
empty
()
const
{
return
size
()
==
0
;
}
...
...
@@ -1621,8 +1678,9 @@ public:
PYBIND11_OBJECT_DEFAULT
(
function
,
object
,
PyCallable_Check
)
handle
cpp_function
()
const
{
handle
fun
=
detail
::
get_function
(
m_ptr
);
if
(
fun
&&
PyCFunction_Check
(
fun
.
ptr
()))
if
(
fun
&&
PyCFunction_Check
(
fun
.
ptr
()))
{
return
fun
;
}
return
handle
();
}
bool
is_cpp_function
()
const
{
return
(
bool
)
cpp_function
();
}
...
...
@@ -1639,7 +1697,9 @@ public:
buffer_info
request
(
bool
writable
=
false
)
const
{
int
flags
=
PyBUF_STRIDES
|
PyBUF_FORMAT
;
if
(
writable
)
flags
|=
PyBUF_WRITABLE
;
if
(
writable
)
{
flags
|=
PyBUF_WRITABLE
;
}
auto
*
view
=
new
Py_buffer
();
if
(
PyObject_GetBuffer
(
m_ptr
,
view
,
flags
)
!=
0
)
{
delete
view
;
...
...
@@ -1663,14 +1723,16 @@ public:
use ``memoryview(const object& obj)`` instead of this constructor.
\endrst */
explicit
memoryview
(
const
buffer_info
&
info
)
{
if
(
!
info
.
view
())
if
(
!
info
.
view
())
{
pybind11_fail
(
"Prohibited to create memoryview without Py_buffer"
);
}
// Note: PyMemoryView_FromBuffer never increments obj reference.
m_ptr
=
(
info
.
view
()
->
obj
)
?
PyMemoryView_FromObject
(
info
.
view
()
->
obj
)
:
PyMemoryView_FromBuffer
(
info
.
view
());
if
(
!
m_ptr
)
if
(
!
m_ptr
)
{
pybind11_fail
(
"Unable to create memoryview from buffer descriptor"
);
}
}
/** \rst
...
...
@@ -1744,8 +1806,9 @@ public:
PyObject
*
ptr
=
PyMemoryView_FromMemory
(
reinterpret_cast
<
char
*>
(
mem
),
size
,
(
readonly
)
?
PyBUF_READ
:
PyBUF_WRITE
);
if
(
!
ptr
)
if
(
!
ptr
)
{
pybind11_fail
(
"Could not allocate memoryview object!"
);
}
return
memoryview
(
object
(
ptr
,
stolen_t
{}));
}
...
...
@@ -1768,11 +1831,13 @@ inline memoryview memoryview::from_buffer(
detail
::
any_container
<
ssize_t
>
shape
,
detail
::
any_container
<
ssize_t
>
strides
,
bool
readonly
)
{
size_t
ndim
=
shape
->
size
();
if
(
ndim
!=
strides
->
size
())
if
(
ndim
!=
strides
->
size
())
{
pybind11_fail
(
"memoryview: shape length doesn't match strides length"
);
}
ssize_t
size
=
ndim
!=
0u
?
1
:
0
;
for
(
size_t
i
=
0
;
i
<
ndim
;
++
i
)
for
(
size_t
i
=
0
;
i
<
ndim
;
++
i
)
{
size
*=
(
*
shape
)[
i
];
}
Py_buffer
view
;
view
.
buf
=
ptr
;
view
.
obj
=
nullptr
;
...
...
@@ -1786,8 +1851,9 @@ inline memoryview memoryview::from_buffer(
view
.
suboffsets
=
nullptr
;
view
.
internal
=
nullptr
;
PyObject
*
obj
=
PyMemoryView_FromBuffer
(
&
view
);
if
(
!
obj
)
if
(
!
obj
)
{
throw
error_already_set
();
}
return
memoryview
(
object
(
obj
,
stolen_t
{}));
}
/// @endcond
...
...
@@ -1799,8 +1865,9 @@ inline memoryview memoryview::from_buffer(
/// Get the length of a Python object.
inline
size_t
len
(
handle
h
)
{
ssize_t
result
=
PyObject_Length
(
h
.
ptr
());
if
(
result
<
0
)
if
(
result
<
0
)
{
throw
error_already_set
();
}
return
(
size_t
)
result
;
}
...
...
@@ -1823,7 +1890,9 @@ inline size_t len_hint(handle h) {
inline
str
repr
(
handle
h
)
{
PyObject
*
str_value
=
PyObject_Repr
(
h
.
ptr
());
if
(
!
str_value
)
throw
error_already_set
();
if
(
!
str_value
)
{
throw
error_already_set
();
}
#if PY_MAJOR_VERSION < 3
PyObject
*
unicode
=
PyUnicode_FromEncodedObject
(
str_value
,
"utf-8"
,
nullptr
);
Py_XDECREF
(
str_value
);
str_value
=
unicode
;
...
...
@@ -1873,8 +1942,9 @@ handle object_api<D>::get_type() const { return type::handle_of(derived()); }
template
<
typename
D
>
bool
object_api
<
D
>::
rich_compare
(
object_api
const
&
other
,
int
value
)
const
{
int
rv
=
PyObject_RichCompareBool
(
derived
().
ptr
(),
other
.
derived
().
ptr
(),
value
);
if
(
rv
==
-
1
)
if
(
rv
==
-
1
)
{
throw
error_already_set
();
}
return
rv
==
1
;
}
...
...
include/pybind11/stl.h
View file @
ddbc74c6
...
...
@@ -52,14 +52,16 @@ template <typename Type, typename Key> struct set_caster {
using
key_conv
=
make_caster
<
Key
>
;
bool
load
(
handle
src
,
bool
convert
)
{
if
(
!
isinstance
<
pybind11
::
set
>
(
src
))
if
(
!
isinstance
<
pybind11
::
set
>
(
src
))
{
return
false
;
}
auto
s
=
reinterpret_borrow
<
pybind11
::
set
>
(
src
);
value
.
clear
();
for
(
auto
entry
:
s
)
{
key_conv
conv
;
if
(
!
conv
.
load
(
entry
,
convert
))
if
(
!
conv
.
load
(
entry
,
convert
))
{
return
false
;
}
value
.
insert
(
cast_op
<
Key
&&>
(
std
::
move
(
conv
)));
}
return
true
;
...
...
@@ -67,13 +69,15 @@ template <typename Type, typename Key> struct set_caster {
template
<
typename
T
>
static
handle
cast
(
T
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
!
std
::
is_lvalue_reference
<
T
>::
value
)
if
(
!
std
::
is_lvalue_reference
<
T
>::
value
)
{
policy
=
return_value_policy_override
<
Key
>::
policy
(
policy
);
}
pybind11
::
set
s
;
for
(
auto
&&
value
:
src
)
{
auto
value_
=
reinterpret_steal
<
object
>
(
key_conv
::
cast
(
forward_like
<
T
>
(
value
),
policy
,
parent
));
if
(
!
value_
||
!
s
.
add
(
value_
))
if
(
!
value_
||
!
s
.
add
(
value_
))
{
return
handle
();
}
}
return
s
.
release
();
}
...
...
@@ -86,16 +90,17 @@ template <typename Type, typename Key, typename Value> struct map_caster {
using
value_conv
=
make_caster
<
Value
>
;
bool
load
(
handle
src
,
bool
convert
)
{
if
(
!
isinstance
<
dict
>
(
src
))
if
(
!
isinstance
<
dict
>
(
src
))
{
return
false
;
}
auto
d
=
reinterpret_borrow
<
dict
>
(
src
);
value
.
clear
();
for
(
auto
it
:
d
)
{
key_conv
kconv
;
value_conv
vconv
;
if
(
!
kconv
.
load
(
it
.
first
.
ptr
(),
convert
)
||
!
vconv
.
load
(
it
.
second
.
ptr
(),
convert
))
if
(
!
kconv
.
load
(
it
.
first
.
ptr
(),
convert
)
||
!
vconv
.
load
(
it
.
second
.
ptr
(),
convert
))
{
return
false
;
}
value
.
emplace
(
cast_op
<
Key
&&>
(
std
::
move
(
kconv
)),
cast_op
<
Value
&&>
(
std
::
move
(
vconv
)));
}
return
true
;
...
...
@@ -113,8 +118,9 @@ template <typename Type, typename Key, typename Value> struct map_caster {
for
(
auto
&&
kv
:
src
)
{
auto
key
=
reinterpret_steal
<
object
>
(
key_conv
::
cast
(
forward_like
<
T
>
(
kv
.
first
),
policy_key
,
parent
));
auto
value
=
reinterpret_steal
<
object
>
(
value_conv
::
cast
(
forward_like
<
T
>
(
kv
.
second
),
policy_value
,
parent
));
if
(
!
key
||
!
value
)
if
(
!
key
||
!
value
)
{
return
handle
();
}
d
[
key
]
=
value
;
}
return
d
.
release
();
...
...
@@ -127,15 +133,17 @@ template <typename Type, typename Value> struct list_caster {
using
value_conv
=
make_caster
<
Value
>
;
bool
load
(
handle
src
,
bool
convert
)
{
if
(
!
isinstance
<
sequence
>
(
src
)
||
isinstance
<
bytes
>
(
src
)
||
isinstance
<
str
>
(
src
))
if
(
!
isinstance
<
sequence
>
(
src
)
||
isinstance
<
bytes
>
(
src
)
||
isinstance
<
str
>
(
src
))
{
return
false
;
}
auto
s
=
reinterpret_borrow
<
sequence
>
(
src
);
value
.
clear
();
reserve_maybe
(
s
,
&
value
);
for
(
auto
it
:
s
)
{
value_conv
conv
;
if
(
!
conv
.
load
(
it
,
convert
))
if
(
!
conv
.
load
(
it
,
convert
))
{
return
false
;
}
value
.
push_back
(
cast_op
<
Value
&&>
(
std
::
move
(
conv
)));
}
return
true
;
...
...
@@ -153,14 +161,16 @@ private:
public
:
template
<
typename
T
>
static
handle
cast
(
T
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
!
std
::
is_lvalue_reference
<
T
>::
value
)
if
(
!
std
::
is_lvalue_reference
<
T
>::
value
)
{
policy
=
return_value_policy_override
<
Value
>::
policy
(
policy
);
}
list
l
(
src
.
size
());
ssize_t
index
=
0
;
for
(
auto
&&
value
:
src
)
{
auto
value_
=
reinterpret_steal
<
object
>
(
value_conv
::
cast
(
forward_like
<
T
>
(
value
),
policy
,
parent
));
if
(
!
value_
)
if
(
!
value_
)
{
return
handle
();
}
PyList_SET_ITEM
(
l
.
ptr
(),
index
++
,
value_
.
release
().
ptr
());
// steals a reference
}
return
l
.
release
();
...
...
@@ -184,8 +194,9 @@ template <typename ArrayType, typename Value, bool Resizable, size_t Size = 0> s
private
:
template
<
bool
R
=
Resizable
>
bool
require_size
(
enable_if_t
<
R
,
size_t
>
size
)
{
if
(
value
.
size
()
!=
size
)
if
(
value
.
size
()
!=
size
)
{
value
.
resize
(
size
);
}
return
true
;
}
template
<
bool
R
=
Resizable
>
...
...
@@ -195,16 +206,19 @@ private:
public
:
bool
load
(
handle
src
,
bool
convert
)
{
if
(
!
isinstance
<
sequence
>
(
src
))
if
(
!
isinstance
<
sequence
>
(
src
))
{
return
false
;
}
auto
l
=
reinterpret_borrow
<
sequence
>
(
src
);
if
(
!
require_size
(
l
.
size
()))
if
(
!
require_size
(
l
.
size
()))
{
return
false
;
}
size_t
ctr
=
0
;
for
(
auto
it
:
l
)
{
value_conv
conv
;
if
(
!
conv
.
load
(
it
,
convert
))
if
(
!
conv
.
load
(
it
,
convert
))
{
return
false
;
}
value
[
ctr
++
]
=
cast_op
<
Value
&&>
(
std
::
move
(
conv
));
}
return
true
;
...
...
@@ -216,8 +230,9 @@ public:
ssize_t
index
=
0
;
for
(
auto
&&
value
:
src
)
{
auto
value_
=
reinterpret_steal
<
object
>
(
value_conv
::
cast
(
forward_like
<
T
>
(
value
),
policy
,
parent
));
if
(
!
value_
)
if
(
!
value_
)
{
return
handle
();
}
PyList_SET_ITEM
(
l
.
ptr
(),
index
++
,
value_
.
release
().
ptr
());
// steals a reference
}
return
l
.
release
();
...
...
@@ -250,8 +265,9 @@ template<typename Type, typename Value = typename Type::value_type> struct optio
template
<
typename
T
>
static
handle
cast
(
T
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
!
src
)
if
(
!
src
)
{
return
none
().
inc_ref
();
}
if
(
!
std
::
is_lvalue_reference
<
T
>::
value
)
{
policy
=
return_value_policy_override
<
Value
>::
policy
(
policy
);
}
...
...
@@ -266,8 +282,9 @@ template<typename Type, typename Value = typename Type::value_type> struct optio
return
true
;
// default-constructed value is already empty
}
value_conv
inner_caster
;
if
(
!
inner_caster
.
load
(
src
,
convert
))
if
(
!
inner_caster
.
load
(
src
,
convert
))
{
return
false
;
}
value
.
emplace
(
cast_op
<
Value
&&>
(
std
::
move
(
inner_caster
)));
return
true
;
...
...
@@ -341,8 +358,9 @@ struct variant_caster<V<Ts...>> {
// E.g. `py::int_(1).cast<variant<double, int>>()` needs to fill the `int`
// slot of the variant. Without two-pass loading `double` would be filled
// because it appears first and a conversion is possible.
if
(
convert
&&
load_alternative
(
src
,
false
,
type_list
<
Ts
...
>
{}))
if
(
convert
&&
load_alternative
(
src
,
false
,
type_list
<
Ts
...
>
{}))
{
return
true
;
}
return
load_alternative
(
src
,
convert
,
type_list
<
Ts
...
>
{});
}
...
...
include/pybind11/stl_bind.h
View file @
ddbc74c6
...
...
@@ -87,10 +87,11 @@ void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_>
cl
.
def
(
"remove"
,
[](
Vector
&
v
,
const
T
&
x
)
{
auto
p
=
std
::
find
(
v
.
begin
(),
v
.
end
(),
x
);
if
(
p
!=
v
.
end
())
if
(
p
!=
v
.
end
())
{
v
.
erase
(
p
);
else
}
else
{
throw
value_error
();
}
},
arg
(
"x"
),
"Remove the first item from the list whose value is x. "
...
...
@@ -116,10 +117,12 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
using
DiffType
=
typename
Vector
::
difference_type
;
auto
wrap_i
=
[](
DiffType
i
,
SizeType
n
)
{
if
(
i
<
0
)
if
(
i
<
0
)
{
i
+=
n
;
if
(
i
<
0
||
(
SizeType
)
i
>=
n
)
}
if
(
i
<
0
||
(
SizeType
)
i
>=
n
)
{
throw
index_error
();
}
return
i
;
};
...
...
@@ -131,8 +134,9 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
cl
.
def
(
init
([](
const
iterable
&
it
)
{
auto
v
=
std
::
unique_ptr
<
Vector
>
(
new
Vector
());
v
->
reserve
(
len_hint
(
it
));
for
(
handle
h
:
it
)
for
(
handle
h
:
it
)
{
v
->
push_back
(
h
.
cast
<
T
>
());
}
return
v
.
release
();
}));
...
...
@@ -177,26 +181,29 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
cl
.
def
(
"insert"
,
[](
Vector
&
v
,
DiffType
i
,
const
T
&
x
)
{
// Can't use wrap_i; i == v.size() is OK
if
(
i
<
0
)
if
(
i
<
0
)
{
i
+=
v
.
size
();
if
(
i
<
0
||
(
SizeType
)
i
>
v
.
size
())
}
if
(
i
<
0
||
(
SizeType
)
i
>
v
.
size
())
{
throw
index_error
();
}
v
.
insert
(
v
.
begin
()
+
i
,
x
);
},
arg
(
"i"
)
,
arg
(
"x"
),
"Insert an item at a given position."
);
cl
.
def
(
"pop"
,
cl
.
def
(
"pop"
,
[](
Vector
&
v
)
{
if
(
v
.
empty
())
if
(
v
.
empty
())
{
throw
index_error
();
}
T
t
=
std
::
move
(
v
.
back
());
v
.
pop_back
();
return
t
;
},
"Remove and return the last item"
);
"Remove and return the last item"
);
cl
.
def
(
"pop"
,
[
wrap_i
](
Vector
&
v
,
DiffType
i
)
{
...
...
@@ -222,8 +229,9 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
[](
const
Vector
&
v
,
slice
slice
)
->
Vector
*
{
size_t
start
=
0
,
stop
=
0
,
step
=
0
,
slicelength
=
0
;
if
(
!
slice
.
compute
(
v
.
size
(),
&
start
,
&
stop
,
&
step
,
&
slicelength
))
if
(
!
slice
.
compute
(
v
.
size
(),
&
start
,
&
stop
,
&
step
,
&
slicelength
))
{
throw
error_already_set
();
}
auto
*
seq
=
new
Vector
();
seq
->
reserve
((
size_t
)
slicelength
);
...
...
@@ -241,11 +249,14 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
"__setitem__"
,
[](
Vector
&
v
,
slice
slice
,
const
Vector
&
value
)
{
size_t
start
=
0
,
stop
=
0
,
step
=
0
,
slicelength
=
0
;
if
(
!
slice
.
compute
(
v
.
size
(),
&
start
,
&
stop
,
&
step
,
&
slicelength
))
if
(
!
slice
.
compute
(
v
.
size
(),
&
start
,
&
stop
,
&
step
,
&
slicelength
))
{
throw
error_already_set
();
}
if
(
slicelength
!=
value
.
size
())
throw
std
::
runtime_error
(
"Left and right hand size of slice assignment have different sizes!"
);
if
(
slicelength
!=
value
.
size
())
{
throw
std
::
runtime_error
(
"Left and right hand size of slice assignment have different sizes!"
);
}
for
(
size_t
i
=
0
;
i
<
slicelength
;
++
i
)
{
v
[
start
]
=
value
[
i
];
...
...
@@ -267,8 +278,9 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
[](
Vector
&
v
,
slice
slice
)
{
size_t
start
=
0
,
stop
=
0
,
step
=
0
,
slicelength
=
0
;
if
(
!
slice
.
compute
(
v
.
size
(),
&
start
,
&
stop
,
&
step
,
&
slicelength
))
if
(
!
slice
.
compute
(
v
.
size
(),
&
start
,
&
stop
,
&
step
,
&
slicelength
))
{
throw
error_already_set
();
}
if
(
step
==
1
&&
false
)
{
v
.
erase
(
v
.
begin
()
+
(
DiffType
)
start
,
v
.
begin
()
+
DiffType
(
start
+
slicelength
));
...
...
@@ -296,10 +308,12 @@ void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl)
using
ItType
=
typename
Vector
::
iterator
;
auto
wrap_i
=
[](
DiffType
i
,
SizeType
n
)
{
if
(
i
<
0
)
if
(
i
<
0
)
{
i
+=
n
;
if
(
i
<
0
||
(
SizeType
)
i
>=
n
)
}
if
(
i
<
0
||
(
SizeType
)
i
>=
n
)
{
throw
index_error
();
}
return
i
;
};
...
...
@@ -328,15 +342,15 @@ void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl)
using
SizeType
=
typename
Vector
::
size_type
;
using
DiffType
=
typename
Vector
::
difference_type
;
using
ItType
=
typename
Vector
::
iterator
;
cl
.
def
(
"__getitem__"
,
[](
const
Vector
&
v
,
DiffType
i
)
->
T
{
if
(
i
<
0
&&
(
i
+=
v
.
size
())
<
0
)
throw
index_error
();
if
((
SizeType
)
i
>=
v
.
size
())
throw
index_error
();
return
v
[(
SizeType
)
i
];
cl
.
def
(
"__getitem__"
,
[](
const
Vector
&
v
,
DiffType
i
)
->
T
{
if
(
i
<
0
&&
(
i
+=
v
.
size
())
<
0
)
{
throw
index_error
();
}
);
if
((
SizeType
)
i
>=
v
.
size
())
{
throw
index_error
();
}
return
v
[(
SizeType
)
i
];
});
cl
.
def
(
"__iter__"
,
[](
Vector
&
v
)
{
...
...
@@ -358,8 +372,9 @@ template <typename Vector, typename Class_> auto vector_if_insertion_operator(Cl
s
<<
name
<<
'['
;
for
(
size_type
i
=
0
;
i
<
v
.
size
();
++
i
)
{
s
<<
v
[
i
];
if
(
i
!=
v
.
size
()
-
1
)
if
(
i
!=
v
.
size
()
-
1
)
{
s
<<
", "
;
}
}
s
<<
']'
;
return
s
.
str
();
...
...
@@ -402,10 +417,14 @@ void vector_buffer_impl(Class_& cl, std::true_type) {
cl
.
def
(
init
([](
const
buffer
&
buf
)
{
auto
info
=
buf
.
request
();
if
(
info
.
ndim
!=
1
||
info
.
strides
[
0
]
%
static_cast
<
ssize_t
>
(
sizeof
(
T
)))
if
(
info
.
ndim
!=
1
||
info
.
strides
[
0
]
%
static_cast
<
ssize_t
>
(
sizeof
(
T
)))
{
throw
type_error
(
"Only valid 1D buffers can be copied to a vector"
);
if
(
!
detail
::
compare_buffer_info
<
T
>::
compare
(
info
)
||
(
ssize_t
)
sizeof
(
T
)
!=
info
.
itemsize
)
throw
type_error
(
"Format mismatch (Python: "
+
info
.
format
+
" C++: "
+
format_descriptor
<
T
>::
format
()
+
")"
);
}
if
(
!
detail
::
compare_buffer_info
<
T
>::
compare
(
info
)
||
(
ssize_t
)
sizeof
(
T
)
!=
info
.
itemsize
)
{
throw
type_error
(
"Format mismatch (Python: "
+
info
.
format
+
" C++: "
+
format_descriptor
<
T
>::
format
()
+
")"
);
}
T
*
p
=
static_cast
<
T
*>
(
info
.
ptr
);
ssize_t
step
=
info
.
strides
[
0
]
/
static_cast
<
ssize_t
>
(
sizeof
(
T
));
...
...
@@ -415,8 +434,9 @@ void vector_buffer_impl(Class_& cl, std::true_type) {
}
Vector
vec
;
vec
.
reserve
((
size_t
)
info
.
shape
[
0
]);
for
(;
p
!=
end
;
p
+=
step
)
for
(;
p
!=
end
;
p
+=
step
)
{
vec
.
push_back
(
*
p
);
}
return
vec
;
}));
...
...
@@ -545,8 +565,11 @@ void map_assignment(enable_if_t<is_copy_assignable<typename Map::mapped_type>::v
cl
.
def
(
"__setitem__"
,
[](
Map
&
m
,
const
KeyType
&
k
,
const
MappedType
&
v
)
{
auto
it
=
m
.
find
(
k
);
if
(
it
!=
m
.
end
())
it
->
second
=
v
;
else
m
.
emplace
(
k
,
v
);
if
(
it
!=
m
.
end
())
{
it
->
second
=
v
;
}
else
{
m
.
emplace
(
k
,
v
);
}
}
);
}
...
...
@@ -583,8 +606,9 @@ template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &
s
<<
name
<<
'{'
;
bool
f
=
false
;
for
(
auto
const
&
kv
:
m
)
{
if
(
f
)
if
(
f
)
{
s
<<
", "
;
}
s
<<
kv
.
first
<<
": "
<<
kv
.
second
;
f
=
true
;
}
...
...
@@ -675,8 +699,9 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&.
cl
.
def
(
"__getitem__"
,
[](
Map
&
m
,
const
KeyType
&
k
)
->
MappedType
&
{
auto
it
=
m
.
find
(
k
);
if
(
it
==
m
.
end
())
throw
key_error
();
if
(
it
==
m
.
end
())
{
throw
key_error
();
}
return
it
->
second
;
},
return_value_policy
::
reference_internal
// ref + keepalive
...
...
@@ -685,8 +710,9 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&.
cl
.
def
(
"__contains__"
,
[](
Map
&
m
,
const
KeyType
&
k
)
->
bool
{
auto
it
=
m
.
find
(
k
);
if
(
it
==
m
.
end
())
return
false
;
if
(
it
==
m
.
end
())
{
return
false
;
}
return
true
;
}
);
...
...
@@ -699,8 +725,9 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&.
cl
.
def
(
"__delitem__"
,
[](
Map
&
m
,
const
KeyType
&
k
)
{
auto
it
=
m
.
find
(
k
);
if
(
it
==
m
.
end
())
if
(
it
==
m
.
end
())
{
throw
key_error
();
}
m
.
erase
(
it
);
}
);
...
...
@@ -717,8 +744,9 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&.
keys_view
.
def
(
"__contains__"
,
[](
KeysView
&
view
,
const
KeyType
&
k
)
->
bool
{
auto
it
=
view
.
map
.
find
(
k
);
if
(
it
==
view
.
map
.
end
())
if
(
it
==
view
.
map
.
end
())
{
return
false
;
}
return
true
;
}
);
...
...
tests/constructor_stats.h
View file @
ddbc74c6
...
...
@@ -101,10 +101,11 @@ public:
}
void
destroyed
(
void
*
inst
)
{
if
(
--
_instances
[
inst
]
<
0
)
if
(
--
_instances
[
inst
]
<
0
)
{
throw
std
::
runtime_error
(
"cstats.destroyed() called with unknown "
"instance; potential double-destruction "
"or a missing cstats.created()"
);
}
}
static
void
gc
()
{
...
...
@@ -127,9 +128,11 @@ public:
int
alive
()
{
gc
();
int
total
=
0
;
for
(
const
auto
&
p
:
_instances
)
if
(
p
.
second
>
0
)
for
(
const
auto
&
p
:
_instances
)
{
if
(
p
.
second
>
0
)
{
total
+=
p
.
second
;
}
}
return
total
;
}
...
...
@@ -145,7 +148,9 @@ public:
// Move out stored values
py
::
list
values
()
{
py
::
list
l
;
for
(
const
auto
&
v
:
_values
)
l
.
append
(
py
::
cast
(
v
));
for
(
const
auto
&
v
:
_values
)
{
l
.
append
(
py
::
cast
(
v
));
}
_values
.
clear
();
return
l
;
}
...
...
@@ -181,7 +186,9 @@ public:
}
}
catch
(
const
std
::
out_of_range
&
)
{}
if
(
!
t1
)
throw
std
::
runtime_error
(
"Unknown class passed to ConstructorStats::get()"
);
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
// has more constructions (typically one or the other will be 0)
...
...
@@ -189,7 +196,9 @@ public:
auto
&
cs2
=
get
(
*
t2
);
int
cs1_total
=
cs1
.
default_constructions
+
cs1
.
copy_constructions
+
cs1
.
move_constructions
+
(
int
)
cs1
.
_values
.
size
();
int
cs2_total
=
cs2
.
default_constructions
+
cs2
.
copy_constructions
+
cs2
.
move_constructions
+
(
int
)
cs2
.
_values
.
size
();
if
(
cs2_total
>
cs1_total
)
return
cs2
;
if
(
cs2_total
>
cs1_total
)
{
return
cs2
;
}
}
return
cs1
;
}
...
...
tests/object.h
View file @
ddbc74c6
...
...
@@ -27,10 +27,11 @@ public:
*/
void
decRef
(
bool
dealloc
=
true
)
const
{
--
m_refCount
;
if
(
m_refCount
==
0
&&
dealloc
)
if
(
m_refCount
==
0
&&
dealloc
)
{
delete
this
;
else
if
(
m_refCount
<
0
)
}
else
if
(
m_refCount
<
0
)
{
throw
std
::
runtime_error
(
"Internal error: reference count < 0!"
);
}
}
virtual
std
::
string
toString
()
const
=
0
;
...
...
@@ -66,7 +67,9 @@ public:
/// Construct a reference from a pointer
explicit
ref
(
T
*
ptr
)
:
m_ptr
(
ptr
)
{
if
(
m_ptr
)
((
Object
*
)
m_ptr
)
->
incRef
();
if
(
m_ptr
)
{
((
Object
*
)
m_ptr
)
->
incRef
();
}
print_created
(
this
,
"from pointer"
,
m_ptr
);
track_created
((
ref_tag
*
)
this
,
"from pointer"
);
...
...
@@ -74,8 +77,9 @@ public:
/// Copy constructor
ref
(
const
ref
&
r
)
:
m_ptr
(
r
.
m_ptr
)
{
if
(
m_ptr
)
if
(
m_ptr
)
{
((
Object
*
)
m_ptr
)
->
incRef
();
}
print_copy_created
(
this
,
"with pointer"
,
m_ptr
);
track_copy_created
((
ref_tag
*
)
this
);
}
...
...
@@ -89,8 +93,9 @@ public:
/// Destroy this reference
~
ref
()
{
if
(
m_ptr
)
if
(
m_ptr
)
{
((
Object
*
)
m_ptr
)
->
decRef
();
}
print_destroyed
(
this
);
track_destroyed
((
ref_tag
*
)
this
);
}
...
...
@@ -99,10 +104,12 @@ public:
ref
&
operator
=
(
ref
&&
r
)
noexcept
{
print_move_assigned
(
this
,
"pointer"
,
r
.
m_ptr
);
track_move_assigned
((
ref_tag
*
)
this
);
if
(
*
this
==
r
)
if
(
*
this
==
r
)
{
return
*
this
;
if
(
m_ptr
)
}
if
(
m_ptr
)
{
((
Object
*
)
m_ptr
)
->
decRef
();
}
m_ptr
=
r
.
m_ptr
;
r
.
m_ptr
=
nullptr
;
return
*
this
;
...
...
@@ -116,13 +123,16 @@ public:
print_copy_assigned
(
this
,
"pointer"
,
r
.
m_ptr
);
track_copy_assigned
((
ref_tag
*
)
this
);
if
(
m_ptr
==
r
.
m_ptr
)
if
(
m_ptr
==
r
.
m_ptr
)
{
return
*
this
;
if
(
m_ptr
)
}
if
(
m_ptr
)
{
((
Object
*
)
m_ptr
)
->
decRef
();
}
m_ptr
=
r
.
m_ptr
;
if
(
m_ptr
)
if
(
m_ptr
)
{
((
Object
*
)
m_ptr
)
->
incRef
();
}
return
*
this
;
}
...
...
@@ -130,13 +140,16 @@ public:
ref
&
operator
=
(
T
*
ptr
)
{
print_values
(
this
,
"assigned pointer"
);
track_values
((
ref_tag
*
)
this
,
"assigned pointer"
);
if
(
m_ptr
==
ptr
)
if
(
m_ptr
==
ptr
)
{
return
*
this
;
if
(
m_ptr
)
}
if
(
m_ptr
)
{
((
Object
*
)
m_ptr
)
->
decRef
();
}
m_ptr
=
ptr
;
if
(
m_ptr
)
if
(
m_ptr
)
{
((
Object
*
)
m_ptr
)
->
incRef
();
}
return
*
this
;
}
...
...
tests/pybind11_cross_module_tests.cpp
View file @
ddbc74c6
...
...
@@ -39,7 +39,9 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
m
.
def
(
"throw_local_simple_error"
,
[]()
{
throw
LocalSimpleException
(
"external mod"
);
});
py
::
register_exception_translator
([](
std
::
exception_ptr
p
)
{
try
{
if
(
p
)
std
::
rethrow_exception
(
p
);
if
(
p
)
{
std
::
rethrow_exception
(
p
);
}
}
catch
(
const
shared_exception
&
e
)
{
PyErr_SetString
(
PyExc_KeyError
,
e
.
what
());
}
...
...
tests/pybind11_tests.cpp
View file @
ddbc74c6
...
...
@@ -86,6 +86,7 @@ PYBIND11_MODULE(pybind11_tests, m) {
.
def
(
py
::
init
<
int
>
())
.
def
(
"__repr__"
,
[](
const
IncType
&
u
)
{
return
"IncType({})"
_s
.
format
(
u
.
value
());
});
for
(
const
auto
&
initializer
:
initializers
())
for
(
const
auto
&
initializer
:
initializers
())
{
initializer
(
m
);
}
}
tests/test_buffers.cpp
View file @
ddbc74c6
...
...
@@ -85,8 +85,9 @@ TEST_SUBMODULE(buffers, m) {
/// Construct from a buffer
.
def
(
py
::
init
([](
const
py
::
buffer
&
b
)
{
py
::
buffer_info
info
=
b
.
request
();
if
(
info
.
format
!=
py
::
format_descriptor
<
float
>::
format
()
||
info
.
ndim
!=
2
)
if
(
info
.
format
!=
py
::
format_descriptor
<
float
>::
format
()
||
info
.
ndim
!=
2
)
{
throw
std
::
runtime_error
(
"Incompatible buffer format!"
);
}
auto
v
=
new
Matrix
(
info
.
shape
[
0
],
info
.
shape
[
1
]);
memcpy
(
v
->
data
(),
info
.
ptr
,
sizeof
(
float
)
*
(
size_t
)
(
v
->
rows
()
*
v
->
cols
()));
...
...
@@ -99,14 +100,16 @@ TEST_SUBMODULE(buffers, m) {
/// Bare bones interface
.
def
(
"__getitem__"
,
[](
const
Matrix
&
m
,
std
::
pair
<
py
::
ssize_t
,
py
::
ssize_t
>
i
)
{
if
(
i
.
first
>=
m
.
rows
()
||
i
.
second
>=
m
.
cols
())
if
(
i
.
first
>=
m
.
rows
()
||
i
.
second
>=
m
.
cols
())
{
throw
py
::
index_error
();
}
return
m
(
i
.
first
,
i
.
second
);
})
.
def
(
"__setitem__"
,
[](
Matrix
&
m
,
std
::
pair
<
py
::
ssize_t
,
py
::
ssize_t
>
i
,
float
v
)
{
if
(
i
.
first
>=
m
.
rows
()
||
i
.
second
>=
m
.
cols
())
if
(
i
.
first
>=
m
.
rows
()
||
i
.
second
>=
m
.
cols
())
{
throw
py
::
index_error
();
}
m
(
i
.
first
,
i
.
second
)
=
v
;
})
/// Provide buffer access
...
...
tests/test_builtin_casters.cpp
View file @
ddbc74c6
...
...
@@ -93,8 +93,11 @@ TEST_SUBMODULE(builtin_casters, m) {
#if PY_MAJOR_VERSION >= 3
// Under Python 2.7, invalid unicode UTF-32 characters don't appear to trigger UnicodeDecodeError
m
.
def
(
"bad_utf32_string"
,
[
=
]()
{
return
std
::
u32string
({
a32
,
char32_t
(
0xd800
),
z32
});
});
if
(
PYBIND11_SILENCE_MSVC_C4127
(
sizeof
(
wchar_t
)
==
2
))
m
.
def
(
"bad_wchar_string"
,
[
=
]()
{
return
std
::
wstring
({
wchar_t
(
0x61
),
wchar_t
(
0xd800
)
});
});
if
(
PYBIND11_SILENCE_MSVC_C4127
(
sizeof
(
wchar_t
)
==
2
))
{
m
.
def
(
"bad_wchar_string"
,
[
=
]()
{
return
std
::
wstring
({
wchar_t
(
0x61
),
wchar_t
(
0xd800
)});
});
}
#endif
m
.
def
(
"u8_Z"
,
[]()
->
char
{
return
'Z'
;
});
m
.
def
(
"u8_eacute"
,
[]()
->
char
{
return
'\xe9'
;
});
...
...
@@ -133,9 +136,21 @@ TEST_SUBMODULE(builtin_casters, m) {
m
.
def
(
"string_view_print"
,
[](
std
::
string_view
s
)
{
py
::
print
(
s
,
s
.
size
());
});
m
.
def
(
"string_view16_print"
,
[](
std
::
u16string_view
s
)
{
py
::
print
(
s
,
s
.
size
());
});
m
.
def
(
"string_view32_print"
,
[](
std
::
u32string_view
s
)
{
py
::
print
(
s
,
s
.
size
());
});
m
.
def
(
"string_view_chars"
,
[](
std
::
string_view
s
)
{
py
::
list
l
;
for
(
auto
c
:
s
)
l
.
append
((
std
::
uint8_t
)
c
);
return
l
;
});
m
.
def
(
"string_view16_chars"
,
[](
std
::
u16string_view
s
)
{
py
::
list
l
;
for
(
auto
c
:
s
)
l
.
append
((
int
)
c
);
return
l
;
});
m
.
def
(
"string_view32_chars"
,
[](
std
::
u32string_view
s
)
{
py
::
list
l
;
for
(
auto
c
:
s
)
l
.
append
((
int
)
c
);
return
l
;
});
m
.
def
(
"string_view_chars"
,
[](
std
::
string_view
s
)
{
py
::
list
l
;
for
(
auto
c
:
s
)
{
l
.
append
((
std
::
uint8_t
)
c
);
}
return
l
;
});
m
.
def
(
"string_view16_chars"
,
[](
std
::
u16string_view
s
)
{
py
::
list
l
;
for
(
auto
c
:
s
)
{
l
.
append
((
int
)
c
);
}
return
l
;
});
m
.
def
(
"string_view32_chars"
,
[](
std
::
u32string_view
s
)
{
py
::
list
l
;
for
(
auto
c
:
s
)
{
l
.
append
((
int
)
c
);
}
return
l
;
});
m
.
def
(
"string_view_return"
,
[]()
{
return
std
::
string_view
((
const
char
*
)
u8"utf8 secret \U0001f382"
);
});
m
.
def
(
"string_view16_return"
,
[]()
{
return
std
::
u16string_view
(
u"utf16 secret \U0001f382"
);
});
m
.
def
(
"string_view32_return"
,
[]()
{
return
std
::
u32string_view
(
U"utf32 secret \U0001f382"
);
});
...
...
tests/test_call_policies.cpp
View file @
ddbc74c6
...
...
@@ -95,8 +95,9 @@ TEST_SUBMODULE(call_policies, m) {
// but it's unclear how to test it without `PyGILState_GetThisThreadState`.
auto
report_gil_status
=
[]()
{
auto
is_gil_held
=
false
;
if
(
auto
tstate
=
py
::
detail
::
get_thread_state_unchecked
())
if
(
auto
tstate
=
py
::
detail
::
get_thread_state_unchecked
())
{
is_gil_held
=
(
tstate
==
PyGILState_GetThisThreadState
());
}
return
is_gil_held
?
"GIL held"
:
"GIL released"
;
};
...
...
tests/test_callbacks.cpp
View file @
ddbc74c6
...
...
@@ -136,11 +136,16 @@ TEST_SUBMODULE(callbacks, m) {
m
.
def
(
"dummy_function_overloaded"
,
[](
int
i
,
int
j
)
{
return
i
+
j
;
});
m
.
def
(
"dummy_function_overloaded"
,
&
dummy_function
);
m
.
def
(
"dummy_function2"
,
[](
int
i
,
int
j
)
{
return
i
+
j
;
});
m
.
def
(
"roundtrip"
,
[](
std
::
function
<
int
(
int
)
>
f
,
bool
expect_none
=
false
)
{
if
(
expect_none
&&
f
)
throw
std
::
runtime_error
(
"Expected None to be converted to empty std::function"
);
return
f
;
},
py
::
arg
(
"f"
),
py
::
arg
(
"expect_none"
)
=
false
);
m
.
def
(
"roundtrip"
,
[](
std
::
function
<
int
(
int
)
>
f
,
bool
expect_none
=
false
)
{
if
(
expect_none
&&
f
)
{
throw
std
::
runtime_error
(
"Expected None to be converted to empty std::function"
);
}
return
f
;
},
py
::
arg
(
"f"
),
py
::
arg
(
"expect_none"
)
=
false
);
m
.
def
(
"test_dummy_function"
,
[](
const
std
::
function
<
int
(
int
)
>
&
f
)
->
std
::
string
{
using
fn_type
=
int
(
*
)(
int
);
auto
result
=
f
.
target
<
fn_type
>
();
...
...
@@ -215,8 +220,9 @@ TEST_SUBMODULE(callbacks, m) {
};
// spawn worker threads
for
(
auto
i
:
work
)
for
(
auto
i
:
work
)
{
start_f
(
py
::
cast
<
int
>
(
i
));
}
});
m
.
def
(
"callback_num_times"
,
[](
const
py
::
function
&
f
,
std
::
size_t
num
)
{
...
...
tests/test_class.cpp
View file @
ddbc74c6
...
...
@@ -139,9 +139,13 @@ TEST_SUBMODULE(class_, m) {
m
.
def
(
"return_class_1"
,
[]()
->
BaseClass
*
{
return
new
DerivedClass1
();
});
m
.
def
(
"return_class_2"
,
[]()
->
BaseClass
*
{
return
new
DerivedClass2
();
});
m
.
def
(
"return_class_n"
,
[](
int
n
)
->
BaseClass
*
{
if
(
n
==
1
)
return
new
DerivedClass1
();
if
(
n
==
2
)
return
new
DerivedClass2
();
m
.
def
(
"return_class_n"
,
[](
int
n
)
->
BaseClass
*
{
if
(
n
==
1
)
{
return
new
DerivedClass1
();
}
if
(
n
==
2
)
{
return
new
DerivedClass2
();
}
return
new
BaseClass
();
});
m
.
def
(
"return_none"
,
[]()
->
BaseClass
*
{
return
nullptr
;
});
...
...
@@ -167,8 +171,9 @@ TEST_SUBMODULE(class_, m) {
// See https://github.com/pybind/pybind11/issues/2486
// if (category == 2)
// return py::type::of<int>();
if
(
category
==
1
)
if
(
category
==
1
)
{
return
py
::
type
::
of
<
DerivedClass1
>
();
}
return
py
::
type
::
of
<
Invalid
>
();
});
...
...
tests/test_copy_move.cpp
View file @
ddbc74c6
...
...
@@ -104,7 +104,9 @@ public:
bool
load
(
handle
src
,
bool
)
{
value
=
CopyOnlyInt
(
src
.
cast
<
int
>
());
return
true
;
}
static
handle
cast
(
const
CopyOnlyInt
&
m
,
return_value_policy
r
,
handle
p
)
{
return
pybind11
::
cast
(
m
.
value
,
r
,
p
);
}
static
handle
cast
(
const
CopyOnlyInt
*
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
!
src
)
return
none
().
release
();
if
(
!
src
)
{
return
none
().
release
();
}
return
cast
(
*
src
,
policy
,
parent
);
}
explicit
operator
CopyOnlyInt
*
()
{
return
&
value
;
}
...
...
@@ -203,8 +205,9 @@ TEST_SUBMODULE(copy_move_policies, m) {
private
:
void
*
operator
new
(
size_t
bytes
)
{
void
*
ptr
=
std
::
malloc
(
bytes
);
if
(
ptr
)
if
(
ptr
)
{
return
ptr
;
}
throw
std
::
bad_alloc
{};
}
};
...
...
tests/test_eigen.cpp
View file @
ddbc74c6
...
...
@@ -28,8 +28,11 @@ using MatrixXdR = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::R
// Sets/resets a testing reference matrix to have values of 10*r + c, where r and c are the
// (1-based) row/column number.
template
<
typename
M
>
void
reset_ref
(
M
&
x
)
{
for
(
int
i
=
0
;
i
<
x
.
rows
();
i
++
)
for
(
int
j
=
0
;
j
<
x
.
cols
();
j
++
)
x
(
i
,
j
)
=
11
+
10
*
i
+
j
;
for
(
int
i
=
0
;
i
<
x
.
rows
();
i
++
)
{
for
(
int
j
=
0
;
j
<
x
.
cols
();
j
++
)
{
x
(
i
,
j
)
=
11
+
10
*
i
+
j
;
}
}
}
// Returns a static, column-major matrix
...
...
@@ -63,9 +66,11 @@ double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); };
// reference is referencing rows/columns correctly).
template
<
typename
MatrixArgType
>
Eigen
::
MatrixXd
adjust_matrix
(
MatrixArgType
m
)
{
Eigen
::
MatrixXd
ret
(
m
);
for
(
int
c
=
0
;
c
<
m
.
cols
();
c
++
)
for
(
int
r
=
0
;
r
<
m
.
rows
();
r
++
)
ret
(
r
,
c
)
+=
10
*
r
+
100
*
c
;
// NOLINT(clang-analyzer-core.uninitialized.Assign)
for
(
int
c
=
0
;
c
<
m
.
cols
();
c
++
)
{
for
(
int
r
=
0
;
r
<
m
.
rows
();
r
++
)
{
ret
(
r
,
c
)
+=
10
*
r
+
100
*
c
;
// NOLINT(clang-analyzer-core.uninitialized.Assign)
}
}
return
ret
;
}
...
...
@@ -225,7 +230,9 @@ TEST_SUBMODULE(eigen, m) {
// Returns a DiagonalMatrix with diagonal (1,2,3,...)
m
.
def
(
"incr_diag"
,
[](
int
k
)
{
Eigen
::
DiagonalMatrix
<
int
,
Eigen
::
Dynamic
>
m
(
k
);
for
(
int
i
=
0
;
i
<
k
;
i
++
)
m
.
diagonal
()[
i
]
=
i
+
1
;
for
(
int
i
=
0
;
i
<
k
;
i
++
)
{
m
.
diagonal
()[
i
]
=
i
+
1
;
}
return
m
;
});
...
...
@@ -320,8 +327,9 @@ TEST_SUBMODULE(eigen, m) {
"matrix_multiply"
,
[](
const
py
::
EigenDRef
<
const
Eigen
::
MatrixXd
>
&
A
,
const
py
::
EigenDRef
<
const
Eigen
::
MatrixXd
>
&
B
)
->
Eigen
::
MatrixXd
{
if
(
A
.
cols
()
!=
B
.
rows
())
if
(
A
.
cols
()
!=
B
.
rows
())
{
throw
std
::
domain_error
(
"Nonconformable matrices!"
);
}
return
A
*
B
;
},
py
::
arg
(
"A"
),
...
...
tests/test_embed/test_interpreter.cpp
View file @
ddbc74c6
...
...
@@ -307,7 +307,11 @@ TEST_CASE("Threads") {
struct
scope_exit
{
std
::
function
<
void
()
>
f_
;
explicit
scope_exit
(
std
::
function
<
void
()
>
f
)
noexcept
:
f_
(
std
::
move
(
f
))
{}
~
scope_exit
()
{
if
(
f_
)
f_
();
}
~
scope_exit
()
{
if
(
f_
)
{
f_
();
}
}
};
TEST_CASE
(
"Reload module from file"
)
{
...
...
tests/test_eval.cpp
View file @
ddbc74c6
...
...
@@ -93,8 +93,9 @@ TEST_SUBMODULE(eval_, m) {
// test_eval_empty_globals
m
.
def
(
"eval_empty_globals"
,
[](
py
::
object
global
)
{
if
(
global
.
is_none
())
if
(
global
.
is_none
())
{
global
=
py
::
dict
();
}
auto
int_class
=
py
::
eval
(
"isinstance(42, int)"
,
global
);
return
global
;
});
...
...
tests/test_exceptions.cpp
View file @
ddbc74c6
...
...
@@ -116,7 +116,9 @@ TEST_SUBMODULE(exceptions, m) {
static
py
::
exception
<
MyException
>
ex
(
m
,
"MyException"
);
py
::
register_exception_translator
([](
std
::
exception_ptr
p
)
{
try
{
if
(
p
)
std
::
rethrow_exception
(
p
);
if
(
p
)
{
std
::
rethrow_exception
(
p
);
}
}
catch
(
const
MyException
&
e
)
{
// Set MyException as the active python error
ex
(
e
.
what
());
...
...
@@ -128,7 +130,9 @@ TEST_SUBMODULE(exceptions, m) {
// never by visible from Python
py
::
register_exception_translator
([](
std
::
exception_ptr
p
)
{
try
{
if
(
p
)
std
::
rethrow_exception
(
p
);
if
(
p
)
{
std
::
rethrow_exception
(
p
);
}
}
catch
(
const
MyException2
&
e
)
{
// Translate this exception to a standard RuntimeError
PyErr_SetString
(
PyExc_RuntimeError
,
e
.
what
());
...
...
@@ -140,7 +144,9 @@ TEST_SUBMODULE(exceptions, m) {
// translator for MyException by throwing a new exception
py
::
register_exception_translator
([](
std
::
exception_ptr
p
)
{
try
{
if
(
p
)
std
::
rethrow_exception
(
p
);
if
(
p
)
{
std
::
rethrow_exception
(
p
);
}
}
catch
(
const
MyException4
&
e
)
{
throw
MyException
(
e
.
what
());
}
...
...
@@ -181,7 +187,9 @@ TEST_SUBMODULE(exceptions, m) {
py
::
object
o
=
foo
[
"bar"
];
}
catch
(
py
::
error_already_set
&
ex
)
{
if
(
!
ex
.
matches
(
PyExc_KeyError
))
throw
;
if
(
!
ex
.
matches
(
PyExc_KeyError
))
{
throw
;
}
return
true
;
}
return
false
;
...
...
@@ -193,7 +201,9 @@ TEST_SUBMODULE(exceptions, m) {
py
::
object
o
=
foo
[
"bar"
];
}
catch
(
py
::
error_already_set
&
ex
)
{
if
(
!
ex
.
matches
(
PyExc_Exception
))
throw
;
if
(
!
ex
.
matches
(
PyExc_Exception
))
{
throw
;
}
return
true
;
}
return
false
;
...
...
@@ -204,15 +214,18 @@ TEST_SUBMODULE(exceptions, m) {
py
::
module_
::
import
(
"nonexistent"
);
}
catch
(
py
::
error_already_set
&
ex
)
{
if
(
!
ex
.
matches
(
PyExc_ImportError
))
throw
;
if
(
!
ex
.
matches
(
PyExc_ImportError
))
{
throw
;
}
return
true
;
}
return
false
;
});
m
.
def
(
"throw_already_set"
,
[](
bool
err
)
{
if
(
err
)
if
(
err
)
{
PyErr_SetString
(
PyExc_ValueError
,
"foo"
);
}
try
{
throw
py
::
error_already_set
();
}
catch
(
const
std
::
runtime_error
&
e
)
{
...
...
@@ -224,8 +237,9 @@ TEST_SUBMODULE(exceptions, m) {
}
}
PyErr_Clear
();
if
(
err
)
if
(
err
)
{
PyErr_SetString
(
PyExc_ValueError
,
"foo"
);
}
throw
py
::
error_already_set
();
});
...
...
@@ -252,10 +266,11 @@ TEST_SUBMODULE(exceptions, m) {
try
{
f
(
*
args
);
}
catch
(
py
::
error_already_set
&
ex
)
{
if
(
ex
.
matches
(
exc_type
))
if
(
ex
.
matches
(
exc_type
))
{
py
::
print
(
ex
.
what
());
else
}
else
{
throw
;
}
}
});
...
...
tests/test_iostream.cpp
View file @
ddbc74c6
...
...
@@ -22,8 +22,9 @@
void
noisy_function
(
const
std
::
string
&
msg
,
bool
flush
)
{
std
::
cout
<<
msg
;
if
(
flush
)
if
(
flush
)
{
std
::
cout
<<
std
::
flush
;
}
}
void
noisy_funct_dual
(
const
std
::
string
&
msg
,
const
std
::
string
&
emsg
)
{
...
...
tests/test_kwargs_and_defaults.cpp
View file @
ddbc74c6
...
...
@@ -26,8 +26,9 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {
std
::
vector
<
int
>
list
{{
13
,
17
}};
m
.
def
(
"kw_func4"
,
[](
const
std
::
vector
<
int
>
&
entries
)
{
std
::
string
ret
=
"{"
;
for
(
int
i
:
entries
)
for
(
int
i
:
entries
)
{
ret
+=
std
::
to_string
(
i
)
+
" "
;
}
ret
.
back
()
=
'}'
;
return
ret
;
},
py
::
arg
(
"myList"
)
=
list
);
...
...
@@ -89,18 +90,20 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {
m
.
def
(
"args_refcount"
,
[](
py
::
args
a
)
{
GC_IF_NEEDED
;
py
::
tuple
t
(
a
.
size
());
for
(
size_t
i
=
0
;
i
<
a
.
size
();
i
++
)
for
(
size_t
i
=
0
;
i
<
a
.
size
();
i
++
)
{
// Use raw Python API here to avoid an extra, intermediate incref on the tuple item:
t
[
i
]
=
(
int
)
Py_REFCNT
(
PyTuple_GET_ITEM
(
a
.
ptr
(),
static_cast
<
py
::
ssize_t
>
(
i
)));
}
return
t
;
});
m
.
def
(
"mixed_args_refcount"
,
[](
const
py
::
object
&
o
,
py
::
args
a
)
{
GC_IF_NEEDED
;
py
::
tuple
t
(
a
.
size
()
+
1
);
t
[
0
]
=
o
.
ref_count
();
for
(
size_t
i
=
0
;
i
<
a
.
size
();
i
++
)
for
(
size_t
i
=
0
;
i
<
a
.
size
();
i
++
)
{
// Use raw Python API here to avoid an extra, intermediate incref on the tuple item:
t
[
i
+
1
]
=
(
int
)
Py_REFCNT
(
PyTuple_GET_ITEM
(
a
.
ptr
(),
static_cast
<
py
::
ssize_t
>
(
i
)));
}
return
t
;
});
...
...
tests/test_local_bindings.cpp
View file @
ddbc74c6
...
...
@@ -47,8 +47,9 @@ TEST_SUBMODULE(local_bindings, m) {
auto
main
=
py
::
module_
::
import
(
"pybind11_tests"
);
if
(
py
::
hasattr
(
main
,
"class_"
))
{
bind_local
<
LocalExternal
,
7
>
(
m
,
"LocalExternal"
,
py
::
module_local
());
}
else
{
throw
std
::
runtime_error
(
"test_class not enabled"
);
}
else
throw
std
::
runtime_error
(
"test_class not enabled"
);
});
// test_stl_bind_local
...
...
tests/test_numpy_array.cpp
View file @
ddbc74c6
...
...
@@ -90,15 +90,17 @@ template<typename... Ix> arr data_t(const arr_t& a, Ix... index) {
template
<
typename
...
Ix
>
arr
&
mutate_data
(
arr
&
a
,
Ix
...
index
)
{
auto
ptr
=
(
uint8_t
*
)
a
.
mutable_data
(
index
...);
for
(
py
::
ssize_t
i
=
0
;
i
<
a
.
nbytes
()
-
a
.
offset_at
(
index
...);
i
++
)
for
(
py
::
ssize_t
i
=
0
;
i
<
a
.
nbytes
()
-
a
.
offset_at
(
index
...);
i
++
)
{
ptr
[
i
]
=
(
uint8_t
)
(
ptr
[
i
]
*
2
);
}
return
a
;
}
template
<
typename
...
Ix
>
arr_t
&
mutate_data_t
(
arr_t
&
a
,
Ix
...
index
)
{
auto
ptr
=
a
.
mutable_data
(
index
...);
for
(
py
::
ssize_t
i
=
0
;
i
<
a
.
size
()
-
a
.
index_at
(
index
...);
i
++
)
for
(
py
::
ssize_t
i
=
0
;
i
<
a
.
size
()
-
a
.
index_at
(
index
...);
i
++
)
{
ptr
[
i
]
++
;
}
return
a
;
}
...
...
@@ -116,7 +118,9 @@ template<typename... Ix> arr_t& mutate_at_t(arr_t& a, Ix... idx) { a.mutable_at(
sm.def(#name, [](type a, int i, int j, int k) { return name(a, i, j, k); });
template
<
typename
T
,
typename
T2
>
py
::
handle
auxiliaries
(
T
&&
r
,
T2
&&
r2
)
{
if
(
r
.
ndim
()
!=
2
)
throw
std
::
domain_error
(
"error: ndim != 2"
);
if
(
r
.
ndim
()
!=
2
)
{
throw
std
::
domain_error
(
"error: ndim != 2"
);
}
py
::
list
l
;
l
.
append
(
*
r
.
data
(
0
,
0
));
l
.
append
(
*
r2
.
mutable_data
(
0
,
0
));
...
...
@@ -292,34 +296,43 @@ TEST_SUBMODULE(numpy_array, sm) {
// test_array_unchecked_fixed_dims
sm
.
def
(
"proxy_add2"
,
[](
py
::
array_t
<
double
>
a
,
double
v
)
{
auto
r
=
a
.
mutable_unchecked
<
2
>
();
for
(
py
::
ssize_t
i
=
0
;
i
<
r
.
shape
(
0
);
i
++
)
for
(
py
::
ssize_t
j
=
0
;
j
<
r
.
shape
(
1
);
j
++
)
for
(
py
::
ssize_t
i
=
0
;
i
<
r
.
shape
(
0
);
i
++
)
{
for
(
py
::
ssize_t
j
=
0
;
j
<
r
.
shape
(
1
);
j
++
)
{
r
(
i
,
j
)
+=
v
;
}
}
},
py
::
arg
{}.
noconvert
(),
py
::
arg
());
sm
.
def
(
"proxy_init3"
,
[](
double
start
)
{
py
::
array_t
<
double
,
py
::
array
::
c_style
>
a
({
3
,
3
,
3
});
auto
r
=
a
.
mutable_unchecked
<
3
>
();
for
(
py
::
ssize_t
i
=
0
;
i
<
r
.
shape
(
0
);
i
++
)
for
(
py
::
ssize_t
j
=
0
;
j
<
r
.
shape
(
1
);
j
++
)
for
(
py
::
ssize_t
k
=
0
;
k
<
r
.
shape
(
2
);
k
++
)
r
(
i
,
j
,
k
)
=
start
++
;
for
(
py
::
ssize_t
i
=
0
;
i
<
r
.
shape
(
0
);
i
++
)
{
for
(
py
::
ssize_t
j
=
0
;
j
<
r
.
shape
(
1
);
j
++
)
{
for
(
py
::
ssize_t
k
=
0
;
k
<
r
.
shape
(
2
);
k
++
)
{
r
(
i
,
j
,
k
)
=
start
++
;
}
}
}
return
a
;
});
sm
.
def
(
"proxy_init3F"
,
[](
double
start
)
{
py
::
array_t
<
double
,
py
::
array
::
f_style
>
a
({
3
,
3
,
3
});
auto
r
=
a
.
mutable_unchecked
<
3
>
();
for
(
py
::
ssize_t
k
=
0
;
k
<
r
.
shape
(
2
);
k
++
)
for
(
py
::
ssize_t
j
=
0
;
j
<
r
.
shape
(
1
);
j
++
)
for
(
py
::
ssize_t
i
=
0
;
i
<
r
.
shape
(
0
);
i
++
)
r
(
i
,
j
,
k
)
=
start
++
;
for
(
py
::
ssize_t
k
=
0
;
k
<
r
.
shape
(
2
);
k
++
)
{
for
(
py
::
ssize_t
j
=
0
;
j
<
r
.
shape
(
1
);
j
++
)
{
for
(
py
::
ssize_t
i
=
0
;
i
<
r
.
shape
(
0
);
i
++
)
{
r
(
i
,
j
,
k
)
=
start
++
;
}
}
}
return
a
;
});
sm
.
def
(
"proxy_squared_L2_norm"
,
[](
const
py
::
array_t
<
double
>
&
a
)
{
auto
r
=
a
.
unchecked
<
1
>
();
double
sumsq
=
0
;
for
(
py
::
ssize_t
i
=
0
;
i
<
r
.
shape
(
0
);
i
++
)
for
(
py
::
ssize_t
i
=
0
;
i
<
r
.
shape
(
0
);
i
++
)
{
sumsq
+=
r
[
i
]
*
r
(
i
);
// Either notation works for a 1D array
}
return
sumsq
;
});
...
...
@@ -345,19 +358,28 @@ TEST_SUBMODULE(numpy_array, sm) {
// Same as the above, but without a compile-time dimensions specification:
sm
.
def
(
"proxy_add2_dyn"
,
[](
py
::
array_t
<
double
>
a
,
double
v
)
{
auto
r
=
a
.
mutable_unchecked
();
if
(
r
.
ndim
()
!=
2
)
throw
std
::
domain_error
(
"error: ndim != 2"
);
for
(
py
::
ssize_t
i
=
0
;
i
<
r
.
shape
(
0
);
i
++
)
for
(
py
::
ssize_t
j
=
0
;
j
<
r
.
shape
(
1
);
j
++
)
if
(
r
.
ndim
()
!=
2
)
{
throw
std
::
domain_error
(
"error: ndim != 2"
);
}
for
(
py
::
ssize_t
i
=
0
;
i
<
r
.
shape
(
0
);
i
++
)
{
for
(
py
::
ssize_t
j
=
0
;
j
<
r
.
shape
(
1
);
j
++
)
{
r
(
i
,
j
)
+=
v
;
}
}
},
py
::
arg
{}.
noconvert
(),
py
::
arg
());
sm
.
def
(
"proxy_init3_dyn"
,
[](
double
start
)
{
py
::
array_t
<
double
,
py
::
array
::
c_style
>
a
({
3
,
3
,
3
});
auto
r
=
a
.
mutable_unchecked
();
if
(
r
.
ndim
()
!=
3
)
throw
std
::
domain_error
(
"error: ndim != 3"
);
for
(
py
::
ssize_t
i
=
0
;
i
<
r
.
shape
(
0
);
i
++
)
for
(
py
::
ssize_t
j
=
0
;
j
<
r
.
shape
(
1
);
j
++
)
for
(
py
::
ssize_t
k
=
0
;
k
<
r
.
shape
(
2
);
k
++
)
r
(
i
,
j
,
k
)
=
start
++
;
if
(
r
.
ndim
()
!=
3
)
{
throw
std
::
domain_error
(
"error: ndim != 3"
);
}
for
(
py
::
ssize_t
i
=
0
;
i
<
r
.
shape
(
0
);
i
++
)
{
for
(
py
::
ssize_t
j
=
0
;
j
<
r
.
shape
(
1
);
j
++
)
{
for
(
py
::
ssize_t
k
=
0
;
k
<
r
.
shape
(
2
);
k
++
)
{
r
(
i
,
j
,
k
)
=
start
++
;
}
}
}
return
a
;
});
sm
.
def
(
"proxy_auxiliaries2_dyn"
,
[](
py
::
array_t
<
double
>
a
)
{
...
...
@@ -386,8 +408,10 @@ TEST_SUBMODULE(numpy_array, sm) {
// reshape array to 2D without changing size
sm
.
def
(
"array_reshape2"
,
[](
py
::
array_t
<
double
>
a
)
{
const
auto
dim_sz
=
(
py
::
ssize_t
)
std
::
sqrt
(
a
.
size
());
if
(
dim_sz
*
dim_sz
!=
a
.
size
())
throw
std
::
domain_error
(
"array_reshape2: input array total size is not a squared integer"
);
if
(
dim_sz
*
dim_sz
!=
a
.
size
())
{
throw
std
::
domain_error
(
"array_reshape2: input array total size is not a squared integer"
);
}
a
.
resize
({
dim_sz
,
dim_sz
});
});
...
...
tests/test_numpy_dtypes.cpp
View file @
ddbc74c6
...
...
@@ -108,30 +108,35 @@ PYBIND11_PACKED(struct EnumStruct {
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
StringStruct
&
v
)
{
os
<<
"a='"
;
for
(
size_t
i
=
0
;
i
<
3
&&
(
v
.
a
[
i
]
!=
0
);
i
++
)
for
(
size_t
i
=
0
;
i
<
3
&&
(
v
.
a
[
i
]
!=
0
);
i
++
)
{
os
<<
v
.
a
[
i
];
}
os
<<
"',b='"
;
for
(
size_t
i
=
0
;
i
<
3
&&
(
v
.
b
[
i
]
!=
0
);
i
++
)
for
(
size_t
i
=
0
;
i
<
3
&&
(
v
.
b
[
i
]
!=
0
);
i
++
)
{
os
<<
v
.
b
[
i
];
}
return
os
<<
"'"
;
}
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
ArrayStruct
&
v
)
{
os
<<
"a={"
;
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
if
(
i
>
0
)
if
(
i
>
0
)
{
os
<<
','
;
}
os
<<
'{'
;
for
(
int
j
=
0
;
j
<
3
;
j
++
)
for
(
int
j
=
0
;
j
<
3
;
j
++
)
{
os
<<
v
.
a
[
i
][
j
]
<<
','
;
}
os
<<
v
.
a
[
i
][
3
]
<<
'}'
;
}
os
<<
"},b={"
<<
v
.
b
[
0
]
<<
','
<<
v
.
b
[
1
];
os
<<
"},c={"
<<
int
(
v
.
c
[
0
])
<<
','
<<
int
(
v
.
c
[
1
])
<<
','
<<
int
(
v
.
c
[
2
]);
os
<<
"},d={"
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
if
(
i
>
0
)
if
(
i
>
0
)
{
os
<<
','
;
}
os
<<
'{'
<<
v
.
d
[
i
][
0
]
<<
','
<<
v
.
d
[
i
][
1
]
<<
'}'
;
}
return
os
<<
'}'
;
...
...
@@ -198,7 +203,9 @@ py::array_t<int32_t, 0> test_array_ctors(int i) {
auto
fill
=
[](
py
::
array
arr
)
{
auto
req
=
arr
.
request
();
for
(
int
i
=
0
;
i
<
6
;
i
++
)
((
int32_t
*
)
req
.
ptr
)[
i
]
=
i
+
1
;
for
(
int
i
=
0
;
i
<
6
;
i
++
)
{
((
int32_t
*
)
req
.
ptr
)[
i
]
=
i
+
1
;
}
return
arr
;
};
...
...
@@ -373,32 +380,33 @@ TEST_SUBMODULE(numpy_dtypes, m) {
m
.
def
(
"print_dtypes"
,
[]()
{
py
::
list
l
;
for
(
const
py
::
handle
&
d
:
{
py
::
dtype
::
of
<
SimpleStruct
>
(),
py
::
dtype
::
of
<
PackedStruct
>
(),
py
::
dtype
::
of
<
NestedStruct
>
(),
py
::
dtype
::
of
<
PartialStruct
>
(),
py
::
dtype
::
of
<
PartialNestedStruct
>
(),
py
::
dtype
::
of
<
StringStruct
>
(),
py
::
dtype
::
of
<
ArrayStruct
>
(),
py
::
dtype
::
of
<
EnumStruct
>
(),
py
::
dtype
::
of
<
StructWithUglyNames
>
(),
py
::
dtype
::
of
<
ComplexStruct
>
()
})
for
(
const
py
::
handle
&
d
:
{
py
::
dtype
::
of
<
SimpleStruct
>
(),
py
::
dtype
::
of
<
PackedStruct
>
(),
py
::
dtype
::
of
<
NestedStruct
>
(),
py
::
dtype
::
of
<
PartialStruct
>
(),
py
::
dtype
::
of
<
PartialNestedStruct
>
(),
py
::
dtype
::
of
<
StringStruct
>
(),
py
::
dtype
::
of
<
ArrayStruct
>
(),
py
::
dtype
::
of
<
EnumStruct
>
(),
py
::
dtype
::
of
<
StructWithUglyNames
>
(),
py
::
dtype
::
of
<
ComplexStruct
>
()})
{
l
.
append
(
py
::
str
(
d
));
}
return
l
;
});
m
.
def
(
"test_dtype_ctors"
,
&
test_dtype_ctors
);
m
.
def
(
"test_dtype_kind"
,
[
dtype_names
]()
{
py
::
list
list
;
for
(
auto
&
dt_name
:
dtype_names
)
for
(
auto
&
dt_name
:
dtype_names
)
{
list
.
append
(
py
::
dtype
(
dt_name
).
kind
());
}
return
list
;
});
m
.
def
(
"test_dtype_char_"
,
[
dtype_names
]()
{
py
::
list
list
;
for
(
auto
&
dt_name
:
dtype_names
)
for
(
auto
&
dt_name
:
dtype_names
)
{
list
.
append
(
py
::
dtype
(
dt_name
).
char_
());
}
return
list
;
});
m
.
def
(
"test_dtype_methods"
,
[]()
{
...
...
@@ -423,8 +431,9 @@ TEST_SUBMODULE(numpy_dtypes, m) {
if
(
non_empty
)
{
auto
req
=
arr
.
request
();
auto
ptr
=
static_cast
<
StringStruct
*>
(
req
.
ptr
);
for
(
py
::
ssize_t
i
=
0
;
i
<
req
.
size
*
req
.
itemsize
;
i
++
)
static_cast
<
char
*>
(
req
.
ptr
)[
i
]
=
0
;
for
(
py
::
ssize_t
i
=
0
;
i
<
req
.
size
*
req
.
itemsize
;
i
++
)
{
static_cast
<
char
*>
(
req
.
ptr
)[
i
]
=
0
;
}
ptr
[
1
].
a
[
0
]
=
'a'
;
ptr
[
1
].
b
[
0
]
=
'a'
;
ptr
[
2
].
a
[
0
]
=
'a'
;
ptr
[
2
].
b
[
0
]
=
'a'
;
ptr
[
3
].
a
[
0
]
=
'a'
;
ptr
[
3
].
b
[
0
]
=
'a'
;
...
...
@@ -443,16 +452,22 @@ TEST_SUBMODULE(numpy_dtypes, m) {
py
::
array_t
<
ArrayStruct
,
0
>
arr
=
mkarray_via_buffer
<
ArrayStruct
>
(
n
);
auto
ptr
=
(
ArrayStruct
*
)
arr
.
mutable_data
();
for
(
size_t
i
=
0
;
i
<
n
;
i
++
)
{
for
(
size_t
j
=
0
;
j
<
3
;
j
++
)
for
(
size_t
k
=
0
;
k
<
4
;
k
++
)
for
(
size_t
j
=
0
;
j
<
3
;
j
++
)
{
for
(
size_t
k
=
0
;
k
<
4
;
k
++
)
{
ptr
[
i
].
a
[
j
][
k
]
=
char
(
'A'
+
(
i
*
100
+
j
*
10
+
k
)
%
26
);
for
(
size_t
j
=
0
;
j
<
2
;
j
++
)
}
}
for
(
size_t
j
=
0
;
j
<
2
;
j
++
)
{
ptr
[
i
].
b
[
j
]
=
int32_t
(
i
*
1000
+
j
);
for
(
size_t
j
=
0
;
j
<
3
;
j
++
)
}
for
(
size_t
j
=
0
;
j
<
3
;
j
++
)
{
ptr
[
i
].
c
[
j
]
=
uint8_t
(
i
*
10
+
j
);
for
(
size_t
j
=
0
;
j
<
4
;
j
++
)
for
(
size_t
k
=
0
;
k
<
2
;
k
++
)
}
for
(
size_t
j
=
0
;
j
<
4
;
j
++
)
{
for
(
size_t
k
=
0
;
k
<
2
;
k
++
)
{
ptr
[
i
].
d
[
j
][
k
]
=
float
(
i
)
*
100.0
f
+
float
(
j
)
*
10.0
f
+
float
(
k
);
}
}
}
return
arr
;
});
...
...
tests/test_opaque_types.cpp
View file @
ddbc74c6
...
...
@@ -45,8 +45,9 @@ TEST_SUBMODULE(opaque_types, m) {
std
::
string
ret
=
"Opaque list: ["
;
bool
first
=
true
;
for
(
const
auto
&
entry
:
l
)
{
if
(
!
first
)
if
(
!
first
)
{
ret
+=
", "
;
}
ret
+=
entry
;
first
=
false
;
}
...
...
tests/test_pickling.cpp
View file @
ddbc74c6
...
...
@@ -39,13 +39,15 @@ void wrap(py::module m) {
.
def
(
py
::
pickle
(
[](
const
py
::
object
&
self
)
{
py
::
dict
d
;
if
(
py
::
hasattr
(
self
,
"__dict__"
))
if
(
py
::
hasattr
(
self
,
"__dict__"
))
{
d
=
self
.
attr
(
"__dict__"
);
}
return
py
::
make_tuple
(
self
.
attr
(
"num"
),
d
);
},
[](
const
py
::
tuple
&
t
)
{
if
(
t
.
size
()
!=
2
)
if
(
t
.
size
()
!=
2
)
{
throw
std
::
runtime_error
(
"Invalid state!"
);
}
auto
cpp_state
=
std
::
unique_ptr
<
SimpleBase
>
(
new
SimpleBaseTrampoline
);
cpp_state
->
num
=
t
[
0
].
cast
<
int
>
();
auto
py_state
=
t
[
1
].
cast
<
py
::
dict
>
();
...
...
@@ -101,8 +103,9 @@ TEST_SUBMODULE(pickling, m) {
});
ignoreOldStyleInitWarnings
([
&
pyPickleable
]()
{
pyPickleable
.
def
(
"__setstate__"
,
[](
Pickleable
&
p
,
const
py
::
tuple
&
t
)
{
if
(
t
.
size
()
!=
3
)
if
(
t
.
size
()
!=
3
)
{
throw
std
::
runtime_error
(
"Invalid state!"
);
}
/* Invoke the constructor (need to use in-place version) */
new
(
&
p
)
Pickleable
(
t
[
0
].
cast
<
std
::
string
>
());
...
...
@@ -119,8 +122,9 @@ TEST_SUBMODULE(pickling, m) {
return
py
::
make_tuple
(
p
.
value
(),
p
.
extra1
(),
p
.
extra2
());
},
[](
const
py
::
tuple
&
t
)
{
if
(
t
.
size
()
!=
3
)
if
(
t
.
size
()
!=
3
)
{
throw
std
::
runtime_error
(
"Invalid state!"
);
}
auto
p
=
PickleableNew
(
t
[
0
].
cast
<
std
::
string
>
());
p
.
setExtra1
(
t
[
1
].
cast
<
int
>
());
...
...
@@ -153,8 +157,9 @@ TEST_SUBMODULE(pickling, m) {
});
ignoreOldStyleInitWarnings
([
&
pyPickleableWithDict
]()
{
pyPickleableWithDict
.
def
(
"__setstate__"
,
[](
const
py
::
object
&
self
,
const
py
::
tuple
&
t
)
{
if
(
t
.
size
()
!=
3
)
if
(
t
.
size
()
!=
3
)
{
throw
std
::
runtime_error
(
"Invalid state!"
);
}
/* Cast and construct */
auto
&
p
=
self
.
cast
<
PickleableWithDict
&>
();
new
(
&
p
)
PickleableWithDict
(
t
[
0
].
cast
<
std
::
string
>
());
...
...
@@ -174,8 +179,9 @@ TEST_SUBMODULE(pickling, m) {
return
py
::
make_tuple
(
self
.
attr
(
"value"
),
self
.
attr
(
"extra"
),
self
.
attr
(
"__dict__"
));
},
[](
const
py
::
tuple
&
t
)
{
if
(
t
.
size
()
!=
3
)
if
(
t
.
size
()
!=
3
)
{
throw
std
::
runtime_error
(
"Invalid state!"
);
}
auto
cpp_state
=
PickleableWithDictNew
(
t
[
0
].
cast
<
std
::
string
>
());
cpp_state
.
extra
=
t
[
1
].
cast
<
int
>
();
...
...
tests/test_pytypes.cpp
View file @
ddbc74c6
...
...
@@ -40,8 +40,9 @@ TEST_SUBMODULE(pytypes, m) {
});
m
.
def
(
"print_list"
,
[](
const
py
::
list
&
list
)
{
int
index
=
0
;
for
(
auto
item
:
list
)
for
(
auto
item
:
list
)
{
py
::
print
(
"list item {}: {}"
_s
.
format
(
index
++
,
item
));
}
});
// test_none
m
.
def
(
"get_none"
,
[]{
return
py
::
none
();});
...
...
@@ -56,8 +57,9 @@ TEST_SUBMODULE(pytypes, m) {
return
set
;
});
m
.
def
(
"print_set"
,
[](
const
py
::
set
&
set
)
{
for
(
auto
item
:
set
)
for
(
auto
item
:
set
)
{
py
::
print
(
"key:"
,
item
);
}
});
m
.
def
(
"set_contains"
,
[](
const
py
::
set
&
set
,
const
py
::
object
&
key
)
{
return
set
.
contains
(
key
);
});
...
...
@@ -66,8 +68,9 @@ TEST_SUBMODULE(pytypes, m) {
// test_dict
m
.
def
(
"get_dict"
,
[]()
{
return
py
::
dict
(
"key"
_a
=
"value"
);
});
m
.
def
(
"print_dict"
,
[](
const
py
::
dict
&
dict
)
{
for
(
auto
item
:
dict
)
for
(
auto
item
:
dict
)
{
py
::
print
(
"key: {}, value={}"
_s
.
format
(
item
.
first
,
item
.
second
));
}
});
m
.
def
(
"dict_keyword_constructor"
,
[]()
{
auto
d1
=
py
::
dict
(
"x"
_a
=
1
,
"y"
_a
=
2
);
...
...
@@ -405,9 +408,9 @@ TEST_SUBMODULE(pytypes, m) {
m
.
def
(
"test_memoryview_from_buffer"
,
[](
bool
is_unsigned
)
{
static
const
int16_t
si16
[]
=
{
3
,
1
,
4
,
1
,
5
};
static
const
uint16_t
ui16
[]
=
{
2
,
7
,
1
,
8
};
if
(
is_unsigned
)
return
py
::
memoryview
::
from_buffer
(
ui16
,
{
4
},
{
sizeof
(
uint16_t
)
});
if
(
is_unsigned
)
{
return
py
::
memoryview
::
from_buffer
(
ui16
,
{
4
},
{
sizeof
(
uint16_t
)});
}
return
py
::
memoryview
::
from_buffer
(
si16
,
{
5
},
{
sizeof
(
int16_t
)});
});
...
...
tests/test_sequences_and_iterators.cpp
View file @
ddbc74c6
...
...
@@ -74,8 +74,9 @@ PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>);
template
<
typename
PythonType
>
py
::
list
test_random_access_iterator
(
PythonType
x
)
{
if
(
x
.
size
()
<
5
)
if
(
x
.
size
()
<
5
)
{
throw
py
::
value_error
(
"Please provide at least 5 elements for testing."
);
}
auto
checks
=
py
::
list
();
auto
assert_equal
=
[
&
checks
](
py
::
handle
a
,
py
::
handle
b
)
{
...
...
@@ -125,8 +126,9 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
.
def
(
py
::
init
<
int
>
())
.
def
(
"__getitem__"
,
[](
const
Sliceable
&
s
,
const
py
::
slice
&
slice
)
{
py
::
ssize_t
start
=
0
,
stop
=
0
,
step
=
0
,
slicelength
=
0
;
if
(
!
slice
.
compute
(
s
.
size
,
&
start
,
&
stop
,
&
step
,
&
slicelength
))
if
(
!
slice
.
compute
(
s
.
size
,
&
start
,
&
stop
,
&
step
,
&
slicelength
))
{
throw
py
::
error_already_set
();
}
int
istart
=
static_cast
<
int
>
(
start
);
int
istop
=
static_cast
<
int
>
(
stop
);
int
istep
=
static_cast
<
int
>
(
step
);
...
...
@@ -195,10 +197,14 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
}
bool
operator
==
(
const
Sequence
&
s
)
const
{
if
(
m_size
!=
s
.
size
())
return
false
;
for
(
size_t
i
=
0
;
i
<
m_size
;
++
i
)
if
(
m_data
[
i
]
!=
s
[
i
])
if
(
m_size
!=
s
.
size
())
{
return
false
;
}
for
(
size_t
i
=
0
;
i
<
m_size
;
++
i
)
{
if
(
m_data
[
i
]
!=
s
[
i
])
{
return
false
;
}
}
return
true
;
}
bool
operator
!=
(
const
Sequence
&
s
)
const
{
return
!
operator
==
(
s
);
}
...
...
@@ -207,16 +213,19 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
float
&
operator
[](
size_t
index
)
{
return
m_data
[
index
];
}
bool
contains
(
float
v
)
const
{
for
(
size_t
i
=
0
;
i
<
m_size
;
++
i
)
if
(
v
==
m_data
[
i
])
for
(
size_t
i
=
0
;
i
<
m_size
;
++
i
)
{
if
(
v
==
m_data
[
i
])
{
return
true
;
}
}
return
false
;
}
Sequence
reversed
()
const
{
Sequence
result
(
m_size
);
for
(
size_t
i
=
0
;
i
<
m_size
;
++
i
)
for
(
size_t
i
=
0
;
i
<
m_size
;
++
i
)
{
result
[
m_size
-
i
-
1
]
=
m_data
[
i
];
}
return
result
;
}
...
...
@@ -235,14 +244,16 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
/// Bare bones interface
.
def
(
"__getitem__"
,
[](
const
Sequence
&
s
,
size_t
i
)
{
if
(
i
>=
s
.
size
())
if
(
i
>=
s
.
size
())
{
throw
py
::
index_error
();
}
return
s
[
i
];
})
.
def
(
"__setitem__"
,
[](
Sequence
&
s
,
size_t
i
,
float
v
)
{
if
(
i
>=
s
.
size
())
if
(
i
>=
s
.
size
())
{
throw
py
::
index_error
();
}
s
[
i
]
=
v
;
})
.
def
(
"__len__"
,
&
Sequence
::
size
)
...
...
@@ -257,8 +268,9 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
.
def
(
"__getitem__"
,
[](
const
Sequence
&
s
,
const
py
::
slice
&
slice
)
->
Sequence
*
{
size_t
start
=
0
,
stop
=
0
,
step
=
0
,
slicelength
=
0
;
if
(
!
slice
.
compute
(
s
.
size
(),
&
start
,
&
stop
,
&
step
,
&
slicelength
))
if
(
!
slice
.
compute
(
s
.
size
(),
&
start
,
&
stop
,
&
step
,
&
slicelength
))
{
throw
py
::
error_already_set
();
}
auto
*
seq
=
new
Sequence
(
slicelength
);
for
(
size_t
i
=
0
;
i
<
slicelength
;
++
i
)
{
(
*
seq
)[
i
]
=
s
[
start
];
...
...
@@ -269,11 +281,13 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
.
def
(
"__setitem__"
,
[](
Sequence
&
s
,
const
py
::
slice
&
slice
,
const
Sequence
&
value
)
{
size_t
start
=
0
,
stop
=
0
,
step
=
0
,
slicelength
=
0
;
if
(
!
slice
.
compute
(
s
.
size
(),
&
start
,
&
stop
,
&
step
,
&
slicelength
))
if
(
!
slice
.
compute
(
s
.
size
(),
&
start
,
&
stop
,
&
step
,
&
slicelength
))
{
throw
py
::
error_already_set
();
if
(
slicelength
!=
value
.
size
())
}
if
(
slicelength
!=
value
.
size
())
{
throw
std
::
runtime_error
(
"Left and right hand size of slice assignment have different sizes!"
);
}
for
(
size_t
i
=
0
;
i
<
slicelength
;
++
i
)
{
s
[
start
]
=
value
[
i
];
start
+=
step
;
...
...
tests/test_smart_ptr.cpp
View file @
ddbc74c6
...
...
@@ -113,8 +113,9 @@ public:
static
void
cleanupAllInstances
()
{
auto
tmp
=
std
::
move
(
myobject4_instances
);
myobject4_instances
.
clear
();
for
(
auto
o
:
tmp
)
for
(
auto
o
:
tmp
)
{
delete
o
;
}
}
private
:
~
MyObject4
()
{
...
...
@@ -140,8 +141,9 @@ public:
static
void
cleanupAllInstances
()
{
auto
tmp
=
std
::
move
(
myobject4a_instances
);
myobject4a_instances
.
clear
();
for
(
auto
o
:
tmp
)
for
(
auto
o
:
tmp
)
{
delete
o
;
}
}
protected
:
virtual
~
MyObject4a
()
{
...
...
@@ -445,8 +447,9 @@ TEST_SUBMODULE(smart_ptr, m) {
.
def
(
"add"
,
&
ElementList
::
add
)
.
def
(
"get"
,
[](
ElementList
&
el
)
{
py
::
list
list
;
for
(
auto
&
e
:
el
.
l
)
for
(
auto
&
e
:
el
.
l
)
{
list
.
append
(
py
::
cast
(
e
));
}
return
list
;
});
}
tests/test_stl_binders.cpp
View file @
ddbc74c6
...
...
@@ -42,23 +42,27 @@ public:
template
<
class
Container
>
Container
*
one_to_n
(
int
n
)
{
auto
v
=
new
Container
();
for
(
int
i
=
1
;
i
<=
n
;
i
++
)
for
(
int
i
=
1
;
i
<=
n
;
i
++
)
{
v
->
emplace_back
(
i
);
}
return
v
;
}
template
<
class
Map
>
Map
*
times_ten
(
int
n
)
{
auto
m
=
new
Map
();
for
(
int
i
=
1
;
i
<=
n
;
i
++
)
m
->
emplace
(
int
(
i
),
E_nc
(
10
*
i
));
for
(
int
i
=
1
;
i
<=
n
;
i
++
)
{
m
->
emplace
(
int
(
i
),
E_nc
(
10
*
i
));
}
return
m
;
}
template
<
class
NestMap
>
NestMap
*
times_hundred
(
int
n
)
{
auto
m
=
new
NestMap
();
for
(
int
i
=
1
;
i
<=
n
;
i
++
)
for
(
int
j
=
1
;
j
<=
n
;
j
++
)
(
*
m
)[
i
].
emplace
(
int
(
j
*
10
),
E_nc
(
100
*
j
));
for
(
int
i
=
1
;
i
<=
n
;
i
++
)
{
for
(
int
j
=
1
;
j
<=
n
;
j
++
)
{
(
*
m
)[
i
].
emplace
(
int
(
j
*
10
),
E_nc
(
100
*
j
));
}
}
return
m
;
}
...
...
@@ -98,9 +102,11 @@ TEST_SUBMODULE(stl_binders, m) {
m
.
def
(
"get_nvnc"
,
[](
int
n
)
{
auto
m
=
new
std
::
map
<
int
,
std
::
vector
<
E_nc
>>
();
for
(
int
i
=
1
;
i
<=
n
;
i
++
)
for
(
int
j
=
1
;
j
<=
n
;
j
++
)
for
(
int
i
=
1
;
i
<=
n
;
i
++
)
{
for
(
int
j
=
1
;
j
<=
n
;
j
++
)
{
(
*
m
)[
i
].
emplace_back
(
j
);
}
}
return
m
;
});
py
::
bind_map
<
std
::
map
<
int
,
std
::
map
<
int
,
E_nc
>>>
(
m
,
"MapMapENC"
);
...
...
tests/test_tagbased_polymorphic.cpp
View file @
ddbc74c6
...
...
@@ -100,8 +100,12 @@ const std::type_info* Animal::type_of_kind(Kind kind)
case
Kind
:
:
LastCat
:
break
;
}
if
(
kind
>=
Kind
::
Dog
&&
kind
<=
Kind
::
LastDog
)
return
&
typeid
(
Dog
);
if
(
kind
>=
Kind
::
Cat
&&
kind
<=
Kind
::
LastCat
)
return
&
typeid
(
Cat
);
if
(
kind
>=
Kind
::
Dog
&&
kind
<=
Kind
::
LastDog
)
{
return
&
typeid
(
Dog
);
}
if
(
kind
>=
Kind
::
Cat
&&
kind
<=
Kind
::
LastCat
)
{
return
&
typeid
(
Cat
);
}
return
nullptr
;
}
...
...
tests/test_virtual_functions.cpp
View file @
ddbc74c6
...
...
@@ -112,8 +112,9 @@ public:
void
operator
=
(
const
NonCopyable
&
)
=
delete
;
void
operator
=
(
NonCopyable
&&
)
=
delete
;
std
::
string
get_value
()
const
{
if
(
value
)
if
(
value
)
{
return
std
::
to_string
(
*
value
);
}
return
"(null)"
;
}
~
NonCopyable
()
{
print_destroyed
(
this
);
}
...
...
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