Skip to content

Commit a78a398

Browse files
committed
Use real types for these instead of object
They can be null if you "steal" a null handle.
1 parent 8ad086d commit a78a398

File tree

1 file changed

+23
-23
lines changed

1 file changed

+23
-23
lines changed

include/pybind11/cast.h

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,7 +2204,10 @@ template <return_value_policy policy>
22042204
class unpacking_collector {
22052205
public:
22062206
template <typename... Ts>
2207-
explicit unpacking_collector(Ts &&...values) {
2207+
explicit unpacking_collector(Ts &&...values)
2208+
: m_names(reinterpret_steal<tuple>(
2209+
handle())) // initialize to null to avoid useless allocation of 0-length tuple
2210+
{
22082211
/*
22092212
Python can sometimes utilize an extra space before the arguments to prepend `self`.
22102213
This is important enough that there is a special flag for it:
@@ -2216,7 +2219,7 @@ class unpacking_collector {
22162219
m_args.emplace_back();
22172220

22182221
if (args_has_keyword_or_ds<Ts...>()) {
2219-
object names_list = list();
2222+
list names_list;
22202223

22212224
// collect_arguments guarantees this can't be constructed with kwargs before the last
22222225
// positional so we don't need to worry about Ts... being in anything but normal python
@@ -2226,7 +2229,8 @@ class unpacking_collector {
22262229

22272230
m_names = reinterpret_steal<tuple>(PyList_AsTuple(names_list.ptr()));
22282231
} else {
2229-
object not_used;
2232+
auto not_used
2233+
= reinterpret_steal<list>(handle()); // initialize as null (to avoid an allocation)
22302234

22312235
using expander = int[];
22322236
(void) expander{0, (process(not_used, std::forward<Ts>(values)), 0)...};
@@ -2237,10 +2241,10 @@ class unpacking_collector {
22372241
object call(PyObject *ptr) const {
22382242
size_t nargs = m_args.size() - 1; // -1 for PY_VECTORCALL_ARGUMENTS_OFFSET (see ctor)
22392243
if (m_names) {
2240-
nargs -= static_cast<size_t>(PyTuple_GET_SIZE(m_names.ptr()));
2244+
nargs -= m_names.size();
22412245
}
22422246
static_assert(sizeof(object) == sizeof(PyObject *),
2243-
"this cast requires objects to be wrapped pointers");
2247+
"this cast requires object to be interpreted as PyObject*");
22442248
PyObject *result
22452249
= _PyObject_Vectorcall(ptr,
22462250
reinterpret_cast<PyObject *const *>(m_args.data() + 1),
@@ -2255,7 +2259,7 @@ class unpacking_collector {
22552259
tuple args() const {
22562260
size_t nargs = m_args.size() - 1; // -1 for PY_VECTORCALL_ARGUMENTS_OFFSET (see ctor)
22572261
if (m_names) {
2258-
nargs -= static_cast<size_t>(PyTuple_GET_SIZE(m_names.ptr()));
2262+
nargs -= m_names.size();
22592263
}
22602264
tuple val(nargs);
22612265
for (size_t i = 0; i < nargs; ++i) {
@@ -2267,10 +2271,9 @@ class unpacking_collector {
22672271
dict kwargs() const {
22682272
dict val;
22692273
if (m_names) {
2270-
auto namestup = reinterpret_borrow<tuple>(m_names);
2271-
size_t offset = m_args.size() - namestup.size();
2272-
for (size_t i = 0; i < namestup.size(); ++i, ++offset) {
2273-
val[namestup[i]] = m_args[offset];
2274+
size_t offset = m_args.size() - m_names.size();
2275+
for (size_t i = 0; i < m_names.size(); ++i, ++offset) {
2276+
val[m_names[i]] = m_args[offset];
22742277
}
22752278
}
22762279
return val;
@@ -2279,7 +2282,7 @@ class unpacking_collector {
22792282
private:
22802283
// normal argument, possibly needing conversion
22812284
template <typename T>
2282-
void process(object & /*names_list*/, T &&x) {
2285+
void process(list & /*names_list*/, T &&x) {
22832286
auto o = reinterpret_steal<object>(
22842287
detail::make_caster<T>::cast(std::forward<T>(x), policy, {}));
22852288
if (!o) {
@@ -2294,17 +2297,18 @@ class unpacking_collector {
22942297
}
22952298

22962299
// * unpacking
2297-
void process(object & /*names_list*/, detail::args_proxy ap) {
2300+
void process(list & /*names_list*/, detail::args_proxy ap) {
22982301
if (!ap) {
22992302
return;
23002303
}
23012304
for (auto a : ap) {
2302-
m_args.emplace_back(reinterpret_borrow<object>(a)); // keep alive
2305+
m_args.emplace_back(reinterpret_borrow<object>(a));
23032306
}
23042307
}
23052308

23062309
// named argument
2307-
void process(object &names_list, arg_v a) {
2310+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
2311+
void process(list &names_list, arg_v a) {
23082312
assert(names_list);
23092313
if (!a.name) {
23102314
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
@@ -2328,14 +2332,12 @@ class unpacking_collector {
23282332
throw cast_error_unable_to_convert_call_arg(a.name, a.type);
23292333
#endif
23302334
}
2331-
if (PyList_Append(names_list.ptr(), name.release().ptr()) < 0) {
2332-
throw error_already_set();
2333-
}
2335+
names_list.append(std::move(name));
23342336
m_args.emplace_back(a.value);
23352337
}
23362338

23372339
// ** unpacking
2338-
void process(object &names_list, detail::kwargs_proxy kp) {
2340+
void process(list &names_list, detail::kwargs_proxy kp) {
23392341
if (!kp) {
23402342
return;
23412343
}
@@ -2349,10 +2351,8 @@ class unpacking_collector {
23492351
multiple_values_error(name);
23502352
#endif
23512353
}
2352-
if (PyList_Append(names_list.ptr(), name.release().ptr()) < 0) {
2353-
throw error_already_set();
2354-
}
2355-
m_args.emplace_back(reinterpret_borrow<object>(k.second)); // keep alive
2354+
names_list.append(std::move(name));
2355+
m_args.emplace_back(reinterpret_borrow<object>(k.second));
23562356
}
23572357
}
23582358

@@ -2379,7 +2379,7 @@ class unpacking_collector {
23792379

23802380
private:
23812381
small_vector<object, arg_vector_small_size> m_args;
2382-
object m_names; // null or a tuple of names
2382+
tuple m_names;
23832383
};
23842384

23852385
/// Collect all arguments, including keywords and unpacking

0 commit comments

Comments
 (0)