diff options
| author | Eric Smith <eric@trueblade.com> | 2008-08-18 14:27:38 (GMT) | 
|---|---|---|
| committer | Eric Smith <eric@trueblade.com> | 2008-08-18 14:27:38 (GMT) | 
| commit | e5bdccc77b2a0da0b72f4a6ebbc2d9a1a9680dcd (patch) | |
| tree | 83d9377c099d20153fa1def09adf06f7b963b69e /Objects/stringlib/string_format.h | |
| parent | 8e439a16b25c3204ddddb71628d38745cc4299f4 (diff) | |
| download | cpython-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/stringlib/string_format.h')
| -rw-r--r-- | Objects/stringlib/string_format.h | 48 | 
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;  }  | 
