]> granicus.if.org Git - python/commitdiff
Make int, long and float subclassable.
authorGuido van Rossum <guido@python.org>
Wed, 29 Aug 2001 15:47:46 +0000 (15:47 +0000)
committerGuido van Rossum <guido@python.org>
Wed, 29 Aug 2001 15:47:46 +0000 (15:47 +0000)
This uses a slightly wimpy and wasteful approach, but it works. :-)

Objects/floatobject.c
Objects/intobject.c
Objects/longobject.c

index 69aede4cc1950417c2ef334278487b1b56fcf027..295f47e8c6fe49ace8cd5a15f915b9bf2a85bf56 100644 (file)
@@ -626,13 +626,17 @@ float_float(PyObject *v)
 }
 
 
+staticforward PyObject *
+float_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
+
 static PyObject *
 float_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
        PyObject *x = Py_False; /* Integer zero */
        static char *kwlist[] = {"x", 0};
 
-       assert(type == &PyFloat_Type);
+       if (type != &PyFloat_Type)
+               return float_subtype_new(type, args, kwds); /* Wimp out */
        if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:float", kwlist, &x))
                return NULL;
        if (PyString_Check(x))
@@ -640,6 +644,29 @@ float_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
        return PyNumber_Float(x);
 }
 
+/* Wimpy, slow approach to tp_new calls for subtypes of float:
+   first create a regular float from whatever arguments we got,
+   then allocate a subtype instance and initialize its ob_fval
+   from the regular float.  The regular float is then thrown away.
+*/
+static PyObject *
+float_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       PyObject *tmp, *new;
+
+       assert(PyType_IsSubtype(type, &PyFloat_Type));
+       tmp = float_new(&PyFloat_Type, args, kwds);
+       if (tmp == NULL)
+               return NULL;
+       assert(PyFloat_Check(tmp));
+       new = type->tp_alloc(type, 0);;
+       if (new == NULL)
+               return NULL;
+       ((PyFloatObject *)new)->ob_fval = ((PyFloatObject *)tmp)->ob_fval;
+       Py_DECREF(tmp);
+       return new;
+}
+
 static char float_doc[] =
 "float(x) -> floating point number\n\
 \n\
@@ -708,7 +735,8 @@ PyTypeObject PyFloat_Type = {
        PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
-       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
+               Py_TPFLAGS_BASETYPE,            /* tp_flags */
        float_doc,                              /* tp_doc */
        0,                                      /* tp_traverse */
        0,                                      /* tp_clear */
@@ -750,7 +778,7 @@ PyFloat_Fini(void)
                for (i = 0, p = &list->objects[0];
                     i < N_FLOATOBJECTS;
                     i++, p++) {
-                       if (PyFloat_Check(p) && p->ob_refcnt != 0)
+                       if (p->ob_type == &PyFloat_Type && p->ob_refcnt != 0)
                                frem++;
                }
                next = list->next;
@@ -760,7 +788,8 @@ PyFloat_Fini(void)
                        for (i = 0, p = &list->objects[0];
                             i < N_FLOATOBJECTS;
                             i++, p++) {
-                               if (!PyFloat_Check(p) || p->ob_refcnt == 0) {
+                               if (p->ob_type != &PyFloat_Type ||
+                                   p->ob_refcnt == 0) {
                                        p->ob_type = (struct _typeobject *)
                                                free_list;
                                        free_list = p;
@@ -792,7 +821,8 @@ PyFloat_Fini(void)
                        for (i = 0, p = &list->objects[0];
                             i < N_FLOATOBJECTS;
                             i++, p++) {
-                               if (PyFloat_Check(p) && p->ob_refcnt != 0) {
+                               if (p->ob_type == &PyFloat_Type &&
+                                   p->ob_refcnt != 0) {
                                        char buf[100];
                                        PyFloat_AsString(buf, p);
                                        fprintf(stderr,
index 77d7e387bd85828cc96e675e0821ce147c1c9357..80cdf4b4208b3c81b03918fb38623e6b58ec376c 100644 (file)
@@ -134,8 +134,12 @@ PyInt_FromLong(long ival)
 static void
 int_dealloc(PyIntObject *v)
 {
-       v->ob_type = (struct _typeobject *)free_list;
-       free_list = v;
+       if (v->ob_type == &PyInt_Type) {
+               v->ob_type = (struct _typeobject *)free_list;
+               free_list = v;
+       }
+       else
+               v->ob_type->tp_free((PyObject *)v);
 }
 
 long
@@ -783,6 +787,9 @@ int_hex(PyIntObject *v)
        return PyString_FromString(buf);
 }
 
+staticforward PyObject *
+int_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
+
 static PyObject *
 int_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
@@ -790,7 +797,8 @@ int_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
        int base = -909;
        static char *kwlist[] = {"x", "base", 0};
 
-       assert(type == &PyInt_Type);
+       if (type != &PyInt_Type)
+               return int_subtype_new(type, args, kwds); /* Wimp out */
        if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:int", kwlist,
                                         &x, &base))
                return NULL;
@@ -811,6 +819,29 @@ int_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
        return NULL;
 }
 
+/* Wimpy, slow approach to tp_new calls for subtypes of int:
+   first create a regular int from whatever arguments we got,
+   then allocate a subtype instance and initialize its ob_ival
+   from the regular int.  The regular int is then thrown away.
+*/
+static PyObject *
+int_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       PyObject *tmp, *new;
+
+       assert(PyType_IsSubtype(type, &PyInt_Type));
+       tmp = int_new(&PyInt_Type, args, kwds);
+       if (tmp == NULL)
+               return NULL;
+       assert(PyInt_Check(tmp));
+       new = type->tp_alloc(type, 0);;
+       if (new == NULL)
+               return NULL;
+       ((PyIntObject *)new)->ob_ival = ((PyIntObject *)tmp)->ob_ival;
+       Py_DECREF(tmp);
+       return new;
+}
+
 static char int_doc[] =
 "int(x[, base]) -> integer\n\
 \n\
@@ -882,7 +913,8 @@ PyTypeObject PyInt_Type = {
        PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
-       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
+               Py_TPFLAGS_BASETYPE,            /* tp_flags */
        int_doc,                                /* tp_doc */
        0,                                      /* tp_traverse */
        0,                                      /* tp_clear */
@@ -934,7 +966,7 @@ PyInt_Fini(void)
                for (i = 0, p = &list->objects[0];
                     i < N_INTOBJECTS;
                     i++, p++) {
-                       if (PyInt_Check(p) && p->ob_refcnt != 0)
+                       if (p->ob_type == &PyInt_Type && p->ob_refcnt != 0)
                                irem++;
                }
                next = list->next;
@@ -944,7 +976,8 @@ PyInt_Fini(void)
                        for (i = 0, p = &list->objects[0];
                             i < N_INTOBJECTS;
                             i++, p++) {
-                               if (!PyInt_Check(p) || p->ob_refcnt == 0) {
+                               if (p->ob_type != &PyInt_Type ||
+                                   p->ob_refcnt == 0) {
                                        p->ob_type = (struct _typeobject *)
                                                free_list;
                                        free_list = p;
@@ -986,7 +1019,7 @@ PyInt_Fini(void)
                        for (i = 0, p = &list->objects[0];
                             i < N_INTOBJECTS;
                             i++, p++) {
-                               if (PyInt_Check(p) && p->ob_refcnt != 0)
+                               if (p->ob_type == &PyInt_Type && p->ob_refcnt != 0)
                                        fprintf(stderr,
                                "#   <int at %p, refcnt=%d, val=%ld>\n",
                                                p, p->ob_refcnt, p->ob_ival);
index 01a7276893426c7ade9f0f95cd5ad90802019b54..ea0685ec1a94f1a4d956d456add8e80cdd431531 100644 (file)
@@ -2038,6 +2038,8 @@ long_hex(PyObject *v)
 {
        return long_format(v, 16, 1);
 }
+staticforward PyObject *
+long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
 
 static PyObject *
 long_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
@@ -2046,7 +2048,8 @@ long_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
        int base = -909;                     /* unlikely! */
        static char *kwlist[] = {"x", "base", 0};
 
-       assert(type == &PyLong_Type);
+       if (type != &PyLong_Type)
+               return long_subtype_new(type, args, kwds); /* Wimp out */
        if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:long", kwlist,
                                         &x, &base))
                return NULL;
@@ -2069,6 +2072,36 @@ long_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
        }
 }
 
+/* Wimpy, slow approach to tp_new calls for subtypes of long:
+   first create a regular long from whatever arguments we got,
+   then allocate a subtype instance and initialize it from
+   the regular long.  The regular long is then thrown away.
+*/
+static PyObject *
+long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+       PyLongObject *tmp, *new;
+       int i, n;
+
+       assert(PyType_IsSubtype(type, &PyLong_Type));
+       tmp = (PyLongObject *)long_new(&PyLong_Type, args, kwds);
+       if (tmp == NULL)
+               return NULL;
+       assert(PyLong_Check(tmp));
+       n = tmp->ob_size;
+       if (n < 0)
+               n = -n;
+       new = (PyLongObject *)type->tp_alloc(type, n);
+       if (new == NULL)
+               return NULL;
+       assert(PyLong_Check(new));
+       new->ob_size = type->ob_size;
+       for (i = 0; i < n; i++)
+               new->ob_digit[i] = tmp->ob_digit[i];
+       Py_DECREF(tmp);
+       return (PyObject *)new;
+}
+
 static char long_doc[] =
 "long(x[, base]) -> integer\n\
 \n\
@@ -2140,7 +2173,8 @@ PyTypeObject PyLong_Type = {
        PyObject_GenericGetAttr,                /* tp_getattro */
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
-       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
+               Py_TPFLAGS_BASETYPE,            /* tp_flags */
        long_doc,                               /* tp_doc */
        0,                                      /* tp_traverse */
        0,                                      /* tp_clear */