ext: Update pybind11 to v2.8.1

Change-Id: Ia1c7081377f53fd470addf35526f8b28a949a7b0
Signed-off-by: Jason Lowe-Power <jason@lowepower.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/52523
Maintainer: Bobby R. Bruce <bbruce@ucdavis.edu>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Gabe Black <gabe.black@gmail.com>
This commit is contained in:
Jason Lowe-Power
2021-11-06 13:16:21 -07:00
committed by Jason Lowe-Power
parent ba5f68db3d
commit 1e8aeee698
161 changed files with 7820 additions and 3191 deletions

View File

@@ -12,13 +12,17 @@
#include "cast.h"
#include <functional>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
/// \addtogroup annotations
/// @{
/// Annotation for methods
struct is_method { handle class_; is_method(const handle &c) : class_(c) { } };
struct is_method { handle class_;
explicit is_method(const handle &c) : class_(c) {}
};
/// Annotation for operators
struct is_operator { };
@@ -27,16 +31,24 @@ struct is_operator { };
struct is_final { };
/// Annotation for parent scope
struct scope { handle value; scope(const handle &s) : value(s) { } };
struct scope { handle value;
explicit scope(const handle &s) : value(s) {}
};
/// Annotation for documentation
struct doc { const char *value; doc(const char *value) : value(value) { } };
struct doc { const char *value;
explicit doc(const char *value) : value(value) {}
};
/// Annotation for function names
struct name { const char *value; name(const char *value) : value(value) { } };
struct name { const char *value;
explicit name(const char *value) : value(value) {}
};
/// Annotation indicating that a function is an overload associated with a given "sibling"
struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } };
struct sibling { handle value;
explicit sibling(const handle &value) : value(value.ptr()) {}
};
/// Annotation indicating that a class derives from another given type
template <typename T> struct base {
@@ -62,14 +74,34 @@ struct metaclass {
handle value;
PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.")
metaclass() { } // NOLINT(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute
// NOLINTNEXTLINE(modernize-use-equals-default): breaks MSVC 2015 when adding an attribute
metaclass() {}
/// Override pybind11's default metaclass
explicit metaclass(handle value) : value(value) { }
};
/// Specifies a custom callback with signature `void (PyHeapTypeObject*)` that
/// may be used to customize the Python type.
///
/// The callback is invoked immediately before `PyType_Ready`.
///
/// Note: This is an advanced interface, and uses of it may require changes to
/// work with later versions of pybind11. You may wish to consult the
/// implementation of `make_new_python_type` in `detail/classes.h` to understand
/// the context in which the callback will be run.
struct custom_type_setup {
using callback = std::function<void(PyHeapTypeObject *heap_type)>;
explicit custom_type_setup(callback value) : value(std::move(value)) {}
callback value;
};
/// Annotation that marks a class as local to the module:
struct module_local { const bool value; constexpr module_local(bool v = true) : value(v) { } };
struct module_local { const bool value;
constexpr explicit module_local(bool v = true) : value(v) {}
};
/// Annotation to mark enums as an arithmetic type
struct arithmetic { };
@@ -123,7 +155,7 @@ enum op_id : int;
enum op_type : int;
struct undefined_t;
template <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t> struct op_;
inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret);
void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret);
/// Internal data structure which holds metadata about a keyword argument
struct argument_record {
@@ -259,6 +291,9 @@ struct type_record {
/// Custom metaclass (optional)
handle metaclass;
/// Custom type setup.
custom_type_setup::callback custom_type_setup_callback;
/// Multiple inheritance marker
bool multiple_inheritance : 1;
@@ -377,7 +412,7 @@ template <> struct process_attribute<is_new_style_constructor> : process_attribu
};
inline void process_kw_only_arg(const arg &a, function_record *r) {
if (!a.name || strlen(a.name) == 0)
if (!a.name || a.name[0] == '\0')
pybind11_fail("arg(): cannot specify an unnamed argument after an kw_only() annotation");
++r->nargs_kw_only;
}
@@ -463,6 +498,13 @@ struct process_attribute<dynamic_attr> : process_attribute_default<dynamic_attr>
static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; }
};
template <>
struct process_attribute<custom_type_setup> {
static void init(const custom_type_setup &value, type_record *r) {
r->custom_type_setup_callback = value.value;
}
};
template <>
struct process_attribute<is_final> : process_attribute_default<is_final> {
static void init(const is_final &, type_record *r) { r->is_final = true; }
@@ -515,20 +557,31 @@ template <size_t Nurse, size_t Patient> struct process_attribute<keep_alive<Nurs
/// Recursively iterate over variadic template arguments
template <typename... Args> struct process_attributes {
static void init(const Args&... args, function_record *r) {
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
ignore_unused(unused);
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r);
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r);
using expander = int[];
(void) expander{
0, ((void) process_attribute<typename std::decay<Args>::type>::init(args, r), 0)...};
}
static void init(const Args&... args, type_record *r) {
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::init(args, r), 0) ... };
ignore_unused(unused);
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r);
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r);
using expander = int[];
(void) expander{0,
(process_attribute<typename std::decay<Args>::type>::init(args, r), 0)...};
}
static void precall(function_call &call) {
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::precall(call), 0) ... };
ignore_unused(unused);
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call);
using expander = int[];
(void) expander{0,
(process_attribute<typename std::decay<Args>::type>::precall(call), 0)...};
}
static void postcall(function_call &call, handle fn_ret) {
int unused[] = { 0, (process_attribute<typename std::decay<Args>::type>::postcall(call, fn_ret), 0) ... };
ignore_unused(unused);
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call, fn_ret);
PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(fn_ret);
using expander = int[];
(void) expander{
0, (process_attribute<typename std::decay<Args>::type>::postcall(call, fn_ret), 0)...};
}
};
@@ -544,6 +597,7 @@ template <typename... Extra,
size_t named = constexpr_sum(std::is_base_of<arg, Extra>::value...),
size_t self = constexpr_sum(std::is_same<is_method, Extra>::value...)>
constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(nargs, has_args, has_kwargs);
return named == 0 || (self + named + size_t(has_args) + size_t(has_kwargs)) == nargs;
}

View File

@@ -83,7 +83,7 @@ struct buffer_info {
view->strides
? std::vector<ssize_t>(view->strides, view->strides + view->ndim)
: detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize),
view->readonly) {
(view->readonly != 0)) {
this->m_view = view;
this->ownview = ownview;
}
@@ -91,11 +91,9 @@ struct buffer_info {
buffer_info(const buffer_info &) = delete;
buffer_info& operator=(const buffer_info &) = delete;
buffer_info(buffer_info &&other) {
(*this) = std::move(other);
}
buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); }
buffer_info& operator=(buffer_info &&rhs) {
buffer_info &operator=(buffer_info &&rhs) noexcept {
ptr = rhs.ptr;
itemsize = rhs.itemsize;
size = rhs.size;

File diff suppressed because it is too large Load Diff

View File

@@ -11,9 +11,14 @@
#pragma once
#include "pybind11.h"
#include <chrono>
#include <cmath>
#include <ctime>
#include <chrono>
#include <mutex>
#include <time.h>
#include <datetime.h>
// Backport the PyDateTime_DELTA functions from Python3.3 if required
@@ -35,7 +40,7 @@ public:
using rep = typename type::rep;
using period = typename type::period;
using days = std::chrono::duration<uint_fast32_t, std::ratio<86400>>;
using days = std::chrono::duration<int_least32_t, std::ratio<86400>>; // signed 25 bits required by the standard.
bool load(handle src, bool) {
using namespace std::chrono;
@@ -53,11 +58,11 @@ public:
return true;
}
// If invoked with a float we assume it is seconds and convert
else if (PyFloat_Check(src.ptr())) {
if (PyFloat_Check(src.ptr())) {
value = type(duration_cast<duration<rep, period>>(duration<double>(PyFloat_AsDouble(src.ptr()))));
return true;
}
else return false;
return false;
}
// If this is a duration just return it back
@@ -95,6 +100,22 @@ public:
PYBIND11_TYPE_CASTER(type, _("datetime.timedelta"));
};
inline std::tm *localtime_thread_safe(const std::time_t *time, std::tm *buf) {
#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || defined(_MSC_VER)
if (localtime_s(buf, time))
return nullptr;
return buf;
#else
static std::mutex mtx;
std::lock_guard<std::mutex> lock(mtx);
std::tm *tm_ptr = localtime(time);
if (tm_ptr != nullptr) {
*buf = *tm_ptr;
}
return tm_ptr;
#endif
}
// This is for casting times on the system clock into datetime.datetime instances
template <typename Duration> class type_caster<std::chrono::time_point<std::chrono::system_clock, Duration>> {
public:
@@ -161,10 +182,11 @@ public:
// > If std::time_t has lower precision, it is implementation-defined whether the value is rounded or truncated.
// (https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t)
std::time_t tt = system_clock::to_time_t(time_point_cast<system_clock::duration>(src - us));
// this function uses static memory so it's best to copy it out asap just in case
// otherwise other code that is using localtime may break this (not just python code)
std::tm localtime = *std::localtime(&tt);
std::tm localtime;
std::tm *localtime_ptr = localtime_thread_safe(&tt, &localtime);
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,

View File

@@ -129,8 +129,9 @@ extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyOb
// 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop`
// 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment
const auto static_prop = (PyObject *) get_internals().static_property_type;
const auto call_descr_set = descr && value && PyObject_IsInstance(descr, static_prop)
&& !PyObject_IsInstance(value, static_prop);
const auto call_descr_set = (descr != nullptr) && (value != nullptr)
&& (PyObject_IsInstance(descr, static_prop) != 0)
&& (PyObject_IsInstance(value, static_prop) == 0);
if (call_descr_set) {
// Call `static_property.__set__()` instead of replacing the `static_property`.
#if !defined(PYPY_VERSION)
@@ -162,9 +163,7 @@ extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name
Py_INCREF(descr);
return descr;
}
else {
return PyType_Type.tp_getattro(obj, name);
}
return PyType_Type.tp_getattro(obj, name);
}
#endif
@@ -211,7 +210,7 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
internals.direct_conversions.erase(tindex);
if (tinfo->module_local)
registered_local_types_cpp().erase(tindex);
get_local_internals().registered_types_cpp.erase(tindex);
else
internals.registered_types_cpp.erase(tindex);
internals.registered_types_py.erase(tinfo->type);
@@ -329,7 +328,7 @@ inline bool deregister_instance(instance *self, void *valptr, const type_info *t
inline PyObject *make_new_instance(PyTypeObject *type) {
#if defined(PYPY_VERSION)
// PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first inherited
// object is a a plain Python type (i.e. not derived from an extension type). Fix it.
// object is a plain Python type (i.e. not derived from an extension type). Fix it.
ssize_t instance_size = static_cast<ssize_t>(sizeof(instance));
if (type->tp_basicsize < instance_size) {
type->tp_basicsize = instance_size;
@@ -564,7 +563,7 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
view->len = view->itemsize;
for (auto s : info->shape)
view->len *= s;
view->readonly = info->readonly;
view->readonly = static_cast<int>(info->readonly);
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
view->format = const_cast<char *>(info->format.c_str());
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
@@ -684,11 +683,13 @@ inline PyObject* make_new_python_type(const type_record &rec) {
if (rec.buffer_protocol)
enable_buffer_protocol(heap_type);
if (rec.custom_type_setup_callback)
rec.custom_type_setup_callback(heap_type);
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)
: !PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
assert(!rec.dynamic_attr || PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
/* Register type with the parent scope */
if (rec.scope)

View File

@@ -10,8 +10,12 @@
#pragma once
#define PYBIND11_VERSION_MAJOR 2
#define PYBIND11_VERSION_MINOR 6
#define PYBIND11_VERSION_PATCH 2
#define PYBIND11_VERSION_MINOR 8
#define PYBIND11_VERSION_PATCH 1
// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html
// Additional convention: 0xD = dev
#define PYBIND11_VERSION_HEX 0x02080100
#define PYBIND11_NAMESPACE_BEGIN(name) namespace name {
#define PYBIND11_NAMESPACE_END(name) }
@@ -52,6 +56,9 @@
# elif __INTEL_COMPILER < 1900 && defined(PYBIND11_CPP14)
# error pybind11 supports only C++11 with Intel C++ compiler v18. Use v19 or newer for C++14.
# endif
/* The following pragma cannot be pop'ed:
https://community.intel.com/t5/Intel-C-Compiler/Inline-and-no-inline-warning/td-p/1216764 */
# pragma warning disable 2196 // warning #2196: routine is both "inline" and "noinline"
#elif defined(__clang__) && !defined(__apple_build_version__)
# if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3)
# error pybind11 requires clang 3.3 or newer
@@ -82,13 +89,43 @@
# endif
#endif
#if defined(_MSC_VER)
# define PYBIND11_NOINLINE __declspec(noinline)
#else
# define PYBIND11_NOINLINE __attribute__ ((noinline))
#if !defined(PYBIND11_EXPORT_EXCEPTION)
# ifdef __MINGW32__
// workaround for:
// error: 'dllexport' implies default visibility, but xxx has already been declared with a different visibility
# define PYBIND11_EXPORT_EXCEPTION
# else
# define PYBIND11_EXPORT_EXCEPTION PYBIND11_EXPORT
# endif
#endif
#if defined(PYBIND11_CPP14)
// For CUDA, GCC7, GCC8:
// PYBIND11_NOINLINE_FORCED is incompatible with `-Wattributes -Werror`.
// When defining PYBIND11_NOINLINE_FORCED, it is best to also use `-Wno-attributes`.
// However, the measured shared-library size saving when using noinline are only
// 1.7% for CUDA, -0.2% for GCC7, and 0.0% for GCC8 (using -DCMAKE_BUILD_TYPE=MinSizeRel,
// the default under pybind11/tests).
#if !defined(PYBIND11_NOINLINE_FORCED) && \
(defined(__CUDACC__) || (defined(__GNUC__) && (__GNUC__ == 7 || __GNUC__ == 8)))
# define PYBIND11_NOINLINE_DISABLED
#endif
// The PYBIND11_NOINLINE macro is for function DEFINITIONS.
// In contrast, FORWARD DECLARATIONS should never use this macro:
// https://stackoverflow.com/questions/9317473/forward-declaration-of-inline-functions
#if defined(PYBIND11_NOINLINE_DISABLED) // Option for maximum portability and experimentation.
# define PYBIND11_NOINLINE inline
#elif defined(_MSC_VER)
# define PYBIND11_NOINLINE __declspec(noinline) inline
#else
# define PYBIND11_NOINLINE __attribute__ ((noinline)) inline
#endif
#if defined(__MINGW32__)
// For unknown reasons all PYBIND11_DEPRECATED member trigger a warning when declared
// whether it is used or not
# define PYBIND11_DEPRECATED(reason)
#elif defined(PYBIND11_CPP14)
# define PYBIND11_DEPRECATED(reason) [[deprecated(reason)]]
#else
# define PYBIND11_DEPRECATED(reason) __attribute__((deprecated(reason)))
@@ -114,13 +151,38 @@
# define HAVE_ROUND 1
# endif
# pragma warning(push)
# pragma warning(disable: 4510 4610 4512 4005)
// C4505: 'PySlice_GetIndicesEx': unreferenced local function has been removed (PyPy only)
# pragma warning(disable: 4505)
# if defined(_DEBUG) && !defined(Py_DEBUG)
# define PYBIND11_DEBUG_MARKER
# undef _DEBUG
# endif
#endif
// https://en.cppreference.com/w/c/chrono/localtime
#if defined(__STDC_LIB_EXT1__) && !defined(__STDC_WANT_LIB_EXT1__)
# define __STDC_WANT_LIB_EXT1__
#endif
#ifdef __has_include
// std::optional (but including it in c++14 mode isn't allowed)
# if defined(PYBIND11_CPP17) && __has_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>))
# define PYBIND11_HAS_EXP_OPTIONAL 1
# endif
// std::variant
# if defined(PYBIND11_CPP17) && __has_include(<variant>)
# define PYBIND11_HAS_VARIANT 1
# endif
#elif defined(_MSC_VER) && defined(PYBIND11_CPP17)
# define PYBIND11_HAS_OPTIONAL 1
# define PYBIND11_HAS_VARIANT 1
#endif
#include <Python.h>
#include <frameobject.h>
#include <pythread.h>
@@ -162,6 +224,24 @@
#include <memory>
#include <typeindex>
#include <type_traits>
#if defined(__has_include)
# if __has_include(<version>)
# include <version>
# endif
#endif
// #define PYBIND11_STR_LEGACY_PERMISSIVE
// If DEFINED, pybind11::str can hold PyUnicodeObject or PyBytesObject
// (probably surprising and never documented, but this was the
// legacy behavior until and including v2.6.x). As a side-effect,
// pybind11::isinstance<str>() is true for both pybind11::str and
// pybind11::bytes.
// If UNDEFINED, pybind11::str can only hold PyUnicodeObject, and
// pybind11::isinstance<str>() is true only for pybind11::str.
// However, for Python 2 only (!), the pybind11::str caster
// implicitly decodes bytes to PyUnicodeObject. This is to ease
// the transition from the legacy behavior to the non-permissive
// behavior.
#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
@@ -175,8 +255,8 @@
#define PYBIND11_BYTES_SIZE PyBytes_Size
#define PYBIND11_LONG_CHECK(o) PyLong_Check(o)
#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)
#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) o)
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) o)
#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) (o))
#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) (o))
#define PYBIND11_BYTES_NAME "bytes"
#define PYBIND11_STRING_NAME "str"
#define PYBIND11_SLICE_OBJECT PyObject
@@ -254,6 +334,19 @@ extern "C" {
} \
}
#if PY_VERSION_HEX >= 0x03030000
#define PYBIND11_CATCH_INIT_EXCEPTIONS \
catch (pybind11::error_already_set &e) { \
pybind11::raise_from(e, PyExc_ImportError, "initialization failed"); \
return nullptr; \
} catch (const std::exception &e) { \
PyErr_SetString(PyExc_ImportError, e.what()); \
return nullptr; \
} \
#else
#define PYBIND11_CATCH_INIT_EXCEPTIONS \
catch (pybind11::error_already_set &e) { \
PyErr_SetString(PyExc_ImportError, e.what()); \
@@ -263,6 +356,8 @@ extern "C" {
return nullptr; \
} \
#endif
/** \rst
***Deprecated in favor of PYBIND11_MODULE***
@@ -311,30 +406,35 @@ extern "C" {
});
}
\endrst */
#define PYBIND11_MODULE(name, variable) \
static ::pybind11::module_::module_def \
PYBIND11_CONCAT(pybind11_module_def_, name) PYBIND11_MAYBE_UNUSED; \
PYBIND11_MAYBE_UNUSED \
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
PYBIND11_PLUGIN_IMPL(name) { \
PYBIND11_CHECK_PYTHON_VERSION \
PYBIND11_ENSURE_INTERNALS_READY \
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 \
} \
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &variable)
#define PYBIND11_MODULE(name, variable) \
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name) \
PYBIND11_MAYBE_UNUSED; \
PYBIND11_MAYBE_UNUSED \
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
PYBIND11_PLUGIN_IMPL(name) { \
PYBIND11_CHECK_PYTHON_VERSION \
PYBIND11_ENSURE_INTERNALS_READY \
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 \
} \
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable))
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
using ssize_t = Py_ssize_t;
using size_t = std::size_t;
template <typename IntType>
inline ssize_t ssize_t_cast(const IntType &val) {
static_assert(sizeof(IntType) <= sizeof(ssize_t), "Implicit narrowing is not permitted.");
return static_cast<ssize_t>(val);
}
/// Approach used to cast a previously unknown C++ instance into a Python object
enum class return_value_policy : uint8_t {
/** This is the default return value policy, which falls back to the policy
@@ -690,9 +790,6 @@ using function_signature_t = conditional_t<
template <typename T> using is_lambda = satisfies_none_of<remove_reference_t<T>,
std::is_function, std::is_pointer, std::is_member_pointer>;
/// Ignore that a variable is unused in compiler warnings
inline void ignore_unused(const int *) { }
// [workaround(intel)] Internal error on fold expression
/// Apply a function over each element of a parameter pack
#if defined(__cpp_fold_expressions) && !defined(__INTEL_COMPILER)
@@ -705,16 +802,23 @@ using expand_side_effects = bool[];
PYBIND11_NAMESPACE_END(detail)
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4275) // warning C4275: An exported class was derived from a class that wasn't exported. Can be ignored when derived from a STL class.
#endif
/// C++ bindings of builtin Python exceptions
class builtin_exception : public std::runtime_error {
class PYBIND11_EXPORT_EXCEPTION builtin_exception : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
/// Set the error using the Python C API
virtual void set_error() const = 0;
};
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
#define PYBIND11_RUNTIME_EXCEPTION(name, type) \
class name : public builtin_exception { public: \
class PYBIND11_EXPORT_EXCEPTION name : public builtin_exception { public: \
using builtin_exception::builtin_exception; \
name() : name("") { } \
void set_error() const override { PyErr_SetString(type, what()); } \
@@ -727,11 +831,12 @@ PYBIND11_RUNTIME_EXCEPTION(value_error, PyExc_ValueError)
PYBIND11_RUNTIME_EXCEPTION(type_error, PyExc_TypeError)
PYBIND11_RUNTIME_EXCEPTION(buffer_error, PyExc_BufferError)
PYBIND11_RUNTIME_EXCEPTION(import_error, PyExc_ImportError)
PYBIND11_RUNTIME_EXCEPTION(attribute_error, PyExc_AttributeError)
PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybind11::cast or handle::call fail due to a type casting error
PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally
[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); }
[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); }
[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const char *reason) { throw std::runtime_error(reason); }
[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); }
template <typename T, typename SFINAE = void> struct format_descriptor { };
@@ -776,7 +881,8 @@ struct nodelete { template <typename T> void operator()(T*) { } };
PYBIND11_NAMESPACE_BEGIN(detail)
template <typename... Args>
struct overload_cast_impl {
constexpr overload_cast_impl() {}; // NOLINT(modernize-use-equals-default): MSVC 2015 needs this
// NOLINTNEXTLINE(modernize-use-equals-default): MSVC 2015 needs this
constexpr overload_cast_impl() {}
template <typename Return>
constexpr auto operator()(Return (*pf)(Args...)) const noexcept
@@ -832,6 +938,7 @@ public:
// Implicit conversion constructor from any arbitrary container type with values convertible to T
template <typename Container, typename = enable_if_t<std::is_convertible<decltype(*std::begin(std::declval<const Container &>())), T>::value>>
// NOLINTNEXTLINE(google-explicit-constructor)
any_container(const Container &c) : any_container(std::begin(c), std::end(c)) { }
// initializer_list's aren't deducible, so don't get matched by the above template; we need this
@@ -840,9 +947,11 @@ public:
any_container(const std::initializer_list<TIn> &c) : any_container(c.begin(), c.end()) { }
// Avoid copying if given an rvalue vector of the correct type.
// NOLINTNEXTLINE(google-explicit-constructor)
any_container(std::vector<T> &&v) : v(std::move(v)) { }
// Moves the vector out of an rvalue any_container
// NOLINTNEXTLINE(google-explicit-constructor)
operator std::vector<T> &&() && { return std::move(v); }
// Dereferencing obtains a reference to the underlying vector
@@ -857,5 +966,57 @@ public:
// Forward-declaration; see detail/class.h
std::string get_fully_qualified_tp_name(PyTypeObject*);
template <typename T>
inline static std::shared_ptr<T> try_get_shared_from_this(std::enable_shared_from_this<T> *holder_value_ptr) {
// Pre C++17, this code path exploits undefined behavior, but is known to work on many platforms.
// Use at your own risk!
// See also https://en.cppreference.com/w/cpp/memory/enable_shared_from_this, and in particular
// the `std::shared_ptr<Good> gp1 = not_so_good.getptr();` and `try`-`catch` parts of the example.
#if defined(__cpp_lib_enable_shared_from_this) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
return holder_value_ptr->weak_from_this().lock();
#else
try {
return holder_value_ptr->shared_from_this();
}
catch (const std::bad_weak_ptr &) {
return nullptr;
}
#endif
}
// For silencing "unused" compiler warnings in special situations.
template <typename... Args>
#if defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER < 1920 // MSVC 2017
constexpr
#endif
inline void silence_unused_warnings(Args &&...) {}
// MSVC warning C4100: Unreferenced formal parameter
#if defined(_MSC_VER) && _MSC_VER <= 1916
# define PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(...) \
detail::silence_unused_warnings(__VA_ARGS__)
#else
# define PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(...)
#endif
// GCC -Wunused-but-set-parameter All GCC versions (as of July 2021).
#if defined(__GNUG__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
# define PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(...) \
detail::silence_unused_warnings(__VA_ARGS__)
#else
# define PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(...)
#endif
#if defined(_MSC_VER) // All versions (as of July 2021).
// warning C4127: Conditional expression is constant
constexpr inline bool silence_msvc_c4127(bool cond) { return cond; }
# define PYBIND11_SILENCE_MSVC_C4127(...) ::pybind11::detail::silence_msvc_c4127(__VA_ARGS__)
#else
# define PYBIND11_SILENCE_MSVC_C4127(...) __VA_ARGS__
#endif
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -23,15 +23,17 @@ PYBIND11_NAMESPACE_BEGIN(detail)
/* Concatenate type signatures at compile time */
template <size_t N, typename... Ts>
struct descr {
char text[N + 1];
char text[N + 1]{'\0'};
constexpr descr() : text{'\0'} { }
constexpr descr() = default;
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr descr(char const (&s)[N+1]) : descr(s, make_index_sequence<N>()) { }
template <size_t... Is>
constexpr descr(char const (&s)[N+1], index_sequence<Is...>) : text{s[Is]..., '\0'} { }
template <typename... Chars>
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\0'} { }
static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() {
@@ -42,6 +44,7 @@ struct descr {
template <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2>
constexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a, const descr<N2, Ts2...> &b,
index_sequence<Is1...>, index_sequence<Is2...>) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b);
return {a.text[Is1]..., b.text[Is2]...};
}
@@ -74,7 +77,8 @@ constexpr enable_if_t<B, T1> _(const T1 &d, const T2 &) { return d; }
template <bool B, typename T1, typename T2>
constexpr enable_if_t<!B, T2> _(const T1 &, const T2 &d) { return d; }
template <size_t Size> auto constexpr _() -> decltype(int_to_str<Size / 10, Size % 10>::digits) {
template <size_t Size>
auto constexpr _() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {
return int_to_str<Size / 10, Size % 10>::digits;
}

View File

@@ -23,7 +23,7 @@ public:
}
template <typename> using cast_op_type = value_and_holder &;
operator value_and_holder &() { return *value; }
explicit operator value_and_holder &() { return *value; }
static constexpr auto name = _<value_and_holder>();
private:
@@ -94,8 +94,9 @@ void construct(...) {
// construct an Alias from the returned base instance.
template <typename Class>
void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
no_nullptr(ptr);
if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias && !is_alias<Class>(ptr)) {
// We're going to try to construct an alias by moving the cpp type. Whether or not
// that succeeds, we still need to destroy the original cpp pointer (either the
// moved away leftover, if the alias construction works, or the value itself if we
@@ -131,10 +132,11 @@ void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
// derived type (through those holder's implicit conversion from derived class holder constructors).
template <typename Class>
void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(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 (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");
@@ -148,9 +150,10 @@ void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
// need it, we simply move-construct the cpp value into a new instance.
template <typename Class>
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 (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
v_h.value_ptr() = new Cpp<Class>(std::move(result));
@@ -219,7 +222,8 @@ template <typename Func, typename Return, typename... Args>
struct factory<Func, void_type (*)(), Return(Args...)> {
remove_reference_t<Func> class_factory;
factory(Func &&f) : class_factory(std::forward<Func>(f)) { }
// NOLINTNEXTLINE(google-explicit-constructor)
factory(Func &&f) : class_factory(std::forward<Func>(f)) {}
// The given class either has no alias or has no separate alias factory;
// this always constructs the class itself. If the class is registered with an alias
@@ -293,7 +297,13 @@ template <typename Class, typename T, typename O,
enable_if_t<std::is_convertible<O, handle>::value, int> = 0>
void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
construct<Class>(v_h, std::move(result.first), need_alias);
setattr((PyObject *) v_h.inst, "__dict__", result.second);
auto d = handle(result.second);
if (PyDict_Check(d.ptr()) && PyDict_Size(d.ptr()) == 0) {
// Skipping setattr below, to not force use of py::dynamic_attr() for Class unnecessarily.
// See PR #2972 for details.
return;
}
setattr((PyObject *) v_h.inst, "__dict__", d);
}
/// Implementation for py::pickle(GetState, SetState)

View File

@@ -11,8 +11,30 @@
#include "../pytypes.h"
/// Tracks the `internals` and `type_info` ABI version independent of the main library version.
///
/// Some portions of the code use an ABI that is conditional depending on this
/// version number. That allows ABI-breaking changes to be "pre-implemented".
/// Once the default version number is incremented, the conditional logic that
/// no longer applies can be removed. Additionally, users that need not
/// maintain ABI compatibility can increase the version number in order to take
/// advantage of any functionality/efficiency improvements that depend on the
/// newer ABI.
///
/// WARNING: If you choose to manually increase the ABI version, note that
/// pybind11 may not be tested as thoroughly with a non-default ABI version, and
/// further ABI-incompatible changes may be made before the ABI is officially
/// changed to the new version.
#ifndef PYBIND11_INTERNALS_VERSION
# define PYBIND11_INTERNALS_VERSION 4
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
using ExceptionTranslator = void (*)(std::exception_ptr);
PYBIND11_NAMESPACE_BEGIN(detail)
// Forward declarations
inline PyTypeObject *make_static_property_type();
inline PyTypeObject *make_default_metaclass();
@@ -21,30 +43,59 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass);
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
// Thread Specific Storage (TSS) API.
#if PY_VERSION_HEX >= 0x03070000
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
#else
// Usually an int but a long on Cygwin64 with Python 3.x
# define PYBIND11_TLS_KEY_INIT(var) decltype(PyThread_create_key()) var = 0
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
# if PY_MAJOR_VERSION < 3
# define PYBIND11_TLS_DELETE_VALUE(key) \
PyThread_delete_key_value(key)
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
do { \
PyThread_delete_key_value((key)); \
PyThread_set_key_value((key), (value)); \
} while (false)
// Avoid unnecessary allocation of `Py_tss_t`, since we cannot use
// `Py_LIMITED_API` anyway.
# if PYBIND11_INTERNALS_VERSION > 4
# define PYBIND11_TLS_KEY_REF Py_tss_t &
# ifdef __GNUC__
// Clang on macOS warns due to `Py_tss_NEEDS_INIT` not specifying an initializer
// for every field.
# define PYBIND11_TLS_KEY_INIT(var) \
_Pragma("GCC diagnostic push") /**/ \
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \
Py_tss_t var \
= Py_tss_NEEDS_INIT; \
_Pragma("GCC diagnostic pop")
# else
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;
# endif
# define PYBIND11_TLS_KEY_CREATE(var) (PyThread_tss_create(&(var)) == 0)
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get(&(key))
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set(&(key), (value))
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set(&(key), nullptr)
# define PYBIND11_TLS_FREE(key) PyThread_tss_delete(&(key))
# else
# define PYBIND11_TLS_DELETE_VALUE(key) \
PyThread_set_key_value((key), nullptr)
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
PyThread_set_key_value((key), (value))
# define PYBIND11_TLS_KEY_REF Py_tss_t *
# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr;
# define PYBIND11_TLS_KEY_CREATE(var) \
(((var) = PyThread_tss_alloc()) != nullptr && (PyThread_tss_create((var)) == 0))
# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
# endif
# define PYBIND11_TLS_FREE(key) (void)key
#else
// Usually an int but a long on Cygwin64 with Python 3.x
# define PYBIND11_TLS_KEY_REF decltype(PyThread_create_key())
# define PYBIND11_TLS_KEY_INIT(var) PYBIND11_TLS_KEY_REF var = 0;
# define PYBIND11_TLS_KEY_CREATE(var) (((var) = PyThread_create_key()) != -1)
# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))
# if PY_MAJOR_VERSION < 3 || defined(PYPY_VERSION)
// On CPython < 3.4 and on PyPy, `PyThread_set_key_value` strangely does not set
// the value if it has already been set. Instead, it must first be deleted and
// then set again.
inline void tls_replace_value(PYBIND11_TLS_KEY_REF key, void *value) {
PyThread_delete_key_value(key);
PyThread_set_key_value(key, value);
}
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_delete_key_value(key)
# define PYBIND11_TLS_REPLACE_VALUE(key, value) \
::pybind11::detail::tls_replace_value((key), (value))
# else
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_set_key_value((key), nullptr)
# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_set_key_value((key), (value))
# endif
# define PYBIND11_TLS_FREE(key) (void) key
#endif
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
@@ -100,24 +151,33 @@ struct internals {
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash> inactive_override_cache;
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
std::forward_list<void (*) (std::exception_ptr)> registered_exception_translators;
std::forward_list<ExceptionTranslator> registered_exception_translators;
std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across extensions
std::vector<PyObject *> loader_patient_stack; // Used by `loader_life_support`
#if PYBIND11_INTERNALS_VERSION == 4
std::vector<PyObject *> unused_loader_patient_stack_remove_at_v5;
#endif
std::forward_list<std::string> static_strings; // Stores the std::strings backing detail::c_str()
PyTypeObject *static_property_type;
PyTypeObject *default_metaclass;
PyObject *instance_base;
#if defined(WITH_THREAD)
PYBIND11_TLS_KEY_INIT(tstate);
PYBIND11_TLS_KEY_INIT(tstate)
# if PYBIND11_INTERNALS_VERSION > 4
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
# endif // PYBIND11_INTERNALS_VERSION > 4
PyInterpreterState *istate = nullptr;
~internals() {
# if PYBIND11_INTERNALS_VERSION > 4
PYBIND11_TLS_FREE(loader_life_support_tls_key);
# endif // PYBIND11_INTERNALS_VERSION > 4
// This destructor is called *after* Py_Finalize() in finalize_interpreter().
// That *SHOULD BE* fine. The following details what happens when PyThread_tss_free is called.
// PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does nothing.
// PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree.
// PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX). Neither
// of those have anything to do with CPython internals.
// PyMem_RawFree *requires* that the `tstate` be allocated with the CPython allocator.
// That *SHOULD BE* fine. The following details what happens when PyThread_tss_free is
// called. PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does
// nothing. PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree.
// PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX).
// Neither of those have anything to do with CPython internals. PyMem_RawFree *requires*
// that the `tstate` be allocated with the CPython allocator.
PYBIND11_TLS_FREE(tstate);
}
#endif
@@ -149,9 +209,6 @@ struct type_info {
bool module_local : 1;
};
/// Tracks the `internals` and `type_info` ABI version independent of the main library version
#define PYBIND11_INTERNALS_VERSION 4
/// On MSVC, debug and release builds are not ABI-compatible!
#if defined(_MSC_VER) && defined(_DEBUG)
# define PYBIND11_BUILD_TYPE "_debug"
@@ -253,7 +310,7 @@ inline void translate_local_exception(std::exception_ptr p) {
#endif
/// Return a reference to the current `internals` data
PYBIND11_NOINLINE inline internals &get_internals() {
PYBIND11_NOINLINE internals &get_internals() {
auto **&internals_pp = get_internals_pp();
if (internals_pp && *internals_pp)
return **internals_pp;
@@ -276,6 +333,8 @@ PYBIND11_NOINLINE inline internals &get_internals() {
// initial exception translator, below, so add another for our local exception classes.
//
// libstdc++ doesn't require this (types there are identified only by name)
// libc++ with CPython doesn't require this (types are explicitly exported)
// libc++ with PyPy still need it, awaiting further investigation
#if !defined(__GLIBCXX__)
(*internals_pp)->registered_exception_translators.push_front(&translate_local_exception);
#endif
@@ -285,21 +344,21 @@ PYBIND11_NOINLINE inline internals &get_internals() {
internals_ptr = new internals();
#if defined(WITH_THREAD)
#if PY_VERSION_HEX < 0x03090000
PyEval_InitThreads();
#endif
# if PY_VERSION_HEX < 0x03090000
PyEval_InitThreads();
# endif
PyThreadState *tstate = PyThreadState_Get();
#if PY_VERSION_HEX >= 0x03070000
internals_ptr->tstate = PyThread_tss_alloc();
if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate))
pybind11_fail("get_internals: could not successfully initialize the TSS key!");
PyThread_tss_set(internals_ptr->tstate, tstate);
#else
internals_ptr->tstate = PyThread_create_key();
if (internals_ptr->tstate == -1)
pybind11_fail("get_internals: could not successfully initialize the TLS key!");
PyThread_set_key_value(internals_ptr->tstate, tstate);
#endif
if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->tstate)) {
pybind11_fail("get_internals: could not successfully initialize the tstate TSS key!");
}
PYBIND11_TLS_REPLACE_VALUE(internals_ptr->tstate, tstate);
# if PYBIND11_INTERNALS_VERSION > 4
if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->loader_life_support_tls_key)) {
pybind11_fail("get_internals: could not successfully initialize the "
"loader_life_support TSS key!");
}
# endif
internals_ptr->istate = tstate->interp;
#endif
builtins[id] = capsule(internals_pp);
@@ -311,12 +370,57 @@ PYBIND11_NOINLINE inline internals &get_internals() {
return **internals_pp;
}
/// Works like `internals.registered_types_cpp`, but for module-local registered types:
inline type_map<type_info *> &registered_local_types_cpp() {
static type_map<type_info *> locals{};
return locals;
// the internals struct (above) is shared between all the modules. local_internals are only
// for a single module. Any changes made to internals may require an update to
// PYBIND11_INTERNALS_VERSION, breaking backwards compatibility. local_internals is, by design,
// restricted to a single module. Whether a module has local internals or not should not
// impact any other modules, because the only things accessing the local internals is the
// module that contains them.
struct local_internals {
type_map<type_info *> registered_types_cpp;
std::forward_list<ExceptionTranslator> registered_exception_translators;
#if defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
// For ABI compatibility, we can't store the loader_life_support TLS key in
// the `internals` struct directly. Instead, we store it in `shared_data` and
// cache a copy in `local_internals`. If we allocated a separate TLS key for
// each instance of `local_internals`, we could end up allocating hundreds of
// TLS keys if hundreds of different pybind11 modules are loaded (which is a
// plausible number).
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
// Holds the shared TLS key for the loader_life_support stack.
struct shared_loader_life_support_data {
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
shared_loader_life_support_data() {
if (!PYBIND11_TLS_KEY_CREATE(loader_life_support_tls_key)) {
pybind11_fail("local_internals: could not successfully initialize the "
"loader_life_support TLS key!");
}
}
// We can't help but leak the TLS key, because Python never unloads extension modules.
};
local_internals() {
auto &internals = get_internals();
// Get or create the `loader_life_support_stack_key`.
auto &ptr = internals.shared_data["_life_support"];
if (!ptr) {
ptr = new shared_loader_life_support_data;
}
loader_life_support_tls_key
= static_cast<shared_loader_life_support_data *>(ptr)->loader_life_support_tls_key;
}
#endif // defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
};
/// Works like `get_internals`, but for things which are locally registered.
inline local_internals &get_local_internals() {
static local_internals locals;
return locals;
}
/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its
/// `c_str()`. Such strings objects have a long storage duration -- the internal strings are only
/// cleared when the program exits or after interpreter shutdown (when embedding), and so are
@@ -333,14 +437,14 @@ PYBIND11_NAMESPACE_END(detail)
/// Returns a named pointer that is shared among all extension modules (using the same
/// pybind11 version) running in the current interpreter. Names starting with underscores
/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.
inline PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
PYBIND11_NOINLINE void *get_shared_data(const std::string &name) {
auto &internals = detail::get_internals();
auto it = internals.shared_data.find(name);
return it != internals.shared_data.end() ? it->second : nullptr;
}
/// Set the shared data that can be later recovered by `get_shared_data()`.
inline PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {
detail::get_internals().shared_data[name] = data;
return data;
}

View File

@@ -0,0 +1,985 @@
/*
pybind11/detail/type_caster_base.h (originally first part of pybind11/cast.h)
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "../pytypes.h"
#include "common.h"
#include "descr.h"
#include "internals.h"
#include "typeid.h"
#include <cstdint>
#include <iterator>
#include <new>
#include <string>
#include <type_traits>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <utility>
#include <vector>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
/// A life support system for temporary objects created by `type_caster::load()`.
/// Adding a patient will keep it alive up until the enclosing function returns.
class loader_life_support {
private:
loader_life_support* parent = nullptr;
std::unordered_set<PyObject *> keep_alive;
#if defined(WITH_THREAD)
// Store stack pointer in thread-local storage.
static PYBIND11_TLS_KEY_REF get_stack_tls_key() {
# if PYBIND11_INTERNALS_VERSION == 4
return get_local_internals().loader_life_support_tls_key;
# else
return get_internals().loader_life_support_tls_key;
# endif
}
static loader_life_support *get_stack_top() {
return static_cast<loader_life_support *>(PYBIND11_TLS_GET_VALUE(get_stack_tls_key()));
}
static void set_stack_top(loader_life_support *value) {
PYBIND11_TLS_REPLACE_VALUE(get_stack_tls_key(), value);
}
#else
// Use single global variable for stack.
static loader_life_support **get_stack_pp() {
static loader_life_support *global_stack = nullptr;
return global_stack;
}
static loader_life_support *get_stack_top() { return *get_stack_pp(); }
static void set_stack_top(loader_life_support *value) { *get_stack_pp() = value; }
#endif
public:
/// A new patient frame is created when a function is entered
loader_life_support() {
parent = get_stack_top();
set_stack_top(this);
}
/// ... and destroyed after it returns
~loader_life_support() {
if (get_stack_top() != this)
pybind11_fail("loader_life_support: internal error");
set_stack_top(parent);
for (auto* item : keep_alive)
Py_DECREF(item);
}
/// This can only be used inside a pybind11-bound function, either by `argument_loader`
/// at argument preparation time or by `py::cast()` at execution time.
PYBIND11_NOINLINE static void add_patient(handle h) {
loader_life_support *frame = get_stack_top();
if (!frame) {
// NOTE: It would be nice to include the stack frames here, as this indicates
// use of pybind11::cast<> outside the normal call framework, finding such
// a location is challenging. Developers could consider printing out
// stack frame addresses here using something like __builtin_frame_address(0)
throw cast_error("When called outside a bound function, py::cast() cannot "
"do Python -> C++ conversions which require the creation "
"of temporary values");
}
if (frame->keep_alive.insert(h.ptr()).second)
Py_INCREF(h.ptr());
}
};
// Gets the cache entry for the given type, creating it if necessary. The return value is the pair
// returned by emplace, i.e. an iterator for the entry and a bool set to `true` if the entry was
// just created.
inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_type_info_get_cache(PyTypeObject *type);
// 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))
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;
// Check `type` in the current set of registered python types:
auto it = type_dict.find(type);
if (it != type_dict.end()) {
// We found a cache entry for it, so it's either pybind-registered or has pre-computed
// pybind bases, but we have to make sure we haven't already seen the type(s) before: we
// want to follow Python/virtual C++ rules that there should only be one instance of a
// common base.
for (auto *tinfo : it->second) {
// NB: Could use a second set here, rather than doing a linear search, but since
// having a large number of immediate pybind11-registered types seems fairly
// unlikely, that probably isn't worthwhile.
bool found = false;
for (auto *known : bases) {
if (known == tinfo) { found = true; break; }
}
if (!found) bases.push_back(tinfo);
}
}
else if (type->tp_bases) {
// It's some python type, so keep follow its bases classes to look for one or more
// registered types
if (i + 1 == check.size()) {
// When we're at the end, we can pop off the current element to avoid growing
// `check` when adding just one base (which is typical--i.e. when there is no
// multiple inheritance)
check.pop_back();
i--;
}
for (handle parent : reinterpret_borrow<tuple>(type->tp_bases))
check.push_back((PyTypeObject *) parent.ptr());
}
}
}
/**
* Extracts vector of type_info pointers of pybind-registered roots of the given Python type. Will
* be just 1 pybind type for the Python type of a pybind-registered class, or for any Python-side
* derived class that uses single inheritance. Will contain as many types as required for a Python
* class that uses multiple inheritance to inherit (directly or indirectly) from multiple
* pybind-registered classes. Will be empty if neither the type nor any base classes are
* pybind-registered.
*
* The value is cached for the lifetime of the Python type.
*/
inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type) {
auto ins = all_type_info_get_cache(type);
if (ins.second)
// New cache entry: populate it
all_type_info_populate(type, ins.first->second);
return ins.first->second;
}
/**
* Gets a single pybind11 type info for a python type. Returns nullptr if neither the type nor any
* ancestors are pybind11-registered. Throws an exception if there are multiple bases--use
* `all_type_info` instead if you want to support multiple bases.
*/
PYBIND11_NOINLINE detail::type_info* get_type_info(PyTypeObject *type) {
auto &bases = all_type_info(type);
if (bases.empty())
return nullptr;
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())
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())
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))
return ltype;
if (auto gtype = get_global_type_info(tp))
return gtype;
if (throw_if_missing) {
std::string tname = tp.name();
detail::clean_type_id(tname);
pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname + "\"");
}
return nullptr;
}
PYBIND11_NOINLINE handle get_type_handle(const std::type_info &tp, bool throw_if_missing) {
detail::type_info *type_info = get_type_info(tp, throw_if_missing);
return handle(type_info ? ((PyObject *) type_info->type) : nullptr);
}
// Searches the inheritance graph for a registered Python instance, using all_type_info().
PYBIND11_NOINLINE handle find_registered_python_instance(void *src,
const detail::type_info *tinfo) {
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))
return handle((PyObject *) it_i->second).inc_ref();
}
}
return handle();
}
struct value_and_holder {
instance *inst = nullptr;
size_t index = 0u;
const detail::type_info *type = nullptr;
void **vh = nullptr;
// Main constructor for a found value/holder:
value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index) :
inst{i}, index{index}, type{type},
vh{inst->simple_layout ? inst->simple_value_holder : &inst->nonsimple.values_and_holders[vpos]}
{}
// Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
value_and_holder() = default;
// Used for past-the-end iterator
explicit value_and_holder(size_t index) : index{index} {}
template <typename V = void> V *&value_ptr() const {
return reinterpret_cast<V *&>(vh[0]);
}
// True if this `value_and_holder` has a non-null value pointer
explicit operator bool() const { return value_ptr() != nullptr; }
template <typename H> H &holder() const {
return reinterpret_cast<H &>(vh[1]);
}
bool holder_constructed() const {
return inst->simple_layout
? inst->simple_holder_constructed
: (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u;
}
// NOLINTNEXTLINE(readability-make-member-function-const)
void set_holder_constructed(bool v = true) {
if (inst->simple_layout)
inst->simple_holder_constructed = v;
else if (v)
inst->nonsimple.status[index] |= instance::status_holder_constructed;
else
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed;
}
bool instance_registered() const {
return inst->simple_layout
? inst->simple_instance_registered
: ((inst->nonsimple.status[index] & instance::status_instance_registered) != 0);
}
// NOLINTNEXTLINE(readability-make-member-function-const)
void set_instance_registered(bool v = true) {
if (inst->simple_layout)
inst->simple_instance_registered = v;
else if (v)
inst->nonsimple.status[index] |= instance::status_instance_registered;
else
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered;
}
};
// Container for accessing and iterating over an instance's values/holders
struct values_and_holders {
private:
instance *inst;
using type_vec = std::vector<detail::type_info *>;
const type_vec &tinfo;
public:
explicit values_and_holders(instance *inst)
: inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {}
struct iterator {
private:
instance *inst = nullptr;
const type_vec *types = nullptr;
value_and_holder curr;
friend struct values_and_holders;
iterator(instance *inst, const type_vec *tinfo)
: inst{inst}, types{tinfo},
curr(inst /* instance */,
types->empty() ? nullptr : (*types)[0] /* type info */,
0, /* vpos: (non-simple types only): the first vptr comes first */
0 /* index */)
{}
// Past-the-end iterator:
explicit iterator(size_t end) : curr(end) {}
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)
curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs;
++curr.index;
curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr;
return *this;
}
value_and_holder &operator*() { return curr; }
value_and_holder *operator->() { return &curr; }
};
iterator begin() { return iterator(inst, &tinfo); }
iterator end() { return iterator(tinfo.size()); }
iterator find(const type_info *find_type) {
auto it = begin(), endit = end();
while (it != endit && it->type != find_type) ++it;
return it;
}
size_t size() { return tinfo.size(); }
};
/**
* Extracts C++ value and holder pointer references from an instance (which may contain multiple
* values/holders for python-side multiple inheritance) that match the given type. Throws an error
* if the given type (or ValueType, if omitted) is not a pybind11 base of the given instance. If
* `find_type` is omitted (or explicitly specified as nullptr) the first value/holder are returned,
* regardless of type (and the resulting .type will be nullptr).
*
* The returned object should be short-lived: in particular, it must not outlive the called-upon
* instance.
*/
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)
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())
return *it;
if (!throw_if_missing)
return value_and_holder();
#if defined(NDEBUG)
pybind11_fail("pybind11::detail::instance::get_value_and_holder: "
"type is not a pybind11 base of the given instance "
"(compile in debug mode for type details)");
#else
pybind11_fail("pybind11::detail::instance::get_value_and_holder: `" +
get_fully_qualified_tp_name(find_type->type) + "' is not a pybind11 base of the given `" +
get_fully_qualified_tp_name(Py_TYPE(this)) + "' instance");
#endif
}
PYBIND11_NOINLINE void instance::allocate_layout() {
auto &tinfo = all_type_info(Py_TYPE(this));
const size_t n_types = tinfo.size();
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();
// Simple path: no python-side multiple inheritance, and a small-enough holder
if (simple_layout) {
simple_value_holder[0] = nullptr;
simple_holder_constructed = false;
simple_instance_registered = false;
}
else { // multiple base types or a too-large holder
// Allocate space to hold: [v1*][h1][v2*][h2]...[bb...] where [vN*] is a value pointer,
// [hN] is the (uninitialized) holder instance for value N, and [bb...] is a set of bool
// values that tracks whether each associated holder has been initialized. Each [block] is
// padded, if necessary, to an integer multiple of sizeof(void *).
size_t space = 0;
for (auto t : tinfo) {
space += 1; // value pointer
space += t->holder_size_in_ptrs; // holder instance
}
size_t flags_at = space;
space += size_in_ptrs(n_types); // status bytes (holder_constructed and instance_registered)
// Allocate space for flags, values, and holders, and initialize it to 0 (flags and values,
// in particular, need to be 0). Use Python's memory allocation functions: in Python 3.6
// they default to using pymalloc, which is designed to be efficient for small allocations
// like the one we're doing here; in earlier versions (and for larger allocations) they are
// 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();
#else
nonsimple.values_and_holders = (void **) PyMem_New(void *, space);
if (!nonsimple.values_and_holders) throw std::bad_alloc();
std::memset(nonsimple.values_and_holders, 0, space * sizeof(void *));
#endif
nonsimple.status = reinterpret_cast<std::uint8_t *>(&nonsimple.values_and_holders[flags_at]);
}
owned = true;
}
// NOLINTNEXTLINE(readability-make-member-function-const)
PYBIND11_NOINLINE void instance::deallocate_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)
return false;
return isinstance(obj, type);
}
PYBIND11_NOINLINE std::string error_string() {
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred");
return "Unknown internal error occurred";
}
error_scope scope; // Preserve error state
std::string errorString;
if (scope.type) {
errorString += handle(scope.type).attr("__name__").cast<std::string>();
errorString += ": ";
}
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)
PyException_SetTraceback(scope.value, scope.trace);
#endif
#if !defined(PYPY_VERSION)
if (scope.trace) {
auto *trace = (PyTracebackObject *) scope.trace;
/* Get the deepest trace possible */
while (trace->tb_next)
trace = trace->tb_next;
PyFrameObject *frame = trace->tb_frame;
errorString += "\n\nAt:\n";
while (frame) {
#if PY_VERSION_HEX >= 0x03090000
PyCodeObject *f_code = PyFrame_GetCode(frame);
#else
PyCodeObject *f_code = frame->f_code;
Py_INCREF(f_code);
#endif
int lineno = PyFrame_GetLineNumber(frame);
errorString +=
" " + handle(f_code->co_filename).cast<std::string>() +
"(" + std::to_string(lineno) + "): " +
handle(f_code->co_name).cast<std::string>() + "\n";
frame = frame->f_back;
Py_DECREF(f_code);
}
}
#endif
return errorString;
}
PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_info *type ) {
auto &instances = get_internals().registered_instances;
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)
return handle((PyObject *) it->second);
}
}
return handle();
}
inline PyThreadState *get_thread_state_unchecked() {
#if defined(PYPY_VERSION)
return PyThreadState_GET();
#elif PY_VERSION_HEX < 0x03000000
return _PyThreadState_Current;
#elif PY_VERSION_HEX < 0x03050000
return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current);
#elif PY_VERSION_HEX < 0x03050200
return (PyThreadState*) _PyThreadState_Current.value;
#else
return _PyThreadState_UncheckedGet();
#endif
}
// Forward declarations
void keep_alive_impl(handle nurse, handle patient);
inline PyObject *make_new_instance(PyTypeObject *type);
class type_caster_generic {
public:
PYBIND11_NOINLINE explicit type_caster_generic(const std::type_info &type_info)
: typeinfo(get_type_info(type_info)), cpptype(&type_info) {}
explicit type_caster_generic(const type_info *typeinfo)
: typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) {}
bool load(handle src, bool convert) {
return load_impl<type_caster_generic>(src, convert);
}
PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent,
const detail::type_info *tinfo,
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
return handle();
void *src = const_cast<void *>(_src);
if (src == nullptr)
return none().release();
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());
wrapper->owned = false;
void *&valueptr = values_and_holders(wrapper).begin()->value_ptr();
switch (policy) {
case return_value_policy::automatic:
case return_value_policy::take_ownership:
valueptr = src;
wrapper->owned = true;
break;
case return_value_policy::automatic_reference:
case return_value_policy::reference:
valueptr = src;
wrapper->owned = false;
break;
case return_value_policy::copy:
if (copy_constructor)
valueptr = copy_constructor(src);
else {
#if defined(NDEBUG)
throw cast_error("return_value_policy = copy, but type is "
"non-copyable! (compile in debug mode for details)");
#else
std::string type_name(tinfo->cpptype->name());
detail::clean_type_id(type_name);
throw cast_error("return_value_policy = copy, but type " +
type_name + " is non-copyable!");
#endif
}
wrapper->owned = true;
break;
case return_value_policy::move:
if (move_constructor)
valueptr = move_constructor(src);
else if (copy_constructor)
valueptr = copy_constructor(src);
else {
#if defined(NDEBUG)
throw cast_error("return_value_policy = move, but type is neither "
"movable nor copyable! "
"(compile in debug mode for details)");
#else
std::string type_name(tinfo->cpptype->name());
detail::clean_type_id(type_name);
throw cast_error("return_value_policy = move, but type " +
type_name + " is neither movable nor copyable!");
#endif
}
wrapper->owned = true;
break;
case return_value_policy::reference_internal:
valueptr = src;
wrapper->owned = false;
keep_alive_impl(inst, parent);
break;
default:
throw cast_error("unhandled return_value_policy: should not happen!");
}
tinfo->init_instance(wrapper, existing_holder);
return inst.release();
}
// Base methods for generic caster; there are overridden in copyable_holder_caster
void load_value(value_and_holder &&v_h) {
auto *&vptr = v_h.value_ptr();
// Lazy allocation for unallocated values:
if (vptr == nullptr) {
auto *type = v_h.type ? v_h.type : typeinfo;
if (type->operator_new) {
vptr = type->operator_new(type->type_size);
} else {
#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
vptr = ::operator new(type->type_size,
std::align_val_t(type->type_align));
else
#endif
vptr = ::operator new(type->type_size);
}
}
value = vptr;
}
bool try_implicit_casts(handle src, bool convert) {
for (auto &cast : typeinfo->implicit_casts) {
type_caster_generic sub_caster(*cast.first);
if (sub_caster.load(src, convert)) {
value = cast.second(sub_caster.value);
return true;
}
}
return false;
}
bool try_direct_conversions(handle src) {
for (auto &converter : *typeinfo->direct_conversions) {
if (converter(src.ptr(), value))
return true;
}
return false;
}
void check_holder_compat() {}
PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) {
auto caster = type_caster_generic(ti);
if (caster.load(src, false))
return caster.value;
return nullptr;
}
/// Try to load with foreign typeinfo, if available. Used when there is no
/// native typeinfo, or when the native one wasn't able to produce a value.
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))
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)))
return false;
if (auto result = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo)) {
value = result;
return true;
}
return false;
}
// Implementation of `load`; this takes the type of `this` so that it can dispatch the relevant
// bits of code between here and copyable_holder_caster where the two classes need different
// 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);
auto &this_ = static_cast<ThisT &>(*this);
this_.check_holder_compat();
PyTypeObject *srctype = Py_TYPE(src.ptr());
// Case 1: If src is an exact type match for the target type then we can reinterpret_cast
// the instance's value pointer to the target type:
if (srctype == typeinfo->type) {
this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder());
return true;
}
// Case 2: We have a derived class
if (PyType_IsSubtype(srctype, typeinfo->type)) {
auto &bases = all_type_info(srctype);
bool no_cpp_mi = typeinfo->simple_type;
// Case 2a: the python type is a Python-inherited derived class that inherits from just
// one simple (no MI) pybind11 class, or is an exact match, so the C++ instance is of
// the right type and we can use reinterpret_cast.
// (This is essentially the same as case 2b, but because not using multiple inheritance
// is extremely common, we handle it specially to avoid the loop iterator and type
// pointer lookup overhead)
if (bases.size() == 1 && (no_cpp_mi || bases.front()->type == typeinfo->type)) {
this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder());
return true;
}
// Case 2b: the python type inherits from multiple C++ bases. Check the bases to see if
// we can find an exact match (or, for a simple C++ type, an inherited match); if so, we
// can safely reinterpret_cast to the relevant pointer.
if (bases.size() > 1) {
for (auto base : bases) {
if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type) : base->type == typeinfo->type) {
this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder(base));
return true;
}
}
}
// 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))
return true;
}
// Perform an implicit conversion
if (convert) {
for (auto &converter : typeinfo->implicit_conversions) {
auto temp = reinterpret_steal<object>(converter(src.ptr(), typeinfo->type));
if (load_impl<ThisT>(temp, false)) {
loader_life_support::add_patient(temp);
return true;
}
}
if (this_.try_direct_conversions(src))
return true;
}
// Failed to match local typeinfo. Try again with global.
if (typeinfo->module_local) {
if (auto gtype = get_global_type_info(*typeinfo->cpptype)) {
typeinfo = gtype;
return load(src, false);
}
}
// Global typeinfo has precedence over foreign module_local
if (try_load_foreign_module_local(src)) {
return true;
}
// 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;
value = nullptr;
return true;
}
return false;
}
// Called to do type lookup and wrap the pointer and type in a pair when a dynamic_cast
// isn't needed or can't be used. If the type is unknown, sets the error and returns a pair
// with .second = nullptr. (p.first = nullptr is not an error: it becomes None).
PYBIND11_NOINLINE static std::pair<const void *, const type_info *> src_and_type(
const void *src, const std::type_info &cast_type, const std::type_info *rtti_type = nullptr) {
if (auto *tpi = get_type_info(cast_type))
return {src, const_cast<const type_info *>(tpi)};
// Not found, set error:
std::string tname = rtti_type ? rtti_type->name() : cast_type.name();
detail::clean_type_id(tname);
std::string msg = "Unregistered type : " + tname;
PyErr_SetString(PyExc_TypeError, msg.c_str());
return {nullptr, nullptr};
}
const type_info *typeinfo = nullptr;
const std::type_info *cpptype = nullptr;
void *value = nullptr;
};
/**
* Determine suitable casting operator for pointer-or-lvalue-casting type casters. The type caster
* needs to provide `operator T*()` and `operator T&()` operators.
*
* If the type supports moving the value away via an `operator T&&() &&` method, it should use
* `movable_cast_op_type` instead.
*/
template <typename T>
using cast_op_type =
conditional_t<std::is_pointer<remove_reference_t<T>>::value,
typename std::add_pointer<intrinsic_t<T>>::type,
typename std::add_lvalue_reference<intrinsic_t<T>>::type>;
/**
* Determine suitable casting operator for a type caster with a movable value. Such a type caster
* needs to provide `operator T*()`, `operator T&()`, and `operator T&&() &&`. The latter will be
* called in appropriate contexts where the value can be moved rather than copied.
*
* These operator are automatically provided when using the PYBIND11_TYPE_CASTER macro.
*/
template <typename T>
using movable_cast_op_type =
conditional_t<std::is_pointer<typename std::remove_reference<T>::type>::value,
typename std::add_pointer<intrinsic_t<T>>::type,
conditional_t<std::is_rvalue_reference<T>::value,
typename std::add_rvalue_reference<intrinsic_t<T>>::type,
typename std::add_lvalue_reference<intrinsic_t<T>>::type>>;
// std::is_copy_constructible isn't quite enough: it lets std::vector<T> (and similar) through when
// T is non-copyable, but code containing such a copy constructor fails to actually compile.
template <typename T, typename SFINAE = void> struct is_copy_constructible : std::is_copy_constructible<T> {};
// Specialization for types that appear to be copy constructible but also look like stl containers
// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if
// so, copy constructability depends on whether the value_type is copy constructible.
template <typename Container> struct is_copy_constructible<Container, enable_if_t<all_of<
std::is_copy_constructible<Container>,
std::is_same<typename Container::value_type &, typename Container::reference>,
// Avoid infinite recursion
negation<std::is_same<Container, typename Container::value_type>>
>::value>> : is_copy_constructible<typename Container::value_type> {};
// Likewise for std::pair
// (after C++17 it is mandatory that the copy constructor not exist when the two types aren't themselves
// copy constructible, but this can not be relied upon when T1 or T2 are themselves containers).
template <typename T1, typename T2> struct is_copy_constructible<std::pair<T1, T2>>
: all_of<is_copy_constructible<T1>, is_copy_constructible<T2>> {};
// The same problems arise with std::is_copy_assignable, so we use the same workaround.
template <typename T, typename SFINAE = void> struct is_copy_assignable : std::is_copy_assignable<T> {};
template <typename Container> struct is_copy_assignable<Container, enable_if_t<all_of<
std::is_copy_assignable<Container>,
std::is_same<typename Container::value_type &, typename Container::reference>
>::value>> : is_copy_assignable<typename Container::value_type> {};
template <typename T1, typename T2> struct is_copy_assignable<std::pair<T1, T2>>
: all_of<is_copy_assignable<T1>, is_copy_assignable<T2>> {};
PYBIND11_NAMESPACE_END(detail)
// polymorphic_type_hook<itype>::get(src, tinfo) determines whether the object pointed
// to by `src` actually is an instance of some class derived from `itype`.
// If so, it sets `tinfo` to point to the std::type_info representing that derived
// type, and returns a pointer to the start of the most-derived object of that type
// (in which `src` is a subobject; this will be the same address as `src` in most
// single inheritance cases). If not, or if `src` is nullptr, it simply returns `src`
// and leaves `tinfo` at its default value of nullptr.
//
// The default polymorphic_type_hook just returns src. A specialization for polymorphic
// types determines the runtime type of the passed object and adjusts the this-pointer
// appropriately via dynamic_cast<void*>. This is what enables a C++ Animal* to appear
// to Python as a Dog (if Dog inherits from Animal, Animal is polymorphic, Dog is
// registered with pybind11, and this Animal is in fact a Dog).
//
// You may specialize polymorphic_type_hook yourself for types that want to appear
// polymorphic to Python but do not use C++ RTTI. (This is a not uncommon pattern
// in performance-sensitive applications, used most notably in LLVM.)
//
// polymorphic_type_hook_base allows users to specialize polymorphic_type_hook with
// std::enable_if. User provided specializations will always have higher priority than
// the default implementation and specialization provided in polymorphic_type_hook_base.
template <typename itype, typename SFINAE = void>
struct polymorphic_type_hook_base
{
static const void *get(const itype *src, const std::type_info*&) { return src; }
};
template <typename itype>
struct polymorphic_type_hook_base<itype, detail::enable_if_t<std::is_polymorphic<itype>::value>>
{
static const void *get(const itype *src, const std::type_info*& type) {
type = src ? &typeid(*src) : nullptr;
return dynamic_cast<const void*>(src);
}
};
template <typename itype, typename SFINAE = void>
struct polymorphic_type_hook : public polymorphic_type_hook_base<itype> {};
PYBIND11_NAMESPACE_BEGIN(detail)
/// Generic type caster for objects stored on the heap
template <typename type> class type_caster_base : public type_caster_generic {
using itype = intrinsic_t<type>;
public:
static constexpr auto name = _<type>();
type_caster_base() : type_caster_base(typeid(type)) { }
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)
policy = return_value_policy::copy;
return cast(&src, policy, parent);
}
static handle cast(itype &&src, return_value_policy, handle parent) {
return cast(&src, return_value_policy::move, parent);
}
// Returns a (pointer, type_info) pair taking care of necessary type lookup for a
// polymorphic type (using RTTI by default, but can be overridden by specializing
// polymorphic_type_hook). If the instance isn't derived, returns the base version.
static std::pair<const void *, const type_info *> src_and_type(const itype *src) {
auto &cast_type = typeid(itype);
const std::type_info *instance_type = nullptr;
const void *vsrc = polymorphic_type_hook<itype>::get(src, instance_type);
if (instance_type && !same_type(cast_type, *instance_type)) {
// This is a base pointer to a derived type. If the derived type is registered
// with pybind11, we want to make the full derived object available.
// In the typical case where itype is polymorphic, we get the correct
// derived pointer (which may be != base pointer) by a dynamic_cast to
// most derived type. If itype is not polymorphic, we won't get here
// except via a user-provided specialization of polymorphic_type_hook,
// and the user has promised that no this-pointer adjustment is
// required in that case, so it's OK to use static_cast.
if (const auto *tpi = get_type_info(*instance_type))
return {vsrc, tpi};
}
// Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer, so
// don't do a cast
return type_caster_generic::src_and_type(src, cast_type, instance_type);
}
static handle cast(const itype *src, return_value_policy policy, handle parent) {
auto st = src_and_type(src);
return type_caster_generic::cast(
st.first, policy, parent, st.second,
make_copy_constructor(src), make_move_constructor(src));
}
static handle cast_holder(const itype *src, const void *holder) {
auto st = src_and_type(src);
return type_caster_generic::cast(
st.first, return_value_policy::take_ownership, {}, st.second,
nullptr, nullptr, holder);
}
template <typename T> using cast_op_type = detail::cast_op_type<T>;
// NOLINTNEXTLINE(google-explicit-constructor)
operator itype*() { return (type *) value; }
// NOLINTNEXTLINE(google-explicit-constructor)
operator itype&() { if (!value) throw reference_cast_error(); return *((itype *) value); }
protected:
using Constructor = void *(*)(const void *);
/* Only enabled when the types are {copy,move}-constructible *and* when the type
does not have a private operator new implementation. A comma operator is used in the decltype
argument to apply SFINAE to the public copy/move constructors.*/
template <typename T, typename = enable_if_t<is_copy_constructible<T>::value>>
static auto make_copy_constructor(const T *) -> decltype(new T(std::declval<const T>()), Constructor{}) {
return [](const void *arg) -> void * {
return new T(*reinterpret_cast<const T *>(arg));
};
}
template <typename T, typename = enable_if_t<std::is_move_constructible<T>::value>>
static auto make_move_constructor(const T *) -> decltype(new T(std::declval<T&&>()), Constructor{}) {
return [](const void *arg) -> void * {
return new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg))));
};
}
static Constructor make_copy_constructor(...) { return nullptr; }
static Constructor make_move_constructor(...) { return nullptr; }
};
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -29,7 +29,7 @@ inline void erase_all(std::string &string, const std::string &search) {
}
}
PYBIND11_NOINLINE inline void clean_type_id(std::string &name) {
PYBIND11_NOINLINE void clean_type_id(std::string &name) {
#if defined(__GNUG__)
int status = 0;
std::unique_ptr<char, void (*)(void *)> res {

View File

@@ -9,33 +9,31 @@
#pragma once
/* 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
*/
#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
// The C4127 suppression was introduced for Eigen 3.4.0. In theory we could
// make it version specific, or even remove it later, but considering that
// 1. C4127 is generally far more distracting than useful for modern template code, and
// 2. we definitely want to ignore any MSVC warnings originating from Eigen code,
// it is probably best to keep this around indefinitely.
#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
# pragma warning(disable: 4127) // C4127: conditional expression is constant
#endif
#include <Eigen/Core>
#include <Eigen/SparseCore>
#if defined(_MSC_VER)
# pragma warning(pop)
#endif
// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit
// move constructors that break things. We could detect this an explicitly copy, but an extra copy
// of matrices seems highly undesirable.
@@ -77,6 +75,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 +103,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 +153,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,25 +166,22 @@ 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};
}
else if (fixed) {
if (fixed) {
// The type has a fixed size, but is not a vector: abort
return false;
}
else if (fixed_cols) {
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;
return {1, n, stride};
}
else {
// Otherwise it's either fully dynamic, or column dynamic; both become a column vector
if (fixed_rows && rows != n) return false;
} // 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;
return {n, 1, stride};
}
}
static constexpr bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
@@ -344,8 +342,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>;
@@ -469,7 +470,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>;
@@ -570,7 +573,9 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
if (!values || !innerIndices || !outerIndices)
return false;
value = Eigen::MappedSparseMatrix<Scalar, Type::Flags, StorageIndex>(
value = Eigen::MappedSparseMatrix<Scalar,
Type::Flags & (Eigen::RowMajor | Eigen::ColMajor),
StorageIndex>(
shape[0].cast<Index>(), shape[1].cast<Index>(), nnz,
outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data());
@@ -599,9 +604,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

View File

@@ -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)
@@ -76,7 +77,7 @@ struct embedded_module {
using init_t = void (*)();
#endif
embedded_module(const char *name, init_t init) {
if (Py_IsInitialized())
if (Py_IsInitialized() != 0)
pybind11_fail("Can't add new modules after the interpreter has been initialized");
auto result = PyImport_AppendInittab(name, init);
@@ -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) {
if (Py_IsInitialized())
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;

View File

@@ -1,5 +1,5 @@
/*
pybind11/exec.h: Support for evaluating Python expressions and statements
pybind11/eval.h: Support for evaluating Python expressions and statements
from strings and files
Copyright (c) 2016 Klemens Morgenstern <klemens.morgenstern@ed-chemnitz.de> and
@@ -11,6 +11,8 @@
#pragma once
#include <utility>
#include "pybind11.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
@@ -43,7 +45,7 @@ enum eval_mode {
};
template <eval_mode mode = eval_expr>
object eval(str expr, object global = globals(), object local = object()) {
object eval(const str &expr, object global = globals(), object local = object()) {
if (!local)
local = global;
@@ -53,7 +55,7 @@ object eval(str expr, object global = globals(), object local = object()) {
this seems to be the only alternative */
std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
int start;
int start = 0;
switch (mode) {
case eval_expr: start = Py_eval_input; break;
case eval_single_statement: start = Py_single_input; break;
@@ -75,8 +77,8 @@ object eval(const char (&s)[N], object global = globals(), object local = object
return eval<mode>(expr, global, local);
}
inline void exec(str expr, object global = globals(), object local = object()) {
eval<eval_statements>(expr, global, local);
inline void exec(const str &expr, object global = globals(), object local = object()) {
eval<eval_statements>(expr, std::move(global), std::move(local));
}
template <size_t N>
@@ -105,7 +107,7 @@ object eval_file(str fname, object global = globals(), object local = object())
detail::ensure_builtins_in_globals(global);
int start;
int start = 0;
switch (mode) {
case eval_expr: start = Py_eval_input; break;
case eval_single_statement: start = Py_single_input; break;
@@ -134,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());

View File

@@ -43,24 +43,42 @@ public:
captured variables), in which case the roundtrip can be avoided.
*/
if (auto cfunc = func.cpp_function()) {
auto c = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(cfunc.ptr()));
auto rec = (function_record *) c;
auto cfunc_self = PyCFunction_GET_SELF(cfunc.ptr());
if (isinstance<capsule>(cfunc_self)) {
auto c = reinterpret_borrow<capsule>(cfunc_self);
auto rec = (function_record *) c;
if (rec && rec->is_stateless &&
same_type(typeid(function_type), *reinterpret_cast<const std::type_info *>(rec->data[1]))) {
struct capture { function_type f; };
value = ((capture *) &rec->data)->f;
return true;
while (rec != nullptr) {
if (rec->is_stateless
&& same_type(typeid(function_type),
*reinterpret_cast<const std::type_info *>(rec->data[1]))) {
struct capture {
function_type f;
};
value = ((capture *) &rec->data)->f;
return true;
}
rec = rec->next;
}
}
// PYPY segfaults here when passing builtin function like sum.
// Raising an fail exception here works to prevent the segfault, but only on gcc.
// See PR #1413 for full details
}
// ensure GIL is held during functor destruction
struct func_handle {
function f;
func_handle(function&& f_) : f(std::move(f_)) {}
func_handle(const func_handle& f_) {
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
// 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_) {
gil_scoped_acquire acq;
f = f_.f;
return *this;
}
~func_handle() {
gil_scoped_acquire acq;
@@ -71,7 +89,7 @@ public:
// to emulate 'move initialization capture' in C++11
struct func_wrapper {
func_handle hfunc;
func_wrapper(func_handle&& hf): 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)...));
@@ -92,8 +110,7 @@ public:
auto result = f_.template target<function_type>();
if (result)
return cpp_function(*result, policy).release();
else
return cpp_function(std::forward<Func>(f_), policy).release();
return cpp_function(std::forward<Func>(f_), policy).release();
}
PYBIND11_TYPE_CASTER(type, _("Callable[[") + concat(make_caster<Args>::name...) + _("], ")

View File

@@ -0,0 +1,193 @@
/*
pybind11/gil.h: RAII helpers for managing the GIL
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#pragma once
#include "detail/common.h"
#include "detail/internals.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
// forward declarations
PyThreadState *get_thread_state_unchecked();
PYBIND11_NAMESPACE_END(detail)
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
/* The functions below essentially reproduce the PyGILState_* API using a RAII
* pattern, but there are a few important differences:
*
* 1. When acquiring the GIL from an non-main thread during the finalization
* phase, the GILState API blindly terminates the calling thread, which
* is often not what is wanted. This API does not do this.
*
* 2. The gil_scoped_release function can optionally cut the relationship
* of a PyThreadState and its associated thread, which allows moving it to
* another thread (this is a fairly rare/advanced use case).
*
* 3. The reference count of an acquired thread state can be controlled. This
* can be handy to prevent cases where callbacks issued from an external
* thread would otherwise constantly construct and destroy thread state data
* structures.
*
* See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an
* example which uses features 2 and 3 to migrate the Python thread of
* execution to another thread (to run the event loop on the original thread,
* in this case).
*/
class gil_scoped_acquire {
public:
PYBIND11_NOINLINE gil_scoped_acquire() {
auto &internals = detail::get_internals();
tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate);
if (!tstate) {
/* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if
calling from a Python thread). Since we use a different key, this ensures
we don't create a new thread state and deadlock in PyEval_AcquireThread
below. Note we don't save this state with internals.tstate, since we don't
create it we would fail to clear it (its reference count should be > 0). */
tstate = PyGILState_GetThisThreadState();
}
if (!tstate) {
tstate = PyThreadState_New(internals.istate);
#if !defined(NDEBUG)
if (!tstate)
pybind11_fail("scoped_acquire: could not create thread state!");
#endif
tstate->gilstate_counter = 0;
PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
} else {
release = detail::get_thread_state_unchecked() != tstate;
}
if (release) {
PyEval_AcquireThread(tstate);
}
inc_ref();
}
void inc_ref() {
++tstate->gilstate_counter;
}
PYBIND11_NOINLINE void dec_ref() {
--tstate->gilstate_counter;
#if !defined(NDEBUG)
if (detail::get_thread_state_unchecked() != tstate)
pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
if (tstate->gilstate_counter < 0)
pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
#endif
if (tstate->gilstate_counter == 0) {
#if !defined(NDEBUG)
if (!release)
pybind11_fail("scoped_acquire::dec_ref(): internal error!");
#endif
PyThreadState_Clear(tstate);
if (active)
PyThreadState_DeleteCurrent();
PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate);
release = false;
}
}
/// This method will disable the PyThreadState_DeleteCurrent call and the
/// GIL won't be acquired. This method should be used if the interpreter
/// could be shutting down when this is called, as thread deletion is not
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
/// protect subsequent code.
PYBIND11_NOINLINE void disarm() {
active = false;
}
PYBIND11_NOINLINE ~gil_scoped_acquire() {
dec_ref();
if (release)
PyEval_SaveThread();
}
private:
PyThreadState *tstate = nullptr;
bool release = true;
bool active = true;
};
class gil_scoped_release {
public:
explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) {
// `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`.
auto &internals = detail::get_internals();
tstate = PyEval_SaveThread();
if (disassoc) {
auto key = internals.tstate;
PYBIND11_TLS_DELETE_VALUE(key);
}
}
/// This method will disable the PyThreadState_DeleteCurrent call and the
/// GIL won't be acquired. This method should be used if the interpreter
/// could be shutting down when this is called, as thread deletion is not
/// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
/// protect subsequent code.
PYBIND11_NOINLINE void disarm() {
active = false;
}
~gil_scoped_release() {
if (!tstate)
return;
// `PyEval_RestoreThread()` should not be called if runtime is finalizing
if (active)
PyEval_RestoreThread(tstate);
if (disassoc) {
auto key = detail::get_internals().tstate;
PYBIND11_TLS_REPLACE_VALUE(key, tstate);
}
}
private:
PyThreadState *tstate;
bool disassoc;
bool active = true;
};
#elif defined(PYPY_VERSION)
class gil_scoped_acquire {
PyGILState_STATE state;
public:
gil_scoped_acquire() { state = PyGILState_Ensure(); }
~gil_scoped_acquire() { PyGILState_Release(state); }
void disarm() {}
};
class gil_scoped_release {
PyThreadState *state;
public:
gil_scoped_release() { state = PyEval_SaveThread(); }
~gil_scoped_release() { PyEval_RestoreThread(state); }
void disarm() {}
};
#else
class gil_scoped_acquire {
void disarm() {}
};
class gil_scoped_release {
void disarm() {}
};
#endif
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -5,17 +5,31 @@
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
WARNING: The implementation in this file is NOT thread safe. Multiple
threads writing to a redirected ostream concurrently cause data races
and potentially buffer overflows. Therefore it is currently a requirement
that all (possibly) concurrent redirected ostream writes are protected by
a mutex.
#HelpAppreciated: Work on iostream.h thread safety.
For more background see the discussions under
https://github.com/pybind/pybind11/pull/2982 and
https://github.com/pybind/pybind11/pull/2995.
*/
#pragma once
#include "pybind11.h"
#include <streambuf>
#include <ostream>
#include <string>
#include <memory>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <iterator>
#include <memory>
#include <ostream>
#include <streambuf>
#include <string>
#include <utility>
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
@@ -38,25 +52,68 @@ private:
return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof();
}
// This function must be non-virtual to be called in a destructor. If the
// rare MSVC test failure shows up with this version, then this should be
// simplified to a fully qualified call.
// Computes how many bytes at the end of the buffer are part of an
// incomplete sequence of UTF-8 bytes.
// Precondition: pbase() < pptr()
size_t utf8_remainder() const {
const auto rbase = std::reverse_iterator<char *>(pbase());
const auto rpptr = std::reverse_iterator<char *>(pptr());
auto is_ascii = [](char c) {
return (static_cast<unsigned char>(c) & 0x80) == 0x00;
};
auto is_leading = [](char c) {
return (static_cast<unsigned char>(c) & 0xC0) == 0xC0;
};
auto is_leading_2b = [](char c) {
return static_cast<unsigned char>(c) <= 0xDF;
};
auto is_leading_3b = [](char c) {
return static_cast<unsigned char>(c) <= 0xEF;
};
// If the last character is ASCII, there are no incomplete code points
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)
return 0;
const auto dist = static_cast<size_t>(leading - rpptr);
size_t remainder = 0;
if (dist == 0)
remainder = 1; // 1-byte code point is impossible
else if (dist == 1)
remainder = is_leading_2b(*leading) ? 0 : dist + 1;
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
// to a Python string, so that's not handled here.
return remainder;
}
// This function must be non-virtual to be called in a destructor.
int _sync() {
if (pbase() != pptr()) {
{
gil_scoped_acquire tmp;
// This subtraction cannot be negative, so dropping the sign.
str line(pbase(), static_cast<size_t>(pptr() - pbase()));
if (pbase() != pptr()) { // If buffer is not empty
gil_scoped_acquire tmp;
// This subtraction cannot be negative, so dropping the sign.
auto size = static_cast<size_t>(pptr() - pbase());
size_t remainder = utf8_remainder();
if (size > remainder) {
str line(pbase(), size - remainder);
pywrite(line);
pyflush();
// Placed inside gil_scoped_aquire as a mutex to avoid a race
setp(pbase(), epptr());
}
// Copy the remainder at the end of the buffer to the beginning:
if (remainder > 0)
std::memmove(pbase(), pptr() - remainder, remainder);
setp(pbase(), epptr());
pbump(static_cast<int>(remainder));
}
return 0;
}
@@ -66,11 +123,8 @@ private:
}
public:
pythonbuf(object pyostream, size_t buffer_size = 1024)
: buf_size(buffer_size),
d_buffer(new char[buf_size]),
pywrite(pyostream.attr("write")),
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);
}
@@ -117,9 +171,9 @@ protected:
detail::pythonbuf buffer;
public:
scoped_ostream_redirect(
std::ostream &costream = std::cout,
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);
}
@@ -148,10 +202,10 @@ public:
\endrst */
class scoped_estream_redirect : public scoped_ostream_redirect {
public:
scoped_estream_redirect(
std::ostream &costream = std::cerr,
object pyostream = module_::import("sys").attr("stderr"))
: scoped_ostream_redirect(costream,pyostream) {}
explicit scoped_estream_redirect(std::ostream &costream = std::cerr,
const object &pyostream
= module_::import("sys").attr("stderr"))
: scoped_ostream_redirect(costream, pyostream) {}
};
@@ -165,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() {
@@ -210,11 +264,12 @@ PYBIND11_NAMESPACE_END(detail)
m.noisy_function_with_error_printing()
\endrst */
inline class_<detail::OstreamRedirect> add_ostream_redirect(module_ m, std::string name = "ostream_redirect") {
return class_<detail::OstreamRedirect>(m, name.c_str(), module_local())
.def(init<bool,bool>(), arg("stdout")=true, arg("stderr")=true)
inline class_<detail::OstreamRedirect>
add_ostream_redirect(module_ m, const std::string &name = "ostream_redirect") {
return class_<detail::OstreamRedirect>(std::move(m), name.c_str(), module_local())
.def(init<bool, bool>(), arg("stdout") = true, arg("stderr") = true)
.def("__enter__", &detail::OstreamRedirect::enter)
.def("__exit__", [](detail::OstreamRedirect &self_, args) { self_.exit(); });
.def("__exit__", [](detail::OstreamRedirect &self_, const args &) { self_.exit(); });
}
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -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");
}
@@ -164,10 +159,10 @@ struct npy_api {
NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_),
};
typedef struct {
struct PyArray_Dims {
Py_intptr_t *ptr;
int len;
} PyArray_Dims;
};
static npy_api& get() {
static npy_api api = lookup();
@@ -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,14 +322,13 @@ 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(__GNUG__) || defined(_LIBCPP_VERSION) || defined(_GLIBCXX_USE_CXX11_ABI)
// _GLIBCXX_USE_CXX11_ABI indicates that we're using libstdc++ from GCC 5 or newer, independent
// of the actual compiler (Clang can also use libstdc++, but it always defines __GNUC__ == 4).
std::is_trivially_copyable<T>,
#else
// GCC 4 doesn't implement is_trivially_copyable, so approximate it
#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>,
satisfies_any_of<T, std::has_trivial_copy_constructor, std::has_trivial_copy_assign>,
#else
std::is_trivially_copyable<T>,
#endif
satisfies_none_of<T, std::is_reference, std::is_array, is_std_array, std::is_arithmetic, is_complex, std::is_enum>
>;
@@ -466,28 +468,30 @@ public:
explicit dtype(const buffer_info &info) {
dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format)));
// If info.itemsize == 0, use the value calculated from the format string
m_ptr = descr.strip_padding(info.itemsize ? info.itemsize : descr.itemsize()).release().ptr();
m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize())
.release()
.ptr();
}
explicit dtype(const std::string &format) {
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.
static dtype from_args(object args) {
PyObject *ptr = nullptr;
if (!detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) || !ptr)
if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr)
throw error_already_set();
return reinterpret_steal<dtype>(ptr);
}
@@ -507,11 +511,21 @@ public:
return detail::array_descriptor_proxy(m_ptr)->names != nullptr;
}
/// Single-character type code.
/// Single-character code for dtype's kind.
/// For example, floating point types are 'f' and integral types are 'i'.
char kind() const {
return detail::array_descriptor_proxy(m_ptr)->kind;
}
/// Single-character for dtype's type.
/// For example, ``float`` is 'f', ``double`` 'd', ``int`` 'i', and ``long`` 'l'.
char char_() const {
// Note: The signature, `dtype::char_` follows the naming of NumPy's
// public Python API (i.e., ``dtype.char``), rather than its internal
// C API (``PyArray_Descr::type``).
return detail::array_descriptor_proxy(m_ptr)->type;
}
private:
static object _dtype_from_pep3118() {
static PyObject *obj = module_::import("numpy.core._internal")
@@ -533,7 +547,7 @@ 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) && 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});
}
@@ -549,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);
}
};
@@ -736,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());
@@ -750,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());
@@ -779,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) {
@@ -853,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();
}
@@ -863,11 +905,12 @@ public:
: array(std::move(shape), std::move(strides), ptr, base) { }
explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle())
: array_t(private_ctor{}, std::move(shape),
ExtraFlags & f_style
? detail::f_strides(*shape, itemsize())
: detail::c_strides(*shape, itemsize()),
ptr, base) { }
: array_t(private_ctor{},
std::move(shape),
(ExtraFlags & f_style) != 0 ? detail::f_strides(*shape, itemsize())
: detail::c_strides(*shape, itemsize()),
ptr,
base) {}
explicit array_t(ssize_t count, const T *ptr = nullptr, handle base = handle())
: array({count}, {}, ptr, base) { }
@@ -1020,7 +1063,10 @@ struct npy_format_descriptor_name<T, enable_if_t<std::is_integral<T>::value>> {
template <typename T>
struct npy_format_descriptor_name<T, enable_if_t<std::is_floating_point<T>::value>> {
static constexpr auto name = _<std::is_same<T, float>::value || std::is_same<T, double>::value>(
static constexpr auto name = _<std::is_same<T, float>::value
|| std::is_same<T, const float>::value
|| std::is_same<T, double>::value
|| std::is_same<T, const double>::value>(
_("numpy.float") + _<sizeof(T)*8>(), _("numpy.longdouble")
);
};
@@ -1028,7 +1074,9 @@ struct npy_format_descriptor_name<T, enable_if_t<std::is_floating_point<T>::valu
template <typename T>
struct npy_format_descriptor_name<T, enable_if_t<is_complex<T>::value>> {
static constexpr auto name = _<std::is_same<typename T::value_type, float>::value
|| std::is_same<typename T::value_type, double>::value>(
|| std::is_same<typename T::value_type, const float>::value
|| std::is_same<typename T::value_type, double>::value
|| std::is_same<typename T::value_type, const double>::value>(
_("numpy.complex") + _<sizeof(typename T::value_type)*16>(), _("numpy.longcomplex")
);
};
@@ -1093,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 *&)) {
@@ -1117,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
@@ -1277,7 +1328,7 @@ public:
using value_type = container_type::value_type;
using size_type = container_type::size_type;
common_iterator() : p_ptr(0), m_strides() {}
common_iterator() : m_strides() {}
common_iterator(void* ptr, const container_type& strides, const container_type& shape)
: p_ptr(reinterpret_cast<char*>(ptr)), m_strides(strides.size()) {
@@ -1298,7 +1349,7 @@ public:
}
private:
char* p_ptr;
char *p_ptr{0};
container_type m_strides;
};
@@ -1326,9 +1377,8 @@ public:
if (++m_index[i] != m_shape[i]) {
increment_common_iterator(i);
break;
} else {
m_index[i] = 0;
}
m_index[i] = 0;
}
return *this;
}
@@ -1479,8 +1529,7 @@ struct vectorize_returned_array {
static Type create(broadcast_trivial trivial, const std::vector<ssize_t> &shape) {
if (trivial == broadcast_trivial::f_trivial)
return array_t<Return, array::f_style>(shape);
else
return array_t<Return>(shape);
return array_t<Return>(shape);
}
static Return *mutable_data(Type &array) {
@@ -1536,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...,
@@ -1687,7 +1739,3 @@ Helper vectorize(Return (Class::*f)(Args...) const) {
}
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
#if defined(_MSC_VER)
#pragma warning(pop)
#endif

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}
@@ -279,8 +287,10 @@ protected:
struct borrowed_t { };
struct stolen_t { };
#ifndef DOXYGEN_SHOULD_SKIP_THIS // Issue in breathe 4.26.1
template <typename T> friend T reinterpret_borrow(handle);
template <typename T> friend T reinterpret_steal(handle);
#endif
public:
// Only accessible from derived classes and the reinterpret_* functions
@@ -314,14 +324,18 @@ 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)
# pragma warning(push)
# pragma warning(disable: 4275 4251) // warning C4275: An exported class was derived from a class that wasn't exported. Can be ignored when derived from a STL class.
#endif
/// Fetch and hold an error which was already set in Python. An instance of this is typically
/// thrown to propagate python-side errors back through C++ which can either be caught manually or
/// else falls back to the function dispatcher (which then raises the captured error back to
/// python).
class error_already_set : public std::runtime_error {
class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::runtime_error {
public:
/// Constructs a new exception from the current Python error indicator, if any. The current
/// Python error indicator will be cleared.
@@ -339,16 +353,17 @@ public:
/// error variables (but the `.what()` string is still available).
void restore() { PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr()); }
/// If it is impossible to raise the currently-held error, such as in destructor, we can write
/// it out using Python's unraisable hook (sys.unraisablehook). The error context should be
/// some object whose repr() helps identify the location of the error. Python already knows the
/// type and value of the error, so there is no need to repeat that. For example, __func__ could
/// be helpful. After this call, the current object no longer stores the error variables,
/// and neither does Python.
/// If it is impossible to raise the currently-held error, such as in a destructor, we can write
/// it out using Python's unraisable hook (`sys.unraisablehook`). The error context should be
/// some object whose `repr()` helps identify the location of the error. Python already knows the
/// type and value of the error, so there is no need to repeat that. After this call, the current
/// object no longer stores the error variables, and neither does Python.
void discard_as_unraisable(object err_context) {
restore();
PyErr_WriteUnraisable(err_context.ptr());
}
/// An alternate version of `discard_as_unraisable()`, where a string provides information on the
/// location of the error. For example, `__func__` could be helpful.
void discard_as_unraisable(const char *err_context) {
discard_as_unraisable(reinterpret_steal<object>(PYBIND11_FROM_STRING(err_context)));
}
@@ -360,7 +375,9 @@ public:
/// Check if the currently trapped error type matches the given Python exception class (or a
/// subclass thereof). May also be passed a tuple to search for any exception class matches in
/// the given tuple.
bool matches(handle exc) const { return PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()); }
bool matches(handle exc) const {
return (PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()) != 0);
}
const object& type() const { return m_type; }
const object& value() const { return m_value; }
@@ -369,6 +386,50 @@ public:
private:
object m_type, m_value, m_trace;
};
#if defined(_MSC_VER)
# 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
@@ -431,19 +492,17 @@ inline object getattr(handle obj, const char *name) {
inline object getattr(handle obj, handle name, handle default_) {
if (PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr())) {
return reinterpret_steal<object>(result);
} else {
PyErr_Clear();
return reinterpret_borrow<object>(default_);
}
PyErr_Clear();
return reinterpret_borrow<object>(default_);
}
inline object getattr(handle obj, const char *name, handle default_) {
if (PyObject *result = PyObject_GetAttrString(obj.ptr(), name)) {
return reinterpret_steal<object>(result);
} else {
PyErr_Clear();
return reinterpret_borrow<object>(default_);
}
PyErr_Clear();
return reinterpret_borrow<object>(default_);
}
inline void setattr(handle obj, handle name, handle value) {
@@ -476,6 +535,43 @@ inline handle get_function(handle value) {
return value;
}
// Reimplementation of python's dict helper functions to ensure that exceptions
// aren't swallowed (see #2862)
// copied from cpython _PyDict_GetItemStringWithError
inline PyObject * dict_getitemstring(PyObject *v, const char *key)
{
#if PY_MAJOR_VERSION >= 3
PyObject *kv = nullptr, *rv = nullptr;
kv = PyUnicode_FromString(key);
if (kv == NULL) {
throw error_already_set();
}
rv = PyDict_GetItemWithError(v, kv);
Py_DECREF(kv);
if (rv == NULL && PyErr_Occurred()) {
throw error_already_set();
}
return rv;
#else
return PyDict_GetItemString(v, key);
#endif
}
inline PyObject * dict_getitem(PyObject *v, PyObject *key)
{
#if PY_MAJOR_VERSION >= 3
PyObject *rv = PyDict_GetItemWithError(v, key);
if (rv == NULL && PyErr_Occurred()) {
throw error_already_set();
}
return rv;
#else
return PyDict_GetItem(v, key);
#endif
}
// Helper aliases/functions to support implicit casting of values given to python accessors/methods.
// When given a pyobject, this simply returns the pyobject as-is; for other C++ type, the value goes
// through pybind11::cast(obj) to convert it to an `object`.
@@ -487,6 +583,10 @@ object object_or_cast(T &&o);
// Match a PyObject*, which we want to convert directly to handle via its converting constructor
inline handle object_or_cast(PyObject *ptr) { return ptr; }
#if defined(_MSC_VER) && _MSC_VER < 1920
# pragma warning(push)
# pragma warning(disable: 4522) // warning C4522: multiple assignment operators specified
#endif
template <typename Policy>
class accessor : public object_api<accessor<Policy>> {
using key_type = typename Policy::key_type;
@@ -494,7 +594,7 @@ class accessor : public object_api<accessor<Policy>> {
public:
accessor(handle obj, key_type key) : obj(obj), key(std::move(key)) { }
accessor(const accessor &) = default;
accessor(accessor &&) = default;
accessor(accessor &&) noexcept = default;
// accessor overload required to override default assignment operator (templates are not allowed
// to replace default compiler-generated assignments).
@@ -520,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>(); }
@@ -535,6 +636,9 @@ private:
key_type key;
mutable object cache;
};
#if defined(_MSC_VER) && _MSC_VER < 1920
# pragma warning(pop)
#endif
PYBIND11_NAMESPACE_BEGIN(accessor_policies)
struct obj_attr {
@@ -566,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();
}
}
@@ -583,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();
}
}
@@ -600,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();
}
}
@@ -630,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; }
@@ -660,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; }
};
@@ -669,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; }
@@ -712,14 +826,19 @@ 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)) { pos = -1; } }
void increment() {
if (PyDict_Next(obj.ptr(), &pos, &key, &value) == 0) {
pos = -1;
}
}
bool equal(const dict_readonly &b) const { return pos == b.pos; }
private:
@@ -745,16 +864,20 @@ inline bool PyIterable_Check(PyObject *obj) {
if (iter) {
Py_DECREF(iter);
return true;
} else {
PyErr_Clear();
return false;
}
PyErr_Clear();
return false;
}
inline bool PyNone_Check(PyObject *o) { return o == Py_None; }
inline bool PyEllipsis_Check(PyObject *o) { return o == Py_Ellipsis; }
#ifdef PYBIND11_STR_LEGACY_PERMISSIVE
inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); }
#define PYBIND11_STR_CHECK_FUN detail::PyUnicode_Check_Permissive
#else
#define PYBIND11_STR_CHECK_FUN PyUnicode_Check
#endif
inline bool PyStaticMethod_Check(PyObject *o) { return o->ob_type == &PyStaticMethod_Type; }
@@ -797,21 +920,28 @@ PYBIND11_NAMESPACE_END(detail)
Name(handle h, borrowed_t) : Parent(h, borrowed_t{}) { } \
Name(handle h, stolen_t) : Parent(h, stolen_t{}) { } \
PYBIND11_DEPRECATED("Use py::isinstance<py::python_type>(obj) instead") \
bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } \
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(); }
#define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun) \
PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \
Name() : Parent() { }
#define PYBIND11_OBJECT_CHECK_FAILED(Name, o_ptr) \
::pybind11::type_error("Object of type '" + \
::pybind11::detail::get_fully_qualified_tp_name(Py_TYPE(o_ptr)) + \
@@ -820,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); }
@@ -845,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)
@@ -861,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);
@@ -934,19 +1067,22 @@ class bytes;
class str : public object {
public:
PYBIND11_OBJECT_CVT(str, object, detail::PyUnicode_Check_Permissive, raw_str)
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);
@@ -957,15 +1093,16 @@ 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)) {
temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(m_ptr));
if (!temp)
pybind11_fail("Unable to extract string contents! (encoding issue)");
throw error_already_set();
}
char *buffer;
ssize_t length;
char *buffer = nullptr;
ssize_t length = 0;
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);
@@ -1004,24 +1141,28 @@ 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;
ssize_t length;
char *buffer = nullptr;
ssize_t length = 0;
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);
@@ -1038,8 +1179,8 @@ inline bytes::bytes(const pybind11::str &s) {
if (!temp)
pybind11_fail("Unable to extract string contents! (encoding issue)");
}
char *buffer;
ssize_t length;
char *buffer = nullptr;
ssize_t length = 0;
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));
@@ -1049,16 +1190,45 @@ inline bytes::bytes(const pybind11::str &s) {
}
inline str::str(const bytes& b) {
char *buffer;
ssize_t length;
char *buffer = nullptr;
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();
}
/// \addtogroup pytypes
/// @{
class bytearray : public object {
public:
PYBIND11_OBJECT_CVT(bytearray, object, PyByteArray_Check, PyByteArray_FromObject)
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!");
}
bytearray()
: bytearray("", 0) {}
explicit bytearray(const std::string &s) : bytearray(s.data(), s.size()) { }
size_t size() const { return static_cast<size_t>(PyByteArray_Size(m_ptr)); }
explicit operator std::string() const {
char *buffer = PyByteArray_AS_STRING(m_ptr);
ssize_t size = PyByteArray_GET_SIZE(m_ptr);
return std::string(buffer, static_cast<size_t>(size));
}
};
// Note: breathe >= 4.17.0 will fail to build docs if the below two constructors
// are included in the doxygen group; close here and reopen after as a workaround
/// @} pytypes
/// \addtogroup pytypes
/// @{
class none : public object {
@@ -1078,15 +1248,17 @@ 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{}) { }
operator bool() const { return m_ptr && PyLong_AsLong(m_ptr) != 0; }
// NOLINTNEXTLINE(google-explicit-constructor)
operator bool() const { return (m_ptr != nullptr) && PyLong_AsLong(m_ptr) != 0; }
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;
return handle(value ? Py_True : Py_False).inc_ref().ptr();
return handle(value != 0 ? Py_True : Py_False).inc_ref().ptr();
}
};
@@ -1097,18 +1269,16 @@ 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);
return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
}
else {
unsigned long long v = PyLong_AsUnsignedLongLong(o);
return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
}
unsigned long long v = PyLong_AsUnsignedLongLong(o);
return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
}
PYBIND11_NAMESPACE_END(detail)
@@ -1119,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
@@ -1136,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)
@@ -1149,33 +1321,51 @@ 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); }
};
class weakref : public object {
public:
PYBIND11_OBJECT_DEFAULT(weakref, object, PyWeakref_Check)
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!");
}
private:
static PyObject *raw_weakref(PyObject *o) {
return PyWeakref_NewRef(o, nullptr);
}
};
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,
@@ -1190,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 {
@@ -1225,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();
@@ -1235,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>();
}
@@ -1244,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); }
@@ -1260,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); }
@@ -1296,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;
}
@@ -1329,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); }
@@ -1338,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());
}
};
@@ -1358,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;
}
@@ -1457,7 +1668,7 @@ public:
detail::any_container<ssize_t> shape,
detail::any_container<ssize_t> strides) {
return memoryview::from_buffer(
const_cast<void*>(ptr), itemsize, format, shape, strides, true);
const_cast<void *>(ptr), itemsize, format, std::move(shape), std::move(strides), true);
}
template<typename T>
@@ -1514,7 +1725,7 @@ inline memoryview memoryview::from_buffer(
size_t ndim = shape->size();
if (ndim != strides->size())
pybind11_fail("memoryview: shape length doesn't match strides length");
ssize_t size = ndim ? 1 : 0;
ssize_t size = ndim != 0u ? 1 : 0;
for (size_t i = 0; i < ndim; ++i)
size *= (*shape)[i];
Py_buffer view;

View File

@@ -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)
@@ -144,7 +127,7 @@ 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<str>(src))
if (!isinstance<sequence>(src) || isinstance<bytes>(src) || isinstance<str>(src))
return false;
auto s = reinterpret_borrow<sequence>(src);
value.clear();
@@ -159,10 +142,13 @@ template <typename Type, typename Value> struct list_caster {
}
private:
template <typename T = Type,
enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
void reserve_maybe(sequence s, Type *) { value.reserve(s.size()); }
void reserve_maybe(sequence, void *) { }
template <
typename T = Type,
enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
void reserve_maybe(const sequence &s, Type *) {
value.reserve(s.size());
}
void reserve_maybe(const sequence &, void *) {}
public:
template <typename T>
@@ -170,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;
ssize_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();
}
@@ -227,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;
ssize_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();
}
@@ -259,34 +245,35 @@ template <typename Key, typename Value, typename Hash, typename Equal, typename
: map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> { };
// This type caster is intended to be used for std::optional and std::experimental::optional
template<typename T> struct optional_caster {
using value_conv = make_caster<typename T::value_type>;
template<typename Type, typename Value = typename Type::value_type> struct optional_caster {
using value_conv = make_caster<Value>;
template <typename T_>
static handle cast(T_ &&src, return_value_policy policy, handle parent) {
template <typename T>
static handle cast(T &&src, return_value_policy policy, handle parent) {
if (!src)
return none().inc_ref();
if (!std::is_lvalue_reference<T>::value) {
policy = return_value_policy_override<T>::policy(policy);
policy = return_value_policy_override<Value>::policy(policy);
}
return value_conv::cast(*std::forward<T_>(src), policy, parent);
return value_conv::cast(*std::forward<T>(src), policy, parent);
}
bool load(handle src, bool convert) {
if (!src) {
return false;
} else if (src.is_none()) {
}
if (src.is_none()) {
return true; // default-constructed value is already empty
}
value_conv inner_caster;
if (!inner_caster.load(src, convert))
return false;
value.emplace(cast_op<typename T::value_type &&>(std::move(inner_caster)));
value.emplace(cast_op<Value &&>(std::move(inner_caster)));
return true;
}
PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]"));
PYBIND11_TYPE_CASTER(Type, _("Optional[") + value_conv::name + _("]"));
};
#if defined(PYBIND11_HAS_OPTIONAL)
@@ -377,12 +364,12 @@ struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> {
PYBIND11_NAMESPACE_END(detail)
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
#ifdef PYBIND11_HAS_STRING_VIEW
os << str(obj).cast<std::string_view>();
#else
os << (std::string) str(obj);
#endif
return os;
}
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
#if defined(_MSC_VER)
#pragma warning(pop)
#endif

View File

@@ -0,0 +1,103 @@
// Copyright (c) 2021 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#pragma once
#include "../cast.h"
#include "../pybind11.h"
#include "../pytypes.h"
#include "../detail/common.h"
#include "../detail/descr.h"
#include <string>
#ifdef __has_include
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>) && \
PY_VERSION_HEX >= 0x03060000
# include <filesystem>
# define PYBIND11_HAS_FILESYSTEM 1
# endif
#endif
#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)
# error \
"#include <filesystem> is not available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)"
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
#if defined(PYBIND11_HAS_FILESYSTEM)
template<typename T> struct path_caster {
private:
static PyObject* unicode_from_fs_native(const std::string& w) {
#if !defined(PYPY_VERSION)
return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));
#else
// PyPy mistakenly declares the first parameter as non-const.
return PyUnicode_DecodeFSDefaultAndSize(
const_cast<char*>(w.c_str()), ssize_t(w.size()));
#endif
}
static PyObject* unicode_from_fs_native(const std::wstring& w) {
return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));
}
public:
static handle cast(const T& path, return_value_policy, handle) {
if (auto py_str = unicode_from_fs_native(path.native())) {
return module_::import("pathlib").attr("Path")(reinterpret_steal<object>(py_str))
.release();
}
return nullptr;
}
bool load(handle handle, bool) {
// PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of
// calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy
// issue #3168) so we do it ourselves instead.
PyObject* buf = PyOS_FSPath(handle.ptr());
if (!buf) {
PyErr_Clear();
return false;
}
PyObject* native = nullptr;
if constexpr (std::is_same_v<typename T::value_type, char>) {
if (PyUnicode_FSConverter(buf, &native) != 0) {
if (auto c_str = PyBytes_AsString(native)) {
// AsString returns a pointer to the internal buffer, which
// must not be free'd.
value = c_str;
}
}
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
if (PyUnicode_FSDecoder(buf, &native) != 0) {
if (auto c_str = PyUnicode_AsWideCharString(native, nullptr)) {
// AsWideCharString returns a new string that must be free'd.
value = c_str; // Copies the string.
PyMem_Free(c_str);
}
}
}
Py_XDECREF(native);
Py_DECREF(buf);
if (PyErr_Occurred()) {
PyErr_Clear();
return false;
}
return true;
}
PYBIND11_TYPE_CASTER(T, _("os.PathLike"));
};
template<> struct type_caster<std::filesystem::path>
: public path_caster<std::filesystem::path> {};
#endif // PYBIND11_HAS_FILESYSTEM
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@@ -128,11 +128,11 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
arg("x"),
"Add an item to the end of the list");
cl.def(init([](iterable it) {
cl.def(init([](const iterable &it) {
auto v = std::unique_ptr<Vector>(new Vector());
v->reserve(len_hint(it));
for (handle h : it)
v->push_back(h.cast<T>());
v->push_back(h.cast<T>());
return v.release();
}));
@@ -151,27 +151,28 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
"Extend the list by appending all the items in the given list"
);
cl.def("extend",
[](Vector &v, iterable it) {
const size_t old_size = v.size();
v.reserve(old_size + len_hint(it));
try {
for (handle h : it) {
v.push_back(h.cast<T>());
}
} catch (const cast_error &) {
v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size), v.end());
try {
v.shrink_to_fit();
} catch (const std::exception &) {
// Do nothing
}
throw;
}
},
arg("L"),
"Extend the list by appending all the items in the given list"
);
cl.def(
"extend",
[](Vector &v, const iterable &it) {
const size_t old_size = v.size();
v.reserve(old_size + len_hint(it));
try {
for (handle h : it) {
v.push_back(h.cast<T>());
}
} catch (const cast_error &) {
v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size),
v.end());
try {
v.shrink_to_fit();
} catch (const std::exception &) {
// Do nothing
}
throw;
}
},
arg("L"),
"Extend the list by appending all the items in the given list");
cl.def("insert",
[](Vector &v, DiffType i, const T &x) {
@@ -190,7 +191,7 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
[](Vector &v) {
if (v.empty())
throw index_error();
T t = v.back();
T t = std::move(v.back());
v.pop_back();
return t;
},
@@ -200,8 +201,8 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
cl.def("pop",
[wrap_i](Vector &v, DiffType i) {
i = wrap_i(i, v.size());
T t = v[(SizeType) i];
v.erase(v.begin() + i);
T t = std::move(v[(SizeType) i]);
v.erase(std::next(v.begin(), i));
return t;
},
arg("i"),
@@ -216,9 +217,10 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
);
/// Slicing protocol
cl.def("__getitem__",
cl.def(
"__getitem__",
[](const Vector &v, slice slice) -> Vector * {
size_t start, stop, step, slicelength;
size_t start = 0, stop = 0, step = 0, slicelength = 0;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
throw error_already_set();
@@ -233,12 +235,12 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
return seq;
},
arg("s"),
"Retrieve list elements using a slice object"
);
"Retrieve list elements using a slice object");
cl.def("__setitem__",
[](Vector &v, slice slice, const Vector &value) {
size_t start, stop, step, slicelength;
cl.def(
"__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))
throw error_already_set();
@@ -250,8 +252,7 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
start += step;
}
},
"Assign list elements using a slice object"
);
"Assign list elements using a slice object");
cl.def("__delitem__",
[wrap_i](Vector &v, DiffType i) {
@@ -261,9 +262,10 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
"Delete the list elements at index ``i``"
);
cl.def("__delitem__",
cl.def(
"__delitem__",
[](Vector &v, slice slice) {
size_t start, stop, step, slicelength;
size_t start = 0, stop = 0, step = 0, slicelength = 0;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
throw error_already_set();
@@ -277,9 +279,7 @@ void vector_modifiers(enable_if_t<is_copy_constructible<typename Vector::value_t
}
}
},
"Delete list elements using a slice object"
);
"Delete list elements using a slice object");
}
// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
@@ -400,7 +400,7 @@ void vector_buffer_impl(Class_& cl, std::true_type) {
return buffer_info(v.data(), static_cast<ssize_t>(sizeof(T)), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)});
});
cl.def(init([](buffer buf) {
cl.def(init([](const buffer &buf) {
auto info = buf.request();
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");
@@ -413,13 +413,12 @@ void vector_buffer_impl(Class_& cl, std::true_type) {
if (step == 1) {
return Vector(p, end);
}
else {
Vector vec;
vec.reserve((size_t) info.shape[0]);
for (; p != end; p += step)
vec.push_back(*p);
return vec;
}
Vector vec;
vec.reserve((size_t) info.shape[0]);
for (; p != end; p += step)
vec.push_back(*p);
return vec;
}));
return;
@@ -596,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)
@@ -603,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;
@@ -616,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<>());
@@ -629,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__",
@@ -655,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);
@@ -670,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;
}