Patch #424335: Implement string_richcompare, remove string_compare.
               Use new _PyString_Eq in lookdict_string.
diff --git a/Include/stringobject.h b/Include/stringobject.h
index 12df75a..fbcff31 100644
--- a/Include/stringobject.h
+++ b/Include/stringobject.h
@@ -58,6 +58,7 @@
 extern DL_IMPORT(void) PyString_Concat(PyObject **, PyObject *);
 extern DL_IMPORT(void) PyString_ConcatAndDel(PyObject **, PyObject *);
 extern DL_IMPORT(int) _PyString_Resize(PyObject **, int);
+extern DL_IMPORT(int) _PyString_Eq(PyObject *, PyObject*);
 extern DL_IMPORT(PyObject *) PyString_Format(PyObject *, PyObject *);
 extern DL_IMPORT(PyObject *) _PyString_FormatLong(PyObject*, int, int,
 						  int, char**, int*);
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 2854efc..d5700c9 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -294,7 +294,7 @@
  * this assumption allows testing for errors during PyObject_Compare() to
  * be dropped; string-string comparisons never raise exceptions.  This also
  * means we don't need to go through PyObject_Compare(); we can always use
- * the tp_compare slot of the string type object directly.
+ * _PyString_Eq directly.
  *
  * This really only becomes meaningful if proper error handling in lookdict()
  * is too expensive.
@@ -308,7 +308,6 @@
 	register unsigned int mask = mp->ma_size-1;
 	dictentry *ep0 = mp->ma_table;
 	register dictentry *ep;
-	cmpfunc compare = PyString_Type.tp_compare;
 
 	/* make sure this function doesn't have to handle non-string keys */
 	if (!PyString_Check(key)) {
@@ -328,7 +327,7 @@
 		freeslot = ep;
 	else {
 		if (ep->me_hash == hash
-		    && compare(ep->me_key, key) == 0) {
+		    && _PyString_Eq(ep->me_key, key)) {
 			return ep;
 		}
 		freeslot = NULL;
@@ -347,7 +346,7 @@
 		if (ep->me_key == key
 		    || (ep->me_hash == hash
 		        && ep->me_key != dummy
-			&& compare(ep->me_key, key) == 0))
+			&& _PyString_Eq(ep->me_key, key)))
 			return ep;
 		if (ep->me_key == dummy && freeslot == NULL)
 			freeslot = ep;
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
index cf6421a..da49d81 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -630,20 +630,79 @@
 	return v;
 }
 
-static int
-string_compare(PyStringObject *a, PyStringObject *b)
+static PyObject*
+string_richcompare(PyStringObject *a, PyStringObject *b, int op)
 {
-	int len_a = a->ob_size, len_b = b->ob_size;
-	int min_len = (len_a < len_b) ? len_a : len_b;
-	int cmp;
-	if (min_len > 0) {
-		cmp = Py_CHARMASK(*a->ob_sval) - Py_CHARMASK(*b->ob_sval);
-		if (cmp == 0)
-			cmp = memcmp(a->ob_sval, b->ob_sval, min_len);
-		if (cmp != 0)
-			return cmp;
+	int c;
+	int len_a, len_b;
+	int min_len;
+	PyObject *result;
+
+	/* One of the objects is a string object. Make sure the
+	   other one is one, too.  */
+	if (a->ob_type != b->ob_type) {
+		result = Py_NotImplemented;
+		goto out;
 	}
-	return (len_a < len_b) ? -1 : (len_a > len_b) ? 1 : 0;
+	if (a == b) {
+		switch (op) {
+		case Py_EQ:case Py_LE:case Py_GE:
+			result = Py_True;
+			goto out;
+		case Py_NE:case Py_LT:case Py_GT:
+			result = Py_False;
+			goto out;
+		}
+	}
+	if (op == Py_EQ) {
+		/* Supporting Py_NE here as well does not save
+		   much time, since Py_NE is rarely used.  */
+		if (a->ob_size == b->ob_size
+		    && (a->ob_sval[0] == b->ob_sval[0]
+			&& memcmp(a->ob_sval, b->ob_sval, 
+				  a->ob_size) == 0)) {
+			result = Py_True;
+		} else {
+			result = Py_False;
+		}
+		goto out;
+	}
+	len_a = a->ob_size; len_b = b->ob_size;
+	min_len = (len_a < len_b) ? len_a : len_b;
+	if (min_len > 0) {
+		c = Py_CHARMASK(*a->ob_sval) - Py_CHARMASK(*b->ob_sval);
+		if (c==0)
+			c = memcmp(a->ob_sval, b->ob_sval, min_len);
+	}else
+		c = 0;
+	if (c == 0)
+		c = (len_a < len_b) ? -1 : (len_a > len_b) ? 1 : 0;
+	switch (op) {
+	case Py_LT: c = c <  0; break;
+	case Py_LE: c = c <= 0; break;
+	case Py_EQ: assert(0);  break; /* unreachable */
+	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;
+}
+
+int
+_PyString_Eq(PyObject *o1, PyObject *o2)
+{
+	PyStringObject *a, *b;
+	a = (PyStringObject*)o1;
+	b = (PyStringObject*)o2;
+        return a->ob_size == b->ob_size
+          && *a->ob_sval == *b->ob_sval
+          && memcmp(a->ob_sval, b->ob_sval, a->ob_size) == 0;
 }
 
 static long
@@ -2466,7 +2525,7 @@
 	(printfunc)string_print, /*tp_print*/
 	(getattrfunc)string_getattr,		/*tp_getattr*/
 	0,		/*tp_setattr*/
-	(cmpfunc)string_compare, /*tp_compare*/
+	0,		/*tp_compare*/
 	(reprfunc)string_repr, /*tp_repr*/
 	0,		/*tp_as_number*/
 	&string_as_sequence,	/*tp_as_sequence*/
@@ -2479,6 +2538,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