@@ -2204,7 +2204,10 @@ template <return_value_policy policy>
22042204class unpacking_collector {
22052205public:
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 {
22792282private:
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
23802380private:
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