py/objrange: Implement (in)equality comparison between range objects.
This feature is not often used so is guarded by the config option MICROPY_PY_BUILTINS_RANGE_BINOP which is disabled by default. With this option disabled MicroPython will always return false when comparing two range objects for equality (unless they are exactly the same object instance). This does not match CPython so if (in)equality between range objects is needed then this option should be enabled. Enabling this option costs between 100 and 200 bytes of code space depending on the machine architecture.
This commit is contained in:
parent
5604b710c2
commit
d77da83d55
|
@ -787,6 +787,14 @@ typedef double mp_float_t;
|
|||
#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1)
|
||||
#endif
|
||||
|
||||
// Whether to support binary ops [only (in)equality is defined] between range
|
||||
// objects. With this option disabled all range objects that are not exactly
|
||||
// the same object will compare as not-equal. With it enabled the semantics
|
||||
// match CPython and ranges are equal if they yield the same sequence of items.
|
||||
#ifndef MICROPY_PY_BUILTINS_RANGE_BINOP
|
||||
#define MICROPY_PY_BUILTINS_RANGE_BINOP (0)
|
||||
#endif
|
||||
|
||||
// Whether to support timeout exceptions (like socket.timeout)
|
||||
#ifndef MICROPY_PY_BUILTINS_TIMEOUTERROR
|
||||
#define MICROPY_PY_BUILTINS_TIMEOUTERROR (0)
|
||||
|
|
|
@ -138,6 +138,24 @@ STATIC mp_obj_t range_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
|
|||
}
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BUILTINS_RANGE_BINOP
|
||||
STATIC mp_obj_t range_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
if (!MP_OBJ_IS_TYPE(rhs_in, &mp_type_range) || op != MP_BINARY_OP_EQUAL) {
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
}
|
||||
mp_obj_range_t *lhs = MP_OBJ_TO_PTR(lhs_in);
|
||||
mp_obj_range_t *rhs = MP_OBJ_TO_PTR(rhs_in);
|
||||
mp_int_t lhs_len = range_len(lhs);
|
||||
mp_int_t rhs_len = range_len(rhs);
|
||||
return mp_obj_new_bool(
|
||||
lhs_len == rhs_len
|
||||
&& (lhs_len == 0
|
||||
|| (lhs->start == rhs->start
|
||||
&& (lhs_len == 1 || lhs->step == rhs->step)))
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
if (value == MP_OBJ_SENTINEL) {
|
||||
// load
|
||||
|
@ -195,6 +213,9 @@ const mp_obj_type_t mp_type_range = {
|
|||
.print = range_print,
|
||||
.make_new = range_make_new,
|
||||
.unary_op = range_unary_op,
|
||||
#if MICROPY_PY_BUILTINS_RANGE_BINOP
|
||||
.binary_op = range_binary_op,
|
||||
#endif
|
||||
.subscr = range_subscr,
|
||||
.getiter = range_getiter,
|
||||
#if MICROPY_PY_BUILTINS_RANGE_ATTRS
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# test binary operations on range objects; (in)equality only
|
||||
|
||||
# this "feature test" actually tests the implementation but is the best we can do
|
||||
if range(1) != range(1):
|
||||
print("SKIP")
|
||||
raise SystemExit
|
||||
|
||||
# basic (in)equality
|
||||
print(range(1) == range(1))
|
||||
print(range(1) != range(1))
|
||||
print(range(1) != range(2))
|
||||
|
||||
# empty range
|
||||
print(range(0) == range(0))
|
||||
print(range(1, 0) == range(0))
|
||||
print(range(1, 4, -1) == range(6, 3))
|
||||
|
||||
# 1 element range
|
||||
print(range(1, 4, 10) == range(1, 4, 10))
|
||||
print(range(1, 4, 10) == range(1, 4, 20))
|
||||
print(range(1, 4, 10) == range(1, 8, 20))
|
||||
|
||||
# more than 1 element
|
||||
print(range(0, 3, 2) == range(0, 3, 2))
|
||||
print(range(0, 3, 2) == range(0, 4, 2))
|
||||
print(range(0, 3, 2) == range(0, 5, 2))
|
||||
|
||||
# unsupported binary op
|
||||
try:
|
||||
range(1) + 10
|
||||
except TypeError:
|
||||
print('TypeError')
|
Loading…
Reference in New Issue