Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
gaoqiong
pybind11
Commits
e315e1fe
Unverified
Commit
e315e1fe
authored
Oct 04, 2021
by
Henry Schreiner
Browse files
Merge branch 'master' into stable
parents
71fd5241
97976c16
Changes
143
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
694 additions
and
289 deletions
+694
-289
include/pybind11/eigen.h
include/pybind11/eigen.h
+17
-31
include/pybind11/embed.h
include/pybind11/embed.h
+110
-27
include/pybind11/eval.h
include/pybind11/eval.h
+9
-0
include/pybind11/functional.h
include/pybind11/functional.h
+5
-1
include/pybind11/gil.h
include/pybind11/gil.h
+2
-2
include/pybind11/iostream.h
include/pybind11/iostream.h
+8
-6
include/pybind11/numpy.h
include/pybind11/numpy.h
+58
-25
include/pybind11/operators.h
include/pybind11/operators.h
+2
-12
include/pybind11/pybind11.h
include/pybind11/pybind11.h
+223
-88
include/pybind11/pytypes.h
include/pybind11/pytypes.h
+158
-44
include/pybind11/stl.h
include/pybind11/stl.h
+11
-32
include/pybind11/stl_bind.h
include/pybind11/stl_bind.h
+75
-3
noxfile.py
noxfile.py
+3
-2
pybind11/__init__.py
pybind11/__init__.py
+2
-3
pybind11/__main__.py
pybind11/__main__.py
+1
-1
pybind11/_version.py
pybind11/_version.py
+1
-1
pybind11/_version.pyi
pybind11/_version.pyi
+1
-1
pybind11/commands.py
pybind11/commands.py
+0
-1
pybind11/setup_helpers.py
pybind11/setup_helpers.py
+4
-4
pybind11/setup_helpers.pyi
pybind11/setup_helpers.pyi
+4
-5
No files found.
include/pybind11/eigen.h
View file @
e315e1fe
...
...
@@ -9,29 +9,13 @@
#pragma once
#include "numpy.h"
#if defined(__INTEL_COMPILER)
# pragma warning(disable: 1682) // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem)
#elif defined(__GNUG__) || defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wconversion"
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# ifdef __clang__
// Eigen generates a bunch of implicit-copy-constructor-is-deprecated warnings with -Wdeprecated
// under Clang, so disable that warning here:
# pragma GCC diagnostic ignored "-Wdeprecated"
# endif
# if __GNUC__ >= 7
# pragma GCC diagnostic ignored "-Wint-in-bool-context"
# endif
#endif
/* HINT: To suppress warnings originating from the Eigen headers, use -isystem.
See also:
https://stackoverflow.com/questions/2579576/i-dir-vs-isystem-dir
https://stackoverflow.com/questions/1741816/isystem-for-ms-visual-studio-c-compiler
*/
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
# pragma warning(disable: 4996) // warning C4996: std::unary_negate is deprecated in C++17
#endif
#include "numpy.h"
#include <Eigen/Core>
#include <Eigen/SparseCore>
...
...
@@ -77,6 +61,7 @@ template <bool EigenRowMajor> struct EigenConformable {
EigenDStride
stride
{
0
,
0
};
// Only valid if negativestrides is false!
bool
negativestrides
=
false
;
// If true, do not use stride!
// NOLINTNEXTLINE(google-explicit-constructor)
EigenConformable
(
bool
fits
=
false
)
:
conformable
{
fits
}
{}
// Matrix type:
EigenConformable
(
EigenIndex
r
,
EigenIndex
c
,
...
...
@@ -104,6 +89,7 @@ template <bool EigenRowMajor> struct EigenConformable {
(
props
::
outer_stride
==
Eigen
::
Dynamic
||
props
::
outer_stride
==
stride
.
outer
()
||
(
EigenRowMajor
?
rows
:
cols
)
==
1
);
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator
bool
()
const
{
return
conformable
;
}
};
...
...
@@ -153,7 +139,8 @@ 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
((
fixed_rows
&&
np_rows
!=
rows
)
||
(
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
};
...
...
@@ -165,7 +152,7 @@ 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
(
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
};
}
...
...
@@ -179,7 +166,7 @@ template <typename Type_> struct EigenProps {
if
(
cols
!=
n
)
return
false
;
return
{
1
,
n
,
stride
};
}
// Otherwise it's either fully dynamic, or column dynamic; both become a column vector
if
(
fixed_rows
&&
rows
!=
n
)
return
false
;
if
(
PYBIND11_SILENCE_MSVC_C4127
(
fixed_rows
)
&&
rows
!=
n
)
return
false
;
return
{
n
,
1
,
stride
};
}
...
...
@@ -341,8 +328,11 @@ public:
static
constexpr
auto
name
=
props
::
descriptor
;
// NOLINTNEXTLINE(google-explicit-constructor)
operator
Type
*
()
{
return
&
value
;
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator
Type
&
()
{
return
value
;
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator
Type
&&
()
&&
{
return
std
::
move
(
value
);
}
template
<
typename
T
>
using
cast_op_type
=
movable_cast_op_type
<
T
>
;
...
...
@@ -466,7 +456,9 @@ public:
return
true
;
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator
Type
*
()
{
return
ref
.
get
();
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator
Type
&
()
{
return
*
ref
;
}
template
<
typename
_T
>
using
cast_op_type
=
pybind11
::
detail
::
cast_op_type
<
_T
>
;
...
...
@@ -596,9 +588,3 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
PYBIND11_NAMESPACE_END
(
detail
)
PYBIND11_NAMESPACE_END
(
PYBIND11_NAMESPACE
)
#if defined(__GNUG__) || defined(__clang__)
# pragma GCC diagnostic pop
#elif defined(_MSC_VER)
# pragma warning(pop)
#endif
include/pybind11/embed.h
View file @
e315e1fe
...
...
@@ -12,6 +12,9 @@
#include "pybind11.h"
#include "eval.h"
#include <memory>
#include <vector>
#if defined(PYPY_VERSION)
# error Embedding the interpreter is not supported with PyPy
#endif
...
...
@@ -45,25 +48,23 @@
});
}
\endrst */
#define PYBIND11_EMBEDDED_MODULE(name, variable) \
static ::pybind11::module_::module_def \
PYBIND11_CONCAT(pybind11_module_def_, name); \
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \
auto m = ::pybind11::module_::create_extension_module( \
PYBIND11_TOSTRING(name), nullptr, \
&PYBIND11_CONCAT(pybind11_module_def_, name)); \
try { \
PYBIND11_CONCAT(pybind11_init_, name)(m); \
return m.ptr(); \
} PYBIND11_CATCH_INIT_EXCEPTIONS \
} \
PYBIND11_EMBEDDED_MODULE_IMPL(name) \
::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name) \
(PYBIND11_TOSTRING(name), \
PYBIND11_CONCAT(pybind11_init_impl_, name)); \
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &variable)
#define PYBIND11_EMBEDDED_MODULE(name, variable) \
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name); \
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \
auto m = ::pybind11::module_::create_extension_module( \
PYBIND11_TOSTRING(name), nullptr, &PYBIND11_CONCAT(pybind11_module_def_, name)); \
try { \
PYBIND11_CONCAT(pybind11_init_, name)(m); \
return m.ptr(); \
} \
PYBIND11_CATCH_INIT_EXCEPTIONS \
} \
PYBIND11_EMBEDDED_MODULE_IMPL(name) \
::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name)( \
PYBIND11_TOSTRING(name), PYBIND11_CONCAT(pybind11_init_impl_, name)); \
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ \
& variable) // NOLINT(bugprone-macro-parentheses)
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
PYBIND11_NAMESPACE_BEGIN
(
detail
)
...
...
@@ -85,29 +86,106 @@ struct embedded_module {
}
};
struct
wide_char_arg_deleter
{
void
operator
()(
wchar_t
*
ptr
)
const
{
#if PY_VERSION_HEX >= 0x030500f0
// API docs: https://docs.python.org/3/c-api/sys.html#c.Py_DecodeLocale
PyMem_RawFree
(
ptr
);
#else
delete
[]
ptr
;
#endif
}
};
inline
wchar_t
*
widen_chars
(
const
char
*
safe_arg
)
{
#if PY_VERSION_HEX >= 0x030500f0
wchar_t
*
widened_arg
=
Py_DecodeLocale
(
safe_arg
,
nullptr
);
#else
wchar_t
*
widened_arg
=
nullptr
;
# if defined(HAVE_BROKEN_MBSTOWCS) && HAVE_BROKEN_MBSTOWCS
size_t
count
=
strlen
(
safe_arg
);
# else
size_t
count
=
mbstowcs
(
nullptr
,
safe_arg
,
0
);
# endif
if
(
count
!=
static_cast
<
size_t
>
(
-
1
))
{
widened_arg
=
new
wchar_t
[
count
+
1
];
mbstowcs
(
widened_arg
,
safe_arg
,
count
+
1
);
}
#endif
return
widened_arg
;
}
/// Python 2.x/3.x-compatible version of `PySys_SetArgv`
inline
void
set_interpreter_argv
(
int
argc
,
const
char
*
const
*
argv
,
bool
add_program_dir_to_path
)
{
// Before it was special-cased in python 3.8, passing an empty or null argv
// caused a segfault, so we have to reimplement the special case ourselves.
bool
special_case
=
(
argv
==
nullptr
||
argc
<=
0
);
const
char
*
const
empty_argv
[]{
"
\0
"
};
const
char
*
const
*
safe_argv
=
special_case
?
empty_argv
:
argv
;
if
(
special_case
)
argc
=
1
;
auto
argv_size
=
static_cast
<
size_t
>
(
argc
);
#if PY_MAJOR_VERSION >= 3
// SetArgv* on python 3 takes wchar_t, so we have to convert.
std
::
unique_ptr
<
wchar_t
*
[]
>
widened_argv
(
new
wchar_t
*
[
argv_size
]);
std
::
vector
<
std
::
unique_ptr
<
wchar_t
[],
wide_char_arg_deleter
>>
widened_argv_entries
;
widened_argv_entries
.
reserve
(
argv_size
);
for
(
size_t
ii
=
0
;
ii
<
argv_size
;
++
ii
)
{
widened_argv_entries
.
emplace_back
(
widen_chars
(
safe_argv
[
ii
]));
if
(
!
widened_argv_entries
.
back
())
{
// A null here indicates a character-encoding failure or the python
// interpreter out of memory. Give up.
return
;
}
widened_argv
[
ii
]
=
widened_argv_entries
.
back
().
get
();
}
auto
pysys_argv
=
widened_argv
.
get
();
#else
// python 2.x
std
::
vector
<
std
::
string
>
strings
{
safe_argv
,
safe_argv
+
argv_size
};
std
::
vector
<
char
*>
char_strings
{
argv_size
};
for
(
std
::
size_t
i
=
0
;
i
<
argv_size
;
++
i
)
char_strings
[
i
]
=
&
strings
[
i
][
0
];
char
**
pysys_argv
=
char_strings
.
data
();
#endif
PySys_SetArgvEx
(
argc
,
pysys_argv
,
static_cast
<
int
>
(
add_program_dir_to_path
));
}
PYBIND11_NAMESPACE_END
(
detail
)
/** \rst
Initialize the Python interpreter. No other pybind11 or CPython API functions can be
called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The
optional parameter can be used to skip the registration of
signal handlers (see the
`Python documentation`_ for details). Calling this function
again after the interpreter
has already been initialized is a fatal error.
optional
`init_signal_handlers`
parameter can be used to skip the registration of
signal handlers (see the
`Python documentation`_ for details). Calling this function
again after the interpreter
has already been initialized is a fatal error.
If initializing the Python interpreter fails, then the program is terminated. (This
is controlled by the CPython runtime and is an exception to pybind11's normal behavior
of throwing exceptions on errors.)
The remaining optional parameters, `argc`, `argv`, and `add_program_dir_to_path` are
used to populate ``sys.argv`` and ``sys.path``.
See the |PySys_SetArgvEx documentation|_ for details.
.. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
.. |PySys_SetArgvEx documentation| replace:: ``PySys_SetArgvEx`` documentation
.. _PySys_SetArgvEx documentation: https://docs.python.org/3/c-api/init.html#c.PySys_SetArgvEx
\endrst */
inline
void
initialize_interpreter
(
bool
init_signal_handlers
=
true
)
{
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
)
pybind11_fail
(
"The interpreter is already running"
);
Py_InitializeEx
(
init_signal_handlers
?
1
:
0
);
// Make .py files in the working directory available by default
module_
::
import
(
"sys"
).
attr
(
"path"
).
cast
<
list
>
().
append
(
"."
);
detail
::
set_interpreter_argv
(
argc
,
argv
,
add_program_dir_to_path
);
}
/** \rst
...
...
@@ -169,6 +247,8 @@ inline void finalize_interpreter() {
Scope guard version of `initialize_interpreter` and `finalize_interpreter`.
This a move-only guard and only a single instance can exist.
See `initialize_interpreter` for a discussion of its constructor arguments.
.. code-block:: cpp
#include <pybind11/embed.h>
...
...
@@ -180,8 +260,11 @@ inline void finalize_interpreter() {
\endrst */
class
scoped_interpreter
{
public:
scoped_interpreter
(
bool
init_signal_handlers
=
true
)
{
initialize_interpreter
(
init_signal_handlers
);
explicit
scoped_interpreter
(
bool
init_signal_handlers
=
true
,
int
argc
=
0
,
const
char
*
const
*
argv
=
nullptr
,
bool
add_program_dir_to_path
=
true
)
{
initialize_interpreter
(
init_signal_handlers
,
argc
,
argv
,
add_program_dir_to_path
);
}
scoped_interpreter
(
const
scoped_interpreter
&
)
=
delete
;
...
...
include/pybind11/eval.h
View file @
e315e1fe
...
...
@@ -136,6 +136,15 @@ object eval_file(str fname, object global = globals(), object local = object())
pybind11_fail
(
"File
\"
"
+
fname_str
+
"
\"
could not be opened!"
);
}
// In Python2, this should be encoded by getfilesystemencoding.
// We don't boher setting it since Python2 is past EOL anyway.
// See PR#3233
#if PY_VERSION_HEX >= 0x03000000
if
(
!
global
.
contains
(
"__file__"
))
{
global
[
"__file__"
]
=
std
::
move
(
fname
);
}
#endif
#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
PyObject
*
result
=
PyRun_File
(
f
,
fname_str
.
c_str
(),
start
,
global
.
ptr
(),
local
.
ptr
());
...
...
include/pybind11/functional.h
View file @
e315e1fe
...
...
@@ -69,6 +69,10 @@ public:
// ensure GIL is held during functor destruction
struct
func_handle
{
function
f
;
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17) && PY_MAJOR_VERSION < 3)
// This triggers a syntax error under very special conditions (very weird indeed).
explicit
#endif
func_handle
(
function
&&
f_
)
noexcept
:
f
(
std
::
move
(
f_
))
{}
func_handle
(
const
func_handle
&
f_
)
{
operator
=
(
f_
);
}
func_handle
&
operator
=
(
const
func_handle
&
f_
)
{
...
...
@@ -85,7 +89,7 @@ public:
// to emulate 'move initialization capture' in C++11
struct
func_wrapper
{
func_handle
hfunc
;
func_wrapper
(
func_handle
&&
hf
)
noexcept
:
hfunc
(
std
::
move
(
hf
))
{}
explicit
func_wrapper
(
func_handle
&&
hf
)
noexcept
:
hfunc
(
std
::
move
(
hf
))
{}
Return
operator
()(
Args
...
args
)
const
{
gil_scoped_acquire
acq
;
object
retval
(
hfunc
.
f
(
std
::
forward
<
Args
>
(
args
)...));
...
...
include/pybind11/gil.h
View file @
e315e1fe
...
...
@@ -50,7 +50,7 @@ PYBIND11_NAMESPACE_END(detail)
class
gil_scoped_acquire
{
public:
PYBIND11_NOINLINE
gil_scoped_acquire
()
{
auto
const
&
internals
=
detail
::
get_internals
();
auto
&
internals
=
detail
::
get_internals
();
tstate
=
(
PyThreadState
*
)
PYBIND11_TLS_GET_VALUE
(
internals
.
tstate
);
if
(
!
tstate
)
{
...
...
@@ -132,7 +132,7 @@ public:
// `get_internals()` must be called here unconditionally in order to initialize
// `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an
// initialization race could occur as multiple threads try `gil_scoped_acquire`.
const
auto
&
internals
=
detail
::
get_internals
();
auto
&
internals
=
detail
::
get_internals
();
tstate
=
PyEval_SaveThread
();
if
(
disassoc
)
{
auto
key
=
internals
.
tstate
;
...
...
include/pybind11/iostream.h
View file @
e315e1fe
...
...
@@ -123,7 +123,7 @@ private:
}
public:
pythonbuf
(
const
object
&
pyostream
,
size_t
buffer_size
=
1024
)
explicit
pythonbuf
(
const
object
&
pyostream
,
size_t
buffer_size
=
1024
)
:
buf_size
(
buffer_size
),
d_buffer
(
new
char
[
buf_size
]),
pywrite
(
pyostream
.
attr
(
"write"
)),
pyflush
(
pyostream
.
attr
(
"flush"
))
{
setp
(
d_buffer
.
get
(),
d_buffer
.
get
()
+
buf_size
-
1
);
...
...
@@ -171,8 +171,9 @@ protected:
detail
::
pythonbuf
buffer
;
public:
scoped_ostream_redirect
(
std
::
ostream
&
costream
=
std
::
cout
,
const
object
&
pyostream
=
module_
::
import
(
"sys"
).
attr
(
"stdout"
))
explicit
scoped_ostream_redirect
(
std
::
ostream
&
costream
=
std
::
cout
,
const
object
&
pyostream
=
module_
::
import
(
"sys"
).
attr
(
"stdout"
))
:
costream
(
costream
),
buffer
(
pyostream
)
{
old
=
costream
.
rdbuf
(
&
buffer
);
}
...
...
@@ -201,8 +202,9 @@ public:
\endrst */
class
scoped_estream_redirect
:
public
scoped_ostream_redirect
{
public:
scoped_estream_redirect
(
std
::
ostream
&
costream
=
std
::
cerr
,
const
object
&
pyostream
=
module_
::
import
(
"sys"
).
attr
(
"stderr"
))
explicit
scoped_estream_redirect
(
std
::
ostream
&
costream
=
std
::
cerr
,
const
object
&
pyostream
=
module_
::
import
(
"sys"
).
attr
(
"stderr"
))
:
scoped_ostream_redirect
(
costream
,
pyostream
)
{}
};
...
...
@@ -217,7 +219,7 @@ class OstreamRedirect {
std
::
unique_ptr
<
scoped_estream_redirect
>
redirect_stderr
;
public:
OstreamRedirect
(
bool
do_stdout
=
true
,
bool
do_stderr
=
true
)
explicit
OstreamRedirect
(
bool
do_stdout
=
true
,
bool
do_stderr
=
true
)
:
do_stdout_
(
do_stdout
),
do_stderr_
(
do_stderr
)
{}
void
enter
()
{
...
...
include/pybind11/numpy.h
View file @
e315e1fe
...
...
@@ -25,11 +25,6 @@
#include <vector>
#include <typeindex>
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
#endif
/* This will be true on all flat address space platforms and allows us to reduce the
whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size
and dimension types (e.g. shape, strides, indexing), instead of inflicting this
...
...
@@ -104,7 +99,7 @@ struct numpy_internals {
}
};
inline
PYBIND11_NOINLINE
void
load_numpy_internals
(
numpy_internals
*
&
ptr
)
{
PYBIND11_NOINLINE
void
load_numpy_internals
(
numpy_internals
*
&
ptr
)
{
ptr
=
&
get_or_create_shared_data
<
numpy_internals
>
(
"_numpy_internals"
);
}
...
...
@@ -203,6 +198,9 @@ struct npy_api {
// Unused. Not removed because that affects ABI of the class.
int
(
*
PyArray_SetBaseObject_
)(
PyObject
*
,
PyObject
*
);
PyObject
*
(
*
PyArray_Resize_
)(
PyObject
*
,
PyArray_Dims
*
,
int
,
int
);
PyObject
*
(
*
PyArray_Newshape_
)(
PyObject
*
,
PyArray_Dims
*
,
int
);
PyObject
*
(
*
PyArray_View_
)(
PyObject
*
,
PyObject
*
,
PyObject
*
);
private:
enum
functions
{
API_PyArray_GetNDArrayCFeatureVersion
=
211
,
...
...
@@ -217,10 +215,12 @@ private:
API_PyArray_NewCopy
=
85
,
API_PyArray_NewFromDescr
=
94
,
API_PyArray_DescrNewFromType
=
96
,
API_PyArray_Newshape
=
135
,
API_PyArray_Squeeze
=
136
,
API_PyArray_View
=
137
,
API_PyArray_DescrConverter
=
174
,
API_PyArray_EquivTypes
=
182
,
API_PyArray_GetArrayParamsFromObject
=
278
,
API_PyArray_Squeeze
=
136
,
API_PyArray_SetBaseObject
=
282
};
...
...
@@ -248,11 +248,14 @@ private:
DECL_NPY_API
(
PyArray_NewCopy
);
DECL_NPY_API
(
PyArray_NewFromDescr
);
DECL_NPY_API
(
PyArray_DescrNewFromType
);
DECL_NPY_API
(
PyArray_Newshape
);
DECL_NPY_API
(
PyArray_Squeeze
);
DECL_NPY_API
(
PyArray_View
);
DECL_NPY_API
(
PyArray_DescrConverter
);
DECL_NPY_API
(
PyArray_EquivTypes
);
DECL_NPY_API
(
PyArray_GetArrayParamsFromObject
);
DECL_NPY_API
(
PyArray_Squeeze
);
DECL_NPY_API
(
PyArray_SetBaseObject
);
#undef DECL_NPY_API
return
api
;
}
...
...
@@ -319,7 +322,7 @@ template <typename T> using remove_all_extents_t = typename array_info<T>::type;
template
<
typename
T
>
using
is_pod_struct
=
all_of
<
std
::
is_standard_layout
<
T
>
,
// since we're accessing directly in memory we need a standard layout type
#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150623 || __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803)
#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20150422 || __GLIBCXX__ ==
20150426 || __GLIBCXX__ ==
20150623 || __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803)
// libstdc++ < 5 (including versions 4.8.5, 4.9.3 and 4.9.4 which were released after 5)
// don't implement is_trivially_copyable, so approximate it
std
::
is_trivially_destructible
<
T
>
,
...
...
@@ -474,15 +477,15 @@ public:
m_ptr
=
from_args
(
pybind11
::
str
(
format
)).
release
().
ptr
();
}
dtype
(
const
char
*
format
)
:
dtype
(
std
::
string
(
format
))
{
}
explicit
dtype
(
const
char
*
format
)
:
dtype
(
std
::
string
(
format
))
{}
dtype
(
list
names
,
list
formats
,
list
offsets
,
ssize_t
itemsize
)
{
dict
args
;
args
[
"names"
]
=
names
;
args
[
"formats"
]
=
formats
;
args
[
"offsets"
]
=
offsets
;
args
[
"names"
]
=
std
::
move
(
names
)
;
args
[
"formats"
]
=
std
::
move
(
formats
)
;
args
[
"offsets"
]
=
std
::
move
(
offsets
)
;
args
[
"itemsize"
]
=
pybind11
::
int_
(
itemsize
);
m_ptr
=
from_args
(
args
).
release
().
ptr
();
m_ptr
=
from_args
(
std
::
move
(
args
)
)
.
release
().
ptr
();
}
/// This is essentially the same as calling numpy.dtype(args) in Python.
...
...
@@ -560,7 +563,7 @@ private:
formats
.
append
(
descr
.
format
);
offsets
.
append
(
descr
.
offset
);
}
return
dtype
(
names
,
formats
,
offsets
,
itemsize
);
return
dtype
(
std
::
move
(
names
)
,
std
::
move
(
formats
)
,
std
::
move
(
offsets
)
,
itemsize
);
}
};
...
...
@@ -747,7 +750,7 @@ 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
(
Dims
>=
0
&&
ndim
()
!=
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
());
...
...
@@ -761,7 +764,7 @@ public:
* invalid dimensions or dimension indices.
*/
template
<
typename
T
,
ssize_t
Dims
=
-
1
>
detail
::
unchecked_reference
<
T
,
Dims
>
unchecked
()
const
&
{
if
(
Dims
>=
0
&&
ndim
()
!=
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
());
...
...
@@ -790,6 +793,33 @@ public:
if
(
isinstance
<
array
>
(
new_array
))
{
*
this
=
std
::
move
(
new_array
);
}
}
/// Optional `order` parameter omitted, to be added as needed.
array
reshape
(
ShapeContainer
new_shape
)
{
detail
::
npy_api
::
PyArray_Dims
d
=
{
reinterpret_cast
<
Py_intptr_t
*>
(
new_shape
->
data
()),
int
(
new_shape
->
size
())};
auto
new_array
=
reinterpret_steal
<
array
>
(
detail
::
npy_api
::
get
().
PyArray_Newshape_
(
m_ptr
,
&
d
,
0
));
if
(
!
new_array
)
{
throw
error_already_set
();
}
return
new_array
;
}
/// Create a view of an array in a different data type.
/// This function may fundamentally reinterpret the data in the array.
/// It is the responsibility of the caller to ensure that this is safe.
/// Only supports the `dtype` argument, the `type` argument is omitted,
/// to be added as needed.
array
view
(
const
std
::
string
&
dtype
)
{
auto
&
api
=
detail
::
npy_api
::
get
();
auto
new_view
=
reinterpret_steal
<
array
>
(
api
.
PyArray_View_
(
m_ptr
,
dtype
::
from_args
(
pybind11
::
str
(
dtype
)).
release
().
ptr
(),
nullptr
));
if
(
!
new_view
)
{
throw
error_already_set
();
}
return
new_view
;
}
/// Ensure that the argument is a NumPy array
/// In case of an error, nullptr is returned and the Python error is cleared.
static
array
ensure
(
handle
h
,
int
ExtraFlags
=
0
)
{
...
...
@@ -864,6 +894,7 @@ public:
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
();
}
...
...
@@ -1110,7 +1141,7 @@ struct field_descriptor {
dtype
descr
;
};
inline
PYBIND11_NOINLINE
void
register_structured_dtype
(
PYBIND11_NOINLINE
void
register_structured_dtype
(
any_container
<
field_descriptor
>
fields
,
const
std
::
type_info
&
tinfo
,
ssize_t
itemsize
,
bool
(
*
direct_converter
)(
PyObject
*
,
void
*&
))
{
...
...
@@ -1134,7 +1165,10 @@ inline PYBIND11_NOINLINE void register_structured_dtype(
formats
.
append
(
field
.
descr
);
offsets
.
append
(
pybind11
::
int_
(
field
.
offset
));
}
auto
dtype_ptr
=
pybind11
::
dtype
(
names
,
formats
,
offsets
,
itemsize
).
release
().
ptr
();
auto
dtype_ptr
=
pybind11
::
dtype
(
std
::
move
(
names
),
std
::
move
(
formats
),
std
::
move
(
offsets
),
itemsize
)
.
release
()
.
ptr
();
// There is an existing bug in NumPy (as of v1.11): trailing bytes are
// not encoded explicitly into the format string. This will supposedly
...
...
@@ -1551,8 +1585,11 @@ private:
"pybind11::vectorize(...) requires a function with at least one vectorizable argument"
);
public:
template
<
typename
T
>
explicit
vectorize_helper
(
T
&&
f
)
:
f
(
std
::
forward
<
T
>
(
f
))
{
}
template
<
typename
T
,
// SFINAE to prevent shadowing the copy constructor.
typename
=
detail
::
enable_if_t
<
!
std
::
is_same
<
vectorize_helper
,
typename
std
::
decay
<
T
>
::
type
>::
value
>>
explicit
vectorize_helper
(
T
&&
f
)
:
f
(
std
::
forward
<
T
>
(
f
))
{}
object
operator
()(
typename
vectorize_arg
<
Args
>::
type
...
args
)
{
return
run
(
args
...,
...
...
@@ -1702,7 +1739,3 @@ Helper vectorize(Return (Class::*f)(Args...) const) {
}
PYBIND11_NAMESPACE_END
(
PYBIND11_NAMESPACE
)
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
include/pybind11/operators.h
View file @
e315e1fe
...
...
@@ -11,13 +11,6 @@
#include "pybind11.h"
#if defined(__clang__) && !defined(__INTEL_COMPILER)
# pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type()))
#elif defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
#endif
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
PYBIND11_NAMESPACE_BEGIN
(
detail
)
...
...
@@ -58,7 +51,8 @@ template <op_id id, op_type ot, typename L, typename R> struct op_ {
using
op
=
op_impl
<
id
,
ot
,
Base
,
L_type
,
R_type
>
;
cl
.
def
(
op
::
name
(),
&
op
::
execute
,
is_operator
(),
extra
...);
#if PY_MAJOR_VERSION < 3
if
(
id
==
op_truediv
||
id
==
op_itruediv
)
if
(
PYBIND11_SILENCE_MSVC_C4127
(
id
==
op_truediv
)
||
PYBIND11_SILENCE_MSVC_C4127
(
id
==
op_itruediv
))
cl
.
def
(
id
==
op_itruediv
?
"__idiv__"
:
ot
==
op_l
?
"__div__"
:
"__rdiv__"
,
&
op
::
execute
,
is_operator
(),
extra
...);
#endif
...
...
@@ -167,7 +161,3 @@ using detail::self;
using
detail
::
hash
;
PYBIND11_NAMESPACE_END
(
PYBIND11_NAMESPACE
)
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
include/pybind11/pybind11.h
View file @
e315e1fe
...
...
@@ -10,22 +10,13 @@
#pragma once
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
# pragma warning(push)
# pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter
# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
#elif defined(__GNUG__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
# pragma GCC diagnostic ignored "-Wattributes"
#endif
#include "attr.h"
#include "gil.h"
#include "options.h"
#include "detail/class.h"
#include "detail/init.h"
#include <cstdlib>
#include <memory>
#include <new>
#include <vector>
...
...
@@ -59,20 +50,44 @@
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
PYBIND11_NAMESPACE_BEGIN
(
detail
)
// Apply all the extensions translators from a list
// Return true if one of the translators completed without raising an exception
// itself. Return of false indicates that if there are other translators
// available, they should be tried.
inline
bool
apply_exception_translators
(
std
::
forward_list
<
ExceptionTranslator
>&
translators
)
{
auto
last_exception
=
std
::
current_exception
();
for
(
auto
&
translator
:
translators
)
{
try
{
translator
(
last_exception
);
return
true
;
}
catch
(...)
{
last_exception
=
std
::
current_exception
();
}
}
return
false
;
}
#if defined(_MSC_VER)
# define PYBIND11_COMPAT_STRDUP _strdup
#else
# define PYBIND11_COMPAT_STRDUP strdup
#endif
PYBIND11_NAMESPACE_END
(
detail
)
/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
class
cpp_function
:
public
function
{
public:
cpp_function
()
=
default
;
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function
(
std
::
nullptr_t
)
{
}
/// Construct a cpp_function from a vanilla function pointer
template
<
typename
Return
,
typename
...
Args
,
typename
...
Extra
>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function
(
Return
(
*
f
)(
Args
...),
const
Extra
&
...
extra
)
{
initialize
(
f
,
f
,
extra
...);
}
...
...
@@ -80,6 +95,7 @@ public:
/// Construct a cpp_function from a lambda function (possibly with internal state)
template
<
typename
Func
,
typename
...
Extra
,
typename
=
detail
::
enable_if_t
<
detail
::
is_lambda
<
Func
>
::
value
>>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function
(
Func
&&
f
,
const
Extra
&
...
extra
)
{
initialize
(
std
::
forward
<
Func
>
(
f
),
(
detail
::
function_signature_t
<
Func
>
*
)
nullptr
,
extra
...);
...
...
@@ -87,6 +103,7 @@ public:
/// Construct a cpp_function from a class method (non-const, no ref-qualifier)
template
<
typename
Return
,
typename
Class
,
typename
...
Arg
,
typename
...
Extra
>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function
(
Return
(
Class
::*
f
)(
Arg
...),
const
Extra
&
...
extra
)
{
initialize
([
f
](
Class
*
c
,
Arg
...
args
)
->
Return
{
return
(
c
->*
f
)(
std
::
forward
<
Arg
>
(
args
)...);
},
(
Return
(
*
)
(
Class
*
,
Arg
...))
nullptr
,
extra
...);
...
...
@@ -96,6 +113,7 @@ public:
/// A copy of the overload for non-const functions without explicit ref-qualifier
/// but with an added `&`.
template
<
typename
Return
,
typename
Class
,
typename
...
Arg
,
typename
...
Extra
>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function
(
Return
(
Class
::*
f
)(
Arg
...)
&
,
const
Extra
&
...
extra
)
{
initialize
([
f
](
Class
*
c
,
Arg
...
args
)
->
Return
{
return
(
c
->*
f
)(
args
...);
},
(
Return
(
*
)
(
Class
*
,
Arg
...))
nullptr
,
extra
...);
...
...
@@ -103,6 +121,7 @@ public:
/// Construct a cpp_function from a class method (const, no ref-qualifier)
template
<
typename
Return
,
typename
Class
,
typename
...
Arg
,
typename
...
Extra
>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function
(
Return
(
Class
::*
f
)(
Arg
...)
const
,
const
Extra
&
...
extra
)
{
initialize
([
f
](
const
Class
*
c
,
Arg
...
args
)
->
Return
{
return
(
c
->*
f
)(
std
::
forward
<
Arg
>
(
args
)...);
},
(
Return
(
*
)(
const
Class
*
,
Arg
...))
nullptr
,
extra
...);
...
...
@@ -112,6 +131,7 @@ public:
/// A copy of the overload for const functions without explicit ref-qualifier
/// but with an added `&`.
template
<
typename
Return
,
typename
Class
,
typename
...
Arg
,
typename
...
Extra
>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function
(
Return
(
Class
::*
f
)(
Arg
...)
const
&
,
const
Extra
&
...
extra
)
{
initialize
([
f
](
const
Class
*
c
,
Arg
...
args
)
->
Return
{
return
(
c
->*
f
)(
args
...);
},
(
Return
(
*
)(
const
Class
*
,
Arg
...))
nullptr
,
extra
...);
...
...
@@ -145,7 +165,7 @@ protected:
auto
rec
=
unique_rec
.
get
();
/* Store the capture object directly in the function record if there is enough space */
if
(
sizeof
(
capture
)
<=
sizeof
(
rec
->
data
))
{
if
(
PYBIND11_SILENCE_MSVC_C4127
(
sizeof
(
capture
)
<=
sizeof
(
rec
->
data
))
)
{
/* Without these pragmas, GCC warns that there might not be
enough space to use the placement new operator. However, the
'if' statement above ensures that this is the case. */
...
...
@@ -163,7 +183,7 @@ protected:
#endif
// UB without std::launder, but without breaking ABI and/or
// a significant refactoring it's "impossible" to solve.
if
(
!
std
::
is_trivially_destructible
<
Func
>::
value
)
if
(
!
std
::
is_trivially_destructible
<
capture
>::
value
)
rec
->
free_data
=
[](
function_record
*
r
)
{
auto
data
=
PYBIND11_STD_LAUNDER
((
capture
*
)
&
r
->
data
);
(
void
)
data
;
...
...
@@ -397,7 +417,8 @@ protected:
detail
::
function_record
*
chain
=
nullptr
,
*
chain_start
=
rec
;
if
(
rec
->
sibling
)
{
if
(
PyCFunction_Check
(
rec
->
sibling
.
ptr
()))
{
auto
rec_capsule
=
reinterpret_borrow
<
capsule
>
(
PyCFunction_GET_SELF
(
rec
->
sibling
.
ptr
()));
auto
*
self
=
PyCFunction_GET_SELF
(
rec
->
sibling
.
ptr
());
capsule
rec_capsule
=
isinstance
<
capsule
>
(
self
)
?
reinterpret_borrow
<
capsule
>
(
self
)
:
capsule
(
self
);
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 */
...
...
@@ -561,6 +582,7 @@ protected:
}
}
/// Main dispatch logic for calls to functions bound using pybind11
static
PyObject
*
dispatcher
(
PyObject
*
self
,
PyObject
*
args_in
,
PyObject
*
kwargs_in
)
{
using
namespace
detail
;
...
...
@@ -841,8 +863,12 @@ protected:
#endif
}
catch
(...)
{
/* When an exception is caught, give each registered exception
translator a chance to translate it to a Python exception
in reverse order of registration.
translator a chance to translate it to a Python exception. First
all module-local translators will be tried in reverse order of
registration. If none of the module-locale translators handle
the exception (or there are no module-locale translators) then
the global translators will be tried, also in reverse order of
registration.
A translator may choose to do one of the following:
...
...
@@ -851,17 +877,15 @@ protected:
- do nothing and let the exception fall through to the next translator, or
- delegate translation to the next translator by throwing a new type of exception. */
auto
last_exception
=
std
::
current_exception
();
auto
&
registered_exception_translators
=
get_internals
().
registered_exception_translators
;
for
(
auto
&
translator
:
registered_exception_translators
)
{
try
{
translator
(
last_exception
);
}
catch
(...)
{
last_exception
=
std
::
current_exception
();
continue
;
}
auto
&
local_exception_translators
=
get_local_internals
().
registered_exception_translators
;
if
(
detail
::
apply_exception_translators
(
local_exception_translators
))
{
return
nullptr
;
}
auto
&
exception_translators
=
get_internals
().
registered_exception_translators
;
if
(
detail
::
apply_exception_translators
(
exception_translators
))
{
return
nullptr
;
}
PyErr_SetString
(
PyExc_SystemError
,
"Exception escaped from default exception translator!"
);
return
nullptr
;
}
...
...
@@ -962,6 +986,7 @@ protected:
}
};
/// Wrapper for Python extension modules
class
module_
:
public
object
{
public:
...
...
@@ -1136,7 +1161,7 @@ protected:
auto
tindex
=
std
::
type_index
(
*
rec
.
type
);
tinfo
->
direct_conversions
=
&
internals
.
direct_conversions
[
tindex
];
if
(
rec
.
module_local
)
registered_
local_
types_cpp
()
[
tindex
]
=
tinfo
;
get_local_internals
().
registered_types_cpp
[
tindex
]
=
tinfo
;
else
internals
.
registered_types_cpp
[
tindex
]
=
tinfo
;
internals
.
registered_types_py
[(
PyTypeObject
*
)
m_ptr
]
=
{
tinfo
};
...
...
@@ -1323,7 +1348,7 @@ public:
generic_type
::
initialize
(
record
);
if
(
has_alias
)
{
auto
&
instances
=
record
.
module_local
?
registered_
local_
types_cpp
()
:
get_internals
().
registered_types_cpp
;
auto
&
instances
=
record
.
module_local
?
get_local_internals
().
registered_types_cpp
:
get_internals
().
registered_types_cpp
;
instances
[
std
::
type_index
(
typeid
(
type_alias
))]
=
instances
[
std
::
type_index
(
typeid
(
type
))];
}
}
...
...
@@ -1370,12 +1395,14 @@ public:
template
<
typename
...
Args
,
typename
...
Extra
>
class_
&
def
(
const
detail
::
initimpl
::
constructor
<
Args
...
>
&
init
,
const
Extra
&
...
extra
)
{
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100
(
init
);
init
.
execute
(
*
this
,
extra
...);
return
*
this
;
}
template
<
typename
...
Args
,
typename
...
Extra
>
class_
&
def
(
const
detail
::
initimpl
::
alias_constructor
<
Args
...
>
&
init
,
const
Extra
&
...
extra
)
{
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100
(
init
);
init
.
execute
(
*
this
,
extra
...);
return
*
this
;
}
...
...
@@ -1510,7 +1537,7 @@ public:
char
*
doc_prev
=
rec_fget
->
doc
;
/* 'extra' field may include a property-specific documentation string */
detail
::
process_attributes
<
Extra
...
>::
init
(
extra
...,
rec_fget
);
if
(
rec_fget
->
doc
&&
rec_fget
->
doc
!=
doc_prev
)
{
free
(
doc_prev
);
std
::
free
(
doc_prev
);
rec_fget
->
doc
=
PYBIND11_COMPAT_STRDUP
(
rec_fget
->
doc
);
}
}
...
...
@@ -1518,7 +1545,7 @@ public:
char
*
doc_prev
=
rec_fset
->
doc
;
detail
::
process_attributes
<
Extra
...
>::
init
(
extra
...,
rec_fset
);
if
(
rec_fset
->
doc
&&
rec_fset
->
doc
!=
doc_prev
)
{
free
(
doc_prev
);
std
::
free
(
doc_prev
);
rec_fset
->
doc
=
PYBIND11_COMPAT_STRDUP
(
rec_fset
->
doc
);
}
if
(
!
rec_active
)
rec_active
=
rec_fset
;
...
...
@@ -1646,7 +1673,7 @@ inline str enum_name(handle arg) {
}
struct
enum_base
{
enum_base
(
handle
base
,
handle
parent
)
:
m_base
(
base
),
m_parent
(
parent
)
{
}
enum_base
(
const
handle
&
base
,
const
handle
&
parent
)
:
m_base
(
base
),
m_parent
(
parent
)
{
}
PYBIND11_NOINLINE
void
init
(
bool
is_arithmetic
,
bool
is_convertible
)
{
m_base
.
attr
(
"__entries"
)
=
dict
();
...
...
@@ -1702,7 +1729,7 @@ struct enum_base {
m_base.attr(op) = cpp_function( \
[](const object &a, const object &b) { \
if (!type::handle_of(a).is(type::handle_of(b))) \
strict_behavior;
\
strict_behavior;
/* NOLINT(bugprone-macro-parentheses) */
\
return expr; \
}, \
name(op), \
...
...
@@ -1796,6 +1823,19 @@ struct enum_base {
handle
m_parent
;
};
template
<
bool
is_signed
,
size_t
length
>
struct
equivalent_integer
{};
template
<
>
struct
equivalent_integer
<
true
,
1
>
{
using
type
=
int8_t
;
};
template
<
>
struct
equivalent_integer
<
false
,
1
>
{
using
type
=
uint8_t
;
};
template
<
>
struct
equivalent_integer
<
true
,
2
>
{
using
type
=
int16_t
;
};
template
<
>
struct
equivalent_integer
<
false
,
2
>
{
using
type
=
uint16_t
;
};
template
<
>
struct
equivalent_integer
<
true
,
4
>
{
using
type
=
int32_t
;
};
template
<
>
struct
equivalent_integer
<
false
,
4
>
{
using
type
=
uint32_t
;
};
template
<
>
struct
equivalent_integer
<
true
,
8
>
{
using
type
=
int64_t
;
};
template
<
>
struct
equivalent_integer
<
false
,
8
>
{
using
type
=
uint64_t
;
};
template
<
typename
IntLike
>
using
equivalent_integer_t
=
typename
equivalent_integer
<
std
::
is_signed
<
IntLike
>::
value
,
sizeof
(
IntLike
)
>::
type
;
PYBIND11_NAMESPACE_END
(
detail
)
/// Binds C++ enumerations and enumeration classes to Python
...
...
@@ -1806,13 +1846,17 @@ public:
using
Base
::
attr
;
using
Base
::
def_property_readonly
;
using
Base
::
def_property_readonly_static
;
using
Scalar
=
typename
std
::
underlying_type
<
Type
>::
type
;
using
Underlying
=
typename
std
::
underlying_type
<
Type
>::
type
;
// Scalar is the integer representation of underlying type
using
Scalar
=
detail
::
conditional_t
<
detail
::
any_of
<
detail
::
is_std_char_type
<
Underlying
>
,
std
::
is_same
<
Underlying
,
bool
>
>::
value
,
detail
::
equivalent_integer_t
<
Underlying
>
,
Underlying
>
;
template
<
typename
...
Extra
>
enum_
(
const
handle
&
scope
,
const
char
*
name
,
const
Extra
&
...
extra
)
:
class_
<
Type
>
(
scope
,
name
,
extra
...),
m_base
(
*
this
,
scope
)
{
constexpr
bool
is_arithmetic
=
detail
::
any_of
<
std
::
is_same
<
arithmetic
,
Extra
>
...
>::
value
;
constexpr
bool
is_convertible
=
std
::
is_convertible
<
Type
,
Scalar
>::
value
;
constexpr
bool
is_convertible
=
std
::
is_convertible
<
Type
,
Underlying
>::
value
;
m_base
.
init
(
is_arithmetic
,
is_convertible
);
def
(
init
([](
Scalar
i
)
{
return
static_cast
<
Type
>
(
i
);
}),
arg
(
"value"
));
...
...
@@ -1852,7 +1896,7 @@ private:
PYBIND11_NAMESPACE_BEGIN
(
detail
)
inline
void
keep_alive_impl
(
handle
nurse
,
handle
patient
)
{
PYBIND11_NOINLINE
void
keep_alive_impl
(
handle
nurse
,
handle
patient
)
{
if
(
!
nurse
||
!
patient
)
pybind11_fail
(
"Could not activate keep_alive!"
);
...
...
@@ -1879,7 +1923,7 @@ inline void keep_alive_impl(handle nurse, handle patient) {
}
}
PYBIND11_NOINLINE
inline
void
keep_alive_impl
(
size_t
Nurse
,
size_t
Patient
,
function_call
&
call
,
handle
ret
)
{
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
)
return
ret
;
...
...
@@ -1912,25 +1956,54 @@ inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_t
return
res
;
}
template
<
typename
Iterator
,
typename
Sentinel
,
bool
KeyIterator
,
return_value_policy
Policy
>
/* There are a large number of apparently unused template arguments because
* each combination requires a separate py::class_ registration.
*/
template
<
typename
Access
,
return_value_policy
Policy
,
typename
Iterator
,
typename
Sentinel
,
typename
ValueType
,
typename
...
Extra
>
struct
iterator_state
{
Iterator
it
;
Sentinel
end
;
bool
first_or_done
;
};
PYBIND11_NAMESPACE_END
(
detail
)
// Note: these helpers take the iterator by non-const reference because some
// iterators in the wild can't be dereferenced when const. C++ needs the extra parens in decltype
// to enforce an lvalue. The & after Iterator is required for MSVC < 16.9. SFINAE cannot be
// reused for result_type due to bugs in ICC, NVCC, and PGI compilers. See PR #3293.
template
<
typename
Iterator
,
typename
SFINAE
=
decltype
((
*
std
::
declval
<
Iterator
&
>()))
>
struct
iterator_access
{
using
result_type
=
decltype
((
*
std
::
declval
<
Iterator
&>
()));
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
result_type
operator
()(
Iterator
&
it
)
const
{
return
*
it
;
}
};
/// Makes a python iterator from a first and past-the-end C++ InputIterator.
template
<
return_value_policy
Policy
=
return_value_policy
::
reference_internal
,
template
<
typename
Iterator
,
typename
SFINAE
=
decltype
(((
*
std
::
declval
<
Iterator
&
>()).
first
))
>
struct
iterator_key_access
{
using
result_type
=
decltype
(((
*
std
::
declval
<
Iterator
&>
()).
first
));
result_type
operator
()(
Iterator
&
it
)
const
{
return
(
*
it
).
first
;
}
};
template
<
typename
Iterator
,
typename
SFINAE
=
decltype
(((
*
std
::
declval
<
Iterator
&
>()).
second
))
>
struct
iterator_value_access
{
using
result_type
=
decltype
(((
*
std
::
declval
<
Iterator
&>
()).
second
));
result_type
operator
()(
Iterator
&
it
)
const
{
return
(
*
it
).
second
;
}
};
template
<
typename
Access
,
return_value_policy
Policy
,
typename
Iterator
,
typename
Sentinel
,
#ifndef DOXYGEN_SHOULD_SKIP_THIS // Issue in breathe 4.26.1
typename
ValueType
=
decltype
(
*
std
::
declval
<
Iterator
>()),
#endif
typename
ValueType
,
typename
...
Extra
>
iterator
make_iterator
(
Iterator
first
,
Sentinel
last
,
Extra
&&
...
extra
)
{
using
state
=
detail
::
iterator_state
<
Iterator
,
Sentinel
,
false
,
Policy
>
;
iterator
make_iterator_impl
(
Iterator
first
,
Sentinel
last
,
Extra
&&
...
extra
)
{
using
state
=
detail
::
iterator_state
<
Access
,
Policy
,
Iterator
,
Sentinel
,
ValueType
,
Extra
...
>
;
// TODO: state captures only the types of Extra, not the values
if
(
!
detail
::
get_type_info
(
typeid
(
state
),
false
))
{
class_
<
state
>
(
handle
(),
"iterator"
,
pybind11
::
module_local
())
...
...
@@ -1944,42 +2017,63 @@ iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) {
s
.
first_or_done
=
true
;
throw
stop_iteration
();
}
return
*
s
.
it
;
return
Access
()(
s
.
it
);
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
},
std
::
forward
<
Extra
>
(
extra
)...,
Policy
);
}
return
cast
(
state
{
first
,
last
,
true
});
}
/// Makes an python iterator over the keys (`.first`) of a iterator over pairs from a
/// first and past-the-end InputIterator.
PYBIND11_NAMESPACE_END
(
detail
)
/// Makes a python iterator from a first and past-the-end C++ InputIterator.
template
<
return_value_policy
Policy
=
return_value_policy
::
reference_internal
,
typename
Iterator
,
typename
Sentinel
,
#ifndef DOXYGEN_SHOULD_SKIP_THIS // Issue in breathe 4.26.1
typename
KeyType
=
decltype
((
*
std
::
declval
<
Iterator
>()).
first
),
#endif
typename
ValueType
=
typename
detail
::
iterator_access
<
Iterator
>
::
result_type
,
typename
...
Extra
>
iterator
make_key_iterator
(
Iterator
first
,
Sentinel
last
,
Extra
&&
...
extra
)
{
using
state
=
detail
::
iterator_state
<
Iterator
,
Sentinel
,
true
,
Policy
>
;
iterator
make_iterator
(
Iterator
first
,
Sentinel
last
,
Extra
&&
...
extra
)
{
return
detail
::
make_iterator_impl
<
detail
::
iterator_access
<
Iterator
>
,
Policy
,
Iterator
,
Sentinel
,
ValueType
,
Extra
...
>
(
first
,
last
,
std
::
forward
<
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
)
->
KeyType
{
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
(
*
s
.
it
).
first
;
},
std
::
forward
<
Extra
>
(
extra
)...,
Policy
);
}
/// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a
/// first and past-the-end InputIterator.
template
<
return_value_policy
Policy
=
return_value_policy
::
reference_internal
,
typename
Iterator
,
typename
Sentinel
,
typename
KeyType
=
typename
detail
::
iterator_key_access
<
Iterator
>
::
result_type
,
typename
...
Extra
>
iterator
make_key_iterator
(
Iterator
first
,
Sentinel
last
,
Extra
&&
...
extra
)
{
return
detail
::
make_iterator_impl
<
detail
::
iterator_key_access
<
Iterator
>
,
Policy
,
Iterator
,
Sentinel
,
KeyType
,
Extra
...
>
(
first
,
last
,
std
::
forward
<
Extra
>
(
extra
)...);
}
return
cast
(
state
{
first
,
last
,
true
});
/// Makes a python iterator over the values (`.second`) of a iterator over pairs from a
/// first and past-the-end InputIterator.
template
<
return_value_policy
Policy
=
return_value_policy
::
reference_internal
,
typename
Iterator
,
typename
Sentinel
,
typename
ValueType
=
typename
detail
::
iterator_value_access
<
Iterator
>
::
result_type
,
typename
...
Extra
>
iterator
make_value_iterator
(
Iterator
first
,
Sentinel
last
,
Extra
&&
...
extra
)
{
return
detail
::
make_iterator_impl
<
detail
::
iterator_value_access
<
Iterator
>
,
Policy
,
Iterator
,
Sentinel
,
ValueType
,
Extra
...
>
(
first
,
last
,
std
::
forward
<
Extra
>
(
extra
)...);
}
/// Makes an iterator over values of an stl container or other container supporting
...
...
@@ -1996,10 +2090,17 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
return
make_key_iterator
<
Policy
>
(
std
::
begin
(
value
),
std
::
end
(
value
),
extra
...);
}
/// Makes an iterator over the values (`.second`) of a stl map-like container supporting
/// `std::begin()`/`std::end()`
template
<
return_value_policy
Policy
=
return_value_policy
::
reference_internal
,
typename
Type
,
typename
...
Extra
>
iterator
make_value_iterator
(
Type
&
value
,
Extra
&&
...
extra
)
{
return
make_value_iterator
<
Policy
>
(
std
::
begin
(
value
),
std
::
end
(
value
),
extra
...);
}
template
<
typename
InputType
,
typename
OutputType
>
void
implicitly_convertible
()
{
struct
set_flag
{
bool
&
flag
;
set_flag
(
bool
&
flag_
)
:
flag
(
flag_
)
{
flag_
=
true
;
}
explicit
set_flag
(
bool
&
flag_
)
:
flag
(
flag_
)
{
flag_
=
true
;
}
~
set_flag
()
{
flag
=
false
;
}
};
auto
implicit_caster
=
[](
PyObject
*
obj
,
PyTypeObject
*
type
)
->
PyObject
*
{
...
...
@@ -2023,12 +2124,24 @@ template <typename InputType, typename OutputType> void implicitly_convertible()
pybind11_fail
(
"implicitly_convertible: Unable to find type "
+
type_id
<
OutputType
>
());
}
template
<
typename
ExceptionTranslator
>
void
register_exception_translator
(
ExceptionTranslator
&&
translator
)
{
inline
void
register_exception_translator
(
ExceptionTranslator
&&
translator
)
{
detail
::
get_internals
().
registered_exception_translators
.
push_front
(
std
::
forward
<
ExceptionTranslator
>
(
translator
));
}
/**
* Add a new module-local exception translator. Locally registered functions
* will be tried before any globally registered exception translators, which
* will only be invoked if the module-local handlers do not deal with
* the exception.
*/
inline
void
register_local_exception_translator
(
ExceptionTranslator
&&
translator
)
{
detail
::
get_local_internals
().
registered_exception_translators
.
push_front
(
std
::
forward
<
ExceptionTranslator
>
(
translator
));
}
/**
* Wrapper to generate a new Python exception type.
*
...
...
@@ -2062,22 +2175,20 @@ PYBIND11_NAMESPACE_BEGIN(detail)
// directly in register_exception, but that makes clang <3.5 segfault - issue #1349).
template
<
typename
CppException
>
exception
<
CppException
>
&
get_exception_object
()
{
static
exception
<
CppException
>
ex
;
return
ex
;
}
PYBIND11_NAMESPACE_END
(
detail
)
/**
* Registers a Python exception in `m` of the given `name` and installs an exception translator to
* translate the C++ exception to the created Python exception using the exceptions what() method.
* This is intended for simple exception translations; for more complex translation, register the
* exception object and translator directly.
*/
// Helper function for register_exception and register_local_exception
template
<
typename
CppException
>
exception
<
CppException
>
&
register_exception
(
handle
scope
,
const
char
*
name
,
handle
base
=
PyExc_Exception
)
{
exception
<
CppException
>
&
register_exception_impl
(
handle
scope
,
const
char
*
name
,
handle
base
,
bool
isLocal
)
{
auto
&
ex
=
detail
::
get_exception_object
<
CppException
>
();
if
(
!
ex
)
ex
=
exception
<
CppException
>
(
scope
,
name
,
base
);
register_exception_translator
([](
std
::
exception_ptr
p
)
{
auto
register_func
=
isLocal
?
&
register_local_exception_translator
:
&
register_exception_translator
;
register_func
([](
std
::
exception_ptr
p
)
{
if
(
!
p
)
return
;
try
{
std
::
rethrow_exception
(
p
);
...
...
@@ -2088,8 +2199,38 @@ exception<CppException> ®ister_exception(handle scope,
return
ex
;
}
PYBIND11_NAMESPACE_END
(
detail
)
/**
* Registers a Python exception in `m` of the given `name` and installs a translator to
* translate the C++ exception to the created Python exception using the what() method.
* This is intended for simple exception translations; for more complex translation, register the
* exception object and translator directly.
*/
template
<
typename
CppException
>
exception
<
CppException
>
&
register_exception
(
handle
scope
,
const
char
*
name
,
handle
base
=
PyExc_Exception
)
{
return
detail
::
register_exception_impl
<
CppException
>
(
scope
,
name
,
base
,
false
/* isLocal */
);
}
/**
* Registers a Python exception in `m` of the given `name` and installs a translator to
* translate the C++ exception to the created Python exception using the what() method.
* This translator will only be used for exceptions that are thrown in this module and will be
* tried before global exception translators, including those registered with register_exception.
* This is intended for simple exception translations; for more complex translation, register the
* exception object and translator directly.
*/
template
<
typename
CppException
>
exception
<
CppException
>
&
register_local_exception
(
handle
scope
,
const
char
*
name
,
handle
base
=
PyExc_Exception
)
{
return
detail
::
register_exception_impl
<
CppException
>
(
scope
,
name
,
base
,
true
/* isLocal */
);
}
PYBIND11_NAMESPACE_BEGIN
(
detail
)
PYBIND11_NOINLINE
inline
void
print
(
const
tuple
&
args
,
const
dict
&
kwargs
)
{
PYBIND11_NOINLINE
void
print
(
const
tuple
&
args
,
const
dict
&
kwargs
)
{
auto
strings
=
tuple
(
args
.
size
());
for
(
size_t
i
=
0
;
i
<
args
.
size
();
++
i
)
{
strings
[
i
]
=
str
(
args
[
i
]);
...
...
@@ -2320,9 +2461,3 @@ PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
#if defined(__GNUC__) && __GNUC__ == 7
# pragma GCC diagnostic pop // -Wnoexcept-type
#endif
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
# pragma warning(pop)
#elif defined(__GNUG__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
# pragma GCC diagnostic pop
#endif
include/pybind11/pytypes.h
View file @
e315e1fe
...
...
@@ -14,6 +14,10 @@
#include <utility>
#include <type_traits>
#if defined(PYBIND11_HAS_OPTIONAL)
# include <optional>
#endif
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
/* A few forward declarations */
...
...
@@ -24,7 +28,7 @@ struct arg; struct arg_v;
PYBIND11_NAMESPACE_BEGIN
(
detail
)
class
args_proxy
;
inline
bool
isinstance_generic
(
handle
obj
,
const
std
::
type_info
&
tp
);
bool
isinstance_generic
(
handle
obj
,
const
std
::
type_info
&
tp
);
// Accessor forward declarations
template
<
typename
Policy
>
class
accessor
;
...
...
@@ -178,6 +182,7 @@ public:
/// The default constructor creates a handle with a ``nullptr``-valued pointer
handle
()
=
default
;
/// Creates a ``handle`` from the given raw Python object pointer
// NOLINTNEXTLINE(google-explicit-constructor)
handle
(
PyObject
*
ptr
)
:
m_ptr
(
ptr
)
{
}
// Allow implicit conversion from PyObject*
/// Return the underlying ``PyObject *`` pointer
...
...
@@ -254,8 +259,11 @@ public:
object
&
operator
=
(
const
object
&
other
)
{
other
.
inc_ref
();
dec_ref
();
// Use temporary variable to ensure `*this` remains valid while
// `Py_XDECREF` executes, in case `*this` is accessible from Python.
handle
temp
(
m_ptr
);
m_ptr
=
other
.
m_ptr
;
temp
.
dec_ref
();
return
*
this
;
}
...
...
@@ -316,7 +324,7 @@ template <typename T> T reinterpret_borrow(handle h) { return {h, object::borrow
template
<
typename
T
>
T
reinterpret_steal
(
handle
h
)
{
return
{
h
,
object
::
stolen_t
{}};
}
PYBIND11_NAMESPACE_BEGIN
(
detail
)
inline
std
::
string
error_string
();
std
::
string
error_string
();
PYBIND11_NAMESPACE_END
(
detail
)
#if defined(_MSC_VER)
...
...
@@ -382,6 +390,47 @@ private:
# pragma warning(pop)
#endif
#if PY_VERSION_HEX >= 0x03030000
/// Replaces the current Python error indicator with the chosen error, performing a
/// 'raise from' to indicate that the chosen error was caused by the original error.
inline
void
raise_from
(
PyObject
*
type
,
const
char
*
message
)
{
// Based on _PyErr_FormatVFromCause:
// https://github.com/python/cpython/blob/467ab194fc6189d9f7310c89937c51abeac56839/Python/errors.c#L405
// See https://github.com/pybind/pybind11/pull/2112 for details.
PyObject
*
exc
=
nullptr
,
*
val
=
nullptr
,
*
val2
=
nullptr
,
*
tb
=
nullptr
;
assert
(
PyErr_Occurred
());
PyErr_Fetch
(
&
exc
,
&
val
,
&
tb
);
PyErr_NormalizeException
(
&
exc
,
&
val
,
&
tb
);
if
(
tb
!=
nullptr
)
{
PyException_SetTraceback
(
val
,
tb
);
Py_DECREF
(
tb
);
}
Py_DECREF
(
exc
);
assert
(
!
PyErr_Occurred
());
PyErr_SetString
(
type
,
message
);
PyErr_Fetch
(
&
exc
,
&
val2
,
&
tb
);
PyErr_NormalizeException
(
&
exc
,
&
val2
,
&
tb
);
Py_INCREF
(
val
);
PyException_SetCause
(
val2
,
val
);
PyException_SetContext
(
val2
,
val
);
PyErr_Restore
(
exc
,
val2
,
tb
);
}
/// Sets the current Python error indicator with the chosen error, performing a 'raise from'
/// from the error contained in error_already_set to indicate that the chosen error was
/// caused by the original error. After this function is called error_already_set will
/// no longer contain an error.
inline
void
raise_from
(
error_already_set
&
err
,
PyObject
*
type
,
const
char
*
message
)
{
err
.
restore
();
raise_from
(
type
,
message
);
}
#endif
/** \defgroup python_builtins _
Unless stated otherwise, the following C++ functions behave the same
as their Python counterparts.
...
...
@@ -571,6 +620,7 @@ public:
return
obj
.
contains
(
key
);
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator
object
()
const
{
return
get_cache
();
}
PyObject
*
ptr
()
const
{
return
get_cache
().
ptr
();
}
template
<
typename
T
>
T
cast
()
const
{
return
get_cache
().
template
cast
<
T
>();
}
...
...
@@ -620,15 +670,17 @@ struct generic_item {
struct
sequence_item
{
using
key_type
=
size_t
;
static
object
get
(
handle
obj
,
size_t
index
)
{
PyObject
*
result
=
PySequence_GetItem
(
obj
.
ptr
(),
static_cast
<
ssize_t
>
(
index
));
template
<
typename
IdxType
,
detail
::
enable_if_t
<
std
::
is_integral
<
IdxType
>
::
value
,
int
>
=
0
>
static
object
get
(
handle
obj
,
const
IdxType
&
index
)
{
PyObject
*
result
=
PySequence_GetItem
(
obj
.
ptr
(),
ssize_t_cast
(
index
));
if
(
!
result
)
{
throw
error_already_set
();
}
return
reinterpret_steal
<
object
>
(
result
);
}
static
void
set
(
handle
obj
,
size_t
index
,
handle
val
)
{
template
<
typename
IdxType
,
detail
::
enable_if_t
<
std
::
is_integral
<
IdxType
>
::
value
,
int
>
=
0
>
static
void
set
(
handle
obj
,
const
IdxType
&
index
,
handle
val
)
{
// PySequence_SetItem does not steal a reference to 'val'
if
(
PySequence_SetItem
(
obj
.
ptr
(),
static_cast
<
ssize_t
>
(
index
),
val
.
ptr
())
!=
0
)
{
if
(
PySequence_SetItem
(
obj
.
ptr
(),
ssize_t
_cast
(
index
),
val
.
ptr
())
!=
0
)
{
throw
error_already_set
();
}
}
...
...
@@ -637,15 +689,17 @@ struct sequence_item {
struct
list_item
{
using
key_type
=
size_t
;
static
object
get
(
handle
obj
,
size_t
index
)
{
PyObject
*
result
=
PyList_GetItem
(
obj
.
ptr
(),
static_cast
<
ssize_t
>
(
index
));
template
<
typename
IdxType
,
detail
::
enable_if_t
<
std
::
is_integral
<
IdxType
>
::
value
,
int
>
=
0
>
static
object
get
(
handle
obj
,
const
IdxType
&
index
)
{
PyObject
*
result
=
PyList_GetItem
(
obj
.
ptr
(),
ssize_t_cast
(
index
));
if
(
!
result
)
{
throw
error_already_set
();
}
return
reinterpret_borrow
<
object
>
(
result
);
}
static
void
set
(
handle
obj
,
size_t
index
,
handle
val
)
{
template
<
typename
IdxType
,
detail
::
enable_if_t
<
std
::
is_integral
<
IdxType
>
::
value
,
int
>
=
0
>
static
void
set
(
handle
obj
,
const
IdxType
&
index
,
handle
val
)
{
// PyList_SetItem steals a reference to 'val'
if
(
PyList_SetItem
(
obj
.
ptr
(),
static_cast
<
ssize_t
>
(
index
),
val
.
inc_ref
().
ptr
())
!=
0
)
{
if
(
PyList_SetItem
(
obj
.
ptr
(),
ssize_t
_cast
(
index
),
val
.
inc_ref
().
ptr
())
!=
0
)
{
throw
error_already_set
();
}
}
...
...
@@ -654,15 +708,17 @@ struct list_item {
struct
tuple_item
{
using
key_type
=
size_t
;
static
object
get
(
handle
obj
,
size_t
index
)
{
PyObject
*
result
=
PyTuple_GetItem
(
obj
.
ptr
(),
static_cast
<
ssize_t
>
(
index
));
template
<
typename
IdxType
,
detail
::
enable_if_t
<
std
::
is_integral
<
IdxType
>
::
value
,
int
>
=
0
>
static
object
get
(
handle
obj
,
const
IdxType
&
index
)
{
PyObject
*
result
=
PyTuple_GetItem
(
obj
.
ptr
(),
ssize_t_cast
(
index
));
if
(
!
result
)
{
throw
error_already_set
();
}
return
reinterpret_borrow
<
object
>
(
result
);
}
static
void
set
(
handle
obj
,
size_t
index
,
handle
val
)
{
template
<
typename
IdxType
,
detail
::
enable_if_t
<
std
::
is_integral
<
IdxType
>
::
value
,
int
>
=
0
>
static
void
set
(
handle
obj
,
const
IdxType
&
index
,
handle
val
)
{
// PyTuple_SetItem steals a reference to 'val'
if
(
PyTuple_SetItem
(
obj
.
ptr
(),
static_cast
<
ssize_t
>
(
index
),
val
.
inc_ref
().
ptr
())
!=
0
)
{
if
(
PyTuple_SetItem
(
obj
.
ptr
(),
ssize_t
_cast
(
index
),
val
.
inc_ref
().
ptr
())
!=
0
)
{
throw
error_already_set
();
}
}
...
...
@@ -684,7 +740,9 @@ public:
generic_iterator
()
=
default
;
generic_iterator
(
handle
seq
,
ssize_t
index
)
:
Policy
(
seq
,
index
)
{
}
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
reference
operator
*
()
const
{
return
Policy
::
dereference
();
}
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
reference
operator
[](
difference_type
n
)
const
{
return
*
(
*
this
+
n
);
}
pointer
operator
->
()
const
{
return
**
this
;
}
...
...
@@ -714,7 +772,8 @@ template <typename T>
struct
arrow_proxy
{
T
value
;
arrow_proxy
(
T
&&
value
)
:
value
(
std
::
move
(
value
))
{
}
// NOLINTNEXTLINE(google-explicit-constructor)
arrow_proxy
(
T
&&
value
)
noexcept
:
value
(
std
::
move
(
value
))
{
}
T
*
operator
->
()
const
{
return
&
value
;
}
};
...
...
@@ -723,11 +782,12 @@ class sequence_fast_readonly {
protected:
using
iterator_category
=
std
::
random_access_iterator_tag
;
using
value_type
=
handle
;
using
reference
=
const
handle
;
using
reference
=
const
handle
;
// PR #3263
using
pointer
=
arrow_proxy
<
const
handle
>
;
sequence_fast_readonly
(
handle
obj
,
ssize_t
n
)
:
ptr
(
PySequence_Fast_ITEMS
(
obj
.
ptr
())
+
n
)
{
}
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
reference
dereference
()
const
{
return
*
ptr
;
}
void
increment
()
{
++
ptr
;
}
void
decrement
()
{
--
ptr
;
}
...
...
@@ -766,12 +826,13 @@ class dict_readonly {
protected:
using
iterator_category
=
std
::
forward_iterator_tag
;
using
value_type
=
std
::
pair
<
handle
,
handle
>
;
using
reference
=
const
value_type
;
using
reference
=
const
value_type
;
// PR #3263
using
pointer
=
arrow_proxy
<
const
value_type
>
;
dict_readonly
()
=
default
;
dict_readonly
(
handle
obj
,
ssize_t
pos
)
:
obj
(
obj
),
pos
(
pos
)
{
increment
();
}
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
reference
dereference
()
const
{
return
{
key
,
value
};
}
void
increment
()
{
if
(
PyDict_Next
(
obj
.
ptr
(),
&
pos
,
&
key
,
&
value
)
==
0
)
{
...
...
@@ -862,14 +923,17 @@ PYBIND11_NAMESPACE_END(detail)
bool check() const { return m_ptr != nullptr && (CheckFun(m_ptr) != 0); } \
static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } \
template <typename Policy_> \
/* NOLINTNEXTLINE(google-explicit-constructor) */
\
Name(const ::pybind11::detail::accessor<Policy_> &a) : Name(object(a)) { }
#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
/* This is deliberately not 'explicit' to allow implicit conversion from object: */
\
/* NOLINTNEXTLINE(google-explicit-constructor) */
\
Name(const object &o) \
: Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) \
{ if (!m_ptr) throw error_already_set(); } \
/* NOLINTNEXTLINE(google-explicit-constructor) */
\
Name(object &&o) \
: Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) \
{ if (!m_ptr) throw error_already_set(); }
...
...
@@ -886,8 +950,10 @@ PYBIND11_NAMESPACE_END(detail)
#define PYBIND11_OBJECT(Name, Parent, CheckFun) \
PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \
/* This is deliberately not 'explicit' to allow implicit conversion from object: */
\
/* NOLINTNEXTLINE(google-explicit-constructor) */
\
Name(const object &o) : Parent(o) \
{ if (m_ptr && !check_(m_ptr)) throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr); } \
/* NOLINTNEXTLINE(google-explicit-constructor) */
\
Name(object &&o) : Parent(std::move(o)) \
{ if (m_ptr && !check_(m_ptr)) throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr); }
...
...
@@ -911,7 +977,7 @@ public:
using
iterator_category
=
std
::
input_iterator_tag
;
using
difference_type
=
ssize_t
;
using
value_type
=
handle
;
using
reference
=
const
handle
;
using
reference
=
const
handle
;
// PR #3263
using
pointer
=
const
handle
*
;
PYBIND11_OBJECT_DEFAULT
(
iterator
,
object
,
PyIter_Check
)
...
...
@@ -927,6 +993,7 @@ public:
return
rv
;
}
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
reference
operator
*
()
const
{
if
(
m_ptr
&&
!
value
.
ptr
())
{
auto
&
self
=
const_cast
<
iterator
&>
(
*
this
);
...
...
@@ -1002,17 +1069,20 @@ class str : public object {
public:
PYBIND11_OBJECT_CVT
(
str
,
object
,
PYBIND11_STR_CHECK_FUN
,
raw_str
)
str
(
const
char
*
c
,
size_t
n
)
:
object
(
PyUnicode_FromStringAndSize
(
c
,
(
ssize_t
)
n
),
stolen_t
{})
{
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!"
);
}
// '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!"
);
}
// NOLINTNEXTLINE(google-explicit-constructor)
str
(
const
std
::
string
&
s
)
:
str
(
s
.
data
(),
s
.
size
())
{
}
explicit
str
(
const
bytes
&
b
);
...
...
@@ -1023,6 +1093,7 @@ public:
\endrst */
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
))
{
...
...
@@ -1070,21 +1141,25 @@ public:
PYBIND11_OBJECT
(
bytes
,
object
,
PYBIND11_BYTES_CHECK
)
// Allow implicit conversion:
// 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!"
);
}
bytes
(
const
char
*
c
,
size_t
n
)
:
object
(
PYBIND11_BYTES_FROM_STRING_AND_SIZE
(
c
,
(
ssize_t
)
n
),
stolen_t
{})
{
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!"
);
}
// Allow implicit conversion:
// NOLINTNEXTLINE(google-explicit-constructor)
bytes
(
const
std
::
string
&
s
)
:
bytes
(
s
.
data
(),
s
.
size
())
{
}
explicit
bytes
(
const
pybind11
::
str
&
s
);
// NOLINTNEXTLINE(google-explicit-constructor)
operator
std
::
string
()
const
{
char
*
buffer
=
nullptr
;
ssize_t
length
=
0
;
...
...
@@ -1119,7 +1194,7 @@ inline str::str(const bytes& b) {
ssize_t
length
=
0
;
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
,
(
ssize_t
)
length
));
auto
obj
=
reinterpret_steal
<
object
>
(
PyUnicode_FromStringAndSize
(
buffer
,
length
));
if
(
!
obj
)
pybind11_fail
(
"Could not allocate string object!"
);
m_ptr
=
obj
.
release
().
ptr
();
...
...
@@ -1131,8 +1206,9 @@ class bytearray : public object {
public:
PYBIND11_OBJECT_CVT
(
bytearray
,
object
,
PyByteArray_Check
,
PyByteArray_FromObject
)
bytearray
(
const
char
*
c
,
size_t
n
)
:
object
(
PyByteArray_FromStringAndSize
(
c
,
(
ssize_t
)
n
),
stolen_t
{})
{
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!"
);
}
...
...
@@ -1172,7 +1248,9 @@ public:
PYBIND11_OBJECT_CVT
(
bool_
,
object
,
PyBool_Check
,
raw_bool
)
bool_
()
:
object
(
Py_False
,
borrowed_t
{})
{
}
// Allow implicit conversion from and to `bool`:
// NOLINTNEXTLINE(google-explicit-constructor)
bool_
(
bool
value
)
:
object
(
value
?
Py_True
:
Py_False
,
borrowed_t
{})
{
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator
bool
()
const
{
return
(
m_ptr
!=
nullptr
)
&&
PyLong_AsLong
(
m_ptr
)
!=
0
;
}
private:
...
...
@@ -1191,9 +1269,9 @@ PYBIND11_NAMESPACE_BEGIN(detail)
// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
template
<
typename
Unsigned
>
Unsigned
as_unsigned
(
PyObject
*
o
)
{
if
(
sizeof
(
Unsigned
)
<=
sizeof
(
unsigned
long
)
if
(
PYBIND11_SILENCE_MSVC_C4127
(
sizeof
(
Unsigned
)
<=
sizeof
(
unsigned
long
)
)
#if PY_VERSION_HEX < 0x03000000
||
PyInt_Check
(
o
)
||
PyInt_Check
(
o
)
#endif
)
{
unsigned
long
v
=
PyLong_AsUnsignedLong
(
o
);
...
...
@@ -1211,8 +1289,9 @@ public:
// Allow implicit conversion from C++ integral types:
template
<
typename
T
,
detail
::
enable_if_t
<
std
::
is_integral
<
T
>
::
value
,
int
>
=
0
>
// NOLINTNEXTLINE(google-explicit-constructor)
int_
(
T
value
)
{
if
(
sizeof
(
T
)
<=
sizeof
(
long
))
{
if
(
PYBIND11_SILENCE_MSVC_C4127
(
sizeof
(
T
)
<=
sizeof
(
long
))
)
{
if
(
std
::
is_signed
<
T
>::
value
)
m_ptr
=
PyLong_FromLong
((
long
)
value
);
else
...
...
@@ -1228,6 +1307,7 @@ public:
template
<
typename
T
,
detail
::
enable_if_t
<
std
::
is_integral
<
T
>
::
value
,
int
>
=
0
>
// NOLINTNEXTLINE(google-explicit-constructor)
operator
T
()
const
{
return
std
::
is_unsigned
<
T
>::
value
?
detail
::
as_unsigned
<
T
>
(
m_ptr
)
...
...
@@ -1241,13 +1321,17 @@ class float_ : public object {
public:
PYBIND11_OBJECT_CVT
(
float_
,
object
,
PyFloat_Check
,
PyNumber_Float
)
// 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!"
);
}
// 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!"
);
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator
float
()
const
{
return
(
float
)
PyFloat_AsDouble
(
m_ptr
);
}
// NOLINTNEXTLINE(google-explicit-constructor)
operator
double
()
const
{
return
(
double
)
PyFloat_AsDouble
(
m_ptr
);
}
};
...
...
@@ -1268,11 +1352,20 @@ private:
class
slice
:
public
object
{
public:
PYBIND11_OBJECT_DEFAULT
(
slice
,
object
,
PySlice_Check
)
slice
(
ssize_t
start_
,
ssize_t
stop_
,
ssize_t
step_
)
{
int_
start
(
start_
),
stop
(
stop_
),
step
(
step_
);
slice
(
handle
start
,
handle
stop
,
handle
step
)
{
m_ptr
=
PySlice_New
(
start
.
ptr
(),
stop
.
ptr
(),
step
.
ptr
());
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate slice object!"
);
if
(
!
m_ptr
)
pybind11_fail
(
"Could not allocate slice object!"
);
}
#ifdef PYBIND11_HAS_OPTIONAL
slice
(
std
::
optional
<
ssize_t
>
start
,
std
::
optional
<
ssize_t
>
stop
,
std
::
optional
<
ssize_t
>
step
)
:
slice
(
index_to_object
(
start
),
index_to_object
(
stop
),
index_to_object
(
step
))
{}
#else
slice
(
ssize_t
start_
,
ssize_t
stop_
,
ssize_t
step_
)
:
slice
(
int_
(
start_
),
int_
(
stop_
),
int_
(
step_
))
{}
#endif
bool
compute
(
size_t
length
,
size_t
*
start
,
size_t
*
stop
,
size_t
*
step
,
size_t
*
slicelength
)
const
{
return
PySlice_GetIndicesEx
((
PYBIND11_SLICE_OBJECT
*
)
m_ptr
,
...
...
@@ -1287,6 +1380,12 @@ public:
stop
,
step
,
slicelength
)
==
0
;
}
private:
template
<
typename
T
>
static
object
index_to_object
(
T
index
)
{
return
index
?
object
(
int_
(
*
index
))
:
object
(
none
());
}
};
class
capsule
:
public
object
{
...
...
@@ -1322,7 +1421,7 @@ public:
pybind11_fail
(
"Could not set capsule context!"
);
}
capsule
(
void
(
*
destructor
)())
{
explicit
capsule
(
void
(
*
destructor
)())
{
m_ptr
=
PyCapsule_New
(
reinterpret_cast
<
void
*>
(
destructor
),
nullptr
,
[](
PyObject
*
o
)
{
auto
destructor
=
reinterpret_cast
<
void
(
*
)()
>
(
PyCapsule_GetPointer
(
o
,
nullptr
));
destructor
();
...
...
@@ -1332,6 +1431,7 @@ public:
pybind11_fail
(
"Could not allocate capsule object!"
);
}
// NOLINTNEXTLINE(google-explicit-constructor)
template
<
typename
T
>
operator
T
*
()
const
{
return
get_pointer
<
T
>
();
}
...
...
@@ -1341,14 +1441,19 @@ public:
T
*
get_pointer
()
const
{
auto
name
=
this
->
name
();
T
*
result
=
static_cast
<
T
*>
(
PyCapsule_GetPointer
(
m_ptr
,
name
));
if
(
!
result
)
pybind11_fail
(
"Unable to extract capsule contents!"
);
if
(
!
result
)
{
PyErr_Clear
();
pybind11_fail
(
"Unable to extract capsule contents!"
);
}
return
result
;
}
/// Replaces a capsule's pointer *without* calling the destructor on the existing one.
void
set_pointer
(
const
void
*
value
)
{
if
(
PyCapsule_SetPointer
(
m_ptr
,
const_cast
<
void
*>
(
value
))
!=
0
)
if
(
PyCapsule_SetPointer
(
m_ptr
,
const_cast
<
void
*>
(
value
))
!=
0
)
{
PyErr_Clear
();
pybind11_fail
(
"Could not set capsule pointer"
);
}
}
const
char
*
name
()
const
{
return
PyCapsule_GetName
(
m_ptr
);
}
...
...
@@ -1357,7 +1462,10 @@ public:
class
tuple
:
public
object
{
public:
PYBIND11_OBJECT_CVT
(
tuple
,
object
,
PyTuple_Check
,
PySequence_Tuple
)
explicit
tuple
(
size_t
size
=
0
)
:
object
(
PyTuple_New
((
ssize_t
)
size
),
stolen_t
{})
{
template
<
typename
SzType
=
ssize_t
,
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!"
);
}
size_t
size
()
const
{
return
(
size_t
)
PyTuple_Size
(
m_ptr
);
}
...
...
@@ -1393,7 +1501,7 @@ public:
bool
empty
()
const
{
return
size
()
==
0
;
}
detail
::
dict_iterator
begin
()
const
{
return
{
*
this
,
0
};
}
detail
::
dict_iterator
end
()
const
{
return
{};
}
void
clear
()
const
{
PyDict_Clear
(
ptr
());
}
void
clear
()
/* py-non-
const
*/
{
PyDict_Clear
(
ptr
());
}
template
<
typename
T
>
bool
contains
(
T
&&
key
)
const
{
return
PyDict_Contains
(
m_ptr
,
detail
::
object_or_cast
(
std
::
forward
<
T
>
(
key
)).
ptr
())
==
1
;
}
...
...
@@ -1426,7 +1534,10 @@ public:
class
list
:
public
object
{
public:
PYBIND11_OBJECT_CVT
(
list
,
object
,
PyList_Check
,
PySequence_List
)
explicit
list
(
size_t
size
=
0
)
:
object
(
PyList_New
((
ssize_t
)
size
),
stolen_t
{})
{
template
<
typename
SzType
=
ssize_t
,
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!"
);
}
size_t
size
()
const
{
return
(
size_t
)
PyList_Size
(
m_ptr
);
}
...
...
@@ -1435,12 +1546,15 @@ public:
detail
::
item_accessor
operator
[](
handle
h
)
const
{
return
object
::
operator
[](
h
);
}
detail
::
list_iterator
begin
()
const
{
return
{
*
this
,
0
};
}
detail
::
list_iterator
end
()
const
{
return
{
*
this
,
PyList_GET_SIZE
(
m_ptr
)};
}
template
<
typename
T
>
void
append
(
T
&&
val
)
const
{
template
<
typename
T
>
void
append
(
T
&&
val
)
/* py-non-
const
*/
{
PyList_Append
(
m_ptr
,
detail
::
object_or_cast
(
std
::
forward
<
T
>
(
val
)).
ptr
());
}
template
<
typename
T
>
void
insert
(
size_t
index
,
T
&&
val
)
const
{
PyList_Insert
(
m_ptr
,
static_cast
<
ssize_t
>
(
index
),
detail
::
object_or_cast
(
std
::
forward
<
T
>
(
val
)).
ptr
());
template
<
typename
IdxType
,
typename
ValType
,
detail
::
enable_if_t
<
std
::
is_integral
<
IdxType
>
::
value
,
int
>
=
0
>
void
insert
(
const
IdxType
&
index
,
ValType
&&
val
)
/* py-non-const */
{
PyList_Insert
(
m_ptr
,
ssize_t_cast
(
index
),
detail
::
object_or_cast
(
std
::
forward
<
ValType
>
(
val
)).
ptr
());
}
};
...
...
@@ -1455,10 +1569,10 @@ public:
}
size_t
size
()
const
{
return
(
size_t
)
PySet_Size
(
m_ptr
);
}
bool
empty
()
const
{
return
size
()
==
0
;
}
template
<
typename
T
>
bool
add
(
T
&&
val
)
const
{
template
<
typename
T
>
bool
add
(
T
&&
val
)
/* py-non-
const
*/
{
return
PySet_Add
(
m_ptr
,
detail
::
object_or_cast
(
std
::
forward
<
T
>
(
val
)).
ptr
())
==
0
;
}
void
clear
()
const
{
PySet_Clear
(
m_ptr
);
}
void
clear
()
/* py-non-
const
*/
{
PySet_Clear
(
m_ptr
);
}
template
<
typename
T
>
bool
contains
(
T
&&
val
)
const
{
return
PySet_Contains
(
m_ptr
,
detail
::
object_or_cast
(
std
::
forward
<
T
>
(
val
)).
ptr
())
==
1
;
}
...
...
include/pybind11/stl.h
View file @
e315e1fe
...
...
@@ -9,6 +9,7 @@
#pragma once
#include "detail/common.h"
#include "pybind11.h"
#include <set>
#include <unordered_set>
...
...
@@ -19,33 +20,15 @@
#include <deque>
#include <valarray>
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
// See `detail/common.h` for implementation of these guards.
#if defined(PYBIND11_HAS_OPTIONAL)
# include <optional>
#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
# include <experimental/optional>
#endif
#ifdef __has_include
// std::optional (but including it in c++14 mode isn't allowed)
# if defined(PYBIND11_CPP17) && __has_include(<optional>)
# include <optional>
# define PYBIND11_HAS_OPTIONAL 1
# endif
// std::experimental::optional (but not allowed in c++11 mode)
# if defined(PYBIND11_CPP14) && (__has_include(<experimental/optional>) && \
!__has_include(<optional>))
# include <experimental/optional>
# define PYBIND11_HAS_EXP_OPTIONAL 1
# endif
// std::variant
# if defined(PYBIND11_CPP17) && __has_include(<variant>)
# include <variant>
# define PYBIND11_HAS_VARIANT 1
# endif
#elif defined(_MSC_VER) && defined(PYBIND11_CPP17)
# include <optional>
#if defined(PYBIND11_HAS_VARIANT)
# include <variant>
# define PYBIND11_HAS_OPTIONAL 1
# define PYBIND11_HAS_VARIANT 1
#endif
PYBIND11_NAMESPACE_BEGIN
(
PYBIND11_NAMESPACE
)
...
...
@@ -173,12 +156,12 @@ public:
if
(
!
std
::
is_lvalue_reference
<
T
>::
value
)
policy
=
return_value_policy_override
<
Value
>::
policy
(
policy
);
list
l
(
src
.
size
());
size_t
index
=
0
;
s
size_t
index
=
0
;
for
(
auto
&&
value
:
src
)
{
auto
value_
=
reinterpret_steal
<
object
>
(
value_conv
::
cast
(
forward_like
<
T
>
(
value
),
policy
,
parent
));
if
(
!
value_
)
return
handle
();
PyList_SET_ITEM
(
l
.
ptr
(),
(
ssize_t
)
index
++
,
value_
.
release
().
ptr
());
// steals a reference
PyList_SET_ITEM
(
l
.
ptr
(),
index
++
,
value_
.
release
().
ptr
());
// steals a reference
}
return
l
.
release
();
}
...
...
@@ -230,12 +213,12 @@ public:
template
<
typename
T
>
static
handle
cast
(
T
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
list
l
(
src
.
size
());
size_t
index
=
0
;
s
size_t
index
=
0
;
for
(
auto
&&
value
:
src
)
{
auto
value_
=
reinterpret_steal
<
object
>
(
value_conv
::
cast
(
forward_like
<
T
>
(
value
),
policy
,
parent
));
if
(
!
value_
)
return
handle
();
PyList_SET_ITEM
(
l
.
ptr
(),
(
ssize_t
)
index
++
,
value_
.
release
().
ptr
());
// steals a reference
PyList_SET_ITEM
(
l
.
ptr
(),
index
++
,
value_
.
release
().
ptr
());
// steals a reference
}
return
l
.
release
();
}
...
...
@@ -390,7 +373,3 @@ inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
}
PYBIND11_NAMESPACE_END
(
PYBIND11_NAMESPACE
)
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
include/pybind11/stl_bind.h
View file @
e315e1fe
...
...
@@ -595,6 +595,23 @@ template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &
);
}
template
<
typename
Map
>
struct
keys_view
{
Map
&
map
;
};
template
<
typename
Map
>
struct
values_view
{
Map
&
map
;
};
template
<
typename
Map
>
struct
items_view
{
Map
&
map
;
};
PYBIND11_NAMESPACE_END
(
detail
)
...
...
@@ -602,6 +619,9 @@ template <typename Map, typename holder_type = std::unique_ptr<Map>, typename...
class_
<
Map
,
holder_type
>
bind_map
(
handle
scope
,
const
std
::
string
&
name
,
Args
&&
...
args
)
{
using
KeyType
=
typename
Map
::
key_type
;
using
MappedType
=
typename
Map
::
mapped_type
;
using
KeysView
=
detail
::
keys_view
<
Map
>
;
using
ValuesView
=
detail
::
values_view
<
Map
>
;
using
ItemsView
=
detail
::
items_view
<
Map
>
;
using
Class_
=
class_
<
Map
,
holder_type
>
;
// If either type is a non-module-local bound type then make the map binding non-local as well;
...
...
@@ -615,6 +635,12 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&.
}
Class_
cl
(
scope
,
name
.
c_str
(),
pybind11
::
module_local
(
local
),
std
::
forward
<
Args
>
(
args
)...);
class_
<
KeysView
>
keys_view
(
scope
,
(
"KeysView["
+
name
+
"]"
).
c_str
(),
pybind11
::
module_local
(
local
));
class_
<
ValuesView
>
values_view
(
scope
,
(
"ValuesView["
+
name
+
"]"
).
c_str
(),
pybind11
::
module_local
(
local
));
class_
<
ItemsView
>
items_view
(
scope
,
(
"ItemsView["
+
name
+
"]"
).
c_str
(),
pybind11
::
module_local
(
local
));
cl
.
def
(
init
<>
());
...
...
@@ -628,12 +654,22 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&.
cl
.
def
(
"__iter__"
,
[](
Map
&
m
)
{
return
make_key_iterator
(
m
.
begin
(),
m
.
end
());
},
keep_alive
<
0
,
1
>
()
/* Essential: keep list alive while iterator exists */
keep_alive
<
0
,
1
>
()
/* Essential: keep map alive while iterator exists */
);
cl
.
def
(
"keys"
,
[](
Map
&
m
)
{
return
KeysView
{
m
};
},
keep_alive
<
0
,
1
>
()
/* Essential: keep map alive while view exists */
);
cl
.
def
(
"values"
,
[](
Map
&
m
)
{
return
ValuesView
{
m
};
},
keep_alive
<
0
,
1
>
()
/* Essential: keep map alive while view exists */
);
cl
.
def
(
"items"
,
[](
Map
&
m
)
{
return
make_iterator
(
m
.
begin
(),
m
.
end
())
;
},
keep_alive
<
0
,
1
>
()
/* Essential: keep
list
alive while
iterator
exists */
[](
Map
&
m
)
{
return
ItemsView
{
m
}
;
},
keep_alive
<
0
,
1
>
()
/* Essential: keep
map
alive while
view
exists */
);
cl
.
def
(
"__getitem__"
,
...
...
@@ -654,6 +690,8 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&.
return
true
;
}
);
// Fallback for when the object is not of the key type
cl
.
def
(
"__contains__"
,
[](
Map
&
,
const
object
&
)
->
bool
{
return
false
;
});
// Assignment provided only if the type is copyable
detail
::
map_assignment
<
Map
,
Class_
>
(
cl
);
...
...
@@ -669,6 +707,40 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&.
cl
.
def
(
"__len__"
,
&
Map
::
size
);
keys_view
.
def
(
"__len__"
,
[](
KeysView
&
view
)
{
return
view
.
map
.
size
();
});
keys_view
.
def
(
"__iter__"
,
[](
KeysView
&
view
)
{
return
make_key_iterator
(
view
.
map
.
begin
(),
view
.
map
.
end
());
},
keep_alive
<
0
,
1
>
()
/* Essential: keep view alive while iterator exists */
);
keys_view
.
def
(
"__contains__"
,
[](
KeysView
&
view
,
const
KeyType
&
k
)
->
bool
{
auto
it
=
view
.
map
.
find
(
k
);
if
(
it
==
view
.
map
.
end
())
return
false
;
return
true
;
}
);
// Fallback for when the object is not of the key type
keys_view
.
def
(
"__contains__"
,
[](
KeysView
&
,
const
object
&
)
->
bool
{
return
false
;
});
values_view
.
def
(
"__len__"
,
[](
ValuesView
&
view
)
{
return
view
.
map
.
size
();
});
values_view
.
def
(
"__iter__"
,
[](
ValuesView
&
view
)
{
return
make_value_iterator
(
view
.
map
.
begin
(),
view
.
map
.
end
());
},
keep_alive
<
0
,
1
>
()
/* Essential: keep view alive while iterator exists */
);
items_view
.
def
(
"__len__"
,
[](
ItemsView
&
view
)
{
return
view
.
map
.
size
();
});
items_view
.
def
(
"__iter__"
,
[](
ItemsView
&
view
)
{
return
make_iterator
(
view
.
map
.
begin
(),
view
.
map
.
end
());
},
keep_alive
<
0
,
1
>
()
/* Essential: keep view alive while iterator exists */
);
return
cl
;
}
...
...
noxfile.py
View file @
e315e1fe
import
nox
nox
.
options
.
sessions
=
[
"lint"
,
"tests"
,
"tests_packaging"
]
PYTHON_VERISONS
=
[
"2.7"
,
"3.5"
,
"3.6"
,
"3.7"
,
"3.8"
,
"3.9"
,
"3.10"
]
@
nox
.
session
(
reuse_venv
=
True
)
def
lint
(
session
:
nox
.
Session
)
->
None
:
...
...
@@ -13,7 +14,7 @@ def lint(session: nox.Session) -> None:
session
.
run
(
"pre-commit"
,
"run"
,
"-a"
)
@
nox
.
session
@
nox
.
session
(
python
=
PYTHON_VERISONS
)
def
tests
(
session
:
nox
.
Session
)
->
None
:
"""
Run the tests (requires a compiler).
...
...
pybind11/__init__.py
View file @
e315e1fe
# -*- coding: utf-8 -*-
from
._version
import
version_info
,
__version__
from
.commands
import
get_include
,
get_cmake_dir
from
._version
import
__version__
,
version_info
from
.commands
import
get_cmake_dir
,
get_include
__all__
=
(
"version_info"
,
...
...
pybind11/__main__.py
View file @
e315e1fe
...
...
@@ -5,7 +5,7 @@ import argparse
import
sys
import
sysconfig
from
.commands
import
get_
include
,
get_cmake_dir
from
.commands
import
get_
cmake_dir
,
get_include
def
print_includes
():
...
...
pybind11/_version.py
View file @
e315e1fe
...
...
@@ -8,5 +8,5 @@ def _to_int(s):
return
s
__version__
=
"2.
7.1
"
__version__
=
"2.
8.0
"
version_info
=
tuple
(
_to_int
(
s
)
for
s
in
__version__
.
split
(
"."
))
pybind11/_version.pyi
View file @
e315e1fe
from typing import
Union, Tuple
from typing import
Tuple, Union
def _to_int(s: str) -> Union[int, str]: ...
...
...
pybind11/commands.py
View file @
e315e1fe
# -*- coding: utf-8 -*-
import
os
DIR
=
os
.
path
.
abspath
(
os
.
path
.
dirname
(
__file__
))
...
...
pybind11/setup_helpers.py
View file @
e315e1fe
...
...
@@ -41,23 +41,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import
contextlib
import
os
import
platform
import
shutil
import
sys
import
sysconfig
import
tempfile
import
threading
import
platform
import
warnings
import
sysconfig
try
:
from
setuptools.command.build_ext
import
build_ext
as
_build_ext
from
setuptools
import
Extension
as
_Extension
from
setuptools.command.build_ext
import
build_ext
as
_build_ext
except
ImportError
:
from
distutils.command.build_ext
import
build_ext
as
_build_ext
from
distutils.extension
import
Extension
as
_Extension
import
distutils.errors
import
distutils.ccompiler
import
distutils.errors
WIN
=
sys
.
platform
.
startswith
(
"win32"
)
and
"mingw"
not
in
sysconfig
.
get_platform
()
PY2
=
sys
.
version_info
[
0
]
<
3
...
...
pybind11/setup_helpers.pyi
View file @
e315e1fe
# IMPORTANT: Should stay in sync with setup_helpers.py (mostly checked by CI /
# pre-commit).
from typing import Any, Callable, Dict, Iterator, List, Optional, Type, TypeVar, Union
from types import TracebackType
import contextlib
import distutils.ccompiler
from distutils.command.build_ext import build_ext as _build_ext # type: ignore
from distutils.extension import Extension as _Extension
import distutils.ccompiler
import contextlib
from types import TracebackType
from typing import Any, Callable, Dict, Iterator, List, Optional, Type, TypeVar, Union
WIN: bool
PY2: bool
...
...
Prev
1
2
3
4
5
6
7
8
Next
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