Commit 9cb2b9f1 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Convert several classes to tp_richcompare

int, long, str, tuple, type

int and long are implemented using tp_compare in CPython,
which is the old-style comparison method.  I don't really understand
its semantics which rely on type coercion, and we don't have the
methods it needs, so just implement it as tp_richcompare for now.
I think this is still an overall compatibility improvement.

str_richcompare is very odd where we have to do some weird things
to convince the compiler to produce the best code it can.
parent 0554a034
......@@ -1650,6 +1650,13 @@ static Box* methodGetDoc(Box* b, void*) {
return None;
}
static Box* wrapperdescrGetDoc(Box* b, void*) {
assert(b->cls == wrapperdescr_cls);
auto s = static_cast<BoxedWrapperDescriptor*>(b)->wrapper->doc;
assert(s.size());
return boxString(s);
}
/* extension modules might be compiled with GC support so these
functions must always be available */
......@@ -1738,6 +1745,8 @@ void setupCAPI() {
new BoxedFunction(boxRTFunction((void*)BoxedWrapperDescriptor::__get__, UNKNOWN, 3)));
wrapperdescr_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperDescriptor::__call__,
UNKNOWN, 2, 0, true, true)));
wrapperdescr_cls->giveAttr("__doc__",
new (pyston_getset_cls) BoxedGetsetDescriptor(wrapperdescrGetDoc, NULL, NULL));
wrapperdescr_cls->freeze();
wrapperobject_cls->giveAttr(
......
......@@ -566,109 +566,6 @@ extern "C" Box* intTruediv(BoxedInt* lhs, Box* rhs) {
}
}
extern "C" Box* intEqInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls));
return boxBool(lhs->n == rhs->n);
}
extern "C" Box* intEq(BoxedInt* lhs, Box* rhs) {
if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__eq__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (isSubclass(rhs->cls, int_cls)) {
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxBool(lhs->n == rhs_int->n);
} else {
return NotImplemented;
}
}
extern "C" Box* intNeInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls));
return boxBool(lhs->n != rhs->n);
}
extern "C" Box* intNe(BoxedInt* lhs, Box* rhs) {
if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__ne__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (!isSubclass(rhs->cls, int_cls)) {
return NotImplemented;
}
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxBool(lhs->n != rhs_int->n);
}
extern "C" Box* intLtInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls));
return boxBool(lhs->n < rhs->n);
}
extern "C" Box* intLt(BoxedInt* lhs, Box* rhs) {
if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__lt__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (!isSubclass(rhs->cls, int_cls)) {
return NotImplemented;
}
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxBool(lhs->n < rhs_int->n);
}
extern "C" Box* intLeInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls));
return boxBool(lhs->n <= rhs->n);
}
extern "C" Box* intLe(BoxedInt* lhs, Box* rhs) {
if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__le__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (!isSubclass(rhs->cls, int_cls)) {
return NotImplemented;
}
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxBool(lhs->n <= rhs_int->n);
}
extern "C" Box* intGtInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls));
return boxBool(lhs->n > rhs->n);
}
extern "C" Box* intGt(BoxedInt* lhs, Box* rhs) {
if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__gt__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (!isSubclass(rhs->cls, int_cls)) {
return NotImplemented;
}
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxBool(lhs->n > rhs_int->n);
}
extern "C" Box* intGeInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls));
return boxBool(lhs->n >= rhs->n);
}
extern "C" Box* intGe(BoxedInt* lhs, Box* rhs) {
if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__ge__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (!isSubclass(rhs->cls, int_cls)) {
return NotImplemented;
}
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return boxBool(lhs->n >= rhs_int->n);
}
extern "C" Box* intLShiftInt(BoxedInt* lhs, BoxedInt* rhs) {
assert(isSubclass(lhs->cls, int_cls));
assert(isSubclass(rhs->cls, int_cls));
......@@ -1119,6 +1016,33 @@ static int64_t int_hash(BoxedInt* o) noexcept {
return n;
}
static PyObject* int_richcompare(PyObject* v, PyObject* w, int op) noexcept {
if (!PyInt_Check(v) || !PyInt_Check(w)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
int64_t lhs = static_cast<BoxedInt*>(v)->n;
int64_t rhs = static_cast<BoxedInt*>(w)->n;
switch (op) {
case Py_EQ:
return boxBool(lhs == rhs);
case Py_NE:
return boxBool(lhs != rhs);
case Py_LT:
return boxBool(lhs < rhs);
case Py_LE:
return boxBool(lhs <= rhs);
case Py_GT:
return boxBool(lhs > rhs);
case Py_GE:
return boxBool(lhs >= rhs);
default:
RELEASE_ASSERT(0, "%d", op);
}
}
void setupInt() {
for (int i = 0; i < NUM_INTERNED_INTS; i++) {
interned_ints[i] = new BoxedInt(i);
......@@ -1138,12 +1062,8 @@ void setupInt() {
int_cls->giveAttr("__pow__",
new BoxedFunction(boxRTFunction((void*)intPow, UNKNOWN, 3, 1, false, false), { None }));
_addFuncIntUnknown("__eq__", BOXED_BOOL, (void*)intEqInt, (void*)intEq);
_addFuncIntUnknown("__ne__", BOXED_BOOL, (void*)intNeInt, (void*)intNe);
_addFuncIntUnknown("__lt__", BOXED_BOOL, (void*)intLtInt, (void*)intLt);
_addFuncIntUnknown("__le__", BOXED_BOOL, (void*)intLeInt, (void*)intLe);
_addFuncIntUnknown("__gt__", BOXED_BOOL, (void*)intGtInt, (void*)intGt);
_addFuncIntUnknown("__ge__", BOXED_BOOL, (void*)intGeInt, (void*)intGe);
// Note: CPython implements int comparisons using tp_compare
int_cls->tp_richcompare = int_richcompare;
_addFuncIntUnknown("__lshift__", UNKNOWN, (void*)intLShiftInt, (void*)intLShift);
_addFuncIntUnknown("__rshift__", UNKNOWN, (void*)intRShiftInt, (void*)intRShift);
......
......@@ -20,6 +20,8 @@
#include "llvm/Support/raw_ostream.h"
#include "capi/typeobject.h"
#include "capi/types.h"
#include "core/common.h"
#include "core/options.h"
#include "core/stats.h"
......@@ -846,104 +848,18 @@ extern "C" Box* longXor(BoxedLong* v1, Box* _v2) {
return NotImplemented;
}
// TODO reduce duplication between these 6 functions, and add double support
Box* longGt(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__gt__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) > 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) > 0);
} else {
return NotImplemented;
}
}
Box* longGe(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__ge__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) >= 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) >= 0);
} else {
return NotImplemented;
}
}
Box* longLt(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__lt__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) < 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) < 0);
} else {
return NotImplemented;
}
}
Box* longLe(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__le__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) <= 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) <= 0);
} else {
return NotImplemented;
}
}
Box* longEq(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__eq__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) == 0);
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) == 0);
} else {
return NotImplemented;
}
}
Box* longNe(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__ne__' requires a 'long' object but received a '%s'", getTypeName(v1));
static PyObject* long_richcompare(Box* _v1, Box* _v2, int op) noexcept {
RELEASE_ASSERT(isSubclass(_v1->cls, long_cls), "");
BoxedLong* v1 = static_cast<BoxedLong*>(_v1);
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
return boxBool(mpz_cmp(v1->n, v2->n) != 0);
return convert_3way_to_object(op, mpz_cmp(v1->n, v2->n));
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
return boxBool(mpz_cmp_si(v1->n, v2->n) != 0);
return convert_3way_to_object(op, mpz_cmp_si(v1->n, v2->n));
} else {
return NotImplemented;
}
......@@ -1457,12 +1373,8 @@ void setupLong() {
long_cls->giveAttr("__xor__", new BoxedFunction(boxRTFunction((void*)longXor, UNKNOWN, 2)));
long_cls->giveAttr("__rxor__", long_cls->getattr("__xor__"));
long_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)longGt, UNKNOWN, 2)));
long_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)longGe, UNKNOWN, 2)));
long_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)longLt, UNKNOWN, 2)));
long_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)longLe, UNKNOWN, 2)));
long_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)longEq, UNKNOWN, 2)));
long_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)longNe, UNKNOWN, 2)));
// Note: CPython implements long comparisons using tp_compare
long_cls->tp_richcompare = long_richcompare;
long_cls->giveAttr("__lshift__", new BoxedFunction(boxRTFunction((void*)longLshift, UNKNOWN, 2)));
long_cls->giveAttr("__rshift__", new BoxedFunction(boxRTFunction((void*)longRshift, UNKNOWN, 2)));
......@@ -1488,6 +1400,7 @@ void setupLong() {
long_cls->giveAttr("numerator", new (pyston_getset_cls) BoxedGetsetDescriptor(longLong, NULL, NULL));
long_cls->giveAttr("denominator", new (pyston_getset_cls) BoxedGetsetDescriptor(long1, NULL, NULL));
add_operators(long_cls);
long_cls->freeze();
long_cls->tp_as_number->nb_power = long_pow;
......
......@@ -23,6 +23,7 @@
#include "Python.h"
#include "capi/typeobject.h"
#include "capi/types.h"
#include "core/common.h"
#include "core/types.h"
......@@ -1154,64 +1155,46 @@ extern "C" Box* strMul(BoxedString* lhs, Box* rhs) {
return boxString(buf);
}
extern "C" Box* strLt(BoxedString* lhs, Box* rhs) {
Box* str_richcompare(Box* lhs, Box* rhs, int op) {
assert(isSubclass(lhs->cls, str_cls));
if (!isSubclass(rhs->cls, str_cls))
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s() < srhs->s());
}
extern "C" Box* strLe(BoxedString* lhs, Box* rhs) {
assert(isSubclass(lhs->cls, str_cls));
if (!isSubclass(rhs->cls, str_cls))
return NotImplemented;
// Note: it is somehow about 50% faster to do this check inside the switch
// statement, rather than out here. It's functionally equivalent but the
// generated assembly is somehow quite better:
// if (unlikely(!PyString_Check(rhs)))
// return NotImplemented;
BoxedString* slhs = static_cast<BoxedString*>(lhs);
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s() <= srhs->s());
}
extern "C" Box* strGt(BoxedString* lhs, Box* rhs) {
assert(isSubclass(lhs->cls, str_cls));
if (!isSubclass(rhs->cls, str_cls))
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s() > srhs->s());
}
extern "C" Box* strGe(BoxedString* lhs, Box* rhs) {
assert(isSubclass(lhs->cls, str_cls));
if (!isSubclass(rhs->cls, str_cls))
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s() >= srhs->s());
}
extern "C" Box* strEq(BoxedString* lhs, Box* rhs) {
assert(isSubclass(lhs->cls, str_cls));
if (!isSubclass(rhs->cls, str_cls))
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s() == srhs->s());
}
extern "C" Box* strNe(BoxedString* lhs, Box* rhs) {
assert(isSubclass(lhs->cls, str_cls));
if (!isSubclass(rhs->cls, str_cls))
return NotImplemented;
BoxedString* srhs = static_cast<BoxedString*>(rhs);
return boxBool(lhs->s() != srhs->s());
switch (op) {
case Py_EQ:
if (unlikely(!PyString_Check(rhs)))
return NotImplemented;
return boxBool(slhs->s() == srhs->s());
case Py_NE:
if (unlikely(!PyString_Check(rhs)))
return NotImplemented;
return boxBool(slhs->s() != srhs->s());
case Py_LT:
if (unlikely(!PyString_Check(rhs)))
return NotImplemented;
return boxBool(slhs->s() < srhs->s());
case Py_LE:
if (unlikely(!PyString_Check(rhs)))
return NotImplemented;
return boxBool(slhs->s() <= srhs->s());
case Py_GT:
if (unlikely(!PyString_Check(rhs)))
return NotImplemented;
return boxBool(slhs->s() > srhs->s());
case Py_GE:
if (unlikely(!PyString_Check(rhs)))
return NotImplemented;
return boxBool(slhs->s() >= srhs->s());
default:
llvm_unreachable("invalid op");
}
}
#define JUST_LEFT 0
......@@ -2734,12 +2717,7 @@ void setupStr() {
// TODO not sure if this is right in all cases:
str_cls->giveAttr("__rmul__", new BoxedFunction(boxRTFunction((void*)strMul, UNKNOWN, 2)));
str_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)strLt, UNKNOWN, 2)));
str_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)strLe, UNKNOWN, 2)));
str_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)strGt, UNKNOWN, 2)));
str_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)strGe, UNKNOWN, 2)));
str_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)strEq, UNKNOWN, 2)));
str_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)strNe, UNKNOWN, 2)));
str_cls->tp_richcompare = str_richcompare;
BoxedString* spaceChar = boxStrConstant(" ");
str_cls->giveAttr("ljust",
......@@ -2763,6 +2741,7 @@ void setupStr() {
str_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)strNew, UNKNOWN, 2, 1, false, false), { EmptyString }));
add_operators(str_cls);
str_cls->freeze();
basestring_cls->giveAttr(
......
......@@ -225,89 +225,6 @@ Box* tupleRepr(BoxedTuple* t) {
return boxString(os.str());
}
Box* _tupleCmp(BoxedTuple* lhs, BoxedTuple* rhs, AST_TYPE::AST_TYPE op_type) {
int lsz = lhs->size();
int rsz = rhs->size();
bool is_order
= (op_type == AST_TYPE::Lt || op_type == AST_TYPE::LtE || op_type == AST_TYPE::Gt || op_type == AST_TYPE::GtE);
int n = std::min(lsz, rsz);
for (int i = 0; i < n; i++) {
Box* is_eq = compareInternal(lhs->elts[i], rhs->elts[i], AST_TYPE::Eq, NULL);
bool bis_eq = nonzero(is_eq);
if (bis_eq)
continue;
if (op_type == AST_TYPE::Eq) {
return boxBool(false);
} else if (op_type == AST_TYPE::NotEq) {
return boxBool(true);
} else {
Box* r = compareInternal(lhs->elts[i], rhs->elts[i], op_type, NULL);
return r;
}
}
if (op_type == AST_TYPE::Lt)
return boxBool(lsz < rsz);
else if (op_type == AST_TYPE::LtE)
return boxBool(lsz <= rsz);
else if (op_type == AST_TYPE::Gt)
return boxBool(lsz > rsz);
else if (op_type == AST_TYPE::GtE)
return boxBool(lsz >= rsz);
else if (op_type == AST_TYPE::Eq)
return boxBool(lsz == rsz);
else if (op_type == AST_TYPE::NotEq)
return boxBool(lsz != rsz);
RELEASE_ASSERT(0, "%d", op_type);
}
Box* tupleLt(BoxedTuple* self, Box* rhs) {
if (!isSubclass(rhs->cls, tuple_cls)) {
return NotImplemented;
}
return _tupleCmp(self, static_cast<BoxedTuple*>(rhs), AST_TYPE::Lt);
}
Box* tupleLe(BoxedTuple* self, Box* rhs) {
if (!isSubclass(rhs->cls, tuple_cls)) {
return NotImplemented;
}
return _tupleCmp(self, static_cast<BoxedTuple*>(rhs), AST_TYPE::LtE);
}
Box* tupleGt(BoxedTuple* self, Box* rhs) {
if (!isSubclass(rhs->cls, tuple_cls)) {
return NotImplemented;
}
return _tupleCmp(self, static_cast<BoxedTuple*>(rhs), AST_TYPE::Gt);
}
Box* tupleGe(BoxedTuple* self, Box* rhs) {
if (!isSubclass(rhs->cls, tuple_cls)) {
return NotImplemented;
}
return _tupleCmp(self, static_cast<BoxedTuple*>(rhs), AST_TYPE::GtE);
}
Box* tupleEq(BoxedTuple* self, Box* rhs) {
if (!isSubclass(rhs->cls, tuple_cls)) {
return NotImplemented;
}
return _tupleCmp(self, static_cast<BoxedTuple*>(rhs), AST_TYPE::Eq);
}
Box* tupleNe(BoxedTuple* self, Box* rhs) {
if (!isSubclass(rhs->cls, tuple_cls)) {
return NotImplemented;
}
return _tupleCmp(self, static_cast<BoxedTuple*>(rhs), AST_TYPE::NotEq);
}
Box* tupleNonzero(BoxedTuple* self) {
RELEASE_ASSERT(isSubclass(self->cls, tuple_cls), "");
return boxBool(self->size() != 0);
......@@ -442,6 +359,90 @@ static int64_t tuple_hash(BoxedTuple* v) noexcept {
return x;
}
static PyObject* tuplerichcompare(PyObject* v, PyObject* w, int op) noexcept {
BoxedTuple* vt, *wt;
Py_ssize_t i;
Py_ssize_t vlen, wlen;
if (!PyTuple_Check(v) || !PyTuple_Check(w)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
vt = (BoxedTuple*)v;
wt = (BoxedTuple*)w;
vlen = Py_SIZE(vt);
wlen = Py_SIZE(wt);
/* Note: the corresponding code for lists has an "early out" test
* here when op is EQ or NE and the lengths differ. That pays there,
* but Tim was unable to find any real code where EQ/NE tuple
* compares don't have the same length, so testing for it here would
* have cost without benefit.
*/
/* Search for the first index where items are different.
* Note that because tuples are immutable, it's safe to reuse
* vlen and wlen across the comparison calls.
*/
for (i = 0; i < vlen && i < wlen; i++) {
int k = PyObject_RichCompareBool(vt->elts[i], wt->elts[i], Py_EQ);
if (k < 0)
return NULL;
if (!k)
break;
}
if (i >= vlen || i >= wlen) {
/* No more items to compare -- compare sizes */
int cmp;
PyObject* res;
switch (op) {
case Py_LT:
cmp = vlen < wlen;
break;
case Py_LE:
cmp = vlen <= wlen;
break;
case Py_EQ:
cmp = vlen == wlen;
break;
case Py_NE:
cmp = vlen != wlen;
break;
case Py_GT:
cmp = vlen > wlen;
break;
case Py_GE:
cmp = vlen >= wlen;
break;
default:
return NULL; /* cannot happen */
}
if (cmp)
res = Py_True;
else
res = Py_False;
Py_INCREF(res);
return res;
}
/* We have an item that differs -- shortcuts for EQ/NE */
if (op == Py_EQ) {
Py_INCREF(Py_False);
return Py_False;
}
if (op == Py_NE) {
Py_INCREF(Py_True);
return Py_True;
}
/* Compare the final item again using the proper operator */
return PyObject_RichCompare(vt->elts[i], wt->elts[i], op);
}
void setupTuple() {
tuple_iterator_cls = BoxedHeapClass::create(type_cls, object_cls, &tupleIteratorGCHandler, 0, 0,
sizeof(BoxedTupleIterator), false, "tuple");
......@@ -460,12 +461,7 @@ void setupTuple() {
new BoxedFunction(boxRTFunction((void*)tupleIter, typeFromClass(tuple_iterator_cls), 1)));
tuple_cls->giveAttr("__lt__", new BoxedFunction(boxRTFunction((void*)tupleLt, UNKNOWN, 2)));
tuple_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)tupleLe, UNKNOWN, 2)));
tuple_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)tupleGt, UNKNOWN, 2)));
tuple_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)tupleGe, UNKNOWN, 2)));
tuple_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)tupleEq, UNKNOWN, 2)));
tuple_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)tupleNe, UNKNOWN, 2)));
tuple_cls->tp_richcompare = tuplerichcompare;
tuple_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)tupleNonzero, BOXED_BOOL, 1)));
......
......@@ -2294,6 +2294,63 @@ Box* decodeUTF8StringPtr(const std::string* s) {
return rtn;
}
static PyObject* type_richcompare(PyObject* v, PyObject* w, int op) noexcept {
PyObject* result;
Py_uintptr_t vv, ww;
int c;
/* Make sure both arguments are types. */
if (!PyType_Check(v) || !PyType_Check(w) ||
/* If there is a __cmp__ method defined, let it be called instead
of our dumb function designed merely to warn. See bug
#7491. */
Py_TYPE(v)->tp_compare || Py_TYPE(w)->tp_compare) {
result = Py_NotImplemented;
goto out;
}
/* Py3K warning if comparison isn't == or != */
if (Py_Py3kWarningFlag && op != Py_EQ && op != Py_NE
&& PyErr_WarnEx(PyExc_DeprecationWarning, "type inequality comparisons not supported "
"in 3.x",
1) < 0) {
return NULL;
}
/* Compare addresses */
vv = (Py_uintptr_t)v;
ww = (Py_uintptr_t)w;
switch (op) {
case Py_LT:
c = vv < ww;
break;
case Py_LE:
c = vv <= ww;
break;
case Py_EQ:
c = vv == ww;
break;
case Py_NE:
c = vv != ww;
break;
case Py_GT:
c = vv > ww;
break;
case Py_GE:
c = vv >= ww;
break;
default:
result = Py_NotImplemented;
goto out;
}
result = c ? Py_True : Py_False;
/* incref and return */
out:
Py_INCREF(result);
return result;
}
bool TRACK_ALLOCATIONS = false;
void setupRuntime() {
......@@ -2563,6 +2620,8 @@ void setupRuntime() {
new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedClass, tp_mro)));
type_cls->giveAttr("__subclasses__", new BoxedFunction(boxRTFunction((void*)typeSubclasses, UNKNOWN, 1)));
type_cls->giveAttr("mro", new BoxedFunction(boxRTFunction((void*)typeMro, UNKNOWN, 1)));
type_cls->tp_richcompare = type_richcompare;
add_operators(type_cls);
type_cls->freeze();
none_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)noneRepr, STR, 1)));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment