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
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com