Mercurial > cpython-lru_cache-weakref
diff Objects/stringlib/string_format.h @ 48286:4b4564beb6da legacy-trunk
Backport of r63826.
Optimization of str.format() for cases with str, unicode, int, long,
and float arguments. This gives about 30% speed improvement for the
simplest (but most common) cases. This patch skips the __format__
dispatch, and also avoids creating an object to hold the format_spec.
Unfortunately there's a complication in 2.6 with int, long, and float
because they always expect str format_specs. So in the unicode
version of this optimization, just check for unicode objects. int,
float, long, and str can be added later, if needed.
| author | Eric Smith <eric@trueblade.com> |
|---|---|
| date | Mon, 18 Aug 2008 14:27:38 +0000 |
| parents | 52294af4b663 |
| children | d2d028f65c7c 3f18d609ac1b |
line wrap: on
line diff
--- a/Objects/stringlib/string_format.h Mon Aug 18 13:32:19 2008 +0000 +++ b/Objects/stringlib/string_format.h Mon Aug 18 14:27:38 2008 +0000 @@ -483,13 +483,49 @@ { int ok = 0; PyObject *result = NULL; + PyObject *format_spec_object = NULL; + PyObject *(*formatter)(PyObject *, STRINGLIB_CHAR *, Py_ssize_t) = NULL; + STRINGLIB_CHAR* format_spec_start = format_spec->ptr ? + format_spec->ptr : NULL; + Py_ssize_t format_spec_len = format_spec->ptr ? + format_spec->end - format_spec->ptr : 0; - /* we need to create an object out of the pointers we have */ - PyObject *format_spec_object = SubString_new_object_or_empty(format_spec); - if (format_spec_object == NULL) - goto done; + /* If we know the type exactly, skip the lookup of __format__ and just + call the formatter directly. */ +#if STRINGLIB_IS_UNICODE + if (PyUnicode_CheckExact(fieldobj)) + formatter = _PyUnicode_FormatAdvanced; + /* Unfortunately, there's a problem with checking for int, long, + and float here. If we're being included as unicode, their + formatters expect string format_spec args. For now, just skip + this optimization for unicode. This could be fixed, but it's a + hassle. */ +#else + if (PyString_CheckExact(fieldobj)) + formatter = _PyBytes_FormatAdvanced; + else if (PyInt_CheckExact(fieldobj)) + formatter =_PyInt_FormatAdvanced; + else if (PyLong_CheckExact(fieldobj)) + formatter =_PyLong_FormatAdvanced; + else if (PyFloat_CheckExact(fieldobj)) + formatter = _PyFloat_FormatAdvanced; +#endif - result = PyObject_Format(fieldobj, format_spec_object); + if (formatter) { + /* we know exactly which formatter will be called when __format__ is + looked up, so call it directly, instead. */ + result = formatter(fieldobj, format_spec_start, format_spec_len); + } + else { + /* We need to create an object out of the pointers we have, because + __format__ takes a string/unicode object for format_spec. */ + format_spec_object = STRINGLIB_NEW(format_spec_start, + format_spec_len); + if (format_spec_object == NULL) + goto done; + + result = PyObject_Format(fieldobj, format_spec_object); + } if (result == NULL) goto done; @@ -512,7 +548,7 @@ ok = output_data(output, STRINGLIB_STR(result), STRINGLIB_LEN(result)); done: - Py_DECREF(format_spec_object); + Py_XDECREF(format_spec_object); Py_XDECREF(result); return ok; }
