| 2213 | public: |
| 2214 | template <typename... Ts> |
| 2215 | explicit unpacking_collector(Ts &&...values) |
| 2216 | : m_names(reinterpret_steal<tuple>( |
| 2217 | handle())) // initialize to null to avoid useless allocation of 0-length tuple |
| 2218 | { |
| 2219 | /* |
| 2220 | Python can sometimes utilize an extra space before the arguments to prepend `self`. |
| 2221 | This is important enough that there is a special flag for it: |
| 2222 | PY_VECTORCALL_ARGUMENTS_OFFSET. |
| 2223 | All we have to do is allocate an extra space at the beginning of this array, and set the |
| 2224 | flag. Note that the extra space is not passed directly in to vectorcall. |
| 2225 | */ |
| 2226 | m_args.reserve(sizeof...(values) + 1); |
| 2227 | m_args.push_back_null(); |
| 2228 | |
| 2229 | if (args_has_keyword_or_ds<Ts...>()) { |
| 2230 | list names_list; |
| 2231 | |
| 2232 | // collect_arguments guarantees this can't be constructed with kwargs before the last |
| 2233 | // positional so we don't need to worry about Ts... being in anything but normal python |
| 2234 | // order. |
| 2235 | using expander = int[]; |
| 2236 | (void) expander{0, (process(names_list, std::forward<Ts>(values)), 0)...}; |
| 2237 | |
| 2238 | m_names = reinterpret_steal<tuple>(PyList_AsTuple(names_list.ptr())); |
| 2239 | } else { |
| 2240 | auto not_used |
| 2241 | = reinterpret_steal<list>(handle()); // initialize as null (to avoid an allocation) |
| 2242 | |
| 2243 | using expander = int[]; |
| 2244 | (void) expander{0, (process(not_used, std::forward<Ts>(values)), 0)...}; |
| 2245 | } |
| 2246 | } |
| 2247 | |
| 2248 | /// Call a Python function and pass the collected arguments |
| 2249 | object call(PyObject *ptr) const { |
nothing calls this directly
no test coverage detected