Skip to content

Commit bf39d69

Browse files
committed
Revert _tkinter._flatten()
PyTupleWriter made the function slower.
1 parent b124698 commit bf39d69

File tree

1 file changed

+53
-22
lines changed

1 file changed

+53
-22
lines changed

Modules/_tkinter.c

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3080,33 +3080,60 @@ Tkapp_Dealloc(PyObject *op)
30803080

30813081
/**** Tkinter Module ****/
30823082

3083+
typedef struct {
3084+
PyObject* tuple;
3085+
Py_ssize_t size; /* current size */
3086+
Py_ssize_t maxsize; /* allocated size */
3087+
} FlattenContext;
3088+
30833089
static int
3084-
_flatten1(PyTupleWriter *writer, PyObject *item, int depth)
3090+
_bump(FlattenContext* context, Py_ssize_t size)
3091+
{
3092+
/* expand tuple to hold (at least) size new items.
3093+
return true if successful, false if an exception was raised */
3094+
3095+
Py_ssize_t maxsize = context->maxsize * 2; /* never overflows */
3096+
3097+
if (maxsize < context->size + size)
3098+
maxsize = context->size + size; /* never overflows */
3099+
3100+
context->maxsize = maxsize;
3101+
3102+
return _PyTuple_Resize(&context->tuple, maxsize) >= 0;
3103+
}
3104+
3105+
static int
3106+
_flatten1(FlattenContext* context, PyObject* item, int depth)
30853107
{
30863108
/* add tuple or list to argument tuple (recursively) */
30873109

3110+
Py_ssize_t i, size;
3111+
30883112
if (depth > 1000) {
30893113
PyErr_SetString(PyExc_ValueError,
30903114
"nesting too deep in _flatten");
30913115
return 0;
3092-
}
3093-
3094-
if (PyTuple_Check(item) || PyList_Check(item)) {
3095-
Py_ssize_t size = PySequence_Fast_GET_SIZE(item);
3116+
} else if (PyTuple_Check(item) || PyList_Check(item)) {
3117+
size = PySequence_Fast_GET_SIZE(item);
3118+
/* preallocate (assume no nesting) */
3119+
if (context->size + size > context->maxsize &&
3120+
!_bump(context, size))
3121+
return 0;
30963122
/* copy items to output tuple */
3097-
for (Py_ssize_t i = 0; i < size; i++) {
3123+
for (i = 0; i < size; i++) {
30983124
PyObject *o = PySequence_Fast_GET_ITEM(item, i);
30993125
if (PyList_Check(o) || PyTuple_Check(o)) {
3100-
if (!_flatten1(writer, o, depth + 1))
3126+
if (!_flatten1(context, o, depth + 1))
31013127
return 0;
31023128
} else if (o != Py_None) {
3103-
if (PyTupleWriter_Add(writer, o) < 0) {
3129+
if (context->size + 1 > context->maxsize &&
3130+
!_bump(context, 1))
31043131
return 0;
3105-
}
3132+
PyTuple_SET_ITEM(context->tuple,
3133+
context->size++, Py_NewRef(o));
31063134
}
31073135
}
3108-
}
3109-
else {
3136+
} else {
31103137
PyErr_SetString(PyExc_TypeError, "argument must be sequence");
31113138
return 0;
31123139
}
@@ -3125,25 +3152,29 @@ static PyObject *
31253152
_tkinter__flatten(PyObject *module, PyObject *item)
31263153
/*[clinic end generated code: output=cad02a3f97f29862 input=6b9c12260aa1157f]*/
31273154
{
3128-
Py_ssize_t maxsize = PySequence_Size(item);
3129-
if (maxsize < 0) {
3155+
FlattenContext context;
3156+
3157+
context.maxsize = PySequence_Size(item);
3158+
if (context.maxsize < 0)
31303159
return NULL;
3131-
}
3132-
if (maxsize == 0) {
3160+
if (context.maxsize == 0)
31333161
return PyTuple_New(0);
3134-
}
31353162

3136-
PyTupleWriter *writer = PyTupleWriter_Create(maxsize);
3137-
if (writer == NULL) {
3163+
context.tuple = PyTuple_New(context.maxsize);
3164+
if (!context.tuple)
31383165
return NULL;
3139-
}
31403166

3141-
if (!_flatten1(writer, item, 0)) {
3142-
PyTupleWriter_Discard(writer);
3167+
context.size = 0;
3168+
3169+
if (!_flatten1(&context, item, 0)) {
3170+
Py_XDECREF(context.tuple);
31433171
return NULL;
31443172
}
31453173

3146-
return PyTupleWriter_Finish(writer);
3174+
if (_PyTuple_Resize(&context.tuple, context.size))
3175+
return NULL;
3176+
3177+
return context.tuple;
31473178
}
31483179

31493180
/*[clinic input]

0 commit comments

Comments
 (0)