Refactor and clean up str.format() code (and helpers) in advance of optimizations.
authorEric Smith <eric@trueblade.com>
Fri, 30 May 2008 18:10:19 +0000 (18:10 +0000)
committerEric Smith <eric@trueblade.com>
Fri, 30 May 2008 18:10:19 +0000 (18:10 +0000)
Include/floatobject.h
Include/formatter_unicode.h [deleted file]
Include/longobject.h
Include/unicodeobject.h
Makefile.pre.in
Objects/floatobject.c
Objects/longobject.c
Objects/stringlib/formatter.h
Objects/unicodeobject.c
Python/formatter_unicode.c

index 2021313c42c6f35d57e802fb9758da2a6286344c..650d5448ac7246256d84db00c710ab4824506d70 100644 (file)
@@ -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
diff --git a/Include/formatter_unicode.h b/Include/formatter_unicode.h
deleted file mode 100644 (file)
index ccca883..0000000
+++ /dev/null
@@ -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);
-
index 237e2e62946c88b0ed7f33b2d1aaac2763fa3409..73ca95119645e17c5bdbeb73cdfd0af09ddc8dc2 100644 (file)
@@ -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.
  */
index 79b9a8c5917dd04b6291f977b83c625f42880d9f..384cd5519f68a0ceb4280dec3a8c28d81e9f98b5 100644 (file)
@@ -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 *);
index f61041b1fe83bd3c6824368871d9e451bde6b247..63bac44a0ccc8f0eb857fa4c047c8d4bedb65c92 100644 (file)
@@ -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 \
index 76a5c2c5edc2465395c1fc96178a46dbd365046b..dd3ea938ffc360a172ce24dfbebf6872d40dbe42 100644 (file)
@@ -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,
index 08e767ee7e311b02df5346952fac2ee483b67ee6..10d03ae0b06690ac88f3882b5fd074a0625eb5fb 100644 (file)
@@ -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));
 }
 
 
index 05ccfeae3d2fbe50dbb1349fc1d0a375367fb4c1..2bb2ed2ca894a3ba5073b8283e13cb06d0d82ebf 100644 (file)
@@ -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:
index ca51b0cbce4d4816f64c0ab23c908e8224bfd601..78e38b5e3841a8004b5835e088e2c1a04b8e786d 100644 (file)
@@ -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,
index 114fe3016b8c26b49cc3e6b0c3bee0fa81e277b0..206b64037aa1f1db9c6285696fc235b56ebd7017 100644 (file)
@@ -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"