Skip to content

Commit 64c889b

Browse files
committed
V5 stable
1 parent 862097f commit 64c889b

File tree

1 file changed

+87
-143
lines changed

1 file changed

+87
-143
lines changed

Modules/_functoolsmodule.c

Lines changed: 87 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -376,11 +376,15 @@ partial_vectorcall(partialobject *pto, PyObject *const *args,
376376
return NULL;
377377
}
378378

379+
/* Total sizes */
380+
Py_ssize_t tot_nargs = pto_nargs + nargs - pto_phcount;
381+
Py_ssize_t tot_nkwds;
382+
Py_ssize_t tot_nargskw;
383+
379384
PyObject **pto_args = _PyTuple_ITEMS(pto->args);
380-
PyObject *ret;
381385

382386
/* Special cases */
383-
if (pto_nkwds == 0) {
387+
if (!pto_nkwds) {
384388
/* Fast path if we're called without arguments */
385389
if (nargskw == 0) {
386390
return _PyObject_VectorcallTstate(tstate, pto->fn, pto_args,
@@ -394,175 +398,115 @@ partial_vectorcall(partialobject *pto, PyObject *const *args,
394398
PyObject **newargs = (PyObject **)args - 1;
395399
PyObject *tmp = newargs[0];
396400
newargs[0] = pto_args[0];
397-
ret = _PyObject_VectorcallTstate(tstate, pto->fn, newargs,
398-
nargs + 1, kwnames);
401+
PyObject *ret = _PyObject_VectorcallTstate(tstate, pto->fn, newargs,
402+
nargs + 1, kwnames);
399403
newargs[0] = tmp;
400404
return ret;
401405
}
402-
403406
}
404407

405-
/* Size variables */
406-
Py_ssize_t tot_nargs = pto_nargs + nargs - pto_phcount;
407-
Py_ssize_t tot_nkwds;
408-
Py_ssize_t tot_nargskw;
409-
410-
/* Divergence on whether pto has kwds */
411-
if (pto_nkwds == 0) {
412-
tot_nkwds = nkwds;
413-
tot_nargskw = tot_nargs + tot_nkwds;
408+
tot_nkwds = pto_nkwds + nkwds;
409+
tot_nargskw = tot_nargs + tot_nkwds;
410+
PyObject **stack, *small_stack[_PY_FASTCALL_SMALL_STACK];
411+
PyObject *tot_kwnames = kwnames;
414412

413+
/* Initialize stack & copy keywords to stack */
414+
if (!pto_nkwds) {
415415
/* Allocate Stack */
416-
PyObject **stack, *small_stack[_PY_FASTCALL_SMALL_STACK];
416+
tot_nkwds = pto_nkwds + nkwds;
417+
tot_nargskw = tot_nargs + tot_nkwds;
417418
ALLOCATE_STACK(PyObject, tot_nargskw, small_stack, stack);
418419

419-
/* Copy Positionals to new stack */
420-
if (pto_phcount) {
421-
Py_ssize_t j = 0; // New args index
422-
for (Py_ssize_t i = 0; i < pto_nargs; i++) {
423-
if (pto_args[i] == pto->placeholder){
424-
stack[i] = args[j];
425-
j += 1;
426-
}
427-
else {
428-
stack[i] = pto_args[i];
429-
}
430-
}
431-
assert(j == pto_phcount);
432-
/* Add remaining args from new_args */
433-
if (nargs > pto_phcount) {
434-
memcpy(stack + pto_nargs, args + j, (nargskw - j) * sizeof(PyObject*));
435-
}
436-
}
437-
else {
438-
memcpy(stack, pto_args, pto_nargs * sizeof(PyObject*));
439-
memcpy(stack + pto_nargs, args, nargskw * sizeof(PyObject*));
420+
if (nkwds) {
421+
/* if !pto_nkwds & nkwds, then simply append kw */
422+
memcpy(stack + tot_nargs, args + nargs, nkwds * sizeof(PyObject*));
440423
}
441-
442-
/* Call / Maintenance / Return */
443-
ret = _PyObject_VectorcallTstate(tstate, pto->fn, stack, tot_nargs, kwnames);
444-
DEALLOCATE_STACK(small_stack, stack);
445-
return ret;
446424
}
447425
else {
448426
PyObject *key, *val;
449-
450-
PyObject **pto_kwkeys, *small_pto_kwkeys[_PY_FASTCALL_SMALL_STACK];
451-
PyObject **pto_kwvals, *small_pto_kwvals[_PY_FASTCALL_SMALL_STACK];
452-
ALLOCATE_STACK(PyObject, pto_nkwds, small_pto_kwkeys, pto_kwkeys);
453-
ALLOCATE_STACK(PyObject, pto_nkwds, small_pto_kwvals, pto_kwvals);
454-
Py_ssize_t pos = 0, i = 0;
455-
while (PyDict_Next(pto->kw, &pos, &key, &val)) {
456-
pto_kwkeys[i] = key;
457-
pto_kwvals[i] = val;
458-
i++;
459-
}
460-
461-
/* Calculate total kw size and positions of items to override */
462-
PyObject *tot_kwnames;
463-
PyObject **stack, *small_stack[_PY_FASTCALL_SMALL_STACK];
464-
tot_nkwds = pto_nkwds + nkwds;
465-
if (nkwds) {
466-
Py_ssize_t *positions, small_positions[_PY_FASTCALL_SMALL_STACK];
467-
ALLOCATE_STACK(Py_ssize_t, nkwds, small_positions, positions);
468-
for (Py_ssize_t i=0; i < nkwds; i++) {
469-
positions[i] = -1;
470-
key = PyTuple_GET_ITEM(kwnames, i);
471-
if (PyDict_Contains(pto->kw, key)) {
472-
tot_nkwds--;
473-
for (Py_ssize_t j=0; j < pto_nkwds; j++) {
474-
if (PyObject_RichCompareBool(key, pto_kwkeys[j], Py_EQ)) {
475-
positions[i] = j;
476-
break;
477-
}
478-
}
427+
PyObject *pto_kw = NULL; // pto_kw with duplicates merged (if any)
428+
429+
/* Temporary stack for keywords that are not in pto->kw */
430+
PyObject **kwtail, *small_kwtail[_PY_FASTCALL_SMALL_STACK * 2];
431+
ALLOCATE_STACK(PyObject, nkwds * 2, small_kwtail, kwtail);
432+
433+
/* Merge kw to pto_kw or add to tail (if not duplicate) */
434+
Py_ssize_t n_tail = 0;
435+
for (Py_ssize_t i = 0; i < nkwds; ++i) {
436+
key = PyTuple_GET_ITEM(kwnames, i);
437+
val = args[nargs + i];
438+
if (PyDict_Contains(pto->kw, key)) {
439+
if (pto_kw == NULL) {
440+
pto_kw = PyDict_Copy(pto->kw);
479441
}
442+
PyDict_SetItem(pto_kw, key, val);
480443
}
481-
tot_nargskw = tot_nargs + tot_nkwds;
482-
483-
/* Allocate Stack */
484-
ALLOCATE_STACK(PyObject, tot_nargskw, small_stack, stack);
485-
486-
/* Copy Pto Keywords to stack */
487-
memcpy(stack + tot_nargs, pto_kwvals, pto_nkwds * sizeof(PyObject*));
488-
DEALLOCATE_STACK(small_pto_kwvals, pto_kwvals);
489-
490-
/* Copy New Keywords to stack */
491-
tot_kwnames = PyTuple_New(tot_nkwds);
492-
for (Py_ssize_t i=0; i < pto_nkwds; i++) {
493-
key = pto_kwkeys[i];
494-
PyTuple_SET_ITEM(tot_kwnames, i, key);
495-
Py_INCREF(key);
496-
}
497-
DEALLOCATE_STACK(small_pto_kwkeys, pto_kwkeys);
498-
499-
Py_ssize_t k = 0;
500-
Py_ssize_t j;
501-
for (Py_ssize_t i=0; i < nkwds; i++) {
502-
key = PyTuple_GET_ITEM(kwnames, i);
503-
val = args[nargs + i];
504-
j = positions[i];
505-
if (j != -1) {
506-
stack[tot_nargs + j] = val;
507-
}
508-
else {
509-
PyTuple_SET_ITEM(tot_kwnames, pto_nkwds + k, key);
510-
Py_INCREF(key);
511-
stack[tot_nargs + pto_nkwds + k] = val;
512-
k++;
513-
}
444+
else {
445+
kwtail[n_tail] = key;
446+
kwtail[n_tail + nkwds] = val;
447+
n_tail++;
514448
}
515-
DEALLOCATE_STACK(small_positions, positions);
516449
}
517-
else {
518-
tot_nargskw = tot_nargs + tot_nkwds;
519450

520-
/* Allocate Stack */
521-
ALLOCATE_STACK(PyObject, tot_nargskw, small_stack, stack);
522-
523-
/* Copy Pto Keywords to stack */
524-
memcpy(stack + tot_nargs, pto_kwvals, pto_nkwds * sizeof(PyObject*));
525-
DEALLOCATE_STACK(small_pto_kwvals, pto_kwvals);
451+
/* Allocate Stack */
452+
Py_ssize_t n_merges = nkwds - n_tail;
453+
tot_nkwds = pto_nkwds + nkwds - n_merges;
454+
tot_nargskw = tot_nargs + tot_nkwds;
455+
ALLOCATE_STACK(PyObject, tot_nargskw, small_stack, stack);
456+
tot_kwnames = PyTuple_New(tot_nkwds);
526457

527-
/* Copy New Keywords to stack */
528-
tot_kwnames = PyTuple_New(tot_nkwds);
529-
for (Py_ssize_t i=0; i < pto_nkwds; i++) {
530-
key = pto_kwkeys[i];
531-
PyTuple_SET_ITEM(tot_kwnames, i, key);
532-
Py_INCREF(key);
533-
}
534-
DEALLOCATE_STACK(small_pto_kwkeys, pto_kwkeys);
458+
/* Copy pto_kw to stack */
459+
Py_ssize_t pos = 0, i = 0;
460+
while (PyDict_Next(n_merges ? pto_kw : pto->kw, &pos, &key, &val)) {
461+
PyTuple_SET_ITEM(tot_kwnames, i, key);
462+
Py_INCREF(key);
463+
stack[tot_nargs + i] = val;
464+
i++;
535465
}
466+
Py_XDECREF(pto_kw);
467+
468+
/* Copy kw tail to stack */
469+
for (Py_ssize_t i = 0; i < n_tail; ++i) {
470+
key = kwtail[i];
471+
val = kwtail[i + nkwds];
472+
PyTuple_SET_ITEM(tot_kwnames, pto_nkwds + i, key);
473+
Py_INCREF(key);
474+
stack[tot_nargs + pto_nkwds + i] = val;
475+
}
476+
DEALLOCATE_STACK(small_kwtail, kwtail);
477+
}
536478

537-
/* Copy Positionals to stack */
538-
if (pto_phcount) {
539-
Py_ssize_t j = 0; // New args index
540-
for (Py_ssize_t i = 0; i < pto_nargs; i++) {
541-
if (pto_args[i] == pto->placeholder){
542-
stack[i] = args[j];
543-
j += 1;
544-
}
545-
else {
546-
stack[i] = pto_args[i];
547-
}
479+
/* Copy Positionals to stack */
480+
if (pto_phcount) {
481+
Py_ssize_t j = 0; // New args index
482+
for (Py_ssize_t i = 0; i < pto_nargs; i++) {
483+
if (pto_args[i] == pto->placeholder){
484+
stack[i] = args[j];
485+
j += 1;
548486
}
549-
assert(j == pto_phcount);
550-
/* Add remaining args from new_args */
551-
if (nargs > pto_phcount) {
552-
memcpy(stack + pto_nargs, args + j, (nargs - j) * sizeof(PyObject*));
487+
else {
488+
stack[i] = pto_args[i];
553489
}
554490
}
555-
else {
556-
memcpy(stack, pto_args, pto_nargs * sizeof(PyObject*));
557-
memcpy(stack + pto_nargs, args, nargs * sizeof(PyObject*));
491+
assert(j == pto_phcount);
492+
/* Add remaining args from new_args */
493+
if (nargs > pto_phcount) {
494+
memcpy(stack + pto_nargs, args + j, (nargs - j) * sizeof(PyObject*));
558495
}
496+
}
497+
else {
498+
memcpy(stack, pto_args, pto_nargs * sizeof(PyObject*));
499+
memcpy(stack + pto_nargs, args, nargs * sizeof(PyObject*));
500+
}
559501

560-
/* Call / Maintenance / Return */
561-
ret = _PyObject_VectorcallTstate(tstate, pto->fn, stack, tot_nargs, tot_kwnames);
562-
DEALLOCATE_STACK(small_stack, stack);
502+
/* Call / Maintenance / Return */
503+
PyObject *ret = _PyObject_VectorcallTstate(tstate, pto->fn, stack,
504+
tot_nargs, tot_kwnames);
505+
DEALLOCATE_STACK(small_stack, stack);
506+
if (pto_nkwds) {
563507
Py_DECREF(tot_kwnames);
564-
return ret;
565508
}
509+
return ret;
566510
}
567511

568512
/* Set pto->vectorcall depending on the parameters of the partial object */

0 commit comments

Comments
 (0)