@@ -2191,216 +2191,56 @@ class argument_loader {
21912191 std::tuple<make_caster<Args>...> argcasters;
21922192};
21932193
2194- // / Helper class which collects only positional arguments for a Python function call.
2195- // / A fancier version below can collect any argument, but this one is optimal for simple calls.
2196- template <return_value_policy policy>
2197- class simple_collector {
2198- public:
2199- template <typename ... Ts>
2200- explicit simple_collector (Ts &&...values)
2201- : m_args(pybind11::make_tuple<policy>(std::forward<Ts>(values)...)) {}
2202-
2203- const tuple &args () const & { return m_args; }
2204- dict kwargs () const { return {}; }
2205-
2206- tuple args () && { return std::move (m_args); }
2207-
2208- // / Call a Python function and pass the collected arguments
2209- object call (PyObject *ptr) const {
2210- PyObject *result = PyObject_CallObject (ptr, m_args.ptr ());
2211- if (!result) {
2212- throw error_already_set ();
2213- }
2214- return reinterpret_steal<object>(result);
2215- }
2216-
2217- private:
2218- tuple m_args;
2219- };
2220-
2221- // / Helper class which collects positional, keyword, * and ** arguments for a Python function call
2222- template <return_value_policy policy>
2223- class unpacking_collector {
2224- public:
2225- template <typename ... Ts>
2226- explicit unpacking_collector (Ts &&...values) {
2227- // Tuples aren't (easily) resizable so a list is needed for collection,
2228- // but the actual function call strictly requires a tuple.
2229- auto args_list = list ();
2230- using expander = int [];
2231- (void ) expander{0 , (process (args_list, std::forward<Ts>(values)), 0 )...};
2232-
2233- m_args = std::move (args_list);
2234- }
2235-
2236- const tuple &args () const & { return m_args; }
2237- const dict &kwargs () const & { return m_kwargs; }
2238-
2239- tuple args () && { return std::move (m_args); }
2240- dict kwargs () && { return std::move (m_kwargs); }
2241-
2242- // / Call a Python function and pass the collected arguments
2243- object call (PyObject *ptr) const {
2244- PyObject *result = PyObject_Call (ptr, m_args.ptr (), m_kwargs.ptr ());
2245- if (!result) {
2246- throw error_already_set ();
2247- }
2248- return reinterpret_steal<object>(result);
2249- }
2250-
2251- private:
2252- template <typename T>
2253- void process (list &args_list, T &&x) {
2254- auto o = reinterpret_steal<object>(
2255- detail::make_caster<T>::cast (std::forward<T>(x), policy, {}));
2256- if (!o) {
2257- #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
2258- throw cast_error_unable_to_convert_call_arg (std::to_string (args_list.size ()));
2259- #else
2260- throw cast_error_unable_to_convert_call_arg (std::to_string (args_list.size ()),
2261- type_id<T>());
2262- #endif
2263- }
2264- args_list.append (std::move (o));
2265- }
2266-
2267- void process (list &args_list, detail::args_proxy ap) {
2268- for (auto a : ap) {
2269- args_list.append (a);
2270- }
2271- }
2272-
2273- void process (list & /* args_list*/ , arg_v a) {
2274- if (!a.name ) {
2275- #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
2276- nameless_argument_error ();
2277- #else
2278- nameless_argument_error (a.type );
2279- #endif
2280- }
2281- if (m_kwargs.contains (a.name )) {
2282- #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
2283- multiple_values_error ();
2284- #else
2285- multiple_values_error (a.name );
2286- #endif
2287- }
2288- if (!a.value ) {
2289- #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
2290- throw cast_error_unable_to_convert_call_arg (a.name );
2291- #else
2292- throw cast_error_unable_to_convert_call_arg (a.name , a.type );
2293- #endif
2294- }
2295- m_kwargs[a.name ] = std::move (a.value );
2296- }
2297-
2298- void process (list & /* args_list*/ , detail::kwargs_proxy kp) {
2299- if (!kp) {
2300- return ;
2301- }
2302- for (auto k : reinterpret_borrow<dict>(kp)) {
2303- if (m_kwargs.contains (k.first )) {
2304- #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
2305- multiple_values_error ();
2306- #else
2307- multiple_values_error (str (k.first ));
2308- #endif
2309- }
2310- m_kwargs[k.first ] = k.second ;
2311- }
2312- }
2313-
2314- [[noreturn]] static void nameless_argument_error () {
2315- throw type_error (
2316- " Got kwargs without a name; only named arguments "
2317- " may be passed via py::arg() to a python function call. "
2318- " (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)" );
2319- }
2320- [[noreturn]] static void nameless_argument_error (const std::string &type) {
2321- throw type_error (" Got kwargs without a name of type '" + type
2322- + " '; only named "
2323- " arguments may be passed via py::arg() to a python function call. " );
2324- }
2325- [[noreturn]] static void multiple_values_error () {
2326- throw type_error (
2327- " Got multiple values for keyword argument "
2328- " (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)" );
2329- }
2330-
2331- [[noreturn]] static void multiple_values_error (const std::string &name) {
2332- throw type_error (" Got multiple values for keyword argument '" + name + " '" );
2333- }
2334-
2335- private:
2336- tuple m_args;
2337- dict m_kwargs;
2338- };
2339-
23402194// [workaround(intel)] Separate function required here
23412195// We need to put this into a separate function because the Intel compiler
23422196// fails to compile enable_if_t<!all_of<is_positional<Args>...>::value>
23432197// (tested with ICC 2021.1 Beta 20200827).
23442198template <typename ... Args>
2345- constexpr bool args_are_all_positional () {
2346- return all_of<is_positional<Args>...>::value;
2347- }
2348-
2349- #if PY_VERSION_HEX < 0x030C0000
2350- // / Collect only positional arguments for a Python function call
2351- template <return_value_policy policy,
2352- typename ... Args,
2353- typename = enable_if_t <args_are_all_positional<Args...>()>>
2354- simple_collector<policy> collect_arguments (Args &&...args) {
2355- return simple_collector<policy>(std::forward<Args>(args)...);
2199+ constexpr bool args_has_keyword_or_ds () {
2200+ return any_of<is_keyword_or_ds<Args>...>::value;
23562201}
23572202
2358- // / Collect all arguments, including keywords and unpacking (only instantiated when needed)
2359- template <return_value_policy policy,
2360- typename ... Args,
2361- typename = enable_if_t <!args_are_all_positional<Args...>()>>
2362- unpacking_collector<policy> collect_arguments (Args &&...args) {
2363- // Following argument order rules for generalized unpacking according to PEP 448
2364- static_assert (constexpr_last<is_positional, Args...>()
2365- < constexpr_first<is_keyword_or_ds, Args...>()
2366- && constexpr_last<is_s_unpacking, Args...>()
2367- < constexpr_first<is_ds_unpacking, Args...>(),
2368- " Invalid function call: positional args must precede keywords and ** unpacking; "
2369- " * unpacking must precede ** unpacking" );
2370- return unpacking_collector<policy>(std::forward<Args>(args)...);
2371- }
2372- #else
23732203// / Helper class which collects positional, keyword, * and ** arguments for a Python function call
23742204template <return_value_policy policy>
2375- class unpacking_vectorcall_collector {
2205+ class unpacking_collector {
23762206public:
23772207 template <typename ... Ts>
2378- explicit unpacking_vectorcall_collector (Ts &&...values) {
2208+ explicit unpacking_collector (Ts &&...values) {
2209+ /*
2210+ Python can sometimes utilize an extra space before the arguments to add on `self`.
2211+ This is important enough that there is a special flag for it:
2212+ PY_VECTORCALL_ARGUMENTS_OFFSET.
2213+ All we have to do it allocate an extra space at the beginning of this array, and set the
2214+ flag. Note that the extra space is not passed directly in to vectorcall.
2215+ */
23792216 m_args.reserve (sizeof ...(values) + 1 );
2380- m_args.push_back (
2381- nullptr ); // dummy first argument so we can use PY_VECTORCALL_ARGUMENTS_OFFSET
2217+ m_args.push_back (nullptr );
23822218
2383- object names_list; // null or a list of names
2219+ if (args_has_keyword_or_ds<Ts...>()) {
2220+ object names_list = list ();
23842221
2385- // collect_arguments guarantees this can't be constructed with kwargs before the last
2386- // positional so we don't need to worry about Ts... being in anything but normal python
2387- // order.
2388- using expander = int [];
2389- (void ) expander{0 , (process (names_list, std::forward<Ts>(values)), 0 )...};
2222+ // collect_arguments guarantees this can't be constructed with kwargs before the last
2223+ // positional so we don't need to worry about Ts... being in anything but normal python
2224+ // order.
2225+ using expander = int [];
2226+ (void ) expander{0 , (process (names_list, std::forward<Ts>(values)), 0 )...};
23902227
2391- if (names_list) {
23922228 m_names = reinterpret_steal<tuple>(PyList_AsTuple (names_list.ptr ()));
2229+ } else {
2230+ object not_used;
2231+
2232+ using expander = int [];
2233+ (void ) expander{0 , (process (not_used, std::forward<Ts>(values)), 0 )...};
23932234 }
23942235 }
23952236
23962237 // / Call a Python function and pass the collected arguments
23972238 object call (PyObject *ptr) const {
2398- // -1 to account for PY_VECTORCALL_ARGUMENTS_OFFSET
2399- size_t nargs = m_args.size () - 1 ;
2239+ size_t nargs = m_args.size () - 1 ; // -1 for PY_VECTORCALL_ARGUMENTS_OFFSET (see ctor)
24002240 if (m_names) {
24012241 nargs -= static_cast <size_t >(PyTuple_GET_SIZE (m_names.ptr ()));
24022242 }
2403- PyObject *result = PyObject_Vectorcall (
2243+ PyObject *result = _PyObject_Vectorcall (
24042244 ptr, m_args.data () + 1 , nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, m_names.ptr ());
24052245 if (!result) {
24062246 throw error_already_set ();
@@ -2409,15 +2249,14 @@ class unpacking_vectorcall_collector {
24092249 }
24102250
24112251 tuple args () const {
2412- // -1 to account for PY_VECTORCALL_ARGUMENTS_OFFSET
2413- size_t nargs = m_args.size () - 1 ;
2252+ size_t nargs = m_args.size () - 1 ; // -1 for PY_VECTORCALL_ARGUMENTS_OFFSET (see ctor)
24142253 if (m_names) {
24152254 nargs -= static_cast <size_t >(PyTuple_GET_SIZE (m_names.ptr ()));
24162255 }
24172256 tuple val (nargs);
24182257 for (size_t i = 0 ; i < nargs; ++i) {
2419- // +1 to account for PY_VECTORCALL_ARGUMENTS_OFFSET
2420- val[i] = reinterpret_borrow<object>( m_args[i + 1 ]);
2258+ val[i] = reinterpret_borrow<object>(
2259+ m_args[i + 1 ]); // +1 for PY_VECTORCALL_ARGUMENTS_OFFSET (see ctor)
24212260 }
24222261 return val;
24232262 }
@@ -2441,12 +2280,12 @@ class unpacking_vectorcall_collector {
24412280 auto o = reinterpret_steal<object>(
24422281 detail::make_caster<T>::cast (std::forward<T>(x), policy, {}));
24432282 if (!o) {
2444- # if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
2283+ #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
24452284 throw cast_error_unable_to_convert_call_arg (std::to_string (m_args.size () - 1 ));
2446- # else
2285+ #else
24472286 throw cast_error_unable_to_convert_call_arg (std::to_string (m_args.size () - 1 ),
24482287 type_id<T>());
2449- # endif
2288+ #endif
24502289 }
24512290 m_args.push_back (o.ptr ());
24522291 m_temp.push_back (std::move (o));
@@ -2465,30 +2304,28 @@ class unpacking_vectorcall_collector {
24652304
24662305 // named argument
24672306 void process (object &names_list, arg_v a) {
2468- if (!names_list) {
2469- names_list = list ();
2470- }
2307+ assert (names_list);
24712308 if (!a.name ) {
2472- # if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
2309+ #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
24732310 nameless_argument_error ();
2474- # else
2311+ #else
24752312 nameless_argument_error (a.type );
2476- # endif
2313+ #endif
24772314 }
24782315 auto name = str (a.name );
24792316 if (names_list.contains (name)) {
2480- # if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
2317+ #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
24812318 multiple_values_error ();
2482- # else
2319+ #else
24832320 multiple_values_error (a.name );
2484- # endif
2321+ #endif
24852322 }
24862323 if (!a.value ) {
2487- # if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
2324+ #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
24882325 throw cast_error_unable_to_convert_call_arg (a.name );
2489- # else
2326+ #else
24902327 throw cast_error_unable_to_convert_call_arg (a.name , a.type );
2491- # endif
2328+ #endif
24922329 }
24932330 if (PyList_Append (names_list.ptr (), name.release ().ptr ()) < 0 ) {
24942331 throw error_already_set ();
@@ -2502,17 +2339,15 @@ class unpacking_vectorcall_collector {
25022339 if (!kp) {
25032340 return ;
25042341 }
2505- if (!names_list) {
2506- names_list = list ();
2507- }
2342+ assert (names_list);
25082343 for (auto &&k : reinterpret_borrow<dict>(kp)) {
25092344 auto name = str (k.first );
25102345 if (names_list.contains (name)) {
2511- # if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
2346+ #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
25122347 multiple_values_error ();
2513- # else
2348+ #else
25142349 multiple_values_error (name);
2515- # endif
2350+ #endif
25162351 }
25172352 if (PyList_Append (names_list.ptr (), name.release ().ptr ()) < 0 ) {
25182353 throw error_already_set ();
@@ -2549,19 +2384,18 @@ class unpacking_vectorcall_collector {
25492384 small_vector<object, arg_vector_small_size> m_temp;
25502385};
25512386
2552- // / Collect all arguments, including keywords and unpacking for vectorcall
2387+ // / Collect all arguments, including keywords and unpacking
25532388template <return_value_policy policy, typename ... Args>
2554- unpacking_vectorcall_collector <policy> collect_arguments (Args &&...args) {
2389+ unpacking_collector <policy> collect_arguments (Args &&...args) {
25552390 // Following argument order rules for generalized unpacking according to PEP 448
2556- static_assert (constexpr_last<is_positional, Args...>()
2557- < constexpr_first<is_keyword_or_ds, Args...>()
2558- && constexpr_last<is_s_unpacking, Args...>()
2559- < constexpr_first<is_ds_unpacking , Args...>(),
2560- " Invalid function call: positional args must precede keywords and ** unpacking; "
2561- " * unpacking must precede ** unpacking" );
2562- return unpacking_vectorcall_collector <policy>(std::forward<Args>(args)...);
2391+ static_assert (
2392+ constexpr_last<is_positional, Args...>() < constexpr_first<is_keyword_or_ds, Args...>(),
2393+ " Invalid function call: positional args must precede keywords and */** unpacking; " );
2394+ static_assert (constexpr_last<is_s_unpacking , Args...>()
2395+ < constexpr_first<is_ds_unpacking, Args...>(),
2396+ " Invalid function call: * unpacking must precede ** unpacking" );
2397+ return unpacking_collector <policy>(std::forward<Args>(args)...);
25632398}
2564- #endif
25652399
25662400template <typename Derived>
25672401template <return_value_policy policy, typename ... Args>
0 commit comments