diff -u b/Objects/bytesobject.c b/Objects/bytesobject.c --- b/Objects/bytesobject.c Mon Jan 20 15:55:49 2014 -0600 +++ b/Objects/bytesobject.c Tue Jan 21 18:35:23 2014 -0600 @@ -1486,78 +1486,94 @@ } static PyObject* -bytes_richcompare(PyBytesObject *a, PyBytesObject *b, int op) +bytes_richcompare(PyObject *self, PyObject *other, int op) { - int c; - Py_ssize_t len_a, len_b; - Py_ssize_t min_len; - PyObject *result; - - /* Make sure both arguments are strings. */ - if (!(PyBytes_Check(a) && PyBytes_Check(b))) { - int have_str = (PyObject_IsInstance((PyObject*)a, - (PyObject*)&PyUnicode_Type) || - PyObject_IsInstance((PyObject*)b, - (PyObject*)&PyUnicode_Type)); - if (Py_BytesWarningFlag && (op == Py_EQ || op == Py_NE) && have_str) { - if (PyErr_WarnEx(PyExc_BytesWarning, - "Comparison between bytes and string", 1)) - return NULL; - } - if (Py_BytesComplatibleFormatFlag) - return bytes_compatible_compare((PyObject *)a, (PyObject *)b, op); - result = Py_NotImplemented; - } - else if (a == b) { + Py_ssize_t self_size, other_size; + Py_buffer self_bytes, other_bytes; + PyObject *res; + Py_ssize_t minsize; + int cmp; + + /* fast-path for same object */ + if (self == other) { switch (op) { case Py_EQ: case Py_LE: case Py_GE: /* a string is equal to itself */ - result = Py_True; - break; + res = Py_True; + Py_INCREF(res); + return res; case Py_NE: case Py_LT: case Py_GT: - result = Py_False; - break; + res = Py_False; + Py_INCREF(res); + return res; default: PyErr_BadArgument(); return NULL; } } - else if (op == Py_EQ || op == Py_NE) { - int eq = bytes_compare_eq(a, b); - eq ^= (op == Py_NE); - result = eq ? Py_True : Py_False; + + if (Py_BytesWarningFlag && (op == Py_EQ || op == Py_NE) && + (PyObject_IsInstance(self, (PyObject*)&PyUnicode_Type) || + PyObject_IsInstance(other, (PyObject*)&PyUnicode_Type))) { + if (PyErr_WarnEx(PyExc_BytesWarning, + "Comparison between bytearray and string", 1)) + return NULL; + if (Py_BytesComplatibleFormatFlag) + return bytes_compatible_compare(self, other, op); + } + + self_size = _getbuffer(self, &self_bytes); + if (self_size < 0) { + PyErr_Clear(); + Py_RETURN_NOTIMPLEMENTED; + } + + other_size = _getbuffer(other, &other_bytes); + if (other_size < 0) { + PyErr_Clear(); + PyBuffer_Release(&self_bytes); + Py_RETURN_NOTIMPLEMENTED; + } + + if (self_size != other_size && (op == Py_EQ || op == Py_NE)) { + /* Shortcut: if the lengths differ, the objects differ */ + cmp = (op == Py_NE); } else { - len_a = Py_SIZE(a); - len_b = Py_SIZE(b); - min_len = Py_MIN(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); + minsize = self_size; + if (other_size < minsize) + minsize = other_size; + + cmp = memcmp(self_bytes.buf, other_bytes.buf, minsize); + /* In ISO C, memcmp() guarantees to use unsigned bytes! */ + + if (cmp == 0) { + if (self_size < other_size) + cmp = -1; + else if (self_size > other_size) + cmp = 1; } - 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_GT: c = c > 0; break; - case Py_GE: c = c >= 0; break; - default: - PyErr_BadArgument(); - return NULL; + case Py_LT: cmp = cmp < 0; break; + case Py_LE: cmp = cmp <= 0; break; + case Py_EQ: cmp = cmp == 0; break; + case Py_NE: cmp = cmp != 0; break; + case Py_GT: cmp = cmp > 0; break; + case Py_GE: cmp = cmp >= 0; break; } - result = c ? Py_True : Py_False; } - Py_INCREF(result); - return result; + res = cmp ? Py_True : Py_False; + PyBuffer_Release(&self_bytes); + PyBuffer_Release(&other_bytes); + Py_INCREF(res); + return res; + } static Py_hash_t