[Python-Dev] Comparison speed

Martin v. Loewis martin@loewis.home.cs.tu-berlin.de
Mon, 14 May 2001 23:55:39 +0200


> Anybody care to take a stab at making the new richcmp and/or coerce
> code ugly again?

Hi Tim,

With CVS Python, 1000000 iterations, and a for loop, I currently got

0.780
0.770
0.770
0.780
0.770
0.770
0.770
0.780
0.770
0.770

With the patch below, I get

0.720
0.710
0.710
0.720
0.710
0.710
0.710
0.720
0.710
0.710

The idea is to let strings support richcmp; this also allows some
optimization for the EQ case.

Please let me know what you think.

Martin

Index: stringobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/stringobject.c,v
retrieving revision 2.115
diff -u -r2.115 stringobject.c
--- stringobject.c	2001/05/10 00:32:57	2.115
+++ stringobject.c	2001/05/14 21:36:36
@@ -596,6 +596,51 @@
 	return (len_a < len_b) ? -1 : (len_a > len_b) ? 1 : 0;
 }
 
+/* In the signature, only a is guaranteed to be a PyStringObject.
+   However, as the first thing in the function, we check that b
+   is of that type also.  */
+
+static PyObject*
+string_richcompare(PyStringObject *a, PyStringObject *b, int op)
+{
+	int c;
+	PyObject *result;
+	if (!PyString_Check(b)) {
+		result = Py_NotImplemented;
+		goto out;
+	}
+	if (op == Py_EQ) {
+		if (a->ob_size != b->ob_size) {
+			result = Py_False;
+			goto out;
+		}
+#ifdef CACHE_HASH
+		if (a->ob_shash != b->ob_shash
+		    && a->ob_shash != -1 
+		    && b->ob_shash != -1) {
+			result = Py_False;
+			goto out;
+		}
+#endif
+	}
+	c = string_compare(a, b);
+	switch (op) {
+	case Py_LT: c = c <  0; break;
+	case Py_LE: c = c <= 0; break;
+	case Py_EQ: c = c == 0; break;
+	case Py_NE: c = c != 0; break;
+	case Py_GT: c = c >  0; break;
+	case Py_GE: c = c >= 0; break;
+	default:
+		result = Py_NotImplemented;
+		goto out;
+	}
+	result = c ? Py_True : Py_False;
+  out:
+	Py_INCREF(result);
+	return result;
+}
+
 static long
 string_hash(PyStringObject *a)
 {
@@ -2409,6 +2454,12 @@
 	&string_as_buffer,	/*tp_as_buffer*/
 	Py_TPFLAGS_DEFAULT,	/*tp_flags*/
 	0,		/*tp_doc*/
+	0,		/*tp_traverse*/
+	0,		/*tp_clear*/
+	(richcmpfunc)string_richcompare,	/*tp_richcompare*/
+	0,		/*tp_weaklistoffset*/
+	0,		/*tp_iter*/
+	0,		/*tp_iternext*/
 };
 
 void