summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorEric Smith <eric@trueblade.com>2008-08-18 14:27:38 (GMT)
committerEric Smith <eric@trueblade.com>2008-08-18 14:27:38 (GMT)
commite5bdccc77b2a0da0b72f4a6ebbc2d9a1a9680dcd (patch)
tree83d9377c099d20153fa1def09adf06f7b963b69e /Objects
parent8e439a16b25c3204ddddb71628d38745cc4299f4 (diff)
downloadcpython-e5bdccc77b2a0da0b72f4a6ebbc2d9a1a9680dcd.zip
cpython-e5bdccc77b2a0da0b72f4a6ebbc2d9a1a9680dcd.tar.gz
cpython-e5bdccc77b2a0da0b72f4a6ebbc2d9a1a9680dcd.tar.bz2
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.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/stringlib/string_format.h48
1 files changed, 42 insertions, 6 deletions
diff --git a/Objects/stringlib/string_format.h b/Objects/stringlib/string_format.h
index be8e8080..600e6b0 100644
--- a/Objects/stringlib/string_format.h
+++ b/Objects/stringlib/string_format.h
@@ -483,13 +483,49 @@ render_field(PyObject *fieldobj, SubString *format_spec, OutputString *output)
{
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;
+
+ /* 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
- /* 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 (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);
+ result = PyObject_Format(fieldobj, format_spec_object);
+ }
if (result == NULL)
goto done;
@@ -512,7 +548,7 @@ render_field(PyObject *fieldobj, SubString *format_spec, OutputString *output)
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;
}