Refactor and clean up str.format() code (and helpers) in advance of optimizations.
This commit is contained in:
parent
eb2c964aeb
commit
4a7d76ddb5
|
@ -105,6 +105,12 @@ PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le);
|
|||
/* free list api */
|
||||
PyAPI_FUNC(void) PyFloat_CompactFreeList(size_t *, size_t *, size_t *);
|
||||
|
||||
/* Format the object based on the format_spec, as defined in PEP 3101
|
||||
(Advanced String Formatting). */
|
||||
PyAPI_FUNC(PyObject *) _PyFloat_FormatAdvanced(PyObject *obj,
|
||||
Py_UNICODE *format_spec,
|
||||
Py_ssize_t format_spec_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
PyObject *
|
||||
unicode_unicode__format__(PyObject *self, PyObject *args);
|
||||
|
||||
PyObject *
|
||||
unicode_long__format__(PyObject *self, PyObject *args);
|
||||
|
||||
PyObject *
|
||||
unicode_float__format__(PyObject *self, PyObject *args);
|
||||
|
|
@ -127,6 +127,12 @@ PyAPI_FUNC(int) _PyLong_AsByteArray(PyLongObject* v,
|
|||
appending a base prefix of 0[box] if base is 2, 8 or 16. */
|
||||
PyAPI_FUNC(PyObject *) _PyLong_Format(PyObject *aa, int base);
|
||||
|
||||
/* Format the object based on the format_spec, as defined in PEP 3101
|
||||
(Advanced String Formatting). */
|
||||
PyAPI_FUNC(PyObject *) _PyLong_FormatAdvanced(PyObject *obj,
|
||||
Py_UNICODE *format_spec,
|
||||
Py_ssize_t format_spec_len);
|
||||
|
||||
/* These aren't really part of the long object, but they're handy. The
|
||||
functions are in Python/mystrtoul.c.
|
||||
*/
|
||||
|
|
|
@ -571,6 +571,12 @@ PyAPI_FUNC(PyObject*) PyUnicode_FromObject(
|
|||
PyAPI_FUNC(PyObject *) PyUnicode_FromFormatV(const char*, va_list);
|
||||
PyAPI_FUNC(PyObject *) PyUnicode_FromFormat(const char*, ...);
|
||||
|
||||
/* Format the object based on the format_spec, as defined in PEP 3101
|
||||
(Advanced String Formatting). */
|
||||
PyAPI_FUNC(PyObject *) _PyUnicode_FormatAdvanced(PyObject *obj,
|
||||
Py_UNICODE *format_spec,
|
||||
Py_ssize_t format_spec_len);
|
||||
|
||||
PyAPI_FUNC(void) PyUnicode_InternInPlace(PyObject **);
|
||||
PyAPI_FUNC(void) PyUnicode_InternImmortal(PyObject **);
|
||||
PyAPI_FUNC(PyObject *) PyUnicode_InternFromString(const char *);
|
||||
|
|
|
@ -596,7 +596,6 @@ PYTHON_HEADERS= \
|
|||
Include/eval.h \
|
||||
Include/fileobject.h \
|
||||
Include/floatobject.h \
|
||||
Include/formatter_unicode.h \
|
||||
Include/frameobject.h \
|
||||
Include/funcobject.h \
|
||||
Include/genobject.h \
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
#include "Python.h"
|
||||
#include "structseq.h"
|
||||
|
||||
#include "formatter_unicode.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
|
||||
|
@ -1303,10 +1301,13 @@ float_getzero(PyObject *v, void *closure)
|
|||
static PyObject *
|
||||
float__format__(PyObject *self, PyObject *args)
|
||||
{
|
||||
/* when back porting this to 2.6, check type of the format_spec
|
||||
and call either unicode_long__format__ or
|
||||
string_long__format__ */
|
||||
return unicode_float__format__(self, args);
|
||||
PyObject *format_spec;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "U:__format__", &format_spec))
|
||||
return NULL;
|
||||
return _PyFloat_FormatAdvanced(self,
|
||||
PyUnicode_AS_UNICODE(format_spec),
|
||||
PyUnicode_GET_SIZE(format_spec));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(float__format__doc,
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
#include "Python.h"
|
||||
#include "longintrepr.h"
|
||||
|
||||
#include "formatter_unicode.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef NSMALLPOSINTS
|
||||
|
@ -3590,10 +3588,13 @@ long_getN(PyLongObject *v, void *context) {
|
|||
static PyObject *
|
||||
long__format__(PyObject *self, PyObject *args)
|
||||
{
|
||||
/* when back porting this to 2.6, check type of the format_spec
|
||||
and call either unicode_long__format__ or
|
||||
string_long__format__ */
|
||||
return unicode_long__format__(self, args);
|
||||
PyObject *format_spec;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "U:__format__", &format_spec))
|
||||
return NULL;
|
||||
return _PyLong_FormatAdvanced(self,
|
||||
PyUnicode_AS_UNICODE(format_spec),
|
||||
PyUnicode_GET_SIZE(format_spec));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -102,12 +102,13 @@ typedef struct {
|
|||
if failure, sets the exception
|
||||
*/
|
||||
static int
|
||||
parse_internal_render_format_spec(PyObject *format_spec,
|
||||
parse_internal_render_format_spec(STRINGLIB_CHAR *format_spec,
|
||||
Py_ssize_t format_spec_len,
|
||||
InternalFormatSpec *format,
|
||||
char default_type)
|
||||
{
|
||||
STRINGLIB_CHAR *ptr = STRINGLIB_STR(format_spec);
|
||||
STRINGLIB_CHAR *end = ptr + STRINGLIB_LEN(format_spec);
|
||||
STRINGLIB_CHAR *ptr = format_spec;
|
||||
STRINGLIB_CHAR *end = format_spec + format_spec_len;
|
||||
|
||||
/* end-ptr is used throughout this code to specify the length of
|
||||
the input string */
|
||||
|
@ -756,56 +757,31 @@ done:
|
|||
/************************************************************************/
|
||||
/*********** built in formatters ****************************************/
|
||||
/************************************************************************/
|
||||
#ifdef FORMAT_STRING
|
||||
PyObject *
|
||||
FORMAT_STRING(PyObject* value, PyObject* args)
|
||||
FORMAT_STRING(PyObject *obj,
|
||||
STRINGLIB_CHAR *format_spec,
|
||||
Py_ssize_t format_spec_len)
|
||||
{
|
||||
PyObject *format_spec;
|
||||
PyObject *result = NULL;
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
PyObject *tmp = NULL;
|
||||
#endif
|
||||
InternalFormatSpec format;
|
||||
|
||||
/* If 2.x, we accept either str or unicode, and try to convert it
|
||||
to the right type. In 3.x, we insist on only unicode */
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
if (!PyArg_ParseTuple(args, STRINGLIB_PARSE_CODE ":__format__",
|
||||
&format_spec))
|
||||
goto done;
|
||||
#else
|
||||
/* If 2.x, convert format_spec to the same type as value */
|
||||
/* This is to allow things like u''.format('') */
|
||||
if (!PyArg_ParseTuple(args, "O:__format__", &format_spec))
|
||||
goto done;
|
||||
if (!(PyBytes_Check(format_spec) || PyUnicode_Check(format_spec))) {
|
||||
PyErr_Format(PyExc_TypeError, "__format__ arg must be str "
|
||||
"or unicode, not %s", Py_TYPE(format_spec)->tp_name);
|
||||
goto done;
|
||||
}
|
||||
tmp = STRINGLIB_TOSTR(format_spec);
|
||||
if (tmp == NULL)
|
||||
goto done;
|
||||
format_spec = tmp;
|
||||
#endif
|
||||
PyObject *result = NULL;
|
||||
|
||||
/* check for the special case of zero length format spec, make
|
||||
it equivalent to str(value) */
|
||||
if (STRINGLIB_LEN(format_spec) == 0) {
|
||||
result = STRINGLIB_TOSTR(value);
|
||||
it equivalent to str(obj) */
|
||||
if (format_spec_len == 0) {
|
||||
result = STRINGLIB_TOSTR(obj);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
/* parse the format_spec */
|
||||
if (!parse_internal_render_format_spec(format_spec, &format, 's'))
|
||||
if (!parse_internal_render_format_spec(format_spec, format_spec_len,
|
||||
&format, 's'))
|
||||
goto done;
|
||||
|
||||
/* type conversion? */
|
||||
switch (format.type) {
|
||||
case 's':
|
||||
/* no type conversion needed, already a string. do the formatting */
|
||||
result = format_string_internal(value, &format);
|
||||
result = format_string_internal(obj, &format);
|
||||
break;
|
||||
default:
|
||||
/* unknown */
|
||||
|
@ -826,35 +802,31 @@ FORMAT_STRING(PyObject* value, PyObject* args)
|
|||
}
|
||||
|
||||
done:
|
||||
#if PY_VERSION_HEX < 0x03000000
|
||||
Py_XDECREF(tmp);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
#endif /* FORMAT_STRING */
|
||||
|
||||
#if defined FORMAT_LONG || defined FORMAT_INT
|
||||
static PyObject*
|
||||
format_int_or_long(PyObject* value, PyObject* args, IntOrLongToString tostring)
|
||||
format_int_or_long(PyObject* obj,
|
||||
STRINGLIB_CHAR *format_spec,
|
||||
Py_ssize_t format_spec_len,
|
||||
IntOrLongToString tostring)
|
||||
{
|
||||
PyObject *format_spec;
|
||||
PyObject *result = NULL;
|
||||
PyObject *tmp = NULL;
|
||||
InternalFormatSpec format;
|
||||
|
||||
if (!PyArg_ParseTuple(args, STRINGLIB_PARSE_CODE ":__format__",
|
||||
&format_spec))
|
||||
goto done;
|
||||
|
||||
/* check for the special case of zero length format spec, make
|
||||
it equivalent to str(value) */
|
||||
if (STRINGLIB_LEN(format_spec) == 0) {
|
||||
result = STRINGLIB_TOSTR(value);
|
||||
it equivalent to str(obj) */
|
||||
if (format_spec_len == 0) {
|
||||
result = STRINGLIB_TOSTR(obj);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* parse the format_spec */
|
||||
if (!parse_internal_render_format_spec(format_spec, &format, 'd'))
|
||||
if (!parse_internal_render_format_spec(format_spec,
|
||||
format_spec_len,
|
||||
&format, 'd'))
|
||||
goto done;
|
||||
|
||||
/* type conversion? */
|
||||
|
@ -868,7 +840,7 @@ format_int_or_long(PyObject* value, PyObject* args, IntOrLongToString tostring)
|
|||
case 'n':
|
||||
/* no type conversion needed, already an int (or long). do
|
||||
the formatting */
|
||||
result = format_int_or_long_internal(value, &format, tostring);
|
||||
result = format_int_or_long_internal(obj, &format, tostring);
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
|
@ -879,10 +851,10 @@ format_int_or_long(PyObject* value, PyObject* args, IntOrLongToString tostring)
|
|||
case 'G':
|
||||
case '%':
|
||||
/* convert to float */
|
||||
tmp = PyNumber_Float(value);
|
||||
tmp = PyNumber_Float(obj);
|
||||
if (tmp == NULL)
|
||||
goto done;
|
||||
result = format_float_internal(value, &format);
|
||||
result = format_float_internal(obj, &format);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -917,9 +889,12 @@ long_format(PyObject* value, int base)
|
|||
#endif
|
||||
|
||||
PyObject *
|
||||
FORMAT_LONG(PyObject* value, PyObject* args)
|
||||
FORMAT_LONG(PyObject *obj,
|
||||
STRINGLIB_CHAR *format_spec,
|
||||
Py_ssize_t format_spec_len)
|
||||
{
|
||||
return format_int_or_long(value, args, long_format);
|
||||
return format_int_or_long(obj, format_spec, format_spec_len,
|
||||
long_format);
|
||||
}
|
||||
#endif /* FORMAT_LONG */
|
||||
|
||||
|
@ -935,32 +910,35 @@ int_format(PyObject* value, int base)
|
|||
}
|
||||
|
||||
PyObject *
|
||||
FORMAT_INT(PyObject* value, PyObject* args)
|
||||
FORMAT_INT(PyObject *obj,
|
||||
STRINGLIB_CHAR *format_spec,
|
||||
Py_ssize_t format_spec_len)
|
||||
{
|
||||
return format_int_or_long(value, args, int_format);
|
||||
return format_int_or_long(obj, format_spec, format_spec_len,
|
||||
int_format);
|
||||
}
|
||||
#endif /* FORMAT_INT */
|
||||
|
||||
#ifdef FORMAT_FLOAT
|
||||
PyObject *
|
||||
FORMAT_FLOAT(PyObject *value, PyObject *args)
|
||||
FORMAT_FLOAT(PyObject *obj,
|
||||
STRINGLIB_CHAR *format_spec,
|
||||
Py_ssize_t format_spec_len)
|
||||
{
|
||||
PyObject *format_spec;
|
||||
PyObject *result = NULL;
|
||||
InternalFormatSpec format;
|
||||
|
||||
if (!PyArg_ParseTuple(args, STRINGLIB_PARSE_CODE ":__format__", &format_spec))
|
||||
goto done;
|
||||
|
||||
/* check for the special case of zero length format spec, make
|
||||
it equivalent to str(value) */
|
||||
if (STRINGLIB_LEN(format_spec) == 0) {
|
||||
result = STRINGLIB_TOSTR(value);
|
||||
it equivalent to str(obj) */
|
||||
if (format_spec_len == 0) {
|
||||
result = STRINGLIB_TOSTR(obj);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* parse the format_spec */
|
||||
if (!parse_internal_render_format_spec(format_spec, &format, '\0'))
|
||||
if (!parse_internal_render_format_spec(format_spec,
|
||||
format_spec_len,
|
||||
&format, '\0'))
|
||||
goto done;
|
||||
|
||||
/* type conversion? */
|
||||
|
@ -979,7 +957,7 @@ FORMAT_FLOAT(PyObject *value, PyObject *args)
|
|||
case 'n':
|
||||
case '%':
|
||||
/* no conversion, already a float. do the formatting */
|
||||
result = format_float_internal(value, &format);
|
||||
result = format_float_internal(obj, &format);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -46,8 +46,6 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include "unicodeobject.h"
|
||||
#include "ucnhash.h"
|
||||
|
||||
#include "formatter_unicode.h"
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
@ -8202,6 +8200,19 @@ PyDoc_STRVAR(format__doc__,
|
|||
\n\
|
||||
");
|
||||
|
||||
static PyObject *
|
||||
unicode__format__(PyObject* self, PyObject* args)
|
||||
{
|
||||
PyObject *format_spec;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "U:__format__", &format_spec))
|
||||
return NULL;
|
||||
|
||||
return _PyUnicode_FormatAdvanced(self,
|
||||
PyUnicode_AS_UNICODE(format_spec),
|
||||
PyUnicode_GET_SIZE(format_spec));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(p_format__doc__,
|
||||
"S.__format__(format_spec) -> str\n\
|
||||
\n\
|
||||
|
@ -8259,7 +8270,7 @@ static PyMethodDef unicode_methods[] = {
|
|||
{"isidentifier", (PyCFunction) unicode_isidentifier, METH_NOARGS, isidentifier__doc__},
|
||||
{"zfill", (PyCFunction) unicode_zfill, METH_VARARGS, zfill__doc__},
|
||||
{"format", (PyCFunction) do_string_format, METH_VARARGS | METH_KEYWORDS, format__doc__},
|
||||
{"__format__", (PyCFunction) unicode_unicode__format__, METH_VARARGS, p_format__doc__},
|
||||
{"__format__", (PyCFunction) unicode__format__, METH_VARARGS, p_format__doc__},
|
||||
{"_formatter_field_name_split", (PyCFunction) formatter_field_name_split, METH_NOARGS},
|
||||
{"_formatter_parser", (PyCFunction) formatter_parser, METH_NOARGS},
|
||||
{"maketrans", (PyCFunction) unicode_maketrans,
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
of int.__float__, etc., that take and return unicode objects */
|
||||
|
||||
#include "Python.h"
|
||||
#include "formatter_unicode.h"
|
||||
|
||||
#include "../Objects/stringlib/unicodedefs.h"
|
||||
|
||||
#define FORMAT_STRING unicode_unicode__format__
|
||||
#define FORMAT_LONG unicode_long__format__
|
||||
#define FORMAT_FLOAT unicode_float__format__
|
||||
|
||||
#define FORMAT_STRING _PyUnicode_FormatAdvanced
|
||||
#define FORMAT_LONG _PyLong_FormatAdvanced
|
||||
#define FORMAT_FLOAT _PyFloat_FormatAdvanced
|
||||
|
||||
#include "../Objects/stringlib/formatter.h"
|
||||
|
|
Loading…
Reference in New Issue