diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index fa9d21d7c..d6210d3b1 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -216,7 +216,7 @@ public: auto const &type_dict = get_internals().registered_types_py; bool new_style_class = PyType_Check(tobj); if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) { - tuple parents(tobj->tp_bases, true); + auto parents = reinterpret_borrow(tobj->tp_bases); for (handle parent : parents) { bool result = load(src, convert, (PyTypeObject *) parent.ptr()); if (result) @@ -237,7 +237,7 @@ public: /* Perform an implicit conversion */ if (convert) { for (auto &converter : typeinfo->implicit_conversions) { - temp = object(converter(src.ptr(), typeinfo->type), false); + temp = reinterpret_steal(converter(src.ptr(), typeinfo->type)); if (load(temp, false)) return true; } @@ -284,7 +284,7 @@ public: return handle((PyObject *) it_i->second).inc_ref(); } - object inst(PyType_GenericAlloc(tinfo->type, 0), false); + auto inst = reinterpret_steal(PyType_GenericAlloc(tinfo->type, 0)); auto wrapper = (instance *) inst.ptr(); @@ -487,9 +487,9 @@ public: #endif PyErr_Clear(); if (type_error && PyNumber_Check(src.ptr())) { - object tmp(std::is_floating_point::value - ? PyNumber_Float(src.ptr()) - : PyNumber_Long(src.ptr()), true); + auto tmp = reinterpret_borrow(std::is_floating_point::value + ? PyNumber_Float(src.ptr()) + : PyNumber_Long(src.ptr())); PyErr_Clear(); return load(tmp, false); } @@ -544,7 +544,7 @@ public: /* Check if this is a capsule */ if (isinstance(h)) { - value = capsule(h, true); + value = reinterpret_borrow(h); return true; } @@ -596,7 +596,7 @@ public: if (!src) { return false; } else if (PyUnicode_Check(load_src.ptr())) { - temp = object(PyUnicode_AsUTF8String(load_src.ptr()), false); + temp = reinterpret_steal(PyUnicode_AsUTF8String(load_src.ptr())); if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError load_src = temp; } @@ -637,7 +637,7 @@ public: if (!src) { return false; } else if (!PyUnicode_Check(load_src.ptr())) { - temp = object(PyUnicode_FromObject(load_src.ptr()), false); + temp = reinterpret_steal(PyUnicode_FromObject(load_src.ptr())); if (!temp) { PyErr_Clear(); return false; } load_src = temp; } @@ -646,10 +646,10 @@ public: #if PY_MAJOR_VERSION >= 3 buffer = PyUnicode_AsWideCharString(load_src.ptr(), &length); #else - temp = object( + temp = reinterpret_steal( sizeof(wchar_t) == sizeof(short) ? PyUnicode_AsUTF16String(load_src.ptr()) - : PyUnicode_AsUTF32String(load_src.ptr()), false); + : PyUnicode_AsUTF32String(load_src.ptr())); if (temp) { int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), (char **) &buffer, &length); if (err == -1) { buffer = nullptr; } // TypeError @@ -730,8 +730,8 @@ public: } static handle cast(const type &src, return_value_policy policy, handle parent) { - object o1 = object(make_caster::cast(src.first, policy, parent), false); - object o2 = object(make_caster::cast(src.second, policy, parent), false); + auto o1 = reinterpret_steal(make_caster::cast(src.first, policy, parent)); + auto o2 = reinterpret_steal(make_caster::cast(src.second, policy, parent)); if (!o1 || !o2) return handle(); tuple result(2); @@ -846,7 +846,7 @@ protected: /* Implementation: Convert a C++ tuple into a Python tuple */ template static handle cast(const type &src, return_value_policy policy, handle parent, index_sequence) { std::array entries {{ - object(make_caster::cast(std::get(src), policy, parent), false)... + reinterpret_steal(make_caster::cast(std::get(src), policy, parent))... }}; for (const auto &entry: entries) if (!entry) @@ -905,7 +905,7 @@ public: auto const &type_dict = get_internals().registered_types_py; bool new_style_class = PyType_Check(tobj); if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) { - tuple parents(tobj->tp_bases, true); + auto parents = reinterpret_borrow(tobj->tp_bases); for (handle parent : parents) { bool result = load(src, convert, (PyTypeObject *) parent.ptr()); if (result) @@ -919,7 +919,7 @@ public: if (convert) { for (auto &converter : typeinfo->implicit_conversions) { - temp = object(converter(src.ptr(), typeinfo->type), false); + temp = reinterpret_steal(converter(src.ptr(), typeinfo->type)); if (load(temp, false)) return true; } @@ -1000,7 +1000,7 @@ struct pyobject_caster { bool load(handle src, bool /* convert */) { if (!isinstance(src)) return false; - value = type(src, true); + value = reinterpret_borrow(src); return true; } @@ -1070,6 +1070,7 @@ template make_caster load_type(const handle &handle) { NAMESPACE_END(detail) +// pytype -> C++ type template ::value, int> = 0> T cast(const handle &handle) { static_assert(!detail::cast_is_temporary_value_reference::value, @@ -1078,9 +1079,11 @@ T cast(const handle &handle) { return detail::load_type(handle).operator typename type_caster::template cast_op_type(); } +// pytype -> pytype (calls converting constructor) template ::value, int> = 0> -T cast(const handle &handle) { return {handle, true}; } +T cast(const handle &handle) { return T(reinterpret_borrow(handle)); } +// C++ type -> py::object template ::value, int> = 0> object cast(const T &value, return_value_policy policy = return_value_policy::automatic_reference, handle parent = handle()) { @@ -1088,7 +1091,7 @@ object cast(const T &value, return_value_policy policy = return_value_policy::au policy = std::is_pointer::value ? return_value_policy::take_ownership : return_value_policy::copy; else if (policy == return_value_policy::automatic_reference) policy = std::is_pointer::value ? return_value_policy::reference : return_value_policy::copy; - return object(detail::make_caster::cast(value, policy, parent), false); + return reinterpret_steal(detail::make_caster::cast(value, policy, parent)); } template T handle::cast() const { return pybind11::cast(*this); } @@ -1162,8 +1165,8 @@ template tuple make_tuple(Args&&... args_) { const size_t size = sizeof...(Args); std::array args { - { object(detail::make_caster::cast( - std::forward(args_), policy, nullptr), false)... } + { reinterpret_steal(detail::make_caster::cast( + std::forward(args_), policy, nullptr))... } }; for (auto &arg_value : args) { if (!arg_value) { @@ -1195,7 +1198,9 @@ struct arg_v : arg { template arg_v(const char *name, T &&x, const char *descr = nullptr) : arg(name), - value(detail::make_caster::cast(x, return_value_policy::automatic, handle()), false), + value(reinterpret_steal( + detail::make_caster::cast(x, return_value_policy::automatic, {}) + )), descr(descr) #if !defined(NDEBUG) , type(type_id()) @@ -1256,10 +1261,10 @@ public: /// Call a Python function and pass the collected arguments object call(PyObject *ptr) const { - auto result = object(PyObject_CallObject(ptr, m_args.ptr()), false); + PyObject *result = PyObject_CallObject(ptr, m_args.ptr()); if (!result) throw error_already_set(); - return result; + return reinterpret_steal(result); } private: @@ -1289,16 +1294,16 @@ public: /// Call a Python function and pass the collected arguments object call(PyObject *ptr) const { - auto result = object(PyObject_Call(ptr, m_args.ptr(), m_kwargs.ptr()), false); + PyObject *result = PyObject_Call(ptr, m_args.ptr(), m_kwargs.ptr()); if (!result) throw error_already_set(); - return result; + return reinterpret_steal(result); } private: template void process(list &args_list, T &&x) { - auto o = object(detail::make_caster::cast(std::forward(x), policy, nullptr), false); + auto o = reinterpret_steal(detail::make_caster::cast(std::forward(x), policy, {})); if (!o) { #if defined(NDEBUG) argument_cast_error(); @@ -1335,7 +1340,7 @@ private: void process(list &/*args_list*/, detail::kwargs_proxy kp) { if (!kp) return; - for (const auto &k : dict(kp, true)) { + for (const auto &k : reinterpret_borrow(kp)) { if (m_kwargs.contains(k.first)) { #if defined(NDEBUG) multiple_values_error(); diff --git a/include/pybind11/eigen.h b/include/pybind11/eigen.h index 3da857b71..729d0f655 100644 --- a/include/pybind11/eigen.h +++ b/include/pybind11/eigen.h @@ -182,7 +182,7 @@ struct type_caster::value>> { if (!src) return false; - object obj(src, true); + auto obj = reinterpret_borrow(src); object sparse_module = module::import("scipy.sparse"); object matrix_type = sparse_module.attr( rowMajor ? "csr_matrix" : "csc_matrix"); diff --git a/include/pybind11/eval.h b/include/pybind11/eval.h index b7e7e95c9..204427d77 100644 --- a/include/pybind11/eval.h +++ b/include/pybind11/eval.h @@ -31,7 +31,7 @@ enum eval_mode { template object eval(str expr, object global = object(), object local = object()) { if (!global) { - global = object(PyEval_GetGlobals(), true); + global = reinterpret_borrow(PyEval_GetGlobals()); if (!global) global = dict(); } @@ -50,17 +50,16 @@ object eval(str expr, object global = object(), object local = object()) { default: pybind11_fail("invalid evaluation mode"); } - object result(PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr()), false); - + PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr()); if (!result) throw error_already_set(); - return result; + return reinterpret_steal(result); } template object eval_file(str fname, object global = object(), object local = object()) { if (!global) { - global = object(PyEval_GetGlobals(), true); + global = reinterpret_borrow(PyEval_GetGlobals()); if (!global) global = dict(); } @@ -83,9 +82,9 @@ object eval_file(str fname, object global = object(), object local = object()) { FILE *f = _Py_fopen(fname.ptr(), "r"); #else /* No unicode support in open() :( */ - object fobj(PyFile_FromString( + auto fobj = reinterpret_steal(PyFile_FromString( const_cast(fname_str.c_str()), - const_cast("r")), false); + const_cast("r"))); FILE *f = nullptr; if (fobj) f = PyFile_AsFile(fobj.ptr()); @@ -96,14 +95,11 @@ object eval_file(str fname, object global = object(), object local = object()) { pybind11_fail("File \"" + fname_str + "\" could not be opened!"); } - object result(PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), - local.ptr(), closeFile), - false); - + PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), + local.ptr(), closeFile); if (!result) throw error_already_set(); - - return result; + return reinterpret_steal(result); } NAMESPACE_END(pybind11) diff --git a/include/pybind11/functional.h b/include/pybind11/functional.h index 013b27592..dbeea5dc7 100644 --- a/include/pybind11/functional.h +++ b/include/pybind11/functional.h @@ -36,7 +36,7 @@ public: captured variables), in which case the roundtrip can be avoided. */ if (PyCFunction_Check(src_.ptr())) { - capsule c(PyCFunction_GetSelf(src_.ptr()), true); + auto c = reinterpret_borrow(PyCFunction_GetSelf(src_.ptr())); auto rec = (function_record *) c; using FunctionType = Return (*) (Args...); @@ -47,7 +47,7 @@ public: } } - object src(src_, true); + auto src = reinterpret_borrow(src_); value = [src](Args... args) -> Return { gil_scoped_acquire acq; object retval(src(std::move(args)...)); diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 9fe438502..3cbea0191 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -239,7 +239,7 @@ public: PyObject *ptr = nullptr; if (!detail::npy_api::get().PyArray_DescrConverter_(args.release().ptr(), &ptr) || !ptr) throw error_already_set(); - return object(ptr, false); + return reinterpret_steal(ptr); } /// Return dtype associated with a C++ type. @@ -266,7 +266,7 @@ private: static object _dtype_from_pep3118() { static PyObject *obj = module::import("numpy.core._internal") .attr("_dtype_from_pep3118").cast().release().ptr(); - return object(obj, true); + return reinterpret_borrow(obj); } dtype strip_padding() { @@ -279,7 +279,7 @@ private: std::vector field_descriptors; for (auto field : attr("fields").attr("items")()) { - auto spec = object(field, true).cast(); + auto spec = field.cast(); auto name = spec[0].cast(); auto format = spec[1].cast()[0].cast(); auto offset = spec[1].cast()[1].cast(); @@ -326,22 +326,22 @@ public: if (base && ptr) { if (isinstance(base)) /* Copy flags from base (except baseship bit) */ - flags = array(base, true).flags() & ~detail::npy_api::NPY_ARRAY_OWNDATA_; + flags = reinterpret_borrow(base).flags() & ~detail::npy_api::NPY_ARRAY_OWNDATA_; else /* Writable by default, easy to downgrade later on if needed */ flags = detail::npy_api::NPY_ARRAY_WRITEABLE_; } - object tmp(api.PyArray_NewFromDescr_( + auto tmp = reinterpret_steal(api.PyArray_NewFromDescr_( api.PyArray_Type_, descr.release().ptr(), (int) ndim, (Py_intptr_t *) shape.data(), - (Py_intptr_t *) strides.data(), const_cast(ptr), flags, nullptr), false); + (Py_intptr_t *) strides.data(), const_cast(ptr), flags, nullptr)); if (!tmp) pybind11_fail("NumPy: unable to create array!"); if (ptr) { if (base) { PyArray_GET_(tmp.ptr(), base) = base.inc_ref().ptr(); } else { - tmp = object(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */), false); + tmp = reinterpret_steal(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */)); } } m_ptr = tmp.release().ptr(); @@ -374,7 +374,7 @@ public: /// Array descriptor (dtype) pybind11::dtype dtype() const { - return object(PyArray_GET_(m_ptr, descr), true); + return reinterpret_borrow(PyArray_GET_(m_ptr, descr)); } /// Total number of elements @@ -399,7 +399,7 @@ public: /// Base object object base() const { - return object(PyArray_GET_(m_ptr, base), true); + return reinterpret_borrow(PyArray_GET_(m_ptr, base)); } /// Dimensions of the array @@ -474,14 +474,14 @@ public: /// Return a new view with all of the dimensions of length 1 removed array squeeze() { auto& api = detail::npy_api::get(); - return array(api.PyArray_Squeeze_(m_ptr), false); + return reinterpret_steal(api.PyArray_Squeeze_(m_ptr)); } /// Ensure that the argument is a NumPy array static array ensure(object input, int ExtraFlags = 0) { auto& api = detail::npy_api::get(); - return array(api.PyArray_FromAny_( - input.release().ptr(), nullptr, 0, 0, detail::npy_api::NPY_ENSURE_ARRAY_ | ExtraFlags, nullptr), false); + return reinterpret_steal(api.PyArray_FromAny_( + input.release().ptr(), nullptr, 0, 0, detail::npy_api::NPY_ENSURE_ARRAY_ | ExtraFlags, nullptr)); } protected: @@ -542,7 +542,7 @@ template class array_t : public public: array_t() : array() { } - array_t(handle h, bool borrowed) : array(h, borrowed) { m_ptr = ensure_(m_ptr); } + array_t(handle h, bool is_borrowed) : array(h, is_borrowed) { m_ptr = ensure_(m_ptr); } array_t(const object &o) : array(o) { m_ptr = ensure_(m_ptr); } @@ -668,7 +668,7 @@ public: enum { value = values[detail::log2(sizeof(T)) * 2 + (std::is_unsigned::value ? 1 : 0)] }; static pybind11::dtype dtype() { if (auto ptr = npy_api::get().PyArray_DescrFromType_(value)) - return object(ptr, true); + return reinterpret_borrow(ptr); pybind11_fail("Unsupported buffer format!"); } template ::value, int> = 0> @@ -683,7 +683,7 @@ template constexpr const int npy_format_descriptor< enum { value = npy_api::NumPyName }; \ static pybind11::dtype dtype() { \ if (auto ptr = npy_api::get().PyArray_DescrFromType_(value)) \ - return object(ptr, true); \ + return reinterpret_borrow(ptr); \ pybind11_fail("Unsupported buffer format!"); \ } \ static PYBIND11_DESCR name() { return _(Name); } } @@ -778,7 +778,7 @@ struct npy_format_descriptor::value>> { static PYBIND11_DESCR name() { return _("struct"); } static pybind11::dtype dtype() { - return object(dtype_ptr(), true); + return reinterpret_borrow(dtype_ptr()); } static std::string format() { @@ -801,7 +801,7 @@ private: auto& api = npy_api::get(); if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_)) return false; - if (auto descr = object(api.PyArray_DescrFromScalar_(obj), false)) { + if (auto descr = reinterpret_steal(api.PyArray_DescrFromScalar_(obj))) { if (api.PyArray_EquivTypes_(dtype_ptr(), descr.ptr())) { value = ((PyVoidScalarObject_Proxy *) obj)->obval; return true; diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index ca116eb4c..6804fa91a 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -256,7 +256,7 @@ protected: detail::function_record *chain = nullptr, *chain_start = rec; if (rec->sibling) { if (PyCFunction_Check(rec->sibling.ptr())) { - capsule rec_capsule(PyCFunction_GetSelf(rec->sibling.ptr()), true); + auto rec_capsule = reinterpret_borrow(PyCFunction_GetSelf(rec->sibling.ptr())); chain = (detail::function_record *) rec_capsule; /* Never append a method to an overload chain of a parent class; instead, hide the parent's overloads in this case */ @@ -382,7 +382,7 @@ protected: result = PYBIND11_TRY_NEXT_OVERLOAD; try { for (; it != nullptr; it = it->next) { - tuple args_(args, true); + auto args_ = reinterpret_borrow(args); size_t kwargs_consumed = 0; /* For each overload: @@ -502,7 +502,7 @@ protected: msg += "\n"; } msg += "\nInvoked with: "; - tuple args_(args, true); + auto args_ = reinterpret_borrow(args); for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) { msg += static_cast(pybind11::str(args_[ti])); if ((ti + 1) != args_.size() ) @@ -565,7 +565,7 @@ public: module def_submodule(const char *name, const char *doc = nullptr) { std::string full_name = std::string(PyModule_GetName(m_ptr)) + std::string(".") + std::string(name); - module result(PyImport_AddModule(full_name.c_str()), true); + auto result = reinterpret_borrow(PyImport_AddModule(full_name.c_str())); if (doc && options::show_user_defined_docstrings()) result.attr("__doc__") = pybind11::str(doc); attr(name) = result; @@ -576,7 +576,7 @@ public: PyObject *obj = PyImport_ImportModule(name); if (!obj) throw import_error("Module \"" + std::string(name) + "\" not found!"); - return module(obj, false); + return reinterpret_steal(obj); } // Adds an object to the module using the given name. Throws if an object with the given name @@ -636,7 +636,7 @@ protected: pybind11_fail("generic_type: type \"" + std::string(rec->name) + "\" is already registered!"); - object name(PYBIND11_FROM_STRING(rec->name), false); + auto name = reinterpret_steal(PYBIND11_FROM_STRING(rec->name)); object scope_module; if (rec->scope) { if (hasattr(rec->scope, rec->name)) @@ -657,8 +657,8 @@ protected: scope_qualname = rec->scope.attr("__qualname__"); object ht_qualname; if (scope_qualname) { - ht_qualname = object(PyUnicode_FromFormat( - "%U.%U", scope_qualname.ptr(), name.ptr()), false); + ht_qualname = reinterpret_steal(PyUnicode_FromFormat( + "%U.%U", scope_qualname.ptr(), name.ptr())); } else { ht_qualname = name; } @@ -684,7 +684,7 @@ protected: garbage collector (the GC will call type_traverse(), which will in turn find the newly constructed type in an invalid state) */ - object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false); + auto type_holder = reinterpret_steal(PyType_Type.tp_alloc(&PyType_Type, 0)); auto type = (PyHeapTypeObject*) type_holder.ptr(); if (!type_holder || !name) @@ -768,7 +768,7 @@ protected: /// Helper function which tags all parents of a type using mult. inheritance void mark_parents_nonsimple(PyTypeObject *value) { - tuple t(value->tp_bases, true); + auto t = reinterpret_borrow(value->tp_bases); for (handle h : t) { auto tinfo2 = get_type_info((PyTypeObject *) h.ptr()); if (tinfo2) @@ -785,10 +785,10 @@ protected: if (ob_type == &PyType_Type) { std::string name_ = std::string(ht_type.tp_name) + "__Meta"; #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 - object ht_qualname(PyUnicode_FromFormat("%U__Meta", attr("__qualname__").ptr()), false); + auto ht_qualname = reinterpret_steal(PyUnicode_FromFormat("%U__Meta", attr("__qualname__").ptr())); #endif - object name(PYBIND11_FROM_STRING(name_.c_str()), false); - object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false); + auto name = reinterpret_steal(PYBIND11_FROM_STRING(name_.c_str())); + auto type_holder = reinterpret_steal(PyType_Type.tp_alloc(&PyType_Type, 0)); if (!type_holder || !name) pybind11_fail("generic_type::metaclass(): unable to create type object!"); @@ -936,7 +936,7 @@ public: static_assert(detail::all_of_t::value, "Unknown/invalid class_ template parameters provided"); - PYBIND11_OBJECT(class_, detail::generic_type, PyType_Check) + PYBIND11_OBJECT(class_, generic_type, PyType_Check) template class_(handle scope, const char *name, const Extra &... extra) { @@ -1117,9 +1117,9 @@ public: } } pybind11::str doc_obj = pybind11::str((rec_fget->doc && pybind11::options::show_user_defined_docstrings()) ? rec_fget->doc : ""); - object property( + const auto property = reinterpret_steal( PyObject_CallFunctionObjArgs((PyObject *) &PyProperty_Type, fget.ptr() ? fget.ptr() : Py_None, - fset.ptr() ? fset.ptr() : Py_None, Py_None, doc_obj.ptr(), nullptr), false); + fset.ptr() ? fset.ptr() : Py_None, Py_None, doc_obj.ptr(), nullptr)); if (rec_fget->class_) attr(name) = property; else @@ -1178,8 +1178,8 @@ private: static detail::function_record *get_function_record(handle h) { h = detail::get_function(h); - return h ? (detail::function_record *) capsule( - PyCFunction_GetSelf(h.ptr()), true) : nullptr; + return h ? (detail::function_record *) reinterpret_borrow(PyCFunction_GetSelf(h.ptr())) + : nullptr; } }; diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 9257643e8..d078d58e0 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -102,9 +102,9 @@ protected: class object : public handle { public: object() = default; + PYBIND11_DEPRECATED("Use reinterpret_borrow() or reinterpret_steal()") + object(handle h, bool is_borrowed) : handle(h) { if (is_borrowed) inc_ref(); } object(const object &o) : handle(o) { inc_ref(); } - object(const handle &h, bool borrowed) : handle(h) { if (borrowed) inc_ref(); } - object(PyObject *ptr, bool borrowed) : handle(ptr) { if (borrowed) inc_ref(); } object(object &&other) noexcept { m_ptr = other.m_ptr; other.m_ptr = nullptr; } ~object() { dec_ref(); } @@ -135,8 +135,26 @@ public: template T cast() const &; // Calling on an object rvalue does a move, if needed and/or possible template T cast() &&; + +protected: + // Tags for choosing constructors from raw PyObject * + struct borrowed_t { }; static constexpr borrowed_t borrowed{}; + struct stolen_t { }; static constexpr stolen_t stolen{}; + + template friend T reinterpret_borrow(handle); + template friend T reinterpret_steal(handle); + +public: + // Only accessible from derived classes and the reinterpret_* functions + object(handle h, borrowed_t) : handle(h) { inc_ref(); } + object(handle h, stolen_t) : handle(h) { } }; +/** The following functions don't do any kind of conversion, they simply declare + that a PyObject is a certain type and borrow or steal the reference. */ +template T reinterpret_borrow(handle h) { return {h, object::borrowed}; } +template T reinterpret_steal(handle h) { return {h, object::stolen}; } + /// Check if `obj` is an instance of type `T` template ::value, int> = 0> bool isinstance(handle obj) { return T::_check(obj); } @@ -158,30 +176,30 @@ inline bool hasattr(handle obj, const char *name) { inline object getattr(handle obj, handle name) { PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr()); if (!result) { throw error_already_set(); } - return {result, false}; + return reinterpret_steal(result); } inline object getattr(handle obj, const char *name) { PyObject *result = PyObject_GetAttrString(obj.ptr(), name); if (!result) { throw error_already_set(); } - return {result, false}; + return reinterpret_steal(result); } inline object getattr(handle obj, handle name, handle default_) { if (PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr())) { - return {result, false}; + return reinterpret_steal(result); } else { PyErr_Clear(); - return {default_, true}; + return reinterpret_borrow(default_); } } inline object getattr(handle obj, const char *name, handle default_) { if (PyObject *result = PyObject_GetAttrString(obj.ptr(), name)) { - return {result, false}; + return reinterpret_steal(result); } else { PyErr_Clear(); - return {default_, true}; + return reinterpret_borrow(default_); } } @@ -218,7 +236,7 @@ public: void operator=(const object &o) && { std::move(*this).operator=(handle(o)); } void operator=(const object &o) & { operator=(handle(o)); } void operator=(handle value) && { Policy::set(obj, key, value); } - void operator=(handle value) & { get_cache() = object(value, true); } + void operator=(handle value) & { get_cache() = reinterpret_borrow(value); } template PYBIND11_DEPRECATED("Use of obj.attr(...) as bool is deprecated in favor of pybind11::hasattr(obj, ...)") @@ -267,7 +285,7 @@ struct generic_item { static object get(handle obj, handle key) { PyObject *result = PyObject_GetItem(obj.ptr(), key.ptr()); if (!result) { throw error_already_set(); } - return {result, false}; + return reinterpret_steal(result); } static void set(handle obj, handle key, handle val) { @@ -281,7 +299,7 @@ struct sequence_item { static object get(handle obj, size_t index) { PyObject *result = PySequence_GetItem(obj.ptr(), static_cast(index)); if (!result) { throw error_already_set(); } - return {result, true}; + return reinterpret_borrow(result); } static void set(handle obj, size_t index, handle val) { @@ -298,7 +316,7 @@ struct list_item { static object get(handle obj, size_t index) { PyObject *result = PyList_GetItem(obj.ptr(), static_cast(index)); if (!result) { throw error_already_set(); } - return {result, true}; + return reinterpret_borrow(result); } static void set(handle obj, size_t index, handle val) { @@ -315,7 +333,7 @@ struct tuple_item { static object get(handle obj, size_t index) { PyObject *result = PyTuple_GetItem(obj.ptr(), static_cast(index)); if (!result) { throw error_already_set(); } - return {result, true}; + return reinterpret_borrow(result); } static void set(handle obj, size_t index, handle val) { @@ -390,23 +408,30 @@ class unpacking_collector; NAMESPACE_END(detail) +// TODO: After the deprecated constructors are removed, this macro can be simplified by +// inheriting ctors: `using Parent::Parent`. It's not an option right now because +// the `using` statement triggers the parent deprecation warning even if the ctor +// isn't even used. #define PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ public: \ + PYBIND11_DEPRECATED("Use reinterpret_borrow<"#Name">() or reinterpret_steal<"#Name">()") \ + Name(handle h, bool is_borrowed) : Parent(is_borrowed ? Parent(h, borrowed) : Parent(h, stolen)) { } \ + Name(handle h, borrowed_t) : Parent(h, borrowed) { } \ + Name(handle h, stolen_t) : Parent(h, stolen) { } \ PYBIND11_DEPRECATED("Use py::isinstance(obj) instead") \ bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } \ static bool _check(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } #define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \ PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ - Name(handle h, bool borrowed) : Name(object(h, borrowed)) { } \ /* This is deliberately not 'explicit' to allow implicit conversion from object: */ \ - Name(const object &o) : Parent(ConvertFun(o.ptr()), false) { if (!m_ptr) throw error_already_set(); } + Name(const object &o) : Parent(ConvertFun(o.ptr()), stolen) { if (!m_ptr) throw error_already_set(); } #define PYBIND11_OBJECT(Name, Parent, CheckFun) \ PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ - Name(handle h, bool borrowed) : Parent(h, borrowed) { } \ /* This is deliberately not 'explicit' to allow implicit conversion from object: */ \ - Name(const object &o) : Parent(o) { } + Name(const object &o) : Parent(o) { } \ + Name(object &&o) : Parent(std::move(o)) { } #define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun) \ PYBIND11_OBJECT(Name, Parent, CheckFun) \ @@ -448,7 +473,7 @@ public: } private: - void advance() { value = object(PyIter_Next(m_ptr), false); } + void advance() { value = reinterpret_steal(PyIter_Next(m_ptr)); } private: object value = {}; @@ -467,13 +492,13 @@ public: PYBIND11_OBJECT_CVT(str, object, detail::PyUnicode_Check_Permissive, raw_str) str(const char *c, size_t n) - : object(PyUnicode_FromStringAndSize(c, (ssize_t) n), false) { + : object(PyUnicode_FromStringAndSize(c, (ssize_t) n), stolen) { 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 str(const char *c = "") - : object(PyUnicode_FromString(c), false) { + : object(PyUnicode_FromString(c), stolen) { if (!m_ptr) pybind11_fail("Could not allocate string object!"); } @@ -481,12 +506,12 @@ public: explicit str(const bytes &b); - explicit str(handle h) : object(raw_str(h.ptr()), false) { } + explicit str(handle h) : object(raw_str(h.ptr()), stolen) { } operator std::string() const { object temp = *this; if (PyUnicode_Check(m_ptr)) { - temp = object(PyUnicode_AsUTF8String(m_ptr), false); + temp = reinterpret_steal(PyUnicode_AsUTF8String(m_ptr)); if (!temp) pybind11_fail("Unable to extract string contents! (encoding issue)"); } @@ -526,12 +551,12 @@ public: // Allow implicit conversion: bytes(const char *c = "") - : object(PYBIND11_BYTES_FROM_STRING(c), false) { + : object(PYBIND11_BYTES_FROM_STRING(c), stolen) { if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); } bytes(const char *c, size_t n) - : object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(c, (ssize_t) n), false) { + : object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(c, (ssize_t) n), stolen) { if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); } @@ -552,7 +577,7 @@ public: inline bytes::bytes(const pybind11::str &s) { object temp = s; if (PyUnicode_Check(s.ptr())) { - temp = object(PyUnicode_AsUTF8String(s.ptr()), false); + temp = reinterpret_steal(PyUnicode_AsUTF8String(s.ptr())); if (!temp) pybind11_fail("Unable to extract string contents! (encoding issue)"); } @@ -560,7 +585,7 @@ inline bytes::bytes(const pybind11::str &s) { ssize_t length; if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) pybind11_fail("Unable to extract string contents! (invalid type)"); - auto obj = object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length), false); + auto obj = reinterpret_steal(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length)); if (!obj) pybind11_fail("Could not allocate bytes object!"); m_ptr = obj.release().ptr(); @@ -571,7 +596,7 @@ inline str::str(const bytes& b) { ssize_t length; if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) pybind11_fail("Unable to extract bytes contents!"); - auto obj = object(PyUnicode_FromStringAndSize(buffer, (ssize_t) length), false); + auto obj = reinterpret_steal(PyUnicode_FromStringAndSize(buffer, (ssize_t) length)); if (!obj) pybind11_fail("Could not allocate string object!"); m_ptr = obj.release().ptr(); @@ -580,15 +605,15 @@ inline str::str(const bytes& b) { class none : public object { public: PYBIND11_OBJECT(none, object, detail::PyNone_Check) - none() : object(Py_None, true) { } + none() : object(Py_None, borrowed) { } }; class bool_ : public object { public: PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool) - bool_() : object(Py_False, true) { } + bool_() : object(Py_False, borrowed) { } // Allow implicit conversion from and to `bool`: - bool_(bool value) : object(value ? Py_True : Py_False, true) { } + bool_(bool value) : object(value ? Py_True : Py_False, borrowed) { } operator bool() const { return m_ptr && PyLong_AsLong(m_ptr) != 0; } private: @@ -603,7 +628,7 @@ private: class int_ : public object { public: PYBIND11_OBJECT_CVT(int_, object, PYBIND11_LONG_CHECK, PyNumber_Long) - int_() : object(PyLong_FromLong(0), false) { } + int_() : object(PyLong_FromLong(0), stolen) { } // Allow implicit conversion from C++ integral types: template ::value, int> = 0> @@ -643,10 +668,10 @@ class float_ : public object { public: PYBIND11_OBJECT_CVT(float_, object, PyFloat_Check, PyNumber_Float) // Allow implicit conversion from float/double: - float_(float value) : object(PyFloat_FromDouble((double) value), false) { + float_(float value) : object(PyFloat_FromDouble((double) value), stolen) { if (!m_ptr) pybind11_fail("Could not allocate float object!"); } - float_(double value = .0) : object(PyFloat_FromDouble((double) value), false) { + float_(double value = .0) : object(PyFloat_FromDouble((double) value), stolen) { if (!m_ptr) pybind11_fail("Could not allocate float object!"); } operator float() const { return (float) PyFloat_AsDouble(m_ptr); } @@ -656,7 +681,8 @@ public: class weakref : public object { public: PYBIND11_OBJECT_DEFAULT(weakref, object, PyWeakref_Check) - explicit weakref(handle obj, handle callback = handle()) : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), false) { + explicit weakref(handle obj, handle callback = {}) + : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen) { if (!m_ptr) pybind11_fail("Could not allocate weak reference!"); } }; @@ -681,9 +707,10 @@ public: class capsule : public object { public: PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact) - capsule(PyObject *obj, bool borrowed) : object(obj, borrowed) { } + PYBIND11_DEPRECATED("Use reinterpret_borrow() or reinterpret_steal()") + capsule(PyObject *ptr, bool is_borrowed) : object(is_borrowed ? object(ptr, borrowed) : object(ptr, stolen)) { } explicit capsule(const void *value, void (*destruct)(PyObject *) = nullptr) - : object(PyCapsule_New(const_cast(value), nullptr, destruct), false) { + : object(PyCapsule_New(const_cast(value), nullptr, destruct), stolen) { if (!m_ptr) pybind11_fail("Could not allocate capsule object!"); } template operator T *() const { @@ -696,7 +723,7 @@ public: class tuple : public object { public: PYBIND11_OBJECT_CVT(tuple, object, PyTuple_Check, PySequence_Tuple) - explicit tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), false) { + explicit tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), stolen) { if (!m_ptr) pybind11_fail("Could not allocate tuple object!"); } size_t size() const { return (size_t) PyTuple_Size(m_ptr); } @@ -706,7 +733,7 @@ public: class dict : public object { public: PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict) - dict() : object(PyDict_New(), false) { + dict() : object(PyDict_New(), stolen) { if (!m_ptr) pybind11_fail("Could not allocate dict object!"); } template (str_value); } NAMESPACE_BEGIN(detail) -template iterator object_api::begin() const { return {PyObject_GetIter(derived().ptr()), false}; } -template iterator object_api::end() const { return {nullptr, false}; } -template item_accessor object_api::operator[](handle key) const { return {derived(), object(key, true)}; } -template item_accessor object_api::operator[](const char *key) const { return {derived(), pybind11::str(key)}; } -template obj_attr_accessor object_api::attr(handle key) const { return {derived(), object(key, true)}; } -template str_attr_accessor object_api::attr(const char *key) const { return {derived(), key}; } -template args_proxy object_api::operator*() const { return args_proxy(derived().ptr()); } +template iterator object_api::begin() const { + return reinterpret_steal(PyObject_GetIter(derived().ptr())); +} +template iterator object_api::end() const { + return {}; +} +template item_accessor object_api::operator[](handle key) const { + return {derived(), reinterpret_borrow(key)}; +} +template item_accessor object_api::operator[](const char *key) const { + return {derived(), pybind11::str(key)}; +} +template obj_attr_accessor object_api::attr(handle key) const { + return {derived(), reinterpret_borrow(key)}; +} +template str_attr_accessor object_api::attr(const char *key) const { + return {derived(), key}; +} +template args_proxy object_api::operator*() const { + return args_proxy(derived().ptr()); +} template template bool object_api::contains(T &&key) const { return attr("__contains__")(std::forward(key)).template cast(); } diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index fc058ef25..c1ed0f979 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -47,7 +47,7 @@ template struct set_caster { bool load(handle src, bool convert) { if (!isinstance(src)) return false; - pybind11::set s(src, true); + auto s = reinterpret_borrow(src); value.clear(); key_conv conv; for (auto entry : s) { @@ -61,7 +61,7 @@ template struct set_caster { static handle cast(const type &src, return_value_policy policy, handle parent) { pybind11::set s; for (auto const &value: src) { - object value_ = object(key_conv::cast(value, policy, parent), false); + auto value_ = reinterpret_steal(key_conv::cast(value, policy, parent)); if (!value_ || !s.add(value_)) return handle(); } @@ -79,7 +79,7 @@ template struct map_caster { bool load(handle src, bool convert) { if (!isinstance(src)) return false; - dict d(src, true); + auto d = reinterpret_borrow(src); key_conv kconv; value_conv vconv; value.clear(); @@ -95,8 +95,8 @@ template struct map_caster { static handle cast(const type &src, return_value_policy policy, handle parent) { dict d; for (auto const &kv: src) { - object key = object(key_conv::cast(kv.first, policy, parent), false); - object value = object(value_conv::cast(kv.second, policy, parent), false); + auto key = reinterpret_steal(key_conv::cast(kv.first, policy, parent)); + auto value = reinterpret_steal(value_conv::cast(kv.second, policy, parent)); if (!key || !value) return handle(); d[key] = value; @@ -114,7 +114,7 @@ template struct list_caster { bool load(handle src, bool convert) { if (!isinstance(src)) return false; - sequence s(src, true); + auto s = reinterpret_borrow(src); value_conv conv; value.clear(); reserve_maybe(s, &value); @@ -135,7 +135,7 @@ template struct list_caster { list l(src.size()); size_t index = 0; for (auto const &value: src) { - object value_ = object(value_conv::cast(value, policy, parent), false); + auto value_ = reinterpret_steal(value_conv::cast(value, policy, parent)); if (!value_) return handle(); PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference @@ -159,7 +159,7 @@ template struct type_caster> bool load(handle src, bool convert) { if (!isinstance(src)) return false; - list l(src, true); + auto l = reinterpret_borrow(src); if (l.size() != Size) return false; value_conv conv; @@ -176,7 +176,7 @@ template struct type_caster> list l(Size); size_t index = 0; for (auto const &value: src) { - object value_ = object(value_conv::cast(value, policy, parent), false); + auto value_ = reinterpret_steal(value_conv::cast(value, policy, parent)); if (!value_) return handle(); PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference