Commit ddbc74c6 authored by Ralf W. Grosse-Kunstleve's avatar Ralf W. Grosse-Kunstleve Committed by Ralf W. Grosse-Kunstleve
Browse files

Adding .clang-tidy readability-braces-around-statements option.

clang-tidy automatic changes. NO manual changes.
parent 8581584e
...@@ -31,6 +31,7 @@ modernize-use-override, ...@@ -31,6 +31,7 @@ modernize-use-override,
modernize-use-using, modernize-use-using,
*performance*, *performance*,
readability-avoid-const-params-in-decls, readability-avoid-const-params-in-decls,
readability-braces-around-statements,
readability-const-return-type, readability-const-return-type,
readability-container-size-empty, readability-container-size-empty,
readability-delete-null-pointer, readability-delete-null-pointer,
......
...@@ -330,11 +330,13 @@ struct type_record { ...@@ -330,11 +330,13 @@ struct type_record {
bases.append((PyObject *) base_info->type); bases.append((PyObject *) base_info->type);
if (base_info->type->tp_dictoffset != 0) if (base_info->type->tp_dictoffset != 0) {
dynamic_attr = true; dynamic_attr = true;
}
if (caster) if (caster) {
base_info->implicit_casts.emplace_back(type, caster); base_info->implicit_casts.emplace_back(type, caster);
}
} }
}; };
...@@ -410,13 +412,16 @@ template <> struct process_attribute<is_new_style_constructor> : process_attribu ...@@ -410,13 +412,16 @@ template <> struct process_attribute<is_new_style_constructor> : process_attribu
}; };
inline void check_kw_only_arg(const arg &a, function_record *r) { inline void check_kw_only_arg(const arg &a, function_record *r) {
if (r->args.size() > r->nargs_pos && (!a.name || a.name[0] == '\0')) if (r->args.size() > r->nargs_pos && (!a.name || a.name[0] == '\0')) {
pybind11_fail("arg(): cannot specify an unnamed argument after a kw_only() annotation or args() argument"); pybind11_fail("arg(): cannot specify an unnamed argument after a kw_only() annotation or "
"args() argument");
}
} }
inline void append_self_arg_if_needed(function_record *r) { inline void append_self_arg_if_needed(function_record *r) {
if (r->is_method && r->args.empty()) if (r->is_method && r->args.empty()) {
r->args.emplace_back("self", nullptr, handle(), /*convert=*/ true, /*none=*/ false); r->args.emplace_back("self", nullptr, handle(), /*convert=*/true, /*none=*/false);
}
} }
/// Process a keyword argument attribute (*without* a default value) /// Process a keyword argument attribute (*without* a default value)
...@@ -432,8 +437,10 @@ template <> struct process_attribute<arg> : process_attribute_default<arg> { ...@@ -432,8 +437,10 @@ template <> struct process_attribute<arg> : process_attribute_default<arg> {
/// Process a keyword argument attribute (*with* a default value) /// Process a keyword argument attribute (*with* a default value)
template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> { template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
static void init(const arg_v &a, function_record *r) { static void init(const arg_v &a, function_record *r) {
if (r->is_method && r->args.empty()) if (r->is_method && r->args.empty()) {
r->args.emplace_back("self", /*descr=*/ nullptr, /*parent=*/ handle(), /*convert=*/ true, /*none=*/ false); r->args.emplace_back(
"self", /*descr=*/nullptr, /*parent=*/handle(), /*convert=*/true, /*none=*/false);
}
if (!a.value) { if (!a.value) {
#if !defined(NDEBUG) #if !defined(NDEBUG)
...@@ -466,8 +473,10 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> { ...@@ -466,8 +473,10 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
template <> struct process_attribute<kw_only> : process_attribute_default<kw_only> { template <> struct process_attribute<kw_only> : process_attribute_default<kw_only> {
static void init(const kw_only &, function_record *r) { static void init(const kw_only &, function_record *r) {
append_self_arg_if_needed(r); append_self_arg_if_needed(r);
if (r->has_args && r->nargs_pos != static_cast<std::uint16_t>(r->args.size())) if (r->has_args && r->nargs_pos != static_cast<std::uint16_t>(r->args.size())) {
pybind11_fail("Mismatched args() and kw_only(): they must occur at the same relative argument location (or omit kw_only() entirely)"); pybind11_fail("Mismatched args() and kw_only(): they must occur at the same relative "
"argument location (or omit kw_only() entirely)");
}
r->nargs_pos = static_cast<std::uint16_t>(r->args.size()); r->nargs_pos = static_cast<std::uint16_t>(r->args.size());
} }
}; };
...@@ -477,8 +486,9 @@ template <> struct process_attribute<pos_only> : process_attribute_default<pos_o ...@@ -477,8 +486,9 @@ template <> struct process_attribute<pos_only> : process_attribute_default<pos_o
static void init(const pos_only &, function_record *r) { static void init(const pos_only &, function_record *r) {
append_self_arg_if_needed(r); append_self_arg_if_needed(r);
r->nargs_pos_only = static_cast<std::uint16_t>(r->args.size()); r->nargs_pos_only = static_cast<std::uint16_t>(r->args.size());
if (r->nargs_pos_only > r->nargs_pos) if (r->nargs_pos_only > r->nargs_pos) {
pybind11_fail("pos_only(): cannot follow a py::args() argument"); pybind11_fail("pos_only(): cannot follow a py::args() argument");
}
// It also can't follow a kw_only, but a static_assert in pybind11.h checks that // It also can't follow a kw_only, but a static_assert in pybind11.h checks that
} }
}; };
......
...@@ -19,9 +19,11 @@ PYBIND11_NAMESPACE_BEGIN(detail) ...@@ -19,9 +19,11 @@ PYBIND11_NAMESPACE_BEGIN(detail)
inline std::vector<ssize_t> c_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) { inline std::vector<ssize_t> c_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {
auto ndim = shape.size(); auto ndim = shape.size();
std::vector<ssize_t> strides(ndim, itemsize); std::vector<ssize_t> strides(ndim, itemsize);
if (ndim > 0) if (ndim > 0) {
for (size_t i = ndim - 1; i > 0; --i) for (size_t i = ndim - 1; i > 0; --i) {
strides[i - 1] = strides[i] * shape[i]; strides[i - 1] = strides[i] * shape[i];
}
}
return strides; return strides;
} }
...@@ -29,8 +31,9 @@ inline std::vector<ssize_t> c_strides(const std::vector<ssize_t> &shape, ssize_t ...@@ -29,8 +31,9 @@ inline std::vector<ssize_t> c_strides(const std::vector<ssize_t> &shape, ssize_t
inline std::vector<ssize_t> f_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) { inline std::vector<ssize_t> f_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {
auto ndim = shape.size(); auto ndim = shape.size();
std::vector<ssize_t> strides(ndim, itemsize); std::vector<ssize_t> strides(ndim, itemsize);
for (size_t i = 1; i < ndim; ++i) for (size_t i = 1; i < ndim; ++i) {
strides[i] = strides[i - 1] * shape[i - 1]; strides[i] = strides[i - 1] * shape[i - 1];
}
return strides; return strides;
} }
...@@ -53,10 +56,12 @@ struct buffer_info { ...@@ -53,10 +56,12 @@ struct buffer_info {
detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in, bool readonly=false) detail::any_container<ssize_t> shape_in, detail::any_container<ssize_t> strides_in, bool readonly=false)
: ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),
shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) { shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) {
if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) {
pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length");
for (size_t i = 0; i < (size_t) ndim; ++i) }
for (size_t i = 0; i < (size_t) ndim; ++i) {
size *= shape[i]; size *= shape[i];
}
} }
template <typename T> template <typename T>
......
...@@ -60,8 +60,10 @@ public: ...@@ -60,8 +60,10 @@ public:
static constexpr auto name = caster_t::name; static constexpr auto name = caster_t::name;
static handle cast(const std::reference_wrapper<type> &src, return_value_policy policy, handle parent) { static handle cast(const std::reference_wrapper<type> &src, return_value_policy policy, handle parent) {
// It is definitely wrong to take ownership of this pointer, so mask that rvp // It is definitely wrong to take ownership of this pointer, so mask that rvp
if (policy == return_value_policy::take_ownership || policy == return_value_policy::automatic) if (policy == return_value_policy::take_ownership
|| policy == return_value_policy::automatic) {
policy = return_value_policy::automatic_reference; policy = return_value_policy::automatic_reference;
}
return caster_t::cast(&src.get(), policy, parent); return caster_t::cast(&src.get(), policy, parent);
} }
template <typename T> using cast_op_type = std::reference_wrapper<type>; template <typename T> using cast_op_type = std::reference_wrapper<type>;
...@@ -112,8 +114,9 @@ public: ...@@ -112,8 +114,9 @@ public:
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
py_type py_value; py_type py_value;
if (!src) if (!src) {
return false; return false;
}
#if !defined(PYPY_VERSION) #if !defined(PYPY_VERSION)
auto index_check = [](PyObject *o) { return PyIndex_Check(o); }; auto index_check = [](PyObject *o) { return PyIndex_Check(o); };
...@@ -124,10 +127,11 @@ public: ...@@ -124,10 +127,11 @@ public:
#endif #endif
if (std::is_floating_point<T>::value) { if (std::is_floating_point<T>::value) {
if (convert || PyFloat_Check(src.ptr())) if (convert || PyFloat_Check(src.ptr())) {
py_value = (py_type) PyFloat_AsDouble(src.ptr()); py_value = (py_type) PyFloat_AsDouble(src.ptr());
else } else {
return false; return false;
}
} else if (PyFloat_Check(src.ptr()) } else if (PyFloat_Check(src.ptr())
|| (!convert && !PYBIND11_LONG_CHECK(src.ptr()) && !index_check(src.ptr()))) { || (!convert && !PYBIND11_LONG_CHECK(src.ptr()) && !index_check(src.ptr()))) {
return false; return false;
...@@ -214,8 +218,9 @@ public: ...@@ -214,8 +218,9 @@ public:
template<typename T> struct void_caster { template<typename T> struct void_caster {
public: public:
bool load(handle src, bool) { bool load(handle src, bool) {
if (src && src.is_none()) if (src && src.is_none()) {
return true; return true;
}
return false; return false;
} }
static handle cast(T, return_value_policy /* policy */, handle /* parent */) { static handle cast(T, return_value_policy /* policy */, handle /* parent */) {
...@@ -257,8 +262,9 @@ public: ...@@ -257,8 +262,9 @@ public:
} }
static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) { static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) {
if (ptr) if (ptr) {
return capsule(ptr).release(); return capsule(ptr).release();
}
return none().inc_ref(); return none().inc_ref();
} }
...@@ -274,7 +280,9 @@ template <> class type_caster<std::nullptr_t> : public void_caster<std::nullptr_ ...@@ -274,7 +280,9 @@ template <> class type_caster<std::nullptr_t> : public void_caster<std::nullptr_
template <> class type_caster<bool> { template <> class type_caster<bool> {
public: public:
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
if (!src) return false; if (!src) {
return false;
}
if (src.ptr() == Py_True) { if (src.ptr() == Py_True) {
value = true; value = true;
return true; return true;
...@@ -391,8 +399,9 @@ template <typename StringType, bool IsView = false> struct string_caster { ...@@ -391,8 +399,9 @@ template <typename StringType, bool IsView = false> struct string_caster {
value = StringType(buffer, length); value = StringType(buffer, length);
// If we're loading a string_view we need to keep the encoded Python object alive: // If we're loading a string_view we need to keep the encoded Python object alive:
if (IsView) if (IsView) {
loader_life_support::add_patient(utfNbytes); loader_life_support::add_patient(utfNbytes);
}
return true; return true;
} }
...@@ -401,7 +410,9 @@ template <typename StringType, bool IsView = false> struct string_caster { ...@@ -401,7 +410,9 @@ template <typename StringType, bool IsView = false> struct string_caster {
const char *buffer = reinterpret_cast<const char *>(src.data()); const char *buffer = reinterpret_cast<const char *>(src.data());
auto nbytes = ssize_t(src.size() * sizeof(CharT)); auto nbytes = ssize_t(src.size() * sizeof(CharT));
handle s = decode_utfN(buffer, nbytes); handle s = decode_utfN(buffer, nbytes);
if (!s) throw error_already_set(); if (!s) {
throw error_already_set();
}
return s; return s;
} }
...@@ -463,10 +474,14 @@ template <typename CharT> struct type_caster<CharT, enable_if_t<is_std_char_type ...@@ -463,10 +474,14 @@ template <typename CharT> struct type_caster<CharT, enable_if_t<is_std_char_type
CharT one_char = 0; CharT one_char = 0;
public: public:
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
if (!src) return false; if (!src) {
return false;
}
if (src.is_none()) { if (src.is_none()) {
// Defer accepting None to other overloads (if we aren't in convert mode): // Defer accepting None to other overloads (if we aren't in convert mode):
if (!convert) return false; if (!convert) {
return false;
}
none = true; none = true;
return true; return true;
} }
...@@ -474,14 +489,18 @@ public: ...@@ -474,14 +489,18 @@ public:
} }
static handle cast(const CharT *src, return_value_policy policy, handle parent) { static handle cast(const CharT *src, return_value_policy policy, handle parent) {
if (src == nullptr) return pybind11::none().inc_ref(); if (src == nullptr) {
return pybind11::none().inc_ref();
}
return StringCaster::cast(StringType(src), policy, parent); return StringCaster::cast(StringType(src), policy, parent);
} }
static handle cast(CharT src, return_value_policy policy, handle parent) { static handle cast(CharT src, return_value_policy policy, handle parent) {
if (std::is_same<char, CharT>::value) { if (std::is_same<char, CharT>::value) {
handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr); handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr);
if (!s) throw error_already_set(); if (!s) {
throw error_already_set();
}
return s; return s;
} }
return StringCaster::cast(StringType(1, src), policy, parent); return StringCaster::cast(StringType(1, src), policy, parent);
...@@ -491,13 +510,15 @@ public: ...@@ -491,13 +510,15 @@ public:
return none ? nullptr : const_cast<CharT *>(static_cast<StringType &>(str_caster).c_str()); return none ? nullptr : const_cast<CharT *>(static_cast<StringType &>(str_caster).c_str());
} }
explicit operator CharT &() { explicit operator CharT &() {
if (none) if (none) {
throw value_error("Cannot convert None to a character"); throw value_error("Cannot convert None to a character");
}
auto &value = static_cast<StringType &>(str_caster); auto &value = static_cast<StringType &>(str_caster);
size_t str_len = value.size(); size_t str_len = value.size();
if (str_len == 0) if (str_len == 0) {
throw value_error("Cannot convert empty string to a character"); throw value_error("Cannot convert empty string to a character");
}
// If we're in UTF-8 mode, we have two possible failures: one for a unicode character that // If we're in UTF-8 mode, we have two possible failures: one for a unicode character that
// is too high, and one for multiple unicode characters (caught later), so we need to figure // is too high, and one for multiple unicode characters (caught later), so we need to figure
...@@ -531,12 +552,14 @@ public: ...@@ -531,12 +552,14 @@ public:
// string was too long" error). // string was too long" error).
else if (PYBIND11_SILENCE_MSVC_C4127(StringCaster::UTF_N == 16) && str_len == 2) { else if (PYBIND11_SILENCE_MSVC_C4127(StringCaster::UTF_N == 16) && str_len == 2) {
one_char = static_cast<CharT>(value[0]); one_char = static_cast<CharT>(value[0]);
if (one_char >= 0xD800 && one_char < 0xE000) if (one_char >= 0xD800 && one_char < 0xE000) {
throw value_error("Character code point not in range(0x10000)"); throw value_error("Character code point not in range(0x10000)");
}
} }
if (str_len != 1) if (str_len != 1) {
throw value_error("Expected a character, but multi-character string found"); throw value_error("Expected a character, but multi-character string found");
}
one_char = value[0]; one_char = value[0];
return one_char; return one_char;
...@@ -554,11 +577,13 @@ template <template<typename...> class Tuple, typename... Ts> class tuple_caster ...@@ -554,11 +577,13 @@ template <template<typename...> class Tuple, typename... Ts> class tuple_caster
public: public:
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
if (!isinstance<sequence>(src)) if (!isinstance<sequence>(src)) {
return false; return false;
}
const auto seq = reinterpret_borrow<sequence>(src); const auto seq = reinterpret_borrow<sequence>(src);
if (seq.size() != size) if (seq.size() != size) {
return false; return false;
}
return load_impl(seq, convert, indices{}); return load_impl(seq, convert, indices{});
} }
...@@ -570,7 +595,9 @@ public: ...@@ -570,7 +595,9 @@ public:
// copied from the PYBIND11_TYPE_CASTER macro // copied from the PYBIND11_TYPE_CASTER macro
template <typename T> template <typename T>
static handle cast(T *src, return_value_policy policy, handle parent) { static handle cast(T *src, return_value_policy policy, handle parent) {
if (!src) return none().release(); if (!src) {
return none().release();
}
if (policy == return_value_policy::take_ownership) { if (policy == return_value_policy::take_ownership) {
auto h = cast(std::move(*src), policy, parent); auto h = cast(std::move(*src), policy, parent);
delete src; delete src;
...@@ -597,8 +624,9 @@ protected: ...@@ -597,8 +624,9 @@ protected:
template <size_t... Is> template <size_t... Is>
bool load_impl(const sequence &seq, bool convert, index_sequence<Is...>) { bool load_impl(const sequence &seq, bool convert, index_sequence<Is...>) {
#ifdef __cpp_fold_expressions #ifdef __cpp_fold_expressions
if ((... || !std::get<Is>(subcasters).load(seq[Is], convert))) if ((... || !std::get<Is>(subcasters).load(seq[Is], convert))) {
return false; return false;
}
#else #else
for (bool r : {std::get<Is>(subcasters).load(seq[Is], convert)...}) for (bool r : {std::get<Is>(subcasters).load(seq[Is], convert)...})
if (!r) if (!r)
...@@ -615,13 +643,16 @@ protected: ...@@ -615,13 +643,16 @@ protected:
std::array<object, size> entries{{ std::array<object, size> entries{{
reinterpret_steal<object>(make_caster<Ts>::cast(std::get<Is>(std::forward<T>(src)), policy, parent))... reinterpret_steal<object>(make_caster<Ts>::cast(std::get<Is>(std::forward<T>(src)), policy, parent))...
}}; }};
for (const auto &entry: entries) for (const auto &entry : entries) {
if (!entry) if (!entry) {
return handle(); return handle();
}
}
tuple result(size); tuple result(size);
int counter = 0; int counter = 0;
for (auto & entry: entries) for (auto &entry : entries) {
PyTuple_SET_ITEM(result.ptr(), counter++, entry.release().ptr()); PyTuple_SET_ITEM(result.ptr(), counter++, entry.release().ptr());
}
return result.release(); return result.release();
} }
...@@ -676,8 +707,9 @@ public: ...@@ -676,8 +707,9 @@ public:
protected: protected:
friend class type_caster_generic; friend class type_caster_generic;
void check_holder_compat() { void check_holder_compat() {
if (typeinfo->default_holder) if (typeinfo->default_holder) {
throw cast_error("Unable to load a custom holder type from a default-holder instance"); throw cast_error("Unable to load a custom holder type from a default-holder instance");
}
} }
bool load_value(value_and_holder &&v_h) { bool load_value(value_and_holder &&v_h) {
...@@ -793,8 +825,9 @@ struct pyobject_caster { ...@@ -793,8 +825,9 @@ struct pyobject_caster {
return true; return true;
} }
#endif #endif
if (!isinstance<type>(src)) if (!isinstance<type>(src)) {
return false; return false;
}
value = reinterpret_borrow<type>(src); value = reinterpret_borrow<type>(src);
return true; return true;
} }
...@@ -901,12 +934,14 @@ template <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> = ...@@ -901,12 +934,14 @@ template <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> =
object cast(T &&value, return_value_policy policy = return_value_policy::automatic_reference, object cast(T &&value, return_value_policy policy = return_value_policy::automatic_reference,
handle parent = handle()) { handle parent = handle()) {
using no_ref_T = typename std::remove_reference<T>::type; using no_ref_T = typename std::remove_reference<T>::type;
if (policy == return_value_policy::automatic) if (policy == return_value_policy::automatic) {
policy = std::is_pointer<no_ref_T>::value ? return_value_policy::take_ownership : policy = std::is_pointer<no_ref_T>::value ? return_value_policy::take_ownership :
std::is_lvalue_reference<T>::value ? return_value_policy::copy : return_value_policy::move; std::is_lvalue_reference<T>::value ? return_value_policy::copy : return_value_policy::move;
else if (policy == return_value_policy::automatic_reference) } else if (policy == return_value_policy::automatic_reference) {
policy = std::is_pointer<no_ref_T>::value ? return_value_policy::reference : policy = std::is_pointer<no_ref_T>::value ? return_value_policy::reference
std::is_lvalue_reference<T>::value ? return_value_policy::copy : return_value_policy::move; : std::is_lvalue_reference<T>::value ? return_value_policy::copy
: return_value_policy::move;
}
return reinterpret_steal<object>(detail::make_caster<T>::cast(std::forward<T>(value), policy, parent)); return reinterpret_steal<object>(detail::make_caster<T>::cast(std::forward<T>(value), policy, parent));
} }
...@@ -939,8 +974,9 @@ template <typename T> detail::enable_if_t<detail::move_always<T>::value, T> cast ...@@ -939,8 +974,9 @@ template <typename T> detail::enable_if_t<detail::move_always<T>::value, T> cast
return move<T>(std::move(object)); return move<T>(std::move(object));
} }
template <typename T> detail::enable_if_t<detail::move_if_unreferenced<T>::value, T> cast(object &&object) { template <typename T> detail::enable_if_t<detail::move_if_unreferenced<T>::value, T> cast(object &&object) {
if (object.ref_count() > 1) if (object.ref_count() > 1) {
return cast<T>(object); return cast<T>(object);
}
return move<T>(std::move(object)); return move<T>(std::move(object));
} }
template <typename T> detail::enable_if_t<detail::move_never<T>::value, T> cast(object &&object) { template <typename T> detail::enable_if_t<detail::move_never<T>::value, T> cast(object &&object) {
...@@ -1018,8 +1054,9 @@ template <return_value_policy policy = return_value_policy::automatic_reference, ...@@ -1018,8 +1054,9 @@ template <return_value_policy policy = return_value_policy::automatic_reference,
} }
tuple result(size); tuple result(size);
int counter = 0; int counter = 0;
for (auto &arg_value : args) for (auto &arg_value : args) {
PyTuple_SET_ITEM(result.ptr(), counter++, arg_value.release().ptr()); PyTuple_SET_ITEM(result.ptr(), counter++, arg_value.release().ptr());
}
return result; return result;
} }
...@@ -1231,8 +1268,9 @@ public: ...@@ -1231,8 +1268,9 @@ public:
/// Call a Python function and pass the collected arguments /// Call a Python function and pass the collected arguments
object call(PyObject *ptr) const { object call(PyObject *ptr) const {
PyObject *result = PyObject_CallObject(ptr, m_args.ptr()); PyObject *result = PyObject_CallObject(ptr, m_args.ptr());
if (!result) if (!result) {
throw error_already_set(); throw error_already_set();
}
return reinterpret_steal<object>(result); return reinterpret_steal<object>(result);
} }
...@@ -1264,8 +1302,9 @@ public: ...@@ -1264,8 +1302,9 @@ public:
/// Call a Python function and pass the collected arguments /// Call a Python function and pass the collected arguments
object call(PyObject *ptr) const { object call(PyObject *ptr) const {
PyObject *result = PyObject_Call(ptr, m_args.ptr(), m_kwargs.ptr()); PyObject *result = PyObject_Call(ptr, m_args.ptr(), m_kwargs.ptr());
if (!result) if (!result) {
throw error_already_set(); throw error_already_set();
}
return reinterpret_steal<object>(result); return reinterpret_steal<object>(result);
} }
...@@ -1285,8 +1324,9 @@ private: ...@@ -1285,8 +1324,9 @@ private:
} }
void process(list &args_list, detail::args_proxy ap) { void process(list &args_list, detail::args_proxy ap) {
for (auto a : ap) for (auto a : ap) {
args_list.append(a); args_list.append(a);
}
} }
void process(list &/*args_list*/, arg_v a) { void process(list &/*args_list*/, arg_v a) {
...@@ -1315,8 +1355,9 @@ private: ...@@ -1315,8 +1355,9 @@ private:
} }
void process(list &/*args_list*/, detail::kwargs_proxy kp) { void process(list &/*args_list*/, detail::kwargs_proxy kp) {
if (!kp) if (!kp) {
return; return;
}
for (auto k : reinterpret_borrow<dict>(kp)) { for (auto k : reinterpret_borrow<dict>(kp)) {
if (m_kwargs.contains(k.first)) { if (m_kwargs.contains(k.first)) {
#if defined(NDEBUG) #if defined(NDEBUG)
......
...@@ -46,7 +46,9 @@ public: ...@@ -46,7 +46,9 @@ public:
// Lazy initialise the PyDateTime import // Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) { PyDateTime_IMPORT; } if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
if (!src) return false; if (!src) {
return false;
}
// If invoked with datetime.delta object // If invoked with datetime.delta object
if (PyDelta_Check(src.ptr())) { if (PyDelta_Check(src.ptr())) {
value = type(duration_cast<duration<rep, period>>( value = type(duration_cast<duration<rep, period>>(
...@@ -124,7 +126,9 @@ public: ...@@ -124,7 +126,9 @@ public:
// Lazy initialise the PyDateTime import // Lazy initialise the PyDateTime import
if (!PyDateTimeAPI) { PyDateTime_IMPORT; } if (!PyDateTimeAPI) { PyDateTime_IMPORT; }
if (!src) return false; if (!src) {
return false;
}
std::tm cal; std::tm cal;
microseconds msecs; microseconds msecs;
...@@ -156,8 +160,9 @@ public: ...@@ -156,8 +160,9 @@ public:
cal.tm_year = 70; // earliest available date for Python's datetime cal.tm_year = 70; // earliest available date for Python's datetime
cal.tm_isdst = -1; cal.tm_isdst = -1;
msecs = microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr())); msecs = microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr()));
} else {
return false;
} }
else return false;
value = time_point_cast<Duration>(system_clock::from_time_t(std::mktime(&cal)) + msecs); value = time_point_cast<Duration>(system_clock::from_time_t(std::mktime(&cal)) + msecs);
return true; return true;
...@@ -173,8 +178,9 @@ public: ...@@ -173,8 +178,9 @@ public:
// (cfr. https://github.com/pybind/pybind11/issues/2417) // (cfr. https://github.com/pybind/pybind11/issues/2417)
using us_t = duration<int, std::micro>; using us_t = duration<int, std::micro>;
auto us = duration_cast<us_t>(src.time_since_epoch() % seconds(1)); auto us = duration_cast<us_t>(src.time_since_epoch() % seconds(1));
if (us.count() < 0) if (us.count() < 0) {
us += seconds(1); us += seconds(1);
}
// Subtract microseconds BEFORE `system_clock::to_time_t`, because: // Subtract microseconds BEFORE `system_clock::to_time_t`, because:
// > If std::time_t has lower precision, it is implementation-defined whether the value is rounded or truncated. // > If std::time_t has lower precision, it is implementation-defined whether the value is rounded or truncated.
...@@ -183,8 +189,9 @@ public: ...@@ -183,8 +189,9 @@ public:
std::tm localtime; std::tm localtime;
std::tm *localtime_ptr = localtime_thread_safe(&tt, &localtime); std::tm *localtime_ptr = localtime_thread_safe(&tt, &localtime);
if (!localtime_ptr) if (!localtime_ptr) {
throw cast_error("Unable to represent system_clock in local time"); throw cast_error("Unable to represent system_clock in local time");
}
return PyDateTime_FromDateAndTime(localtime.tm_year + 1900, return PyDateTime_FromDateAndTime(localtime.tm_year + 1900,
localtime.tm_mon + 1, localtime.tm_mon + 1,
localtime.tm_mday, localtime.tm_mday,
......
...@@ -42,10 +42,12 @@ template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t ...@@ -42,10 +42,12 @@ template <typename T> struct is_fmt_numeric<std::complex<T>, detail::enable_if_t
template <typename T> class type_caster<std::complex<T>> { template <typename T> class type_caster<std::complex<T>> {
public: public:
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
if (!src) if (!src) {
return false; return false;
if (!convert && !PyComplex_Check(src.ptr())) }
if (!convert && !PyComplex_Check(src.ptr())) {
return false; return false;
}
Py_complex result = PyComplex_AsCComplex(src.ptr()); Py_complex result = PyComplex_AsCComplex(src.ptr());
if (result.real == -1.0 && PyErr_Occurred()) { if (result.real == -1.0 && PyErr_Occurred()) {
PyErr_Clear(); PyErr_Clear();
......
...@@ -66,8 +66,9 @@ inline PyTypeObject *make_static_property_type() { ...@@ -66,8 +66,9 @@ inline PyTypeObject *make_static_property_type() {
garbage collector (the GC will call type_traverse(), which will in garbage collector (the GC will call type_traverse(), which will in
turn find the newly constructed type in an invalid state) */ turn find the newly constructed type in an invalid state) */
auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0); auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
if (!heap_type) if (!heap_type) {
pybind11_fail("make_static_property_type(): error allocating type!"); pybind11_fail("make_static_property_type(): error allocating type!");
}
heap_type->ht_name = name_obj.inc_ref().ptr(); heap_type->ht_name = name_obj.inc_ref().ptr();
#ifdef PYBIND11_BUILTIN_QUALNAME #ifdef PYBIND11_BUILTIN_QUALNAME
...@@ -81,8 +82,9 @@ inline PyTypeObject *make_static_property_type() { ...@@ -81,8 +82,9 @@ inline PyTypeObject *make_static_property_type() {
type->tp_descr_get = pybind11_static_get; type->tp_descr_get = pybind11_static_get;
type->tp_descr_set = pybind11_static_set; type->tp_descr_set = pybind11_static_set;
if (PyType_Ready(type) < 0) if (PyType_Ready(type) < 0) {
pybind11_fail("make_static_property_type(): failure in PyType_Ready()!"); pybind11_fail("make_static_property_type(): failure in PyType_Ready()!");
}
setattr((PyObject *) type, "__module__", str("pybind11_builtins")); setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
...@@ -209,19 +211,21 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) { ...@@ -209,19 +211,21 @@ extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
auto tindex = std::type_index(*tinfo->cpptype); auto tindex = std::type_index(*tinfo->cpptype);
internals.direct_conversions.erase(tindex); internals.direct_conversions.erase(tindex);
if (tinfo->module_local) if (tinfo->module_local) {
get_local_internals().registered_types_cpp.erase(tindex); get_local_internals().registered_types_cpp.erase(tindex);
else } else {
internals.registered_types_cpp.erase(tindex); internals.registered_types_cpp.erase(tindex);
}
internals.registered_types_py.erase(tinfo->type); internals.registered_types_py.erase(tinfo->type);
// Actually just `std::erase_if`, but that's only available in C++20 // Actually just `std::erase_if`, but that's only available in C++20
auto &cache = internals.inactive_override_cache; auto &cache = internals.inactive_override_cache;
for (auto it = cache.begin(), last = cache.end(); it != last; ) { for (auto it = cache.begin(), last = cache.end(); it != last; ) {
if (it->first == (PyObject *) tinfo->type) if (it->first == (PyObject *) tinfo->type) {
it = cache.erase(it); it = cache.erase(it);
else } else {
++it; ++it;
}
} }
delete tinfo; delete tinfo;
...@@ -242,8 +246,9 @@ inline PyTypeObject* make_default_metaclass() { ...@@ -242,8 +246,9 @@ inline PyTypeObject* make_default_metaclass() {
garbage collector (the GC will call type_traverse(), which will in garbage collector (the GC will call type_traverse(), which will in
turn find the newly constructed type in an invalid state) */ turn find the newly constructed type in an invalid state) */
auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0); auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);
if (!heap_type) if (!heap_type) {
pybind11_fail("make_default_metaclass(): error allocating metaclass!"); pybind11_fail("make_default_metaclass(): error allocating metaclass!");
}
heap_type->ht_name = name_obj.inc_ref().ptr(); heap_type->ht_name = name_obj.inc_ref().ptr();
#ifdef PYBIND11_BUILTIN_QUALNAME #ifdef PYBIND11_BUILTIN_QUALNAME
...@@ -264,8 +269,9 @@ inline PyTypeObject* make_default_metaclass() { ...@@ -264,8 +269,9 @@ inline PyTypeObject* make_default_metaclass() {
type->tp_dealloc = pybind11_meta_dealloc; type->tp_dealloc = pybind11_meta_dealloc;
if (PyType_Ready(type) < 0) if (PyType_Ready(type) < 0) {
pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!"); pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!");
}
setattr((PyObject *) type, "__module__", str("pybind11_builtins")); setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
...@@ -283,8 +289,9 @@ inline void traverse_offset_bases(void *valueptr, const detail::type_info *tinfo ...@@ -283,8 +289,9 @@ inline void traverse_offset_bases(void *valueptr, const detail::type_info *tinfo
for (auto &c : parent_tinfo->implicit_casts) { for (auto &c : parent_tinfo->implicit_casts) {
if (c.first == tinfo->cpptype) { if (c.first == tinfo->cpptype) {
auto *parentptr = c.second(valueptr); auto *parentptr = c.second(valueptr);
if (parentptr != valueptr) if (parentptr != valueptr) {
f(parentptr, self); f(parentptr, self);
}
traverse_offset_bases(parentptr, parent_tinfo, self, f); traverse_offset_bases(parentptr, parent_tinfo, self, f);
break; break;
} }
...@@ -311,14 +318,16 @@ inline bool deregister_instance_impl(void *ptr, instance *self) { ...@@ -311,14 +318,16 @@ inline bool deregister_instance_impl(void *ptr, instance *self) {
inline void register_instance(instance *self, void *valptr, const type_info *tinfo) { inline void register_instance(instance *self, void *valptr, const type_info *tinfo) {
register_instance_impl(valptr, self); register_instance_impl(valptr, self);
if (!tinfo->simple_ancestors) if (!tinfo->simple_ancestors) {
traverse_offset_bases(valptr, tinfo, self, register_instance_impl); traverse_offset_bases(valptr, tinfo, self, register_instance_impl);
}
} }
inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo) { inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo) {
bool ret = deregister_instance_impl(valptr, self); bool ret = deregister_instance_impl(valptr, self);
if (!tinfo->simple_ancestors) if (!tinfo->simple_ancestors) {
traverse_offset_bases(valptr, tinfo, self, deregister_instance_impl); traverse_offset_bases(valptr, tinfo, self, deregister_instance_impl);
}
return ret; return ret;
} }
...@@ -377,8 +386,9 @@ inline void clear_patients(PyObject *self) { ...@@ -377,8 +386,9 @@ inline void clear_patients(PyObject *self) {
auto patients = std::move(pos->second); auto patients = std::move(pos->second);
internals.patients.erase(pos); internals.patients.erase(pos);
instance->has_patients = false; instance->has_patients = false;
for (PyObject *&patient : patients) for (PyObject *&patient : patients) {
Py_CLEAR(patient); Py_CLEAR(patient);
}
} }
/// Clears all internal data from the instance and removes it from registered instances in /// Clears all internal data from the instance and removes it from registered instances in
...@@ -392,25 +402,32 @@ inline void clear_instance(PyObject *self) { ...@@ -392,25 +402,32 @@ inline void clear_instance(PyObject *self) {
// We have to deregister before we call dealloc because, for virtual MI types, we still // We have to deregister before we call dealloc because, for virtual MI types, we still
// need to be able to get the parent pointers. // need to be able to get the parent pointers.
if (v_h.instance_registered() && !deregister_instance(instance, v_h.value_ptr(), v_h.type)) if (v_h.instance_registered()
pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!"); && !deregister_instance(instance, v_h.value_ptr(), v_h.type)) {
pybind11_fail(
"pybind11_object_dealloc(): Tried to deallocate unregistered instance!");
}
if (instance->owned || v_h.holder_constructed()) if (instance->owned || v_h.holder_constructed()) {
v_h.type->dealloc(v_h); v_h.type->dealloc(v_h);
}
} }
} }
// Deallocate the value/holder layout internals: // Deallocate the value/holder layout internals:
instance->deallocate_layout(); instance->deallocate_layout();
if (instance->weakrefs) if (instance->weakrefs) {
PyObject_ClearWeakRefs(self); PyObject_ClearWeakRefs(self);
}
PyObject **dict_ptr = _PyObject_GetDictPtr(self); PyObject **dict_ptr = _PyObject_GetDictPtr(self);
if (dict_ptr) if (dict_ptr) {
Py_CLEAR(*dict_ptr); Py_CLEAR(*dict_ptr);
}
if (instance->has_patients) if (instance->has_patients) {
clear_patients(self); clear_patients(self);
}
} }
/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc` /// Instance destructor function for all pybind11 types. It calls `type_info.dealloc`
...@@ -448,8 +465,9 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) { ...@@ -448,8 +465,9 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
garbage collector (the GC will call type_traverse(), which will in garbage collector (the GC will call type_traverse(), which will in
turn find the newly constructed type in an invalid state) */ turn find the newly constructed type in an invalid state) */
auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0); auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
if (!heap_type) if (!heap_type) {
pybind11_fail("make_object_base_type(): error allocating type!"); pybind11_fail("make_object_base_type(): error allocating type!");
}
heap_type->ht_name = name_obj.inc_ref().ptr(); heap_type->ht_name = name_obj.inc_ref().ptr();
#ifdef PYBIND11_BUILTIN_QUALNAME #ifdef PYBIND11_BUILTIN_QUALNAME
...@@ -469,8 +487,9 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) { ...@@ -469,8 +487,9 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
/* Support weak references (needed for the keep_alive feature) */ /* Support weak references (needed for the keep_alive feature) */
type->tp_weaklistoffset = offsetof(instance, weakrefs); type->tp_weaklistoffset = offsetof(instance, weakrefs);
if (PyType_Ready(type) < 0) if (PyType_Ready(type) < 0) {
pybind11_fail("PyType_Ready failed in make_object_base_type():" + error_string()); pybind11_fail("PyType_Ready failed in make_object_base_type():" + error_string());
}
setattr((PyObject *) type, "__module__", str("pybind11_builtins")); setattr((PyObject *) type, "__module__", str("pybind11_builtins"));
PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);
...@@ -482,8 +501,9 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) { ...@@ -482,8 +501,9 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
/// dynamic_attr: Support for `d = instance.__dict__`. /// dynamic_attr: Support for `d = instance.__dict__`.
extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) { extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) {
PyObject *&dict = *_PyObject_GetDictPtr(self); PyObject *&dict = *_PyObject_GetDictPtr(self);
if (!dict) if (!dict) {
dict = PyDict_New(); dict = PyDict_New();
}
Py_XINCREF(dict); Py_XINCREF(dict);
return dict; return dict;
} }
...@@ -538,12 +558,14 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla ...@@ -538,12 +558,14 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
type_info *tinfo = nullptr; type_info *tinfo = nullptr;
for (auto type : reinterpret_borrow<tuple>(Py_TYPE(obj)->tp_mro)) { for (auto type : reinterpret_borrow<tuple>(Py_TYPE(obj)->tp_mro)) {
tinfo = get_type_info((PyTypeObject *) type.ptr()); tinfo = get_type_info((PyTypeObject *) type.ptr());
if (tinfo && tinfo->get_buffer) if (tinfo && tinfo->get_buffer) {
break; break;
}
} }
if (view == nullptr || !tinfo || !tinfo->get_buffer) { if (view == nullptr || !tinfo || !tinfo->get_buffer) {
if (view) if (view) {
view->obj = nullptr; view->obj = nullptr;
}
PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error"); PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error");
return -1; return -1;
} }
...@@ -561,11 +583,13 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla ...@@ -561,11 +583,13 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
view->buf = info->ptr; view->buf = info->ptr;
view->itemsize = info->itemsize; view->itemsize = info->itemsize;
view->len = view->itemsize; view->len = view->itemsize;
for (auto s : info->shape) for (auto s : info->shape) {
view->len *= s; view->len *= s;
}
view->readonly = static_cast<int>(info->readonly); view->readonly = static_cast<int>(info->readonly);
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
view->format = const_cast<char *>(info->format.c_str()); view->format = const_cast<char *>(info->format.c_str());
}
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
view->ndim = (int) info->ndim; view->ndim = (int) info->ndim;
view->strides = info->strides.data(); view->strides = info->strides.data();
...@@ -608,10 +632,11 @@ inline PyObject* make_new_python_type(const type_record &rec) { ...@@ -608,10 +632,11 @@ inline PyObject* make_new_python_type(const type_record &rec) {
object module_; object module_;
if (rec.scope) { if (rec.scope) {
if (hasattr(rec.scope, "__module__")) if (hasattr(rec.scope, "__module__")) {
module_ = rec.scope.attr("__module__"); module_ = rec.scope.attr("__module__");
else if (hasattr(rec.scope, "__name__")) } else if (hasattr(rec.scope, "__name__")) {
module_ = rec.scope.attr("__name__"); module_ = rec.scope.attr("__name__");
}
} }
auto full_name = c_str( auto full_name = c_str(
...@@ -642,8 +667,9 @@ inline PyObject* make_new_python_type(const type_record &rec) { ...@@ -642,8 +667,9 @@ inline PyObject* make_new_python_type(const type_record &rec) {
: internals.default_metaclass; : internals.default_metaclass;
auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0); auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);
if (!heap_type) if (!heap_type) {
pybind11_fail(std::string(rec.name) + ": Unable to create type object!"); pybind11_fail(std::string(rec.name) + ": Unable to create type object!");
}
heap_type->ht_name = name.release().ptr(); heap_type->ht_name = name.release().ptr();
#ifdef PYBIND11_BUILTIN_QUALNAME #ifdef PYBIND11_BUILTIN_QUALNAME
...@@ -655,8 +681,9 @@ inline PyObject* make_new_python_type(const type_record &rec) { ...@@ -655,8 +681,9 @@ inline PyObject* make_new_python_type(const type_record &rec) {
type->tp_doc = tp_doc; type->tp_doc = tp_doc;
type->tp_base = type_incref((PyTypeObject *)base); type->tp_base = type_incref((PyTypeObject *)base);
type->tp_basicsize = static_cast<ssize_t>(sizeof(instance)); type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));
if (!bases.empty()) if (!bases.empty()) {
type->tp_bases = bases.release().ptr(); type->tp_bases = bases.release().ptr();
}
/* Don't inherit base __init__ */ /* Don't inherit base __init__ */
type->tp_init = pybind11_object_init; type->tp_init = pybind11_object_init;
...@@ -674,31 +701,38 @@ inline PyObject* make_new_python_type(const type_record &rec) { ...@@ -674,31 +701,38 @@ inline PyObject* make_new_python_type(const type_record &rec) {
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
type->tp_flags |= Py_TPFLAGS_CHECKTYPES; type->tp_flags |= Py_TPFLAGS_CHECKTYPES;
#endif #endif
if (!rec.is_final) if (!rec.is_final) {
type->tp_flags |= Py_TPFLAGS_BASETYPE; type->tp_flags |= Py_TPFLAGS_BASETYPE;
}
if (rec.dynamic_attr) if (rec.dynamic_attr) {
enable_dynamic_attributes(heap_type); enable_dynamic_attributes(heap_type);
}
if (rec.buffer_protocol) if (rec.buffer_protocol) {
enable_buffer_protocol(heap_type); enable_buffer_protocol(heap_type);
}
if (rec.custom_type_setup_callback) if (rec.custom_type_setup_callback) {
rec.custom_type_setup_callback(heap_type); rec.custom_type_setup_callback(heap_type);
}
if (PyType_Ready(type) < 0) if (PyType_Ready(type) < 0) {
pybind11_fail(std::string(rec.name) + ": PyType_Ready failed (" + error_string() + ")!"); pybind11_fail(std::string(rec.name) + ": PyType_Ready failed (" + error_string() + ")!");
}
assert(!rec.dynamic_attr || PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)); assert(!rec.dynamic_attr || PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));
/* Register type with the parent scope */ /* Register type with the parent scope */
if (rec.scope) if (rec.scope) {
setattr(rec.scope, rec.name, (PyObject *) type); setattr(rec.scope, rec.name, (PyObject *) type);
else } else {
Py_INCREF(type); // Keep it alive forever (reference leak) Py_INCREF(type); // Keep it alive forever (reference leak)
}
if (module_) // Needed by pydoc if (module_) { // Needed by pydoc
setattr((PyObject *) type, "__module__", module_); setattr((PyObject *) type, "__module__", module_);
}
PYBIND11_SET_OLDPY_QUALNAME(type, qualname); PYBIND11_SET_OLDPY_QUALNAME(type, qualname);
......
...@@ -33,7 +33,9 @@ private: ...@@ -33,7 +33,9 @@ private:
PYBIND11_NAMESPACE_BEGIN(initimpl) PYBIND11_NAMESPACE_BEGIN(initimpl)
inline void no_nullptr(void *ptr) { inline void no_nullptr(void *ptr) {
if (!ptr) throw type_error("pybind11::init(): factory function returned nullptr"); if (!ptr) {
throw type_error("pybind11::init(): factory function returned nullptr");
}
} }
// Implementing functions for all forms of py::init<...> and py::init(...) // Implementing functions for all forms of py::init<...> and py::init(...)
...@@ -136,9 +138,10 @@ void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) { ...@@ -136,9 +138,10 @@ void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
auto *ptr = holder_helper<Holder<Class>>::get(holder); auto *ptr = holder_helper<Holder<Class>>::get(holder);
no_nullptr(ptr); no_nullptr(ptr);
// If we need an alias, check that the held pointer is actually an alias instance // If we need an alias, check that the held pointer is actually an alias instance
if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias && !is_alias<Class>(ptr)) if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias && !is_alias<Class>(ptr)) {
throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance " throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
"is not an alias instance"); "is not an alias instance");
}
v_h.value_ptr() = ptr; v_h.value_ptr() = ptr;
v_h.type->init_instance(v_h.inst, &holder); v_h.type->init_instance(v_h.inst, &holder);
...@@ -153,10 +156,11 @@ void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) { ...@@ -153,10 +156,11 @@ void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias); PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
static_assert(std::is_move_constructible<Cpp<Class>>::value, static_assert(std::is_move_constructible<Cpp<Class>>::value,
"pybind11::init() return-by-value factory function requires a movable class"); "pybind11::init() return-by-value factory function requires a movable class");
if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias) if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias) {
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result)); construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
else } else {
v_h.value_ptr() = new Cpp<Class>(std::move(result)); v_h.value_ptr() = new Cpp<Class>(std::move(result));
}
} }
// return-by-value version 2: returning a value of the alias type itself. We move-construct an // return-by-value version 2: returning a value of the alias type itself. We move-construct an
...@@ -183,12 +187,19 @@ struct constructor { ...@@ -183,12 +187,19 @@ struct constructor {
enable_if_t<Class::has_alias && enable_if_t<Class::has_alias &&
std::is_constructible<Cpp<Class>, Args...>::value, int> = 0> std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
static void execute(Class &cl, const Extra&... extra) { static void execute(Class &cl, const Extra&... extra) {
cl.def("__init__", [](value_and_holder &v_h, Args... args) { cl.def(
if (Py_TYPE(v_h.inst) == v_h.type->type) "__init__",
v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...); [](value_and_holder &v_h, Args... args) {
else if (Py_TYPE(v_h.inst) == v_h.type->type) {
v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...); v_h.value_ptr()
}, is_new_style_constructor(), extra...); = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
} else {
v_h.value_ptr()
= construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
}
},
is_new_style_constructor(),
extra...);
} }
template <typename Class, typename... Extra, template <typename Class, typename... Extra,
......
...@@ -398,8 +398,9 @@ inline void translate_local_exception(std::exception_ptr p) { ...@@ -398,8 +398,9 @@ inline void translate_local_exception(std::exception_ptr p) {
/// Return a reference to the current `internals` data /// Return a reference to the current `internals` data
PYBIND11_NOINLINE internals &get_internals() { PYBIND11_NOINLINE internals &get_internals() {
auto **&internals_pp = get_internals_pp(); auto **&internals_pp = get_internals_pp();
if (internals_pp && *internals_pp) if (internals_pp && *internals_pp) {
return **internals_pp; return **internals_pp;
}
// Ensure that the GIL is held since we will need to make Python calls. // Ensure that the GIL is held since we will need to make Python calls.
// Cannot use py::gil_scoped_acquire here since that constructor calls get_internals. // Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
...@@ -425,7 +426,9 @@ PYBIND11_NOINLINE internals &get_internals() { ...@@ -425,7 +426,9 @@ PYBIND11_NOINLINE internals &get_internals() {
(*internals_pp)->registered_exception_translators.push_front(&translate_local_exception); (*internals_pp)->registered_exception_translators.push_front(&translate_local_exception);
#endif #endif
} else { } else {
if (!internals_pp) internals_pp = new internals*(); if (!internals_pp) {
internals_pp = new internals *();
}
auto *&internals_ptr = *internals_pp; auto *&internals_ptr = *internals_pp;
internals_ptr = new internals(); internals_ptr = new internals();
#if defined(WITH_THREAD) #if defined(WITH_THREAD)
......
...@@ -69,11 +69,13 @@ public: ...@@ -69,11 +69,13 @@ public:
/// ... and destroyed after it returns /// ... and destroyed after it returns
~loader_life_support() { ~loader_life_support() {
if (get_stack_top() != this) if (get_stack_top() != this) {
pybind11_fail("loader_life_support: internal error"); pybind11_fail("loader_life_support: internal error");
}
set_stack_top(parent); set_stack_top(parent);
for (auto* item : keep_alive) for (auto *item : keep_alive) {
Py_DECREF(item); Py_DECREF(item);
}
} }
/// This can only be used inside a pybind11-bound function, either by `argument_loader` /// This can only be used inside a pybind11-bound function, either by `argument_loader`
...@@ -90,8 +92,9 @@ public: ...@@ -90,8 +92,9 @@ public:
"of temporary values"); "of temporary values");
} }
if (frame->keep_alive.insert(h.ptr()).second) if (frame->keep_alive.insert(h.ptr()).second) {
Py_INCREF(h.ptr()); Py_INCREF(h.ptr());
}
} }
}; };
...@@ -103,14 +106,17 @@ inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_t ...@@ -103,14 +106,17 @@ inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_t
// Populates a just-created cache entry. // Populates a just-created cache entry.
PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_info *> &bases) { PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_info *> &bases) {
std::vector<PyTypeObject *> check; std::vector<PyTypeObject *> check;
for (handle parent : reinterpret_borrow<tuple>(t->tp_bases)) for (handle parent : reinterpret_borrow<tuple>(t->tp_bases)) {
check.push_back((PyTypeObject *) parent.ptr()); check.push_back((PyTypeObject *) parent.ptr());
}
auto const &type_dict = get_internals().registered_types_py; auto const &type_dict = get_internals().registered_types_py;
for (size_t i = 0; i < check.size(); i++) { for (size_t i = 0; i < check.size(); i++) {
auto type = check[i]; auto type = check[i];
// Ignore Python2 old-style class super type: // Ignore Python2 old-style class super type:
if (!PyType_Check((PyObject *) type)) continue; if (!PyType_Check((PyObject *) type)) {
continue;
}
// Check `type` in the current set of registered python types: // Check `type` in the current set of registered python types:
auto it = type_dict.find(type); auto it = type_dict.find(type);
...@@ -127,7 +133,9 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_ ...@@ -127,7 +133,9 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_
for (auto *known : bases) { for (auto *known : bases) {
if (known == tinfo) { found = true; break; } if (known == tinfo) { found = true; break; }
} }
if (!found) bases.push_back(tinfo); if (!found) {
bases.push_back(tinfo);
}
} }
} }
else if (type->tp_bases) { else if (type->tp_bases) {
...@@ -140,8 +148,9 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_ ...@@ -140,8 +148,9 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_
check.pop_back(); check.pop_back();
i--; i--;
} }
for (handle parent : reinterpret_borrow<tuple>(type->tp_bases)) for (handle parent : reinterpret_borrow<tuple>(type->tp_bases)) {
check.push_back((PyTypeObject *) parent.ptr()); check.push_back((PyTypeObject *) parent.ptr());
}
} }
} }
} }
...@@ -158,9 +167,10 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_ ...@@ -158,9 +167,10 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_
*/ */
inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type) { inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type) {
auto ins = all_type_info_get_cache(type); auto ins = all_type_info_get_cache(type);
if (ins.second) if (ins.second) {
// New cache entry: populate it // New cache entry: populate it
all_type_info_populate(type, ins.first->second); all_type_info_populate(type, ins.first->second);
}
return ins.first->second; return ins.first->second;
} }
...@@ -172,36 +182,43 @@ inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type) ...@@ -172,36 +182,43 @@ inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type)
*/ */
PYBIND11_NOINLINE detail::type_info* get_type_info(PyTypeObject *type) { PYBIND11_NOINLINE detail::type_info* get_type_info(PyTypeObject *type) {
auto &bases = all_type_info(type); auto &bases = all_type_info(type);
if (bases.empty()) if (bases.empty()) {
return nullptr; return nullptr;
if (bases.size() > 1) }
pybind11_fail("pybind11::detail::get_type_info: type has multiple pybind11-registered bases"); if (bases.size() > 1) {
pybind11_fail(
"pybind11::detail::get_type_info: type has multiple pybind11-registered bases");
}
return bases.front(); return bases.front();
} }
inline detail::type_info *get_local_type_info(const std::type_index &tp) { inline detail::type_info *get_local_type_info(const std::type_index &tp) {
auto &locals = get_local_internals().registered_types_cpp; auto &locals = get_local_internals().registered_types_cpp;
auto it = locals.find(tp); auto it = locals.find(tp);
if (it != locals.end()) if (it != locals.end()) {
return it->second; return it->second;
}
return nullptr; return nullptr;
} }
inline detail::type_info *get_global_type_info(const std::type_index &tp) { inline detail::type_info *get_global_type_info(const std::type_index &tp) {
auto &types = get_internals().registered_types_cpp; auto &types = get_internals().registered_types_cpp;
auto it = types.find(tp); auto it = types.find(tp);
if (it != types.end()) if (it != types.end()) {
return it->second; return it->second;
}
return nullptr; return nullptr;
} }
/// Return the type info for a given C++ type; on lookup failure can either throw or 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, PYBIND11_NOINLINE detail::type_info *get_type_info(const std::type_index &tp,
bool throw_if_missing = false) { bool throw_if_missing = false) {
if (auto ltype = get_local_type_info(tp)) if (auto ltype = get_local_type_info(tp)) {
return ltype; return ltype;
if (auto gtype = get_global_type_info(tp)) }
if (auto gtype = get_global_type_info(tp)) {
return gtype; return gtype;
}
if (throw_if_missing) { if (throw_if_missing) {
std::string tname = tp.name(); std::string tname = tp.name();
...@@ -222,8 +239,9 @@ PYBIND11_NOINLINE handle find_registered_python_instance(void *src, ...@@ -222,8 +239,9 @@ PYBIND11_NOINLINE handle find_registered_python_instance(void *src,
auto it_instances = get_internals().registered_instances.equal_range(src); auto it_instances = get_internals().registered_instances.equal_range(src);
for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) { for (auto 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))) { for (auto instance_type : detail::all_type_info(Py_TYPE(it_i->second))) {
if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) {
return handle((PyObject *) it_i->second).inc_ref(); return handle((PyObject *) it_i->second).inc_ref();
}
} }
} }
return handle(); return handle();
...@@ -263,12 +281,13 @@ struct value_and_holder { ...@@ -263,12 +281,13 @@ struct value_and_holder {
} }
// NOLINTNEXTLINE(readability-make-member-function-const) // NOLINTNEXTLINE(readability-make-member-function-const)
void set_holder_constructed(bool v = true) { void set_holder_constructed(bool v = true) {
if (inst->simple_layout) if (inst->simple_layout) {
inst->simple_holder_constructed = v; inst->simple_holder_constructed = v;
else if (v) } else if (v) {
inst->nonsimple.status[index] |= instance::status_holder_constructed; inst->nonsimple.status[index] |= instance::status_holder_constructed;
else } else {
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed; inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed;
}
} }
bool instance_registered() const { bool instance_registered() const {
return inst->simple_layout return inst->simple_layout
...@@ -277,12 +296,13 @@ struct value_and_holder { ...@@ -277,12 +296,13 @@ struct value_and_holder {
} }
// NOLINTNEXTLINE(readability-make-member-function-const) // NOLINTNEXTLINE(readability-make-member-function-const)
void set_instance_registered(bool v = true) { void set_instance_registered(bool v = true) {
if (inst->simple_layout) if (inst->simple_layout) {
inst->simple_instance_registered = v; inst->simple_instance_registered = v;
else if (v) } else if (v) {
inst->nonsimple.status[index] |= instance::status_instance_registered; inst->nonsimple.status[index] |= instance::status_instance_registered;
else } else {
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered; inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered;
}
} }
}; };
...@@ -317,8 +337,9 @@ public: ...@@ -317,8 +337,9 @@ public:
bool operator==(const iterator &other) const { return curr.index == other.curr.index; } bool operator==(const iterator &other) const { return curr.index == other.curr.index; }
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++() { iterator &operator++() {
if (!inst->simple_layout) if (!inst->simple_layout) {
curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs; curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs;
}
++curr.index; ++curr.index;
curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr; curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr;
return *this; return *this;
...@@ -332,7 +353,9 @@ public: ...@@ -332,7 +353,9 @@ public:
iterator find(const type_info *find_type) { iterator find(const type_info *find_type) {
auto it = begin(), endit = end(); auto it = begin(), endit = end();
while (it != endit && it->type != find_type) ++it; while (it != endit && it->type != find_type) {
++it;
}
return it; return it;
} }
...@@ -351,16 +374,19 @@ public: ...@@ -351,16 +374,19 @@ public:
*/ */
PYBIND11_NOINLINE value_and_holder instance::get_value_and_holder(const type_info *find_type /*= nullptr default in common.h*/, bool throw_if_missing /*= true in common.h*/) { 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: // Optimize common case:
if (!find_type || Py_TYPE(this) == find_type->type) if (!find_type || Py_TYPE(this) == find_type->type) {
return value_and_holder(this, find_type, 0, 0); return value_and_holder(this, find_type, 0, 0);
}
detail::values_and_holders vhs(this); detail::values_and_holders vhs(this);
auto it = vhs.find(find_type); auto it = vhs.find(find_type);
if (it != vhs.end()) if (it != vhs.end()) {
return *it; return *it;
}
if (!throw_if_missing) if (!throw_if_missing) {
return value_and_holder(); return value_and_holder();
}
#if defined(NDEBUG) #if defined(NDEBUG)
pybind11_fail("pybind11::detail::instance::get_value_and_holder: " pybind11_fail("pybind11::detail::instance::get_value_and_holder: "
...@@ -378,8 +404,10 @@ PYBIND11_NOINLINE void instance::allocate_layout() { ...@@ -378,8 +404,10 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
const size_t n_types = tinfo.size(); const size_t n_types = tinfo.size();
if (n_types == 0) if (n_types == 0) {
pybind11_fail("instance allocation failed: new instance has no pybind11-registered base types"); pybind11_fail(
"instance allocation failed: new instance has no pybind11-registered base types");
}
simple_layout = simple_layout =
n_types == 1 && tinfo.front()->holder_size_in_ptrs <= instance_simple_holder_in_ptrs(); n_types == 1 && tinfo.front()->holder_size_in_ptrs <= instance_simple_holder_in_ptrs();
...@@ -410,7 +438,9 @@ PYBIND11_NOINLINE void instance::allocate_layout() { ...@@ -410,7 +438,9 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
// just wrappers around malloc. // just wrappers around malloc.
#if PY_VERSION_HEX >= 0x03050000 #if PY_VERSION_HEX >= 0x03050000
nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *)); nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *));
if (!nonsimple.values_and_holders) throw std::bad_alloc(); if (!nonsimple.values_and_holders) {
throw std::bad_alloc();
}
#else #else
nonsimple.values_and_holders = (void **) PyMem_New(void *, space); nonsimple.values_and_holders = (void **) PyMem_New(void *, space);
if (!nonsimple.values_and_holders) throw std::bad_alloc(); if (!nonsimple.values_and_holders) throw std::bad_alloc();
...@@ -423,14 +453,16 @@ PYBIND11_NOINLINE void instance::allocate_layout() { ...@@ -423,14 +453,16 @@ PYBIND11_NOINLINE void instance::allocate_layout() {
// NOLINTNEXTLINE(readability-make-member-function-const) // NOLINTNEXTLINE(readability-make-member-function-const)
PYBIND11_NOINLINE void instance::deallocate_layout() { PYBIND11_NOINLINE void instance::deallocate_layout() {
if (!simple_layout) if (!simple_layout) {
PyMem_Free(nonsimple.values_and_holders); PyMem_Free(nonsimple.values_and_holders);
}
} }
PYBIND11_NOINLINE bool isinstance_generic(handle obj, const std::type_info &tp) { PYBIND11_NOINLINE bool isinstance_generic(handle obj, const std::type_info &tp) {
handle type = detail::get_type_handle(tp, false); handle type = detail::get_type_handle(tp, false);
if (!type) if (!type) {
return false; return false;
}
return isinstance(obj, type); return isinstance(obj, type);
} }
...@@ -447,14 +479,16 @@ PYBIND11_NOINLINE std::string error_string() { ...@@ -447,14 +479,16 @@ PYBIND11_NOINLINE std::string error_string() {
errorString += handle(scope.type).attr("__name__").cast<std::string>(); errorString += handle(scope.type).attr("__name__").cast<std::string>();
errorString += ": "; errorString += ": ";
} }
if (scope.value) if (scope.value) {
errorString += (std::string) str(scope.value); errorString += (std::string) str(scope.value);
}
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace); PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
if (scope.trace != nullptr) if (scope.trace != nullptr) {
PyException_SetTraceback(scope.value, scope.trace); PyException_SetTraceback(scope.value, scope.trace);
}
#endif #endif
#if !defined(PYPY_VERSION) #if !defined(PYPY_VERSION)
...@@ -462,8 +496,9 @@ PYBIND11_NOINLINE std::string error_string() { ...@@ -462,8 +496,9 @@ PYBIND11_NOINLINE std::string error_string() {
auto *trace = (PyTracebackObject *) scope.trace; auto *trace = (PyTracebackObject *) scope.trace;
/* Get the deepest trace possible */ /* Get the deepest trace possible */
while (trace->tb_next) while (trace->tb_next) {
trace = trace->tb_next; trace = trace->tb_next;
}
PyFrameObject *frame = trace->tb_frame; PyFrameObject *frame = trace->tb_frame;
errorString += "\n\nAt:\n"; errorString += "\n\nAt:\n";
...@@ -493,8 +528,9 @@ PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_i ...@@ -493,8 +528,9 @@ PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_i
auto range = instances.equal_range(ptr); auto range = instances.equal_range(ptr);
for (auto it = range.first; it != range.second; ++it) { for (auto it = range.first; it != range.second; ++it) {
for (const auto &vh : values_and_holders(it->second)) { for (const auto &vh : values_and_holders(it->second)) {
if (vh.type == type) if (vh.type == type) {
return handle((PyObject *) it->second); return handle((PyObject *) it->second);
}
} }
} }
return handle(); return handle();
...@@ -535,15 +571,18 @@ public: ...@@ -535,15 +571,18 @@ public:
void *(*copy_constructor)(const void *), void *(*copy_constructor)(const void *),
void *(*move_constructor)(const void *), void *(*move_constructor)(const void *),
const void *existing_holder = nullptr) { const void *existing_holder = nullptr) {
if (!tinfo) // no type info: error will be set already if (!tinfo) { // no type info: error will be set already
return handle(); return handle();
}
void *src = const_cast<void *>(_src); void *src = const_cast<void *>(_src);
if (src == nullptr) if (src == nullptr) {
return none().release(); return none().release();
}
if (handle registered_inst = find_registered_python_instance(src, tinfo)) if (handle registered_inst = find_registered_python_instance(src, tinfo)) {
return registered_inst; return registered_inst;
}
auto inst = reinterpret_steal<object>(make_new_instance(tinfo->type)); auto inst = reinterpret_steal<object>(make_new_instance(tinfo->type));
auto wrapper = reinterpret_cast<instance *>(inst.ptr()); auto wrapper = reinterpret_cast<instance *>(inst.ptr());
...@@ -564,9 +603,9 @@ public: ...@@ -564,9 +603,9 @@ public:
break; break;
case return_value_policy::copy: case return_value_policy::copy:
if (copy_constructor) if (copy_constructor) {
valueptr = copy_constructor(src); valueptr = copy_constructor(src);
else { } else {
#if defined(NDEBUG) #if defined(NDEBUG)
throw cast_error("return_value_policy = copy, but type is " throw cast_error("return_value_policy = copy, but type is "
"non-copyable! (compile in debug mode for details)"); "non-copyable! (compile in debug mode for details)");
...@@ -581,11 +620,11 @@ public: ...@@ -581,11 +620,11 @@ public:
break; break;
case return_value_policy::move: case return_value_policy::move:
if (move_constructor) if (move_constructor) {
valueptr = move_constructor(src); valueptr = move_constructor(src);
else if (copy_constructor) } else if (copy_constructor) {
valueptr = copy_constructor(src); valueptr = copy_constructor(src);
else { } else {
#if defined(NDEBUG) #if defined(NDEBUG)
throw cast_error("return_value_policy = move, but type is neither " throw cast_error("return_value_policy = move, but type is neither "
"movable nor copyable! " "movable nor copyable! "
...@@ -650,8 +689,9 @@ public: ...@@ -650,8 +689,9 @@ public:
} }
bool try_direct_conversions(handle src) { bool try_direct_conversions(handle src) {
for (auto &converter : *typeinfo->direct_conversions) { for (auto &converter : *typeinfo->direct_conversions) {
if (converter(src.ptr(), value)) if (converter(src.ptr(), value)) {
return true; return true;
}
} }
return false; return false;
} }
...@@ -659,8 +699,9 @@ public: ...@@ -659,8 +699,9 @@ public:
PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) { PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) {
auto caster = type_caster_generic(ti); auto caster = type_caster_generic(ti);
if (caster.load(src, false)) if (caster.load(src, false)) {
return caster.value; return caster.value;
}
return nullptr; return nullptr;
} }
...@@ -669,14 +710,16 @@ public: ...@@ -669,14 +710,16 @@ public:
PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) { PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) {
constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID; constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID;
const auto pytype = type::handle_of(src); const auto pytype = type::handle_of(src);
if (!hasattr(pytype, local_key)) if (!hasattr(pytype, local_key)) {
return false; return false;
}
type_info *foreign_typeinfo = reinterpret_borrow<capsule>(getattr(pytype, local_key)); 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 // 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 if (foreign_typeinfo->module_local_load == &local_load
|| (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype))) || (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype))) {
return false; return false;
}
if (auto result = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo)) { if (auto result = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo)) {
value = result; value = result;
...@@ -690,8 +733,12 @@ public: ...@@ -690,8 +733,12 @@ public:
// logic (without having to resort to virtual inheritance). // logic (without having to resort to virtual inheritance).
template <typename ThisT> template <typename ThisT>
PYBIND11_NOINLINE bool load_impl(handle src, bool convert) { PYBIND11_NOINLINE bool load_impl(handle src, bool convert) {
if (!src) return false; if (!src) {
if (!typeinfo) return try_load_foreign_module_local(src); return false;
}
if (!typeinfo) {
return try_load_foreign_module_local(src);
}
auto &this_ = static_cast<ThisT &>(*this); auto &this_ = static_cast<ThisT &>(*this);
this_.check_holder_compat(); this_.check_holder_compat();
...@@ -734,8 +781,9 @@ public: ...@@ -734,8 +781,9 @@ public:
// Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type match // 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 // in the registered bases, above, so try implicit casting (needed for proper C++ casting
// when MI is involved). // when MI is involved).
if (this_.try_implicit_casts(src, convert)) if (this_.try_implicit_casts(src, convert)) {
return true; return true;
}
} }
// Perform an implicit conversion // Perform an implicit conversion
...@@ -747,8 +795,9 @@ public: ...@@ -747,8 +795,9 @@ public:
return true; return true;
} }
} }
if (this_.try_direct_conversions(src)) if (this_.try_direct_conversions(src)) {
return true; return true;
}
} }
// Failed to match local typeinfo. Try again with global. // Failed to match local typeinfo. Try again with global.
...@@ -767,7 +816,9 @@ public: ...@@ -767,7 +816,9 @@ public:
// Custom converters didn't take None, now we convert None to nullptr. // Custom converters didn't take None, now we convert None to nullptr.
if (src.is_none()) { if (src.is_none()) {
// Defer accepting None to other overloads (if we aren't in convert mode): // Defer accepting None to other overloads (if we aren't in convert mode):
if (!convert) return false; if (!convert) {
return false;
}
value = nullptr; value = nullptr;
return true; return true;
} }
...@@ -907,8 +958,10 @@ public: ...@@ -907,8 +958,10 @@ public:
explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { } 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) { static handle cast(const itype &src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) if (policy == return_value_policy::automatic
|| policy == return_value_policy::automatic_reference) {
policy = return_value_policy::copy; policy = return_value_policy::copy;
}
return cast(&src, policy, parent); return cast(&src, policy, parent);
} }
...@@ -960,7 +1013,12 @@ public: ...@@ -960,7 +1013,12 @@ public:
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
operator itype*() { return (type *) value; } operator itype*() { return (type *) value; }
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
operator itype&() { if (!value) throw reference_cast_error(); return *((itype *) value); } operator itype&() {
if (!value) {
throw reference_cast_error();
}
return *((itype *) value);
}
protected: protected:
using Constructor = void *(*)(const void *); using Constructor = void *(*)(const void *);
......
...@@ -24,7 +24,9 @@ PYBIND11_NAMESPACE_BEGIN(detail) ...@@ -24,7 +24,9 @@ PYBIND11_NAMESPACE_BEGIN(detail)
inline void erase_all(std::string &string, const std::string &search) { inline void erase_all(std::string &string, const std::string &search) {
for (size_t pos = 0;;) { for (size_t pos = 0;;) {
pos = string.find(search, pos); pos = string.find(search, pos);
if (pos == std::string::npos) break; if (pos == std::string::npos) {
break;
}
string.erase(pos, search.length()); string.erase(pos, search.length());
} }
} }
...@@ -34,8 +36,9 @@ PYBIND11_NOINLINE void clean_type_id(std::string &name) { ...@@ -34,8 +36,9 @@ PYBIND11_NOINLINE void clean_type_id(std::string &name) {
int status = 0; int status = 0;
std::unique_ptr<char, void (*)(void *)> res { std::unique_ptr<char, void (*)(void *)> res {
abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free }; abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free };
if (status == 0) if (status == 0) {
name = res.get(); name = res.get();
}
#else #else
detail::erase_all(name, "class "); detail::erase_all(name, "class ");
detail::erase_all(name, "struct "); detail::erase_all(name, "struct ");
......
...@@ -145,8 +145,9 @@ template <typename Type_> struct EigenProps { ...@@ -145,8 +145,9 @@ template <typename Type_> struct EigenProps {
// (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type). // (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).
static EigenConformable<row_major> conformable(const array &a) { static EigenConformable<row_major> conformable(const array &a) {
const auto dims = a.ndim(); const auto dims = a.ndim();
if (dims < 1 || dims > 2) if (dims < 1 || dims > 2) {
return false; return false;
}
if (dims == 2) { // Matrix type: require exact match (or dynamic) if (dims == 2) { // Matrix type: require exact match (or dynamic)
...@@ -155,9 +156,10 @@ template <typename Type_> struct EigenProps { ...@@ -155,9 +156,10 @@ template <typename Type_> struct EigenProps {
np_cols = a.shape(1), np_cols = a.shape(1),
np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)), np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),
np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar)); np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));
if ((PYBIND11_SILENCE_MSVC_C4127(fixed_rows) && np_rows != rows) || if ((PYBIND11_SILENCE_MSVC_C4127(fixed_rows) && np_rows != rows)
(PYBIND11_SILENCE_MSVC_C4127(fixed_cols) && np_cols != cols)) || (PYBIND11_SILENCE_MSVC_C4127(fixed_cols) && np_cols != cols)) {
return false; return false;
}
return {np_rows, np_cols, np_rstride, np_cstride}; return {np_rows, np_cols, np_rstride, np_cstride};
} }
...@@ -168,8 +170,9 @@ template <typename Type_> struct EigenProps { ...@@ -168,8 +170,9 @@ template <typename Type_> struct EigenProps {
stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)); stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));
if (vector) { // Eigen type is a compile-time vector if (vector) { // Eigen type is a compile-time vector
if (PYBIND11_SILENCE_MSVC_C4127(fixed) && size != n) if (PYBIND11_SILENCE_MSVC_C4127(fixed) && size != n) {
return false; // Vector size mismatch return false; // Vector size mismatch
}
return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride}; return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};
} }
if (fixed) { if (fixed) {
...@@ -179,10 +182,14 @@ template <typename Type_> struct EigenProps { ...@@ -179,10 +182,14 @@ template <typename Type_> struct EigenProps {
if (fixed_cols) { if (fixed_cols) {
// Since this isn't a vector, cols must be != 1. We allow this only if it exactly // 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). // equals the number of elements (rows is Dynamic, and so 1 row is allowed).
if (cols != n) return false; if (cols != n) {
return false;
}
return {1, n, stride}; return {1, n, stride};
} // Otherwise it's either fully dynamic, or column dynamic; both become a column vector } // Otherwise it's either fully dynamic, or column dynamic; both become a column vector
if (PYBIND11_SILENCE_MSVC_C4127(fixed_rows) && rows != n) return false; if (PYBIND11_SILENCE_MSVC_C4127(fixed_rows) && rows != n) {
return false;
}
return {n, 1, stride}; return {n, 1, stride};
} }
...@@ -213,14 +220,18 @@ template <typename Type_> struct EigenProps { ...@@ -213,14 +220,18 @@ template <typename Type_> struct EigenProps {
template <typename props> handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) { template <typename props> handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {
constexpr ssize_t elem_size = sizeof(typename props::Scalar); constexpr ssize_t elem_size = sizeof(typename props::Scalar);
array a; array a;
if (props::vector) if (props::vector) {
a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base); a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base);
else } else {
a = array({ src.rows(), src.cols() }, { elem_size * src.rowStride(), elem_size * src.colStride() }, a = array({src.rows(), src.cols()},
src.data(), base); {elem_size * src.rowStride(), elem_size * src.colStride()},
src.data(),
base);
}
if (!writeable) if (!writeable) {
array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_; array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;
}
return a.release(); return a.release();
} }
...@@ -255,28 +266,35 @@ struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> { ...@@ -255,28 +266,35 @@ struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
// If we're in no-convert mode, only load if given an array of the correct type // If we're in no-convert mode, only load if given an array of the correct type
if (!convert && !isinstance<array_t<Scalar>>(src)) if (!convert && !isinstance<array_t<Scalar>>(src)) {
return false; return false;
}
// Coerce into an array, but don't do type conversion yet; the copy below handles it. // Coerce into an array, but don't do type conversion yet; the copy below handles it.
auto buf = array::ensure(src); auto buf = array::ensure(src);
if (!buf) if (!buf) {
return false; return false;
}
auto dims = buf.ndim(); auto dims = buf.ndim();
if (dims < 1 || dims > 2) if (dims < 1 || dims > 2) {
return false; return false;
}
auto fits = props::conformable(buf); auto fits = props::conformable(buf);
if (!fits) if (!fits) {
return false; return false;
}
// Allocate the new type, then build a numpy reference into it // Allocate the new type, then build a numpy reference into it
value = Type(fits.rows, fits.cols); value = Type(fits.rows, fits.cols);
auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value)); auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));
if (dims == 1) ref = ref.squeeze(); if (dims == 1) {
else if (ref.ndim() == 1) buf = buf.squeeze(); ref = ref.squeeze();
} else if (ref.ndim() == 1) {
buf = buf.squeeze();
}
int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr()); int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());
...@@ -323,14 +341,18 @@ public: ...@@ -323,14 +341,18 @@ public:
} }
// lvalue reference return; default (automatic) becomes copy // lvalue reference return; default (automatic) becomes copy
static handle cast(Type &src, return_value_policy policy, handle parent) { static handle cast(Type &src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) if (policy == return_value_policy::automatic
|| policy == return_value_policy::automatic_reference) {
policy = return_value_policy::copy; policy = return_value_policy::copy;
}
return cast_impl(&src, policy, parent); return cast_impl(&src, policy, parent);
} }
// const lvalue reference return; default (automatic) becomes copy // const lvalue reference return; default (automatic) becomes copy
static handle cast(const Type &src, return_value_policy policy, handle parent) { static handle cast(const Type &src, return_value_policy policy, handle parent) {
if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) if (policy == return_value_policy::automatic
|| policy == return_value_policy::automatic_reference) {
policy = return_value_policy::copy; policy = return_value_policy::copy;
}
return cast(&src, policy, parent); return cast(&src, policy, parent);
} }
// non-const pointer return // non-const pointer return
...@@ -439,11 +461,14 @@ public: ...@@ -439,11 +461,14 @@ public:
if (aref && (!need_writeable || aref.writeable())) { if (aref && (!need_writeable || aref.writeable())) {
fits = props::conformable(aref); fits = props::conformable(aref);
if (!fits) return false; // Incompatible dimensions if (!fits) {
if (!fits.template stride_compatible<props>()) return false; // Incompatible dimensions
}
if (!fits.template stride_compatible<props>()) {
need_copy = true; need_copy = true;
else } else {
copy_or_ref = std::move(aref); copy_or_ref = std::move(aref);
}
} }
else { else {
need_copy = true; need_copy = true;
...@@ -454,13 +479,18 @@ public: ...@@ -454,13 +479,18 @@ public:
// We need to copy: If we need a mutable reference, or we're not supposed to convert // We need to copy: If we need a mutable reference, or we're not supposed to convert
// (either because we're in the no-convert overload pass, or because we're explicitly // (either because we're in the no-convert overload pass, or because we're explicitly
// instructed not to copy (via `py::arg().noconvert()`) we have to fail loading. // instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.
if (!convert || need_writeable) return false; if (!convert || need_writeable) {
return false;
}
Array copy = Array::ensure(src); Array copy = Array::ensure(src);
if (!copy) return false; if (!copy) {
return false;
}
fits = props::conformable(copy); fits = props::conformable(copy);
if (!fits || !fits.template stride_compatible<props>()) if (!fits || !fits.template stride_compatible<props>()) {
return false; return false;
}
copy_or_ref = std::move(copy); copy_or_ref = std::move(copy);
loader_life_support::add_patient(copy_or_ref); loader_life_support::add_patient(copy_or_ref);
} }
...@@ -550,8 +580,9 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> { ...@@ -550,8 +580,9 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
static constexpr bool rowMajor = Type::IsRowMajor; static constexpr bool rowMajor = Type::IsRowMajor;
bool load(handle src, bool) { bool load(handle src, bool) {
if (!src) if (!src) {
return false; return false;
}
auto obj = reinterpret_borrow<object>(src); auto obj = reinterpret_borrow<object>(src);
object sparse_module = module_::import("scipy.sparse"); object sparse_module = module_::import("scipy.sparse");
...@@ -572,8 +603,9 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> { ...@@ -572,8 +603,9 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
auto shape = pybind11::tuple((pybind11::object) obj.attr("shape")); auto shape = pybind11::tuple((pybind11::object) obj.attr("shape"));
auto nnz = obj.attr("nnz").cast<Index>(); auto nnz = obj.attr("nnz").cast<Index>();
if (!values || !innerIndices || !outerIndices) if (!values || !innerIndices || !outerIndices) {
return false; return false;
}
value = EigenMapSparseMatrix<Scalar, value = EigenMapSparseMatrix<Scalar,
Type::Flags & (Eigen::RowMajor | Eigen::ColMajor), Type::Flags & (Eigen::RowMajor | Eigen::ColMajor),
......
...@@ -77,12 +77,14 @@ struct embedded_module { ...@@ -77,12 +77,14 @@ struct embedded_module {
using init_t = void (*)(); using init_t = void (*)();
#endif #endif
embedded_module(const char *name, init_t init) { embedded_module(const char *name, init_t init) {
if (Py_IsInitialized() != 0) if (Py_IsInitialized() != 0) {
pybind11_fail("Can't add new modules after the interpreter has been initialized"); pybind11_fail("Can't add new modules after the interpreter has been initialized");
}
auto result = PyImport_AppendInittab(name, init); auto result = PyImport_AppendInittab(name, init);
if (result == -1) if (result == -1) {
pybind11_fail("Insufficient memory to add a new module"); pybind11_fail("Insufficient memory to add a new module");
}
} }
}; };
...@@ -135,8 +137,9 @@ inline void set_interpreter_argv(int argc, const char *const *argv, bool add_pro ...@@ -135,8 +137,9 @@ inline void set_interpreter_argv(int argc, const char *const *argv, bool add_pro
const char *const empty_argv[]{"\0"}; const char *const empty_argv[]{"\0"};
const char *const *safe_argv = special_case ? empty_argv : argv; const char *const *safe_argv = special_case ? empty_argv : argv;
if (special_case) if (special_case) {
argc = 1; argc = 1;
}
auto argv_size = static_cast<size_t>(argc); auto argv_size = static_cast<size_t>(argc);
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
...@@ -192,8 +195,9 @@ inline void initialize_interpreter(bool init_signal_handlers = true, ...@@ -192,8 +195,9 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
int argc = 0, int argc = 0,
const char *const *argv = nullptr, const char *const *argv = nullptr,
bool add_program_dir_to_path = true) { bool add_program_dir_to_path = true) {
if (Py_IsInitialized() != 0) if (Py_IsInitialized() != 0) {
pybind11_fail("The interpreter is already running"); pybind11_fail("The interpreter is already running");
}
Py_InitializeEx(init_signal_handlers ? 1 : 0); Py_InitializeEx(init_signal_handlers ? 1 : 0);
...@@ -244,8 +248,9 @@ inline void finalize_interpreter() { ...@@ -244,8 +248,9 @@ inline void finalize_interpreter() {
// during destruction), so we get the pointer-pointer here and check it after Py_Finalize(). // during destruction), so we get the pointer-pointer here and check it after Py_Finalize().
detail::internals **internals_ptr_ptr = detail::get_internals_pp(); detail::internals **internals_ptr_ptr = detail::get_internals_pp();
// It could also be stashed in builtins, so look there too: // It could also be stashed in builtins, so look there too:
if (builtins.contains(id) && isinstance<capsule>(builtins[id])) if (builtins.contains(id) && isinstance<capsule>(builtins[id])) {
internals_ptr_ptr = capsule(builtins[id]); internals_ptr_ptr = capsule(builtins[id]);
}
Py_Finalize(); Py_Finalize();
...@@ -285,8 +290,9 @@ public: ...@@ -285,8 +290,9 @@ public:
scoped_interpreter &operator=(scoped_interpreter &&) = delete; scoped_interpreter &operator=(scoped_interpreter &&) = delete;
~scoped_interpreter() { ~scoped_interpreter() {
if (is_valid) if (is_valid) {
finalize_interpreter(); finalize_interpreter();
}
} }
private: private:
......
...@@ -46,8 +46,9 @@ enum eval_mode { ...@@ -46,8 +46,9 @@ enum eval_mode {
template <eval_mode mode = eval_expr> template <eval_mode mode = eval_expr>
object eval(const str &expr, object global = globals(), object local = object()) { object eval(const str &expr, object global = globals(), object local = object()) {
if (!local) if (!local) {
local = global; local = global;
}
detail::ensure_builtins_in_globals(global); detail::ensure_builtins_in_globals(global);
...@@ -64,8 +65,9 @@ object eval(const str &expr, object global = globals(), object local = object()) ...@@ -64,8 +65,9 @@ object eval(const str &expr, object global = globals(), object local = object())
} }
PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr()); PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
if (!result) if (!result) {
throw error_already_set(); throw error_already_set();
}
return reinterpret_steal<object>(result); return reinterpret_steal<object>(result);
} }
...@@ -102,8 +104,9 @@ object eval_file(str) { ...@@ -102,8 +104,9 @@ object eval_file(str) {
#else #else
template <eval_mode mode = eval_statements> template <eval_mode mode = eval_statements>
object eval_file(str fname, object global = globals(), object local = object()) { object eval_file(str fname, object global = globals(), object local = object()) {
if (!local) if (!local) {
local = global; local = global;
}
detail::ensure_builtins_in_globals(global); detail::ensure_builtins_in_globals(global);
...@@ -154,8 +157,9 @@ object eval_file(str fname, object global = globals(), object local = object()) ...@@ -154,8 +157,9 @@ object eval_file(str fname, object global = globals(), object local = object())
local.ptr(), closeFile); local.ptr(), closeFile);
#endif #endif
if (!result) if (!result) {
throw error_already_set(); throw error_already_set();
}
return reinterpret_steal<object>(result); return reinterpret_steal<object>(result);
} }
#endif #endif
......
...@@ -25,12 +25,15 @@ public: ...@@ -25,12 +25,15 @@ public:
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
if (src.is_none()) { if (src.is_none()) {
// Defer accepting None to other overloads (if we aren't in convert mode): // Defer accepting None to other overloads (if we aren't in convert mode):
if (!convert) return false; if (!convert) {
return false;
}
return true; return true;
} }
if (!isinstance<function>(src)) if (!isinstance<function>(src)) {
return false; return false;
}
auto func = reinterpret_borrow<function>(src); auto func = reinterpret_borrow<function>(src);
...@@ -104,12 +107,14 @@ public: ...@@ -104,12 +107,14 @@ public:
template <typename Func> template <typename Func>
static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) { static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {
if (!f_) if (!f_) {
return none().inc_ref(); return none().inc_ref();
}
auto result = f_.template target<function_type>(); auto result = f_.template target<function_type>();
if (result) if (result) {
return cpp_function(*result, policy).release(); return cpp_function(*result, policy).release();
}
return cpp_function(std::forward<Func>(f_), policy).release(); return cpp_function(std::forward<Func>(f_), policy).release();
} }
......
...@@ -99,8 +99,9 @@ public: ...@@ -99,8 +99,9 @@ public:
pybind11_fail("scoped_acquire::dec_ref(): internal error!"); pybind11_fail("scoped_acquire::dec_ref(): internal error!");
#endif #endif
PyThreadState_Clear(tstate); PyThreadState_Clear(tstate);
if (active) if (active) {
PyThreadState_DeleteCurrent(); PyThreadState_DeleteCurrent();
}
PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate); PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate);
release = false; release = false;
} }
...@@ -117,8 +118,9 @@ public: ...@@ -117,8 +118,9 @@ public:
PYBIND11_NOINLINE ~gil_scoped_acquire() { PYBIND11_NOINLINE ~gil_scoped_acquire() {
dec_ref(); dec_ref();
if (release) if (release) {
PyEval_SaveThread(); PyEval_SaveThread();
}
} }
private: private:
PyThreadState *tstate = nullptr; PyThreadState *tstate = nullptr;
...@@ -150,11 +152,13 @@ public: ...@@ -150,11 +152,13 @@ public:
} }
~gil_scoped_release() { ~gil_scoped_release() {
if (!tstate) if (!tstate) {
return; return;
}
// `PyEval_RestoreThread()` should not be called if runtime is finalizing // `PyEval_RestoreThread()` should not be called if runtime is finalizing
if (active) if (active) {
PyEval_RestoreThread(tstate); PyEval_RestoreThread(tstate);
}
if (disassoc) { if (disassoc) {
auto key = detail::get_internals().tstate; auto key = detail::get_internals().tstate;
PYBIND11_TLS_REPLACE_VALUE(key, tstate); PYBIND11_TLS_REPLACE_VALUE(key, tstate);
......
...@@ -71,23 +71,26 @@ private: ...@@ -71,23 +71,26 @@ private:
return static_cast<unsigned char>(c) <= 0xEF; return static_cast<unsigned char>(c) <= 0xEF;
}; };
// If the last character is ASCII, there are no incomplete code points // If the last character is ASCII, there are no incomplete code points
if (is_ascii(*rpptr)) if (is_ascii(*rpptr)) {
return 0; return 0;
}
// Otherwise, work back from the end of the buffer and find the first // Otherwise, work back from the end of the buffer and find the first
// UTF-8 leading byte // UTF-8 leading byte
const auto rpend = rbase - rpptr >= 3 ? rpptr + 3 : rbase; const auto rpend = rbase - rpptr >= 3 ? rpptr + 3 : rbase;
const auto leading = std::find_if(rpptr, rpend, is_leading); const auto leading = std::find_if(rpptr, rpend, is_leading);
if (leading == rbase) if (leading == rbase) {
return 0; return 0;
}
const auto dist = static_cast<size_t>(leading - rpptr); const auto dist = static_cast<size_t>(leading - rpptr);
size_t remainder = 0; size_t remainder = 0;
if (dist == 0) if (dist == 0) {
remainder = 1; // 1-byte code point is impossible remainder = 1; // 1-byte code point is impossible
else if (dist == 1) } else if (dist == 1) {
remainder = is_leading_2b(*leading) ? 0 : dist + 1; remainder = is_leading_2b(*leading) ? 0 : dist + 1;
else if (dist == 2) } else if (dist == 2) {
remainder = is_leading_3b(*leading) ? 0 : dist + 1; remainder = is_leading_3b(*leading) ? 0 : dist + 1;
}
// else if (dist >= 3), at least 4 bytes before encountering an UTF-8 // else if (dist >= 3), at least 4 bytes before encountering an UTF-8
// leading byte, either no remainder or invalid UTF-8. // leading byte, either no remainder or invalid UTF-8.
// Invalid UTF-8 will cause an exception later when converting // Invalid UTF-8 will cause an exception later when converting
...@@ -110,8 +113,9 @@ private: ...@@ -110,8 +113,9 @@ private:
} }
// Copy the remainder at the end of the buffer to the beginning: // Copy the remainder at the end of the buffer to the beginning:
if (remainder > 0) if (remainder > 0) {
std::memmove(pbase(), pptr() - remainder, remainder); std::memmove(pbase(), pptr() - remainder, remainder);
}
setp(pbase(), epptr()); setp(pbase(), epptr());
pbump(static_cast<int>(remainder)); pbump(static_cast<int>(remainder));
} }
...@@ -223,10 +227,12 @@ public: ...@@ -223,10 +227,12 @@ public:
: do_stdout_(do_stdout), do_stderr_(do_stderr) {} : do_stdout_(do_stdout), do_stderr_(do_stderr) {}
void enter() { void enter() {
if (do_stdout_) if (do_stdout_) {
redirect_stdout.reset(new scoped_ostream_redirect()); redirect_stdout.reset(new scoped_ostream_redirect());
if (do_stderr_) }
if (do_stderr_) {
redirect_stderr.reset(new scoped_estream_redirect()); redirect_stderr.reset(new scoped_estream_redirect());
}
} }
void exit() { void exit() {
......
...@@ -87,10 +87,12 @@ struct numpy_internals { ...@@ -87,10 +87,12 @@ struct numpy_internals {
numpy_type_info *get_type_info(const std::type_info& tinfo, bool throw_if_missing = true) { numpy_type_info *get_type_info(const std::type_info& tinfo, bool throw_if_missing = true) {
auto it = registered_dtypes.find(std::type_index(tinfo)); auto it = registered_dtypes.find(std::type_index(tinfo));
if (it != registered_dtypes.end()) if (it != registered_dtypes.end()) {
return &(it->second); return &(it->second);
if (throw_if_missing) }
if (throw_if_missing) {
pybind11_fail(std::string("NumPy type info missing for ") + tinfo.name()); pybind11_fail(std::string("NumPy type info missing for ") + tinfo.name());
}
return nullptr; return nullptr;
} }
...@@ -105,8 +107,9 @@ PYBIND11_NOINLINE void load_numpy_internals(numpy_internals* &ptr) { ...@@ -105,8 +107,9 @@ PYBIND11_NOINLINE void load_numpy_internals(numpy_internals* &ptr) {
inline numpy_internals& get_numpy_internals() { inline numpy_internals& get_numpy_internals() {
static numpy_internals* ptr = nullptr; static numpy_internals* ptr = nullptr;
if (!ptr) if (!ptr) {
load_numpy_internals(ptr); load_numpy_internals(ptr);
}
return *ptr; return *ptr;
} }
...@@ -235,8 +238,9 @@ private: ...@@ -235,8 +238,9 @@ private:
npy_api api; npy_api api;
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func]; #define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion); DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion);
if (api.PyArray_GetNDArrayCFeatureVersion_() < 0x7) if (api.PyArray_GetNDArrayCFeatureVersion_() < 0x7) {
pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0"); pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0");
}
DECL_NPY_API(PyArray_Type); DECL_NPY_API(PyArray_Type);
DECL_NPY_API(PyVoidArrType_Type); DECL_NPY_API(PyVoidArrType_Type);
DECL_NPY_API(PyArrayDescr_Type); DECL_NPY_API(PyArrayDescr_Type);
...@@ -491,8 +495,9 @@ public: ...@@ -491,8 +495,9 @@ public:
/// This is essentially the same as calling numpy.dtype(args) in Python. /// This is essentially the same as calling numpy.dtype(args) in Python.
static dtype from_args(object args) { static dtype from_args(object args) {
PyObject *ptr = nullptr; PyObject *ptr = nullptr;
if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr) if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr) {
throw error_already_set(); throw error_already_set();
}
return reinterpret_steal<dtype>(ptr); return reinterpret_steal<dtype>(ptr);
} }
...@@ -536,8 +541,9 @@ private: ...@@ -536,8 +541,9 @@ private:
dtype strip_padding(ssize_t itemsize) { dtype strip_padding(ssize_t itemsize) {
// Recursively strip all void fields with empty names that are generated for // Recursively strip all void fields with empty names that are generated for
// padding fields (as of NumPy v1.11). // padding fields (as of NumPy v1.11).
if (!has_fields()) if (!has_fields()) {
return *this; return *this;
}
struct field_descr { PYBIND11_STR_TYPE name; object format; pybind11::int_ offset; }; struct field_descr { PYBIND11_STR_TYPE name; object format; pybind11::int_ offset; };
std::vector<field_descr> field_descriptors; std::vector<field_descr> field_descriptors;
...@@ -547,8 +553,9 @@ private: ...@@ -547,8 +553,9 @@ private:
auto name = spec[0].cast<pybind11::str>(); auto name = spec[0].cast<pybind11::str>();
auto format = spec[1].cast<tuple>()[0].cast<dtype>(); auto format = spec[1].cast<tuple>()[0].cast<dtype>();
auto offset = spec[1].cast<tuple>()[1].cast<pybind11::int_>(); auto offset = spec[1].cast<tuple>()[1].cast<pybind11::int_>();
if ((len(name) == 0u) && format.kind() == 'V') if ((len(name) == 0u) && format.kind() == 'V') {
continue; continue;
}
field_descriptors.push_back({(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset}); field_descriptors.push_back({(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset});
} }
...@@ -586,22 +593,25 @@ public: ...@@ -586,22 +593,25 @@ public:
array(const pybind11::dtype &dt, ShapeContainer shape, StridesContainer strides, array(const pybind11::dtype &dt, ShapeContainer shape, StridesContainer strides,
const void *ptr = nullptr, handle base = handle()) { const void *ptr = nullptr, handle base = handle()) {
if (strides->empty()) if (strides->empty()) {
*strides = detail::c_strides(*shape, dt.itemsize()); *strides = detail::c_strides(*shape, dt.itemsize());
}
auto ndim = shape->size(); auto ndim = shape->size();
if (ndim != strides->size()) if (ndim != strides->size()) {
pybind11_fail("NumPy: shape ndim doesn't match strides ndim"); pybind11_fail("NumPy: shape ndim doesn't match strides ndim");
}
auto descr = dt; auto descr = dt;
int flags = 0; int flags = 0;
if (base && ptr) { if (base && ptr) {
if (isinstance<array>(base)) if (isinstance<array>(base)) {
/* Copy flags from base (except ownership bit) */ /* Copy flags from base (except ownership bit) */
flags = reinterpret_borrow<array>(base).flags() & ~detail::npy_api::NPY_ARRAY_OWNDATA_; flags = reinterpret_borrow<array>(base).flags() & ~detail::npy_api::NPY_ARRAY_OWNDATA_;
else } else {
/* Writable by default, easy to downgrade later on if needed */ /* Writable by default, easy to downgrade later on if needed */
flags = detail::npy_api::NPY_ARRAY_WRITEABLE_; flags = detail::npy_api::NPY_ARRAY_WRITEABLE_;
}
} }
auto &api = detail::npy_api::get(); auto &api = detail::npy_api::get();
...@@ -611,8 +621,9 @@ public: ...@@ -611,8 +621,9 @@ public:
reinterpret_cast<Py_intptr_t*>(shape->data()), reinterpret_cast<Py_intptr_t*>(shape->data()),
reinterpret_cast<Py_intptr_t*>(strides->data()), reinterpret_cast<Py_intptr_t*>(strides->data()),
const_cast<void *>(ptr), flags, nullptr)); const_cast<void *>(ptr), flags, nullptr));
if (!tmp) if (!tmp) {
throw error_already_set(); throw error_already_set();
}
if (ptr) { if (ptr) {
if (base) { if (base) {
api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr()); api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr());
...@@ -681,8 +692,9 @@ public: ...@@ -681,8 +692,9 @@ public:
/// Dimension along a given axis /// Dimension along a given axis
ssize_t shape(ssize_t dim) const { ssize_t shape(ssize_t dim) const {
if (dim >= ndim()) if (dim >= ndim()) {
fail_dim_check(dim, "invalid axis"); fail_dim_check(dim, "invalid axis");
}
return shape()[dim]; return shape()[dim];
} }
...@@ -693,8 +705,9 @@ public: ...@@ -693,8 +705,9 @@ public:
/// Stride along a given axis /// Stride along a given axis
ssize_t strides(ssize_t dim) const { ssize_t strides(ssize_t dim) const {
if (dim >= ndim()) if (dim >= ndim()) {
fail_dim_check(dim, "invalid axis"); fail_dim_check(dim, "invalid axis");
}
return strides()[dim]; return strides()[dim];
} }
...@@ -730,8 +743,9 @@ public: ...@@ -730,8 +743,9 @@ public:
/// Byte offset from beginning of the array to a given index (full or partial). /// Byte offset from beginning of the array to a given index (full or partial).
/// May throw if the index would lead to out of bounds access. /// May throw if the index would lead to out of bounds access.
template<typename... Ix> ssize_t offset_at(Ix... index) const { template<typename... Ix> ssize_t offset_at(Ix... index) const {
if ((ssize_t) sizeof...(index) > ndim()) if ((ssize_t) sizeof...(index) > ndim()) {
fail_dim_check(sizeof...(index), "too many indices for an array"); fail_dim_check(sizeof...(index), "too many indices for an array");
}
return byte_offset(ssize_t(index)...); return byte_offset(ssize_t(index)...);
} }
...@@ -750,9 +764,11 @@ public: ...@@ -750,9 +764,11 @@ public:
* and the caller must take care not to access invalid dimensions or dimension indices. * 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() & { template <typename T, ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {
if (PYBIND11_SILENCE_MSVC_C4127(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()) + throw std::domain_error("array has incorrect number of dimensions: "
"; expected " + std::to_string(Dims)); + std::to_string(ndim()) + "; expected "
+ std::to_string(Dims));
}
return detail::unchecked_mutable_reference<T, Dims>(mutable_data(), shape(), strides(), ndim()); return detail::unchecked_mutable_reference<T, Dims>(mutable_data(), shape(), strides(), ndim());
} }
...@@ -764,9 +780,11 @@ public: ...@@ -764,9 +780,11 @@ public:
* invalid dimensions or dimension indices. * invalid dimensions or dimension indices.
*/ */
template <typename T, ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const & { template <typename T, ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const & {
if (PYBIND11_SILENCE_MSVC_C4127(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()) + throw std::domain_error("array has incorrect number of dimensions: "
"; expected " + std::to_string(Dims)); + std::to_string(ndim()) + "; expected "
+ std::to_string(Dims));
}
return detail::unchecked_reference<T, Dims>(data(), shape(), strides(), ndim()); return detail::unchecked_reference<T, Dims>(data(), shape(), strides(), ndim());
} }
...@@ -789,7 +807,9 @@ public: ...@@ -789,7 +807,9 @@ public:
auto new_array = reinterpret_steal<object>( auto new_array = reinterpret_steal<object>(
detail::npy_api::get().PyArray_Resize_(m_ptr, &d, int(refcheck), -1) detail::npy_api::get().PyArray_Resize_(m_ptr, &d, int(refcheck), -1)
); );
if (!new_array) throw error_already_set(); if (!new_array) {
throw error_already_set();
}
if (isinstance<array>(new_array)) { *this = std::move(new_array); } if (isinstance<array>(new_array)) { *this = std::move(new_array); }
} }
...@@ -824,8 +844,9 @@ public: ...@@ -824,8 +844,9 @@ public:
/// In case of an error, nullptr is returned and the Python error is cleared. /// In case of an error, nullptr is returned and the Python error is cleared.
static array ensure(handle h, int ExtraFlags = 0) { static array ensure(handle h, int ExtraFlags = 0) {
auto result = reinterpret_steal<array>(raw_array(h.ptr(), ExtraFlags)); auto result = reinterpret_steal<array>(raw_array(h.ptr(), ExtraFlags));
if (!result) if (!result) {
PyErr_Clear(); PyErr_Clear();
}
return result; return result;
} }
...@@ -843,8 +864,9 @@ protected: ...@@ -843,8 +864,9 @@ protected:
} }
void check_writeable() const { void check_writeable() const {
if (!writeable()) if (!writeable()) {
throw std::domain_error("array is not writeable"); throw std::domain_error("array is not writeable");
}
} }
template<typename... Ix> void check_dimensions(Ix... index) const { template<typename... Ix> void check_dimensions(Ix... index) const {
...@@ -890,13 +912,19 @@ public: ...@@ -890,13 +912,19 @@ public:
PYBIND11_DEPRECATED("Use array_t<T>::ensure() instead") PYBIND11_DEPRECATED("Use array_t<T>::ensure() instead")
array_t(handle h, bool is_borrowed) : array(raw_array_t(h.ptr()), stolen_t{}) { array_t(handle h, bool is_borrowed) : array(raw_array_t(h.ptr()), stolen_t{}) {
if (!m_ptr) PyErr_Clear(); if (!m_ptr) {
if (!is_borrowed) Py_XDECREF(h.ptr()); PyErr_Clear();
}
if (!is_borrowed) {
Py_XDECREF(h.ptr());
}
} }
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
array_t(const object &o) : array(raw_array_t(o.ptr()), stolen_t{}) { array_t(const object &o) : array(raw_array_t(o.ptr()), stolen_t{}) {
if (!m_ptr) throw error_already_set(); if (!m_ptr) {
throw error_already_set();
}
} }
explicit array_t(const buffer_info& info, handle base = handle()) : array(info, base) { } explicit array_t(const buffer_info& info, handle base = handle()) : array(info, base) { }
...@@ -933,15 +961,17 @@ public: ...@@ -933,15 +961,17 @@ public:
// Reference to element at a given index // Reference to element at a given index
template<typename... Ix> const T& at(Ix... index) const { template<typename... Ix> const T& at(Ix... index) const {
if ((ssize_t) sizeof...(index) != ndim()) if ((ssize_t) sizeof...(index) != ndim()) {
fail_dim_check(sizeof...(index), "index dimension mismatch"); fail_dim_check(sizeof...(index), "index dimension mismatch");
}
return *(static_cast<const T*>(array::data()) + byte_offset(ssize_t(index)...) / itemsize()); return *(static_cast<const T*>(array::data()) + byte_offset(ssize_t(index)...) / itemsize());
} }
// Mutable reference to element at a given index // Mutable reference to element at a given index
template<typename... Ix> T& mutable_at(Ix... index) { template<typename... Ix> T& mutable_at(Ix... index) {
if ((ssize_t) sizeof...(index) != ndim()) if ((ssize_t) sizeof...(index) != ndim()) {
fail_dim_check(sizeof...(index), "index dimension mismatch"); fail_dim_check(sizeof...(index), "index dimension mismatch");
}
return *(static_cast<T*>(array::mutable_data()) + byte_offset(ssize_t(index)...) / itemsize()); return *(static_cast<T*>(array::mutable_data()) + byte_offset(ssize_t(index)...) / itemsize());
} }
...@@ -970,8 +1000,9 @@ public: ...@@ -970,8 +1000,9 @@ public:
/// it). In case of an error, nullptr is returned and the Python error is cleared. /// it). In case of an error, nullptr is returned and the Python error is cleared.
static array_t ensure(handle h) { static array_t ensure(handle h) {
auto result = reinterpret_steal<array_t>(raw_array_t(h.ptr())); auto result = reinterpret_steal<array_t>(raw_array_t(h.ptr()));
if (!result) if (!result) {
PyErr_Clear(); PyErr_Clear();
}
return result; return result;
} }
...@@ -1032,8 +1063,9 @@ struct pyobject_caster<array_t<T, ExtraFlags>> { ...@@ -1032,8 +1063,9 @@ struct pyobject_caster<array_t<T, ExtraFlags>> {
using type = array_t<T, ExtraFlags>; using type = array_t<T, ExtraFlags>;
bool load(handle src, bool convert) { bool load(handle src, bool convert) {
if (!convert && !type::check_(src)) if (!convert && !type::check_(src)) {
return false; return false;
}
value = type::ensure(src); value = type::ensure(src);
return static_cast<bool>(value); return static_cast<bool>(value);
} }
...@@ -1098,8 +1130,9 @@ public: ...@@ -1098,8 +1130,9 @@ public:
static constexpr int value = values[detail::is_fmt_numeric<T>::index]; static constexpr int value = values[detail::is_fmt_numeric<T>::index];
static pybind11::dtype dtype() { static pybind11::dtype dtype() {
if (auto ptr = npy_api::get().PyArray_DescrFromType_(value)) if (auto ptr = npy_api::get().PyArray_DescrFromType_(value)) {
return reinterpret_steal<pybind11::dtype>(ptr); return reinterpret_steal<pybind11::dtype>(ptr);
}
pybind11_fail("Unsupported buffer format!"); pybind11_fail("Unsupported buffer format!");
} }
}; };
...@@ -1147,8 +1180,9 @@ PYBIND11_NOINLINE void register_structured_dtype( ...@@ -1147,8 +1180,9 @@ PYBIND11_NOINLINE void register_structured_dtype(
bool (*direct_converter)(PyObject *, void *&)) { bool (*direct_converter)(PyObject *, void *&)) {
auto& numpy_internals = get_numpy_internals(); auto& numpy_internals = get_numpy_internals();
if (numpy_internals.get_type_info(tinfo, false)) if (numpy_internals.get_type_info(tinfo, false)) {
pybind11_fail("NumPy: dtype is already registered"); pybind11_fail("NumPy: dtype is already registered");
}
// Use ordered fields because order matters as of NumPy 1.14: // Use ordered fields because order matters as of NumPy 1.14:
// https://docs.scipy.org/doc/numpy/release.html#multiple-field-indexing-assignment-of-structured-arrays // https://docs.scipy.org/doc/numpy/release.html#multiple-field-indexing-assignment-of-structured-arrays
...@@ -1158,9 +1192,10 @@ PYBIND11_NOINLINE void register_structured_dtype( ...@@ -1158,9 +1192,10 @@ PYBIND11_NOINLINE void register_structured_dtype(
list names, formats, offsets; list names, formats, offsets;
for (auto& field : ordered_fields) { for (auto& field : ordered_fields) {
if (!field.descr) if (!field.descr) {
pybind11_fail(std::string("NumPy: unsupported field dtype: `") + pybind11_fail(std::string("NumPy: unsupported field dtype: `") + field.name + "` @ "
field.name + "` @ " + tinfo.name()); + tinfo.name());
}
names.append(PYBIND11_STR_TYPE(field.name)); names.append(PYBIND11_STR_TYPE(field.name));
formats.append(field.descr); formats.append(field.descr);
offsets.append(pybind11::int_(field.offset)); offsets.append(pybind11::int_(field.offset));
...@@ -1186,21 +1221,24 @@ PYBIND11_NOINLINE void register_structured_dtype( ...@@ -1186,21 +1221,24 @@ PYBIND11_NOINLINE void register_structured_dtype(
// isn't guaranteed to work due to https://github.com/numpy/numpy/issues/9049 // isn't guaranteed to work due to https://github.com/numpy/numpy/issues/9049
oss << "^T{"; oss << "^T{";
for (auto& field : ordered_fields) { for (auto& field : ordered_fields) {
if (field.offset > offset) if (field.offset > offset) {
oss << (field.offset - offset) << 'x'; oss << (field.offset - offset) << 'x';
}
oss << field.format << ':' << field.name << ':'; oss << field.format << ':' << field.name << ':';
offset = field.offset + field.size; offset = field.offset + field.size;
} }
if (itemsize > offset) if (itemsize > offset) {
oss << (itemsize - offset) << 'x'; oss << (itemsize - offset) << 'x';
}
oss << '}'; oss << '}';
auto format_str = oss.str(); auto format_str = oss.str();
// Sanity check: verify that NumPy properly parses our buffer format string // Sanity check: verify that NumPy properly parses our buffer format string
auto& api = npy_api::get(); auto& api = npy_api::get();
auto arr = array(buffer_info(nullptr, itemsize, format_str, 1)); auto arr = array(buffer_info(nullptr, itemsize, format_str, 1));
if (!api.PyArray_EquivTypes_(dtype_ptr, arr.dtype().ptr())) if (!api.PyArray_EquivTypes_(dtype_ptr, arr.dtype().ptr())) {
pybind11_fail("NumPy: invalid buffer descriptor!"); pybind11_fail("NumPy: invalid buffer descriptor!");
}
auto tindex = std::type_index(tinfo); auto tindex = std::type_index(tinfo);
numpy_internals.registered_dtypes[tindex] = { dtype_ptr, format_str }; numpy_internals.registered_dtypes[tindex] = { dtype_ptr, format_str };
...@@ -1234,8 +1272,9 @@ private: ...@@ -1234,8 +1272,9 @@ private:
static bool direct_converter(PyObject *obj, void*& value) { static bool direct_converter(PyObject *obj, void*& value) {
auto& api = npy_api::get(); auto& api = npy_api::get();
if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_)) if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_)) {
return false; return false;
}
if (auto descr = reinterpret_steal<object>(api.PyArray_DescrFromScalar_(obj))) { if (auto descr = reinterpret_steal<object>(api.PyArray_DescrFromScalar_(obj))) {
if (api.PyArray_EquivTypes_(dtype_ptr(), descr.ptr())) { if (api.PyArray_EquivTypes_(dtype_ptr(), descr.ptr())) {
value = ((PyVoidScalarObject_Proxy *) obj)->obval; value = ((PyVoidScalarObject_Proxy *) obj)->obval;
...@@ -1363,12 +1402,14 @@ public: ...@@ -1363,12 +1402,14 @@ public:
m_common_iterator() { m_common_iterator() {
// Manual copy to avoid conversion warning if using std::copy // Manual copy to avoid conversion warning if using std::copy
for (size_t i = 0; i < shape.size(); ++i) for (size_t i = 0; i < shape.size(); ++i) {
m_shape[i] = shape[i]; m_shape[i] = shape[i];
}
container_type strides(shape.size()); container_type strides(shape.size());
for (size_t i = 0; i < N; ++i) for (size_t i = 0; i < N; ++i) {
init_common_iterator(buffers[i], shape, m_common_iterator[i], strides); init_common_iterator(buffers[i], shape, m_common_iterator[i], strides);
}
} }
multi_array_iterator& operator++() { multi_array_iterator& operator++() {
...@@ -1401,10 +1442,11 @@ private: ...@@ -1401,10 +1442,11 @@ private:
auto strides_iter = strides.rbegin(); auto strides_iter = strides.rbegin();
while (buffer_shape_iter != buffer.shape.rend()) { while (buffer_shape_iter != buffer.shape.rend()) {
if (*shape_iter == *buffer_shape_iter) if (*shape_iter == *buffer_shape_iter) {
*strides_iter = *buffer_strides_iter; *strides_iter = *buffer_strides_iter;
else } else {
*strides_iter = 0; *strides_iter = 0;
}
++buffer_shape_iter; ++buffer_shape_iter;
++buffer_strides_iter; ++buffer_strides_iter;
...@@ -1417,8 +1459,9 @@ private: ...@@ -1417,8 +1459,9 @@ private:
} }
void increment_common_iterator(size_t dim) { void increment_common_iterator(size_t dim) {
for (auto &iter : m_common_iterator) for (auto &iter : m_common_iterator) {
iter.increment(dim); iter.increment(dim);
}
} }
container_type m_shape; container_type m_shape;
...@@ -1451,26 +1494,30 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t & ...@@ -1451,26 +1494,30 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &
auto &dim_size_out = *res_iter; auto &dim_size_out = *res_iter;
// Each input dimension can either be 1 or `n`, but `n` values must match across buffers // Each input dimension can either be 1 or `n`, but `n` values must match across buffers
if (dim_size_out == 1) if (dim_size_out == 1) {
dim_size_out = dim_size_in; dim_size_out = dim_size_in;
else if (dim_size_in != 1 && dim_size_in != dim_size_out) } else if (dim_size_in != 1 && dim_size_in != dim_size_out) {
pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!"); pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!");
}
} }
} }
bool trivial_broadcast_c = true; bool trivial_broadcast_c = true;
bool trivial_broadcast_f = true; bool trivial_broadcast_f = true;
for (size_t i = 0; i < N && (trivial_broadcast_c || trivial_broadcast_f); ++i) { for (size_t i = 0; i < N && (trivial_broadcast_c || trivial_broadcast_f); ++i) {
if (buffers[i].size == 1) if (buffers[i].size == 1) {
continue; continue;
}
// Require the same number of dimensions: // Require the same number of dimensions:
if (buffers[i].ndim != ndim) if (buffers[i].ndim != ndim) {
return broadcast_trivial::non_trivial; return broadcast_trivial::non_trivial;
}
// Require all dimensions be full-size: // Require all dimensions be full-size:
if (!std::equal(buffers[i].shape.cbegin(), buffers[i].shape.cend(), shape.cbegin())) if (!std::equal(buffers[i].shape.cbegin(), buffers[i].shape.cend(), shape.cbegin())) {
return broadcast_trivial::non_trivial; return broadcast_trivial::non_trivial;
}
// Check for C contiguity (but only if previous inputs were also C contiguous) // Check for C contiguity (but only if previous inputs were also C contiguous)
if (trivial_broadcast_c) { if (trivial_broadcast_c) {
...@@ -1478,10 +1525,11 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t & ...@@ -1478,10 +1525,11 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &
auto end = buffers[i].shape.crend(); auto end = buffers[i].shape.crend();
for (auto shape_iter = buffers[i].shape.crbegin(), stride_iter = buffers[i].strides.crbegin(); for (auto shape_iter = buffers[i].shape.crbegin(), stride_iter = buffers[i].strides.crbegin();
trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) { trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) {
if (expect_stride == *stride_iter) if (expect_stride == *stride_iter) {
expect_stride *= *shape_iter; expect_stride *= *shape_iter;
else } else {
trivial_broadcast_c = false; trivial_broadcast_c = false;
}
} }
} }
...@@ -1491,10 +1539,11 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t & ...@@ -1491,10 +1539,11 @@ broadcast_trivial broadcast(const std::array<buffer_info, N> &buffers, ssize_t &
auto end = buffers[i].shape.cend(); auto end = buffers[i].shape.cend();
for (auto shape_iter = buffers[i].shape.cbegin(), stride_iter = buffers[i].strides.cbegin(); for (auto shape_iter = buffers[i].shape.cbegin(), stride_iter = buffers[i].strides.cbegin();
trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) { trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) {
if (expect_stride == *stride_iter) if (expect_stride == *stride_iter) {
expect_stride *= *shape_iter; expect_stride *= *shape_iter;
else } else {
trivial_broadcast_f = false; trivial_broadcast_f = false;
}
} }
} }
} }
...@@ -1527,8 +1576,9 @@ struct vectorize_returned_array { ...@@ -1527,8 +1576,9 @@ struct vectorize_returned_array {
using Type = array_t<Return>; using Type = array_t<Return>;
static Type create(broadcast_trivial trivial, const std::vector<ssize_t> &shape) { static Type create(broadcast_trivial trivial, const std::vector<ssize_t> &shape) {
if (trivial == broadcast_trivial::f_trivial) if (trivial == broadcast_trivial::f_trivial) {
return array_t<Return, array::f_style>(shape); return array_t<Return, array::f_style>(shape);
}
return array_t<Return>(shape); return array_t<Return>(shape);
} }
...@@ -1644,14 +1694,17 @@ private: ...@@ -1644,14 +1694,17 @@ private:
auto result = returned_array::create(trivial, shape); auto result = returned_array::create(trivial, shape);
if (size == 0) return std::move(result); if (size == 0) {
return std::move(result);
}
/* Call the function */ /* Call the function */
auto mutable_data = returned_array::mutable_data(result); auto mutable_data = returned_array::mutable_data(result);
if (trivial == broadcast_trivial::non_trivial) if (trivial == broadcast_trivial::non_trivial) {
apply_broadcast(buffers, params, mutable_data, size, shape, i_seq, vi_seq, bi_seq); apply_broadcast(buffers, params, mutable_data, size, shape, i_seq, vi_seq, bi_seq);
else } else {
apply_trivial(buffers, params, mutable_data, size, i_seq, vi_seq, bi_seq); apply_trivial(buffers, params, mutable_data, size, i_seq, vi_seq, bi_seq);
}
return std::move(result); return std::move(result);
} }
...@@ -1675,7 +1728,9 @@ private: ...@@ -1675,7 +1728,9 @@ private:
for (size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
returned_array::call(out, i, f, *reinterpret_cast<param_n_t<Index> *>(params[Index])...); returned_array::call(out, i, f, *reinterpret_cast<param_n_t<Index> *>(params[Index])...);
for (auto &x : vecparams) x.first += x.second; for (auto &x : vecparams) {
x.first += x.second;
}
} }
} }
......
This diff is collapsed.
...@@ -242,7 +242,11 @@ class object : public handle { ...@@ -242,7 +242,11 @@ class object : public handle {
public: public:
object() = default; object() = default;
PYBIND11_DEPRECATED("Use reinterpret_borrow<object>() or reinterpret_steal<object>()") PYBIND11_DEPRECATED("Use reinterpret_borrow<object>() or reinterpret_steal<object>()")
object(handle h, bool is_borrowed) : handle(h) { if (is_borrowed) inc_ref(); } object(handle h, bool is_borrowed) : handle(h) {
if (is_borrowed) {
inc_ref();
}
}
/// Copy constructor; always increases the reference count /// Copy constructor; always increases the reference count
object(const object &o) : handle(o) { inc_ref(); } object(const object &o) : handle(o) { inc_ref(); }
/// Move constructor; steals the object from ``other`` and preserves its reference count /// Move constructor; steals the object from ``other`` and preserves its reference count
...@@ -458,8 +462,9 @@ template <> inline bool isinstance<object>(handle obj) { return obj.ptr() != nul ...@@ -458,8 +462,9 @@ template <> inline bool isinstance<object>(handle obj) { return obj.ptr() != nul
/// Return true if ``obj`` is an instance of the ``type``. /// Return true if ``obj`` is an instance of the ``type``.
inline bool isinstance(handle obj, handle type) { inline bool isinstance(handle obj, handle type) {
const auto result = PyObject_IsInstance(obj.ptr(), type.ptr()); const auto result = PyObject_IsInstance(obj.ptr(), type.ptr());
if (result == -1) if (result == -1) {
throw error_already_set(); throw error_already_set();
}
return result != 0; return result != 0;
} }
...@@ -529,12 +534,13 @@ PYBIND11_NAMESPACE_BEGIN(detail) ...@@ -529,12 +534,13 @@ PYBIND11_NAMESPACE_BEGIN(detail)
inline handle get_function(handle value) { inline handle get_function(handle value) {
if (value) { if (value) {
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
if (PyInstanceMethod_Check(value.ptr())) if (PyInstanceMethod_Check(value.ptr())) {
value = PyInstanceMethod_GET_FUNCTION(value.ptr()); value = PyInstanceMethod_GET_FUNCTION(value.ptr());
else } else
#endif #endif
if (PyMethod_Check(value.ptr())) if (PyMethod_Check(value.ptr())) {
value = PyMethod_GET_FUNCTION(value.ptr()); value = PyMethod_GET_FUNCTION(value.ptr());
}
} }
return value; return value;
} }
...@@ -1076,14 +1082,18 @@ public: ...@@ -1076,14 +1082,18 @@ public:
template <typename SzType, detail::enable_if_t<std::is_integral<SzType>::value, int> = 0> template <typename SzType, detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>
str(const char *c, const SzType &n) str(const char *c, const SzType &n)
: object(PyUnicode_FromStringAndSize(c, ssize_t_cast(n)), stolen_t{}) { : object(PyUnicode_FromStringAndSize(c, ssize_t_cast(n)), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate string object!"); if (!m_ptr) {
pybind11_fail("Could not allocate string object!");
}
} }
// 'explicit' is explicitly omitted from the following constructors to allow implicit conversion to py::str from C++ string-like objects // 'explicit' is explicitly omitted from the following constructors to allow implicit conversion to py::str from C++ string-like objects
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
str(const char *c = "") str(const char *c = "")
: object(PyUnicode_FromString(c), stolen_t{}) { : object(PyUnicode_FromString(c), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate string object!"); if (!m_ptr) {
pybind11_fail("Could not allocate string object!");
}
} }
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
...@@ -1109,20 +1119,26 @@ public: ...@@ -1109,20 +1119,26 @@ public:
Return a string representation of the object. This is analogous to Return a string representation of the object. This is analogous to
the ``str()`` function in Python. the ``str()`` function in Python.
\endrst */ \endrst */
explicit str(handle h) : object(raw_str(h.ptr()), stolen_t{}) { if (!m_ptr) throw error_already_set(); } explicit str(handle h) : object(raw_str(h.ptr()), stolen_t{}) {
if (!m_ptr) {
throw error_already_set();
}
}
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
operator std::string() const { operator std::string() const {
object temp = *this; object temp = *this;
if (PyUnicode_Check(m_ptr)) { if (PyUnicode_Check(m_ptr)) {
temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(m_ptr)); temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(m_ptr));
if (!temp) if (!temp) {
throw error_already_set(); throw error_already_set();
}
} }
char *buffer = nullptr; char *buffer = nullptr;
ssize_t length = 0; ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) {
pybind11_fail("Unable to extract string contents! (invalid type)"); pybind11_fail("Unable to extract string contents! (invalid type)");
}
return std::string(buffer, (size_t) length); return std::string(buffer, (size_t) length);
} }
...@@ -1162,13 +1178,17 @@ public: ...@@ -1162,13 +1178,17 @@ public:
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
bytes(const char *c = "") bytes(const char *c = "")
: object(PYBIND11_BYTES_FROM_STRING(c), stolen_t{}) { : object(PYBIND11_BYTES_FROM_STRING(c), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); if (!m_ptr) {
pybind11_fail("Could not allocate bytes object!");
}
} }
template <typename SzType, detail::enable_if_t<std::is_integral<SzType>::value, int> = 0> template <typename SzType, detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>
bytes(const char *c, const SzType &n) bytes(const char *c, const SzType &n)
: object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(c, ssize_t_cast(n)), stolen_t{}) { : object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(c, ssize_t_cast(n)), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); if (!m_ptr) {
pybind11_fail("Could not allocate bytes object!");
}
} }
// Allow implicit conversion: // Allow implicit conversion:
...@@ -1181,8 +1201,9 @@ public: ...@@ -1181,8 +1201,9 @@ public:
operator std::string() const { operator std::string() const {
char *buffer = nullptr; char *buffer = nullptr;
ssize_t length = 0; ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) {
pybind11_fail("Unable to extract bytes contents!"); pybind11_fail("Unable to extract bytes contents!");
}
return std::string(buffer, (size_t) length); return std::string(buffer, (size_t) length);
} }
...@@ -1199,8 +1220,9 @@ public: ...@@ -1199,8 +1220,9 @@ public:
operator std::string_view() const { operator std::string_view() const {
char *buffer = nullptr; char *buffer = nullptr;
ssize_t length = 0; ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) {
pybind11_fail("Unable to extract bytes contents!"); pybind11_fail("Unable to extract bytes contents!");
}
return {buffer, static_cast<size_t>(length)}; return {buffer, static_cast<size_t>(length)};
} }
#endif #endif
...@@ -1214,27 +1236,32 @@ inline bytes::bytes(const pybind11::str &s) { ...@@ -1214,27 +1236,32 @@ inline bytes::bytes(const pybind11::str &s) {
object temp = s; object temp = s;
if (PyUnicode_Check(s.ptr())) { if (PyUnicode_Check(s.ptr())) {
temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(s.ptr())); temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(s.ptr()));
if (!temp) if (!temp) {
pybind11_fail("Unable to extract string contents! (encoding issue)"); pybind11_fail("Unable to extract string contents! (encoding issue)");
}
} }
char *buffer = nullptr; char *buffer = nullptr;
ssize_t length = 0; ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) {
pybind11_fail("Unable to extract string contents! (invalid type)"); pybind11_fail("Unable to extract string contents! (invalid type)");
}
auto obj = reinterpret_steal<object>(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length)); auto obj = reinterpret_steal<object>(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length));
if (!obj) if (!obj) {
pybind11_fail("Could not allocate bytes object!"); pybind11_fail("Could not allocate bytes object!");
}
m_ptr = obj.release().ptr(); m_ptr = obj.release().ptr();
} }
inline str::str(const bytes& b) { inline str::str(const bytes& b) {
char *buffer = nullptr; char *buffer = nullptr;
ssize_t length = 0; ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) {
pybind11_fail("Unable to extract bytes contents!"); pybind11_fail("Unable to extract bytes contents!");
}
auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, length)); auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, length));
if (!obj) if (!obj) {
pybind11_fail("Could not allocate string object!"); pybind11_fail("Could not allocate string object!");
}
m_ptr = obj.release().ptr(); m_ptr = obj.release().ptr();
} }
...@@ -1247,7 +1274,9 @@ public: ...@@ -1247,7 +1274,9 @@ public:
template <typename SzType, detail::enable_if_t<std::is_integral<SzType>::value, int> = 0> template <typename SzType, detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>
bytearray(const char *c, const SzType &n) bytearray(const char *c, const SzType &n)
: object(PyByteArray_FromStringAndSize(c, ssize_t_cast(n)), stolen_t{}) { : object(PyByteArray_FromStringAndSize(c, ssize_t_cast(n)), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate bytearray object!"); if (!m_ptr) {
pybind11_fail("Could not allocate bytearray object!");
}
} }
bytearray() bytearray()
...@@ -1295,7 +1324,9 @@ private: ...@@ -1295,7 +1324,9 @@ private:
/// Return the truth value of an object -- always returns a new reference /// Return the truth value of an object -- always returns a new reference
static PyObject *raw_bool(PyObject *op) { static PyObject *raw_bool(PyObject *op) {
const auto value = PyObject_IsTrue(op); const auto value = PyObject_IsTrue(op);
if (value == -1) return nullptr; if (value == -1) {
return nullptr;
}
return handle(value != 0 ? Py_True : Py_False).inc_ref().ptr(); return handle(value != 0 ? Py_True : Py_False).inc_ref().ptr();
} }
}; };
...@@ -1330,17 +1361,21 @@ public: ...@@ -1330,17 +1361,21 @@ public:
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
int_(T value) { int_(T value) {
if (PYBIND11_SILENCE_MSVC_C4127(sizeof(T) <= sizeof(long))) { if (PYBIND11_SILENCE_MSVC_C4127(sizeof(T) <= sizeof(long))) {
if (std::is_signed<T>::value) if (std::is_signed<T>::value) {
m_ptr = PyLong_FromLong((long) value); m_ptr = PyLong_FromLong((long) value);
else } else {
m_ptr = PyLong_FromUnsignedLong((unsigned long) value); m_ptr = PyLong_FromUnsignedLong((unsigned long) value);
}
} else { } else {
if (std::is_signed<T>::value) if (std::is_signed<T>::value) {
m_ptr = PyLong_FromLongLong((long long) value); m_ptr = PyLong_FromLongLong((long long) value);
else } else {
m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value); m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value);
}
}
if (!m_ptr) {
pybind11_fail("Could not allocate int object!");
} }
if (!m_ptr) pybind11_fail("Could not allocate int object!");
} }
template <typename T, template <typename T,
...@@ -1361,11 +1396,15 @@ public: ...@@ -1361,11 +1396,15 @@ public:
// Allow implicit conversion from float/double: // Allow implicit conversion from float/double:
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
float_(float value) : object(PyFloat_FromDouble((double) value), stolen_t{}) { float_(float value) : object(PyFloat_FromDouble((double) value), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate float object!"); if (!m_ptr) {
pybind11_fail("Could not allocate float object!");
}
} }
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
float_(double value = .0) : object(PyFloat_FromDouble((double) value), stolen_t{}) { float_(double value = .0) : object(PyFloat_FromDouble((double) value), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate float object!"); if (!m_ptr) {
pybind11_fail("Could not allocate float object!");
}
} }
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
operator float() const { return (float) PyFloat_AsDouble(m_ptr); } operator float() const { return (float) PyFloat_AsDouble(m_ptr); }
...@@ -1378,7 +1417,9 @@ public: ...@@ -1378,7 +1417,9 @@ public:
PYBIND11_OBJECT_CVT_DEFAULT(weakref, object, PyWeakref_Check, raw_weakref) PYBIND11_OBJECT_CVT_DEFAULT(weakref, object, PyWeakref_Check, raw_weakref)
explicit weakref(handle obj, handle callback = {}) explicit weakref(handle obj, handle callback = {})
: object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen_t{}) { : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate weak reference!"); if (!m_ptr) {
pybind11_fail("Could not allocate weak reference!");
}
} }
private: private:
...@@ -1392,8 +1433,9 @@ public: ...@@ -1392,8 +1433,9 @@ public:
PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check) PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check)
slice(handle start, handle stop, handle step) { slice(handle start, handle stop, handle step) {
m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr()); m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr());
if (!m_ptr) if (!m_ptr) {
pybind11_fail("Could not allocate slice object!"); pybind11_fail("Could not allocate slice object!");
}
} }
#ifdef PYBIND11_HAS_OPTIONAL #ifdef PYBIND11_HAS_OPTIONAL
...@@ -1434,15 +1476,17 @@ public: ...@@ -1434,15 +1476,17 @@ public:
explicit capsule(const void *value, const char *name = nullptr, void (*destructor)(PyObject *) = nullptr) explicit capsule(const void *value, const char *name = nullptr, void (*destructor)(PyObject *) = nullptr)
: object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) { : object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) {
if (!m_ptr) if (!m_ptr) {
pybind11_fail("Could not allocate capsule object!"); pybind11_fail("Could not allocate capsule object!");
}
} }
PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input") PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input")
capsule(const void *value, void (*destruct)(PyObject *)) capsule(const void *value, void (*destruct)(PyObject *))
: object(PyCapsule_New(const_cast<void*>(value), nullptr, destruct), stolen_t{}) { : object(PyCapsule_New(const_cast<void*>(value), nullptr, destruct), stolen_t{}) {
if (!m_ptr) if (!m_ptr) {
pybind11_fail("Could not allocate capsule object!"); pybind11_fail("Could not allocate capsule object!");
}
} }
capsule(const void *value, void (*destructor)(void *)) { capsule(const void *value, void (*destructor)(void *)) {
...@@ -1452,11 +1496,13 @@ public: ...@@ -1452,11 +1496,13 @@ public:
destructor(ptr); destructor(ptr);
}); });
if (!m_ptr) if (!m_ptr) {
pybind11_fail("Could not allocate capsule object!"); pybind11_fail("Could not allocate capsule object!");
}
if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) {
pybind11_fail("Could not set capsule context!"); pybind11_fail("Could not set capsule context!");
}
} }
explicit capsule(void (*destructor)()) { explicit capsule(void (*destructor)()) {
...@@ -1465,8 +1511,9 @@ public: ...@@ -1465,8 +1511,9 @@ public:
destructor(); destructor();
}); });
if (!m_ptr) if (!m_ptr) {
pybind11_fail("Could not allocate capsule object!"); pybind11_fail("Could not allocate capsule object!");
}
} }
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
...@@ -1504,7 +1551,9 @@ public: ...@@ -1504,7 +1551,9 @@ public:
detail::enable_if_t<std::is_integral<SzType>::value, int> = 0> detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>
// Some compilers generate link errors when using `const SzType &` here: // Some compilers generate link errors when using `const SzType &` here:
explicit tuple(SzType size = 0) : object(PyTuple_New(ssize_t_cast(size)), stolen_t{}) { explicit tuple(SzType size = 0) : object(PyTuple_New(ssize_t_cast(size)), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate tuple object!"); if (!m_ptr) {
pybind11_fail("Could not allocate tuple object!");
}
} }
size_t size() const { return (size_t) PyTuple_Size(m_ptr); } size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
bool empty() const { return size() == 0; } bool empty() const { return size() == 0; }
...@@ -1527,7 +1576,9 @@ class dict : public object { ...@@ -1527,7 +1576,9 @@ class dict : public object {
public: public:
PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict) PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict)
dict() : object(PyDict_New(), stolen_t{}) { dict() : object(PyDict_New(), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate dict object!"); if (!m_ptr) {
pybind11_fail("Could not allocate dict object!");
}
} }
template <typename... Args, template <typename... Args,
typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>, typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>,
...@@ -1547,8 +1598,9 @@ public: ...@@ -1547,8 +1598,9 @@ public:
private: private:
/// Call the `dict` Python type -- always returns a new reference /// Call the `dict` Python type -- always returns a new reference
static PyObject *raw_dict(PyObject *op) { static PyObject *raw_dict(PyObject *op) {
if (PyDict_Check(op)) if (PyDict_Check(op)) {
return handle(op).inc_ref().ptr(); return handle(op).inc_ref().ptr();
}
return PyObject_CallFunctionObjArgs((PyObject *) &PyDict_Type, op, nullptr); return PyObject_CallFunctionObjArgs((PyObject *) &PyDict_Type, op, nullptr);
} }
}; };
...@@ -1558,8 +1610,9 @@ public: ...@@ -1558,8 +1610,9 @@ public:
PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check) PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check)
size_t size() const { size_t size() const {
ssize_t result = PySequence_Size(m_ptr); ssize_t result = PySequence_Size(m_ptr);
if (result == -1) if (result == -1) {
throw error_already_set(); throw error_already_set();
}
return (size_t) result; return (size_t) result;
} }
bool empty() const { return size() == 0; } bool empty() const { return size() == 0; }
...@@ -1576,7 +1629,9 @@ public: ...@@ -1576,7 +1629,9 @@ public:
detail::enable_if_t<std::is_integral<SzType>::value, int> = 0> detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>
// Some compilers generate link errors when using `const SzType &` here: // Some compilers generate link errors when using `const SzType &` here:
explicit list(SzType size = 0) : object(PyList_New(ssize_t_cast(size)), stolen_t{}) { explicit list(SzType size = 0) : object(PyList_New(ssize_t_cast(size)), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate list object!"); if (!m_ptr) {
pybind11_fail("Could not allocate list object!");
}
} }
size_t size() const { return (size_t) PyList_Size(m_ptr); } size_t size() const { return (size_t) PyList_Size(m_ptr); }
bool empty() const { return size() == 0; } bool empty() const { return size() == 0; }
...@@ -1603,7 +1658,9 @@ class set : public object { ...@@ -1603,7 +1658,9 @@ class set : public object {
public: public:
PYBIND11_OBJECT_CVT(set, object, PySet_Check, PySet_New) PYBIND11_OBJECT_CVT(set, object, PySet_Check, PySet_New)
set() : object(PySet_New(nullptr), stolen_t{}) { set() : object(PySet_New(nullptr), stolen_t{}) {
if (!m_ptr) pybind11_fail("Could not allocate set object!"); if (!m_ptr) {
pybind11_fail("Could not allocate set object!");
}
} }
size_t size() const { return (size_t) PySet_Size(m_ptr); } size_t size() const { return (size_t) PySet_Size(m_ptr); }
bool empty() const { return size() == 0; } bool empty() const { return size() == 0; }
...@@ -1621,8 +1678,9 @@ public: ...@@ -1621,8 +1678,9 @@ public:
PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check) PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check)
handle cpp_function() const { handle cpp_function() const {
handle fun = detail::get_function(m_ptr); handle fun = detail::get_function(m_ptr);
if (fun && PyCFunction_Check(fun.ptr())) if (fun && PyCFunction_Check(fun.ptr())) {
return fun; return fun;
}
return handle(); return handle();
} }
bool is_cpp_function() const { return (bool) cpp_function(); } bool is_cpp_function() const { return (bool) cpp_function(); }
...@@ -1639,7 +1697,9 @@ public: ...@@ -1639,7 +1697,9 @@ public:
buffer_info request(bool writable = false) const { buffer_info request(bool writable = false) const {
int flags = PyBUF_STRIDES | PyBUF_FORMAT; int flags = PyBUF_STRIDES | PyBUF_FORMAT;
if (writable) flags |= PyBUF_WRITABLE; if (writable) {
flags |= PyBUF_WRITABLE;
}
auto *view = new Py_buffer(); auto *view = new Py_buffer();
if (PyObject_GetBuffer(m_ptr, view, flags) != 0) { if (PyObject_GetBuffer(m_ptr, view, flags) != 0) {
delete view; delete view;
...@@ -1663,14 +1723,16 @@ public: ...@@ -1663,14 +1723,16 @@ public:
use ``memoryview(const object& obj)`` instead of this constructor. use ``memoryview(const object& obj)`` instead of this constructor.
\endrst */ \endrst */
explicit memoryview(const buffer_info& info) { explicit memoryview(const buffer_info& info) {
if (!info.view()) if (!info.view()) {
pybind11_fail("Prohibited to create memoryview without Py_buffer"); pybind11_fail("Prohibited to create memoryview without Py_buffer");
}
// Note: PyMemoryView_FromBuffer never increments obj reference. // Note: PyMemoryView_FromBuffer never increments obj reference.
m_ptr = (info.view()->obj) ? m_ptr = (info.view()->obj) ?
PyMemoryView_FromObject(info.view()->obj) : PyMemoryView_FromObject(info.view()->obj) :
PyMemoryView_FromBuffer(info.view()); PyMemoryView_FromBuffer(info.view());
if (!m_ptr) if (!m_ptr) {
pybind11_fail("Unable to create memoryview from buffer descriptor"); pybind11_fail("Unable to create memoryview from buffer descriptor");
}
} }
/** \rst /** \rst
...@@ -1744,8 +1806,9 @@ public: ...@@ -1744,8 +1806,9 @@ public:
PyObject* ptr = PyMemoryView_FromMemory( PyObject* ptr = PyMemoryView_FromMemory(
reinterpret_cast<char*>(mem), size, reinterpret_cast<char*>(mem), size,
(readonly) ? PyBUF_READ : PyBUF_WRITE); (readonly) ? PyBUF_READ : PyBUF_WRITE);
if (!ptr) if (!ptr) {
pybind11_fail("Could not allocate memoryview object!"); pybind11_fail("Could not allocate memoryview object!");
}
return memoryview(object(ptr, stolen_t{})); return memoryview(object(ptr, stolen_t{}));
} }
...@@ -1768,11 +1831,13 @@ inline memoryview memoryview::from_buffer( ...@@ -1768,11 +1831,13 @@ inline memoryview memoryview::from_buffer(
detail::any_container<ssize_t> shape, detail::any_container<ssize_t> shape,
detail::any_container<ssize_t> strides, bool readonly) { detail::any_container<ssize_t> strides, bool readonly) {
size_t ndim = shape->size(); size_t ndim = shape->size();
if (ndim != strides->size()) if (ndim != strides->size()) {
pybind11_fail("memoryview: shape length doesn't match strides length"); pybind11_fail("memoryview: shape length doesn't match strides length");
}
ssize_t size = ndim != 0u ? 1 : 0; ssize_t size = ndim != 0u ? 1 : 0;
for (size_t i = 0; i < ndim; ++i) for (size_t i = 0; i < ndim; ++i) {
size *= (*shape)[i]; size *= (*shape)[i];
}
Py_buffer view; Py_buffer view;
view.buf = ptr; view.buf = ptr;
view.obj = nullptr; view.obj = nullptr;
...@@ -1786,8 +1851,9 @@ inline memoryview memoryview::from_buffer( ...@@ -1786,8 +1851,9 @@ inline memoryview memoryview::from_buffer(
view.suboffsets = nullptr; view.suboffsets = nullptr;
view.internal = nullptr; view.internal = nullptr;
PyObject* obj = PyMemoryView_FromBuffer(&view); PyObject* obj = PyMemoryView_FromBuffer(&view);
if (!obj) if (!obj) {
throw error_already_set(); throw error_already_set();
}
return memoryview(object(obj, stolen_t{})); return memoryview(object(obj, stolen_t{}));
} }
/// @endcond /// @endcond
...@@ -1799,8 +1865,9 @@ inline memoryview memoryview::from_buffer( ...@@ -1799,8 +1865,9 @@ inline memoryview memoryview::from_buffer(
/// Get the length of a Python object. /// Get the length of a Python object.
inline size_t len(handle h) { inline size_t len(handle h) {
ssize_t result = PyObject_Length(h.ptr()); ssize_t result = PyObject_Length(h.ptr());
if (result < 0) if (result < 0) {
throw error_already_set(); throw error_already_set();
}
return (size_t) result; return (size_t) result;
} }
...@@ -1823,7 +1890,9 @@ inline size_t len_hint(handle h) { ...@@ -1823,7 +1890,9 @@ inline size_t len_hint(handle h) {
inline str repr(handle h) { inline str repr(handle h) {
PyObject *str_value = PyObject_Repr(h.ptr()); PyObject *str_value = PyObject_Repr(h.ptr());
if (!str_value) throw error_already_set(); if (!str_value) {
throw error_already_set();
}
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr); PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
Py_XDECREF(str_value); str_value = unicode; Py_XDECREF(str_value); str_value = unicode;
...@@ -1873,8 +1942,9 @@ handle object_api<D>::get_type() const { return type::handle_of(derived()); } ...@@ -1873,8 +1942,9 @@ handle object_api<D>::get_type() const { return type::handle_of(derived()); }
template <typename D> template <typename D>
bool object_api<D>::rich_compare(object_api const &other, int value) const { bool object_api<D>::rich_compare(object_api const &other, int value) const {
int rv = PyObject_RichCompareBool(derived().ptr(), other.derived().ptr(), value); int rv = PyObject_RichCompareBool(derived().ptr(), other.derived().ptr(), value);
if (rv == -1) if (rv == -1) {
throw error_already_set(); throw error_already_set();
}
return rv == 1; return rv == 1;
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment