On 8/15/06, "Martin v. Löwis" <[EMAIL PROTECTED]> wrote:

That penalty is already paid today. Much code dealing with
ints has a type test whether it's an int or a long. If
int and long become subtypes of each other or of some abstract
type, performance will decrease even more because a subtype
test is quite expensive if the object is neither int nor
long (it has to traverse the entire base type hierarchy to
find out its not inherited from int).

I was playing around with a little patch to avoid that penalty.  It
doesn't take any additional memory, just a handful of bits we aren't
using. :-)

For the more common builtin types, it stores whether it's a subclass
in tp_flags, so there's no function call necessary and it's a constant
time operation.  It was faster when doing simple stuff.  Haven't
thought much whether this is really worthwhile or not.

n
Index: Include/stringobject.h
===================================================================
--- Include/stringobject.h	(revision 51237)
+++ Include/stringobject.h	(working copy)
@@ -55,8 +55,9 @@
 PyAPI_DATA(PyTypeObject) PyBaseString_Type;
 PyAPI_DATA(PyTypeObject) PyString_Type;
 
-#define PyString_Check(op) PyObject_TypeCheck(op, &PyString_Type)
 #define PyString_CheckExact(op) ((op)->ob_type == &PyString_Type)
+#define PyString_Check(op) (PyString_CheckExact(op) || \
+                 PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_STRING_SUBCLASS))
 
 PyAPI_FUNC(PyObject *) PyString_FromStringAndSize(const char *, Py_ssize_t);
 PyAPI_FUNC(PyObject *) PyString_FromString(const char *);
Index: Include/dictobject.h
===================================================================
--- Include/dictobject.h	(revision 51237)
+++ Include/dictobject.h	(working copy)
@@ -90,8 +90,9 @@
 
 PyAPI_DATA(PyTypeObject) PyDict_Type;
 
-#define PyDict_Check(op) PyObject_TypeCheck(op, &PyDict_Type)
 #define PyDict_CheckExact(op) ((op)->ob_type == &PyDict_Type)
+#define PyDict_Check(op) (PyDict_CheckExact(op) || \
+                 PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_DICT_SUBCLASS))
 
 PyAPI_FUNC(PyObject *) PyDict_New(void);
 PyAPI_FUNC(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key);
Index: Include/unicodeobject.h
===================================================================
--- Include/unicodeobject.h	(revision 51237)
+++ Include/unicodeobject.h	(working copy)
@@ -390,8 +390,9 @@
 
 PyAPI_DATA(PyTypeObject) PyUnicode_Type;
 
-#define PyUnicode_Check(op) PyObject_TypeCheck(op, &PyUnicode_Type)
 #define PyUnicode_CheckExact(op) ((op)->ob_type == &PyUnicode_Type)
+#define PyUnicode_Check(op) (PyUnicode_CheckExact(op) || \
+                 PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_UNICODE_SUBCLASS))
 
 /* Fast access macros */
 #define PyUnicode_GET_SIZE(op) \
Index: Include/intobject.h
===================================================================
--- Include/intobject.h	(revision 51237)
+++ Include/intobject.h	(working copy)
@@ -27,8 +27,9 @@
 
 PyAPI_DATA(PyTypeObject) PyInt_Type;
 
-#define PyInt_Check(op) PyObject_TypeCheck(op, &PyInt_Type)
 #define PyInt_CheckExact(op) ((op)->ob_type == &PyInt_Type)
+#define PyInt_Check(op) (PyInt_CheckExact(op) || \
+		 PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_INT_SUBCLASS))
 
 PyAPI_FUNC(PyObject *) PyInt_FromString(char*, char**, int);
 #ifdef Py_USING_UNICODE
Index: Include/listobject.h
===================================================================
--- Include/listobject.h	(revision 51237)
+++ Include/listobject.h	(working copy)
@@ -40,8 +40,9 @@
 
 PyAPI_DATA(PyTypeObject) PyList_Type;
 
-#define PyList_Check(op) PyObject_TypeCheck(op, &PyList_Type)
 #define PyList_CheckExact(op) ((op)->ob_type == &PyList_Type)
+#define PyList_Check(op) (PyList_CheckExact(op) || \
+		PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_LIST_SUBCLASS))
 
 PyAPI_FUNC(PyObject *) PyList_New(Py_ssize_t size);
 PyAPI_FUNC(Py_ssize_t) PyList_Size(PyObject *);
Index: Include/object.h
===================================================================
--- Include/object.h	(revision 51237)
+++ Include/object.h	(working copy)
@@ -517,6 +517,18 @@
 /* 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. */
+/* Uses bits 30-27. */
+#define Py_TPFLAGS_FAST_SUBCLASS_MASK (0x78000000)
+#define Py_TPFLAGS_FAST_SUBCLASS (1L<<27)
+#define Py_TPFLAGS_INT_SUBCLASS		(Py_TPFLAGS_FAST_SUBCLASS | 0x70000000)
+#define Py_TPFLAGS_LONG_SUBCLASS	(Py_TPFLAGS_FAST_SUBCLASS | 0x60000000)
+#define Py_TPFLAGS_LIST_SUBCLASS	(Py_TPFLAGS_FAST_SUBCLASS | 0x50000000)
+#define Py_TPFLAGS_TUPLE_SUBCLASS	(Py_TPFLAGS_FAST_SUBCLASS | 0x40000000)
+#define Py_TPFLAGS_STRING_SUBCLASS	(Py_TPFLAGS_FAST_SUBCLASS | 0x30000000)
+#define Py_TPFLAGS_UNICODE_SUBCLASS	(Py_TPFLAGS_FAST_SUBCLASS | 0x20000000)
+#define Py_TPFLAGS_DICT_SUBCLASS	(Py_TPFLAGS_FAST_SUBCLASS | 0x10000000)
+
 #define Py_TPFLAGS_DEFAULT  ( \
                              Py_TPFLAGS_HAVE_GETCHARBUFFER | \
                              Py_TPFLAGS_HAVE_SEQUENCE_IN | \
@@ -530,6 +542,7 @@
                             0)
 
 #define PyType_HasFeature(t,f)  (((t)->tp_flags & (f)) != 0)
+#define PyType_FastSubclass(t,f)  (((t)->tp_flags & Py_TPFLAGS_FAST_SUBCLASS_MASK) == (f))
 
 
 /*
Index: Include/tupleobject.h
===================================================================
--- Include/tupleobject.h	(revision 51237)
+++ Include/tupleobject.h	(working copy)
@@ -33,8 +33,9 @@
 
 PyAPI_DATA(PyTypeObject) PyTuple_Type;
 
-#define PyTuple_Check(op) PyObject_TypeCheck(op, &PyTuple_Type)
 #define PyTuple_CheckExact(op) ((op)->ob_type == &PyTuple_Type)
+#define PyTuple_Check(op) (PyTuple_CheckExact(op) || \
+                 PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_TUPLE_SUBCLASS))
 
 PyAPI_FUNC(PyObject *) PyTuple_New(Py_ssize_t size);
 PyAPI_FUNC(Py_ssize_t) PyTuple_Size(PyObject *);
Index: Include/longobject.h
===================================================================
--- Include/longobject.h	(revision 51237)
+++ Include/longobject.h	(working copy)
@@ -11,8 +11,9 @@
 
 PyAPI_DATA(PyTypeObject) PyLong_Type;
 
-#define PyLong_Check(op) PyObject_TypeCheck(op, &PyLong_Type)
 #define PyLong_CheckExact(op) ((op)->ob_type == &PyLong_Type)
+#define PyLong_Check(op) (PyLong_CheckExact(op) || \
+		PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_LONG_SUBCLASS))
 
 PyAPI_FUNC(PyObject *) PyLong_FromLong(long);
 PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long);
Index: Objects/typeobject.c
===================================================================
--- Objects/typeobject.c	(revision 51237)
+++ Objects/typeobject.c	(working copy)
@@ -2956,6 +2956,22 @@
 	if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) {
 		COPYVAL(tp_dictoffset);
 	}
+
+	/* Setup fast subclass flags */
+	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
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to