]> granicus.if.org Git - python/commitdiff
Variation of patch # 1624059 to speed up checking if an object is a subclass
authorNeal Norwitz <nnorwitz@gmail.com>
Sun, 25 Feb 2007 19:44:48 +0000 (19:44 +0000)
committerNeal Norwitz <nnorwitz@gmail.com>
Sun, 25 Feb 2007 19:44:48 +0000 (19:44 +0000)
of some of the common builtin types.

Use a bit in tp_flags for each common builtin type.  Check the bit
to determine if any instance is a subclass of these common types.
The check avoids a function call and O(n) search of the base classes.
The check is done in the various Py*_Check macros rather than calling
PyType_IsSubtype().

All the bits are set in tp_flags when the type is declared
in the Objects/*object.c files because PyType_Ready() is not called
for all the types.  Should PyType_Ready() be called for all types?
If so and the change is made, the changes to the Objects/*object.c files
can be reverted (remove setting the tp_flags).  Objects/typeobject.c
would also have to be modified to add conditions
for Py*_CheckExact() in addition to each the PyType_IsSubtype check.

18 files changed:
Include/dictobject.h
Include/intobject.h
Include/listobject.h
Include/longobject.h
Include/object.h
Include/pyerrors.h
Include/stringobject.h
Include/tupleobject.h
Include/unicodeobject.h
Objects/dictobject.c
Objects/exceptions.c
Objects/intobject.c
Objects/listobject.c
Objects/longobject.c
Objects/stringobject.c
Objects/tupleobject.c
Objects/typeobject.c
Objects/unicodeobject.c

index 44b0838e04210ef77b33ef3f7361a60b8c628d31..ec2e0c82149e10de1628dbe5a54b63b8a4bb0c8c 100644 (file)
@@ -90,7 +90,8 @@ struct _dictobject {
 
 PyAPI_DATA(PyTypeObject) PyDict_Type;
 
-#define PyDict_Check(op) PyObject_TypeCheck(op, &PyDict_Type)
+#define PyDict_Check(op) \
+                 PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_DICT_SUBCLASS)
 #define PyDict_CheckExact(op) ((op)->ob_type == &PyDict_Type)
 
 PyAPI_FUNC(PyObject *) PyDict_New(void);
index 1f4846e86f222427ec21f74e86ac359160a4a28e..51d3e1bfa93b3831cc054ceb82c52ae1ac7b9e1a 100644 (file)
@@ -27,7 +27,8 @@ typedef struct {
 
 PyAPI_DATA(PyTypeObject) PyInt_Type;
 
-#define PyInt_Check(op) PyObject_TypeCheck(op, &PyInt_Type)
+#define PyInt_Check(op) \
+                PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_INT_SUBCLASS)
 #define PyInt_CheckExact(op) ((op)->ob_type == &PyInt_Type)
 
 PyAPI_FUNC(PyObject *) PyInt_FromString(char*, char**, int);
index d9012ce93ec9bdecbf56e9b0ca55cc7c91903fe1..db3124ed56d953641bc75592e4f8963c5a92864c 100644 (file)
@@ -40,7 +40,8 @@ typedef struct {
 
 PyAPI_DATA(PyTypeObject) PyList_Type;
 
-#define PyList_Check(op) PyObject_TypeCheck(op, &PyList_Type)
+#define PyList_Check(op) \
+               PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_LIST_SUBCLASS)
 #define PyList_CheckExact(op) ((op)->ob_type == &PyList_Type)
 
 PyAPI_FUNC(PyObject *) PyList_New(Py_ssize_t size);
index eef4e9b4bcb893d5a0faba393a7a075177b0ceb4..3893ad6a82c6c70cbad20cf3960f90dcc8eb288e 100644 (file)
@@ -11,7 +11,8 @@ typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */
 
 PyAPI_DATA(PyTypeObject) PyLong_Type;
 
-#define PyLong_Check(op) PyObject_TypeCheck(op, &PyLong_Type)
+#define PyLong_Check(op) \
+               PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_LONG_SUBCLASS)
 #define PyLong_CheckExact(op) ((op)->ob_type == &PyLong_Type)
 
 PyAPI_FUNC(PyObject *) PyLong_FromLong(long);
index b0817e6e31c5c901f16cced708cb2d1da10879b4..0f6ff776b3b915524a921e5b82883151dc66ee79 100644 (file)
@@ -376,7 +376,8 @@ PyAPI_DATA(PyTypeObject) PyType_Type; /* built-in 'type' */
 PyAPI_DATA(PyTypeObject) PyBaseObject_Type; /* built-in 'object' */
 PyAPI_DATA(PyTypeObject) PySuper_Type; /* built-in 'super' */
 
-#define PyType_Check(op) PyObject_TypeCheck(op, &PyType_Type)
+#define PyType_Check(op) \
+       PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_TYPE_SUBCLASS)
 #define PyType_CheckExact(op) ((op)->ob_type == &PyType_Type)
 
 PyAPI_FUNC(int) PyType_Ready(PyTypeObject *);
@@ -517,6 +518,17 @@ given type object has a specified feature.
 /* Objects support nb_index in PyNumberMethods */
 #define Py_TPFLAGS_HAVE_INDEX (1L<<17)
 
+/* These flags are used to determine if a type is a subclass. */
+#define Py_TPFLAGS_INT_SUBCLASS                (1L<<23)
+#define Py_TPFLAGS_LONG_SUBCLASS       (1L<<24)
+#define Py_TPFLAGS_LIST_SUBCLASS       (1L<<25)
+#define Py_TPFLAGS_TUPLE_SUBCLASS      (1L<<26)
+#define Py_TPFLAGS_STRING_SUBCLASS     (1L<<27)
+#define Py_TPFLAGS_UNICODE_SUBCLASS    (1L<<28)
+#define Py_TPFLAGS_DICT_SUBCLASS       (1L<<29)
+#define Py_TPFLAGS_BASE_EXC_SUBCLASS   (1L<<30)
+#define Py_TPFLAGS_TYPE_SUBCLASS       (1L<<31)
+
 #define Py_TPFLAGS_DEFAULT  ( \
                              Py_TPFLAGS_HAVE_GETCHARBUFFER | \
                              Py_TPFLAGS_HAVE_SEQUENCE_IN | \
@@ -530,6 +542,7 @@ given type object has a specified feature.
                             0)
 
 #define PyType_HasFeature(t,f)  (((t)->tp_flags & (f)) != 0)
+#define PyType_FastSubclass(t,f)  PyType_HasFeature(t,f)
 
 
 /*
index 9532e32b469e8897a509fc6a3dedc5f8ba2f4c96..96716926d0d3480bbab47050d93735baf5c08bf7 100644 (file)
@@ -95,14 +95,12 @@ PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**);
 /* */
 
 #define PyExceptionClass_Check(x)                                      \
-       (PyClass_Check((x))                                             \
-        || (PyType_Check((x)) && PyType_IsSubtype(                     \
-                    (PyTypeObject*)(x), (PyTypeObject*)PyExc_BaseException)))
-
+       (PyClass_Check((x)) || (PyType_Check((x)) &&                    \
+         PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS)))
 
 #define PyExceptionInstance_Check(x)                   \
        (PyInstance_Check((x)) ||                       \
-        (PyType_IsSubtype((x)->ob_type, (PyTypeObject*)PyExc_BaseException)))
+        PyType_FastSubclass((x)->ob_type, Py_TPFLAGS_BASE_EXC_SUBCLASS))
 
 #define PyExceptionClass_Name(x)                                  \
        (PyClass_Check((x))                                        \
index 5f8a6f02a041e75ab5b8067aa42eb76da7df5a88..03c377763b6095251eb53adc564142c41c4aa361 100644 (file)
@@ -55,7 +55,8 @@ typedef struct {
 PyAPI_DATA(PyTypeObject) PyBaseString_Type;
 PyAPI_DATA(PyTypeObject) PyString_Type;
 
-#define PyString_Check(op) PyObject_TypeCheck(op, &PyString_Type)
+#define PyString_Check(op) \
+                 PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_STRING_SUBCLASS)
 #define PyString_CheckExact(op) ((op)->ob_type == &PyString_Type)
 
 PyAPI_FUNC(PyObject *) PyString_FromStringAndSize(const char *, Py_ssize_t);
index 8c37cabdca36ef9ebf624bd95d7eaadac7a81fd2..738cea1e97cc2a131c8158ff9c78202152d3674c 100644 (file)
@@ -33,7 +33,8 @@ typedef struct {
 
 PyAPI_DATA(PyTypeObject) PyTuple_Type;
 
-#define PyTuple_Check(op) PyObject_TypeCheck(op, &PyTuple_Type)
+#define PyTuple_Check(op) \
+                 PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_TUPLE_SUBCLASS)
 #define PyTuple_CheckExact(op) ((op)->ob_type == &PyTuple_Type)
 
 PyAPI_FUNC(PyObject *) PyTuple_New(Py_ssize_t size);
index 33aa185814abe39c7489c3238ba47bdb17f3e840..0bad8c32a2b1e52cc10c2a16149d37ed26327ea7 100644 (file)
@@ -392,7 +392,8 @@ typedef struct {
 
 PyAPI_DATA(PyTypeObject) PyUnicode_Type;
 
-#define PyUnicode_Check(op) PyObject_TypeCheck(op, &PyUnicode_Type)
+#define PyUnicode_Check(op) \
+                 PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_UNICODE_SUBCLASS)
 #define PyUnicode_CheckExact(op) ((op)->ob_type == &PyUnicode_Type)
 
 /* Fast access macros */
index 1cb3ee6ad862db9187a43130ec67c32f148dceaf..587dad390e615d3400d9bc585158ce0a88e18f0b 100644 (file)
@@ -2112,7 +2112,7 @@ PyTypeObject PyDict_Type = {
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
-               Py_TPFLAGS_BASETYPE,            /* tp_flags */
+               Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DICT_SUBCLASS, /* tp_flags */
        dictionary_doc,                         /* tp_doc */
        dict_traverse,                          /* tp_traverse */
        dict_tp_clear,                          /* tp_clear */
index 0cd819c5a1559396d9aa43ce64615d22578fffbc..c6ea6a40c4fd82124dfc8b127428d291bfccdc04 100644 (file)
@@ -300,7 +300,8 @@ static PyTypeObject _PyExc_BaseException = {
     PyObject_GenericGetAttr,    /*tp_getattro*/
     PyObject_GenericSetAttr,    /*tp_setattro*/
     0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  /*tp_flags*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
+       Py_TPFLAGS_BASE_EXC_SUBCLASS,  /*tp_flags*/
     PyDoc_STR("Common base class for all exceptions"), /* tp_doc */
     (traverseproc)BaseException_traverse, /* tp_traverse */
     (inquiry)BaseException_clear, /* tp_clear */
index f504af7a4ed50105cbe2993c3eb4ad381ba2bb9f..9ffc2950f2e00a60dbaa376aa8d79af527ccd0c8 100644 (file)
@@ -1138,7 +1138,7 @@ PyTypeObject PyInt_Type = {
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
-               Py_TPFLAGS_BASETYPE,            /* tp_flags */
+               Py_TPFLAGS_BASETYPE | Py_TPFLAGS_INT_SUBCLASS,  /* tp_flags */
        int_doc,                                /* tp_doc */
        0,                                      /* tp_traverse */
        0,                                      /* tp_clear */
index 3083b5f3e016fc293c8dd00cd9297ba6fc5bbf69..2ac5e86f576cc2c1a02e0c71deb590822a77aad8 100644 (file)
@@ -2672,7 +2672,7 @@ PyTypeObject PyList_Type = {
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
-               Py_TPFLAGS_BASETYPE,            /* tp_flags */
+               Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LIST_SUBCLASS, /* tp_flags */
        list_doc,                               /* tp_doc */
        (traverseproc)list_traverse,            /* tp_traverse */
        (inquiry)list_clear,                    /* tp_clear */
index 4d886cd7242b27eff3888f513125ed932c4eab8d..ef3e242cc47ed6d0443aabb02f2a5a86273c4cb4 100644 (file)
@@ -3418,7 +3418,7 @@ PyTypeObject PyLong_Type = {
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
-               Py_TPFLAGS_BASETYPE,            /* tp_flags */
+               Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
        long_doc,                               /* tp_doc */
        0,                                      /* tp_traverse */
        0,                                      /* tp_clear */
index 416457d5a59b277f4b6e9d95bd647719988c0c88..ca94d72b3112e142d5720e812746045f2cf7d1d4 100644 (file)
@@ -4017,7 +4017,7 @@ PyTypeObject PyString_Type = {
        0,                                      /* tp_setattro */
        &string_as_buffer,                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
-               Py_TPFLAGS_BASETYPE,            /* tp_flags */
+               Py_TPFLAGS_BASETYPE | Py_TPFLAGS_STRING_SUBCLASS,               /* tp_flags */
        string_doc,                             /* tp_doc */
        0,                                      /* tp_traverse */
        0,                                      /* tp_clear */
index c85b35a6037396e95c558d2775903a97a3e847f2..dacc3ee36f89b64334eb66278ea74280258714fb 100644 (file)
@@ -669,7 +669,7 @@ PyTypeObject PyTuple_Type = {
        0,                                      /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
-               Py_TPFLAGS_BASETYPE,            /* tp_flags */
+               Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TUPLE_SUBCLASS, /* tp_flags */
        tuple_doc,                              /* tp_doc */
        (traverseproc)tupletraverse,            /* tp_traverse */
        0,                                      /* tp_clear */
index 20b530c4343921b7d88d7475e41e309438a2a8f2..4b0816e02aeedc753bad40ce732d1c0460bd8a19 100644 (file)
@@ -2288,7 +2288,7 @@ PyTypeObject PyType_Type = {
        (setattrofunc)type_setattro,            /* tp_setattro */
        0,                                      /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
-               Py_TPFLAGS_BASETYPE,            /* tp_flags */
+               Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TYPE_SUBCLASS, /* tp_flags */
        type_doc,                               /* tp_doc */
        (traverseproc)type_traverse,            /* tp_traverse */
        (inquiry)type_clear,                    /* tp_clear */
@@ -2967,6 +2967,26 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
        if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) {
                COPYVAL(tp_dictoffset);
        }
+
+       /* Setup fast subclass flags */
+       if (PyType_IsSubtype(base, (PyTypeObject*)PyExc_BaseException))
+               type->tp_flags |= Py_TPFLAGS_BASE_EXC_SUBCLASS;
+       else if (PyType_IsSubtype(base, &PyType_Type))
+               type->tp_flags |= Py_TPFLAGS_TYPE_SUBCLASS;
+       else if (PyType_IsSubtype(base, &PyInt_Type))
+               type->tp_flags |= Py_TPFLAGS_INT_SUBCLASS;
+       else if (PyType_IsSubtype(base, &PyLong_Type))
+               type->tp_flags |= Py_TPFLAGS_LONG_SUBCLASS;
+       else if (PyType_IsSubtype(base, &PyString_Type))
+               type->tp_flags |= Py_TPFLAGS_STRING_SUBCLASS;
+       else if (PyType_IsSubtype(base, &PyUnicode_Type))
+               type->tp_flags |= Py_TPFLAGS_UNICODE_SUBCLASS;
+       else if (PyType_IsSubtype(base, &PyTuple_Type))
+               type->tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS;
+       else if (PyType_IsSubtype(base, &PyList_Type))
+               type->tp_flags |= Py_TPFLAGS_LIST_SUBCLASS;
+       else if (PyType_IsSubtype(base, &PyDict_Type))
+               type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS;
 }
 
 static void
index 290e8dfb4759cd6f8b22f4969045ee1eaf3b1e36..a49fe399c6a66867bd09dcbd656cfabe4c58857b 100644 (file)
@@ -7967,7 +7967,7 @@ PyTypeObject PyUnicode_Type = {
     0,                                 /* tp_setattro */
     &unicode_as_buffer,                        /* tp_as_buffer */
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
-           Py_TPFLAGS_BASETYPE,        /* tp_flags */
+           Py_TPFLAGS_BASETYPE | Py_TPFLAGS_UNICODE_SUBCLASS,  /* tp_flags */
     unicode_doc,                       /* tp_doc */
     0,                                 /* tp_traverse */
     0,                                 /* tp_clear */