Skip to content

Commit c1553bc

Browse files
authored
gh-119182: Use public PyUnicodeWriter API in union_repr() (#120797)
The public PyUnicodeWriter API enables overallocation by default and so is more efficient. Benchmark: python -m pyperf timeit \ -s 't = int | float | complex | str | bytes | bytearray' \ ' | memoryview | list | dict' \ 'str(t)' Result: 1.29 us +- 0.02 us -> 1.00 us +- 0.02 us: 1.29x faster
1 parent 73b4492 commit c1553bc

File tree

1 file changed

+30
-24
lines changed

1 file changed

+30
-24
lines changed

Objects/unionobject.c

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -182,15 +182,14 @@ _Py_union_type_or(PyObject* self, PyObject* other)
182182
}
183183

184184
static int
185-
union_repr_item(_PyUnicodeWriter *writer, PyObject *p)
185+
union_repr_item(PyUnicodeWriter *writer, PyObject *p)
186186
{
187187
PyObject *qualname = NULL;
188188
PyObject *module = NULL;
189-
PyObject *r = NULL;
190189
int rc;
191190

192191
if (p == (PyObject *)&_PyNone_Type) {
193-
return _PyUnicodeWriter_WriteASCIIString(writer, "None", 4);
192+
return PyUnicodeWriter_WriteUTF8(writer, "None", 4);
194193
}
195194

196195
if ((rc = PyObject_HasAttrWithError(p, &_Py_ID(__origin__))) > 0 &&
@@ -200,17 +199,17 @@ union_repr_item(_PyUnicodeWriter *writer, PyObject *p)
200199
goto use_repr;
201200
}
202201
if (rc < 0) {
203-
goto exit;
202+
goto error;
204203
}
205204

206205
if (PyObject_GetOptionalAttr(p, &_Py_ID(__qualname__), &qualname) < 0) {
207-
goto exit;
206+
goto error;
208207
}
209208
if (qualname == NULL) {
210209
goto use_repr;
211210
}
212211
if (PyObject_GetOptionalAttr(p, &_Py_ID(__module__), &module) < 0) {
213-
goto exit;
212+
goto error;
214213
}
215214
if (module == NULL || module == Py_None) {
216215
goto use_repr;
@@ -221,24 +220,25 @@ union_repr_item(_PyUnicodeWriter *writer, PyObject *p)
221220
_PyUnicode_EqualToASCIIString(module, "builtins"))
222221
{
223222
// builtins don't need a module name
224-
r = PyObject_Str(qualname);
225-
goto exit;
223+
rc = PyUnicodeWriter_WriteStr(writer, qualname);
224+
goto done;
226225
}
227226
else {
228-
r = PyUnicode_FromFormat("%S.%S", module, qualname);
229-
goto exit;
227+
rc = PyUnicodeWriter_Format(writer, "%S.%S", module, qualname);
228+
goto done;
230229
}
231230

231+
error:
232+
rc = -1;
233+
goto done;
234+
232235
use_repr:
233-
r = PyObject_Repr(p);
234-
exit:
236+
rc = PyUnicodeWriter_WriteRepr(writer, p);
237+
goto done;
238+
239+
done:
235240
Py_XDECREF(qualname);
236241
Py_XDECREF(module);
237-
if (r == NULL) {
238-
return -1;
239-
}
240-
rc = _PyUnicodeWriter_WriteStr(writer, r);
241-
Py_DECREF(r);
242242
return rc;
243243
}
244244

@@ -248,20 +248,26 @@ union_repr(PyObject *self)
248248
unionobject *alias = (unionobject *)self;
249249
Py_ssize_t len = PyTuple_GET_SIZE(alias->args);
250250

251-
_PyUnicodeWriter writer;
252-
_PyUnicodeWriter_Init(&writer);
253-
for (Py_ssize_t i = 0; i < len; i++) {
254-
if (i > 0 && _PyUnicodeWriter_WriteASCIIString(&writer, " | ", 3) < 0) {
251+
// Shortest type name "int" (3 chars) + " | " (3 chars) separator
252+
Py_ssize_t estimate = (len <= PY_SSIZE_T_MAX / 6) ? len * 6 : len;
253+
PyUnicodeWriter *writer = PyUnicodeWriter_Create(estimate);
254+
if (writer == NULL) {
255+
return NULL;
256+
}
257+
258+
for (Py_ssize_t i = 0; i < len; i++) {
259+
if (i > 0 && PyUnicodeWriter_WriteUTF8(writer, " | ", 3) < 0) {
255260
goto error;
256261
}
257262
PyObject *p = PyTuple_GET_ITEM(alias->args, i);
258-
if (union_repr_item(&writer, p) < 0) {
263+
if (union_repr_item(writer, p) < 0) {
259264
goto error;
260265
}
261266
}
262-
return _PyUnicodeWriter_Finish(&writer);
267+
return PyUnicodeWriter_Finish(writer);
268+
263269
error:
264-
_PyUnicodeWriter_Dealloc(&writer);
270+
PyUnicodeWriter_Discard(writer);
265271
return NULL;
266272
}
267273

0 commit comments

Comments
 (0)